diff --git a/.gitee/ISSUE_TEMPLATE.zh-CN.md b/.gitee/ISSUE_TEMPLATE.zh-CN.md new file mode 100644 index 000000000..0bef0b792 --- /dev/null +++ b/.gitee/ISSUE_TEMPLATE.zh-CN.md @@ -0,0 +1,90 @@ +![输入图片说明](https://gitee.com/dotnetchina/Furion/raw/v4/handbook/static/img/tip.png) + +## 💢 特别说明:如果 Issue 没有严格按照模板编写且未提供测试源码下载或 Git 测试仓库地址,则视为无效 `Issue`,将无法得到答复。 + +### TouchSocket(Pro) 版本号 + +哪个版本号? + +--- + +### 哪个组件 + +- [ ] Tcp +- [ ] Udp +- [ ] Http +- [x] Websocket +- [ ] TouchRpc(基于:tcp、udp、http、websocket协议) +- [ ] JsonRpc(基于:tcp、http、websocket) +- [ ] XmlRpc +- [ ] WebApi +- [ ] 其他工具类组件(说明) + +--- + + +### .NET SDK 版本号 + +- [ ] .NET45 +- [ ] .NET461 +- [ ] .NET5 +- [x] .NET6 +- [ ] .NET7 + +--- + +### 项目类型 + +- [ ] Console +- [x] Winform +- [ ] WPF +- [ ] Unity3d +- [ ] Blazor Server +- [ ] MVC +- [ ] 其他(请说明) + + +--- + +### 操作系统和版本 + +- [x] Windows(版本) +- [ ] Linux(版本) +- [ ] MacOS(版本) +- [ ] 其他(版本) + +--- + +### 代码环境 + +- [x] 开发环境(Development) +- [ ] 生产环境(Production) +- [ ] 测试环境(Tests/单元测试/集成测试 ) + +--- + +### 描述你的问题 + +发生了什么? + +--- + +### 异常堆栈信息 + +异常堆栈是什么? + +--- + +### 测试项目代码 + +> **⚠⚠ 必须提供完整可运行且包含错误的 `Git` 仓库 DEMO,DEMO 提供最简单的错误逻辑代码,否则将无法得到答复。⚠⚠** + +您的代码下载地址? + +--- + +### 期待结果 + +期待的结果是? + +--- diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3e8a1553f --- /dev/null +++ b/.gitignore @@ -0,0 +1,341 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true +**/wwwroot/lib/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..b09cd7856 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/PerformanceTest.sln b/PerformanceTest.sln new file mode 100644 index 000000000..9ec7ab5b2 --- /dev/null +++ b/PerformanceTest.sln @@ -0,0 +1,30 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Rpc对比测试", "Rpc对比测试", "{49B4FE19-FB5C-4828-B01E-824B616C3563}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcPerformanceConsoleApp", "performancetest\Rpc对比测试\RpcPerformanceConsoleApp\RpcPerformanceConsoleApp.csproj", "{942F99CD-B6A9-42A0-9504-969465E69FA6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {942F99CD-B6A9-42A0-9504-969465E69FA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {942F99CD-B6A9-42A0-9504-969465E69FA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {942F99CD-B6A9-42A0-9504-969465E69FA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {942F99CD-B6A9-42A0-9504-969465E69FA6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {942F99CD-B6A9-42A0-9504-969465E69FA6} = {49B4FE19-FB5C-4828-B01E-824B616C3563} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {72E3B6D3-F2C0-4758-BADC-6EA7CF063120} + EndGlobalSection +EndGlobal diff --git a/README.en.md b/README.en.md new file mode 100644 index 000000000..86c2fb826 --- /dev/null +++ b/README.en.md @@ -0,0 +1,199 @@ +

+

+

+图片名称 +

+ +
+ +[![NuGet(TouchSocket)](https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket)](https://www.nuget.org/packages/TouchSocket/) +[![NuGet(TouchSocket)](https://img.shields.io/nuget/dt/TouchSocket.svg)](https://www.nuget.org/packages/TouchSocket/) +[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![star](https://gitee.com/dotnetchina/TouchSocket/badge/star.svg?theme=gvp)](https://gitee.com/dotnetchina/TouchSocket/stargazers) +[![fork](https://gitee.com/dotnetchina/TouchSocket/badge/fork.svg?theme=gvp)](https://gitee.com/dotnetchina/TouchSocket/members) + +QQ + +[![NuGet(TouchSocket)](https://img.shields.io/github/stars/RRQM/TouchSocket?logo=github)](https://github.com/RRQM/TouchSocket) + +
+ +
+ +雄关漫道真如铁,而今迈步从头越。从头越,苍山如海,残阳如血。 + +
+ +English | [中文](README.md) + +## 🎀Describe + +【Open source version】 +| Nuget|Url |Describe| +|---|---|---| +|[![NuGet version (TouchSocket)](https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket)](https://www.nuget.org/packages/TouchSocket)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)
[Github](https://github.com/RRQM/TouchSocket)| TouchSocket is a lightweight, comprehensive network communication library that supports plug-in.
Basic communication functions include TCP, UDP, SSL, RPC, HTTP, etc. Among them, HTTP
server supports extended plugins such as WebSocket, Static web pages, XMLRPC, Webapi, JSONRPC
. Touchrpc with a custom protocol, support SSL encryption, asynchronous calls,
permissions management, error status return, service recovery, distributed calls, etc. When the empty load function
executes, 100,000 calls are only 3.8 seconds, and only 0.9 seconds when the state is not returned.| +| [![NuGet version (TouchSocket.AspNetCore)](https://img.shields.io/nuget/v/TouchSocket.AspNetCore.svg?label=TouchSocket.AspNetCore)](https://www.nuget.org/packages/TouchSocket.AspNetCore)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)
[Github](https://github.com/RRQM/TouchSocket) | TouchSocket.AspNetCore is an exclusive version suitable for Aspnetcore.| + +【Enterprise version】 +| Nuget|Url |Describe| +|---|---|---| +|[![NuGet version (TouchSocketPro)](https://img.shields.io/nuget/v/TouchSocketPro.svg?label=TouchSocketPro)](https://www.nuget.org/packages/TouchSocketPro)|[Gitee](https://gitee.com/dotnetchina/TouchSocketPro)
[Github](https://github.com/RRQM/TouchSocketPro)| TouchSocketpro is the enterprise version of TouchSocket, which is based on the original.
There are also some corporate versions. For details, please see [Enterprise Edition Related](https://www.yuque.com/rrqm/touchsocket/80696720a95e415d94c87fa03642513d)| +| [![NuGet version (TouchSocketPro.AspNetCore)](https://img.shields.io/nuget/v/TouchSocketPro.AspNetCore.svg?label=TouchSocketPro.AspNetCore)](https://www.nuget.org/packages/TouchSocketPro.AspNetCore)|[Gitee](https://gitee.com/dotnetchina/TouchSocketPro)
[Github](https://github.com/RRQM/TouchSocketPro) | TouchSocketpro.aspnetcore is an exclusive version suitable for Aspnetcore.| + +## 🖥Support environment +- .NET Framework4.5 Above。 +- .NET Core3.1 Above。 +- .NET Standard2.0 Above。 + +## 🥪Support framework +- Console +- WPF +- Winform +- Blazor Server +- Xamarin +- MAUI +- Avalonia +- Mono +- Unity 3D(Except webgl) +- Others (that is, all C#) + + +## 🌴TouchSocket Features Speed + +#### IOCP mode of traditional IOCP and TouchSocket + +TouchSocket's IOCP is not the same as tradition. Take the official example of Microsoft as an example. Receive data,Then process the copy of the data. And TouchSocket takes a available memory block from the memory pool each time before receiving, and then **is directly used to receive**. After receiving the data, it will directly throw this memory block and process it. Operation, although it is only a small design, when the data of the transmission **10W** times **64KB**, the performance is different **10 times**。 + +#### Data handle adapter + +I believe that everyone has used other socket products, so TouchSocket also borrows the excellent design concept of other products during design. Data processing adapter is one of them, but unlike the design of other products, TouchSocket's adapter functions are more powerful. Easy to use and flexible. It can not only analyze the data packet in advance, but also parse the data object, which can be replaced at any time, and then take effect immediately. For example: the data can be pre -processed using a fixed Baotou to solve the problem of **data subcontracting and** sticky bags. You can also directly analyze the **http** data protocol, WebSocket data protocol, etc. + +#### Compatibility and adaptation + +TouchSocket offers a variety of framework models that can be fully compatible with all protocols in the TCP and UDP protocols. For example: TCPSERVICE and TCPClient, their basic functions are exactly the same as sockets, but they only enhance the framework of the framework and concurrent and connect and to receive data. Out, allowing users to use more friendly use. + +## 🔗Contact the author + +- [CSDN blog homepage](https://blog.csdn.net/qq_40374647) +- [Bilibili video](https://space.bilibili.com/94253567) +- [Source code warehouse homepage](https://gitee.com/RRQM_Home) +- Exchange QQ group:234762506 + +## 🌟Explanation document +- [ Homepage ](http://rrqm_home.gitee.io/touchsocket) + +## 👑Functional cousin + +

+图片名称 +

+ +## ✨Simple example + + **_The following only examples are created in the simplest way. For more details, please see [Explanation Document](http://rrqm_home.gitee.io/touchsocket)。_** + + **【TcpService】** + +``` +TcpService service = new TcpService(); +service.Connecting = (client, e) => { };//Some client is connecting +service.Connected = (client, e) => { };//There is a client connection +service.Disconnected = (client, e) => { };//There is a client that is cut off and connected +service.Received = (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = byteBlock.ToString(); + Console.WriteLine($"Receive information from {client.id}:{mes}"); + + client.Send(mes);//Return the received information directly to the sender + + //client.Send("id",mes);//Return the received information to the client with a specific ID + + var clients = service.GetClients(); + foreach (var targetClient in clients)//Return the received information to all the clients online。 + { + if (targetClient.ID != client.ID) + { + targetClient.Send(mes); + } + } +}; + +service.Setup(new TouchSocketConfig()//Load + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//At the same time, listen to two addresses + .SetMaxCount(10000) + .SetThreadCount(100)) + .Start();//start up +``` + + **【TcpClient】** +``` +TcpClient tcpClient = new TcpClient(); +tcpClient.Connected = (client, e) => { };//Successfully connect to the server +tcpClient.Disconnected = (client, e) => { };//The connection is disconnected from the server, and it will not be triggered when the connection is unsuccessful. +tcpClient.Received = (client, byteBlock, requestInfo) => +{ + //Receive information from the server + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + Console.WriteLine($"Receive information: {MES}"); +}; + +//Declaration configuration +TouchSocketConfig config = new TouchSocketConfig(); +config.SetRemoteIPHost(new IPHost("127.0.0.1:7789")) + .UsePlugin() + .SetBufferLength(1024 * 10); + +//Load +tcpClient.Setup(config); +tcpClient.Connect(); +tcpClient.Send("RRQM"); +``` + + **【TcpClient Break】** +In the config plug -in configuration, you must first enable the plug -in, and then use the re -connected plug -in. + +``` +.UsePlugin() +.ConfigurePlugins(a=> +{ + a.UseReconnection(5, true, 1000); +}); +``` + + **【FixedHeaderPackageAdapter包模式】** + +This adapter mainly solves the problem of TCP adhesion package. The data format adopts a simple and efficient "Baotou+Data Body" mode. Among them, Baotou supports: + +- Byte mode (1+n), one -time receives a maximum of 255 bytes. +- USHORT mode (2+n), maximum receiving 65535 bytes. +- INT mode (4+n), a maximum receiving 2G data at a time. + +The above data header adopts the default end mode (small end mode) of TouchSocketbitConverter. Users can switch the default end mode according to the requirements. + +``` +TouchSocketBitConverter.DefaultEndianType = EndianType.Little; +``` + + **【CustomFixedHeaderDataHandlingAdapter】** + +Users customize fixed Baotou adapters mainly help users solve data frame information with fixed Baotou. For example: The following data format needs to be implemented with only a few interfaces to complete the analysis. For detailed operations, please refer to the API. + +|1|1|1|**********| + + **【CustomUnfixedHeaderDataHandlingAdapter】** + +Users customize non -fixed Baotou adapters mainly help users solve the data frame information with non -fixed Baotou. For example: the most typical HTTP packet, the data head and the data body are separated by "\r\n", and the data header is not fixed due to the different request information of the request request, and the length of the data body is not fixed, and the length of the data body is It is also specified by the value display of the data head, so you can consider using the CustomunfixedHeaderDatahandlingAdapter analysis, which can be achieved only through simple development. + +## 🧲Application scenario simulation +[Scene entrance](https://www.yuque.com/rrqm/touchsocket/wrwx9k) + +*** + +## Thank you + +Thank you for your support for TouchSocket. If you have any other questions, please submit it, or add a group of QQ: 234762506 discussion. + +## Support author + +[Support entrance](https://www.yuque.com/rrqm/touchsocket/a5199820843b324f025633fdeee44394) diff --git a/README.md b/README.md new file mode 100644 index 000000000..6107b3b96 --- /dev/null +++ b/README.md @@ -0,0 +1,204 @@ +

+

+

+图片名称 +

+ +
+ +[![NuGet(TouchSocket)](https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket)](https://www.nuget.org/packages/TouchSocket/) +[![NuGet(TouchSocket)](https://img.shields.io/nuget/dt/TouchSocket.svg)](https://www.nuget.org/packages/TouchSocket/) +[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![star](https://gitee.com/RRQM_Home/TouchSocket/badge/star.svg?theme=gvp)](https://gitee.com/RRQM_Home/TouchSocket/stargazers) +[![fork](https://gitee.com/RRQM_Home/TouchSocket/badge/fork.svg?theme=gvp)](https://gitee.com/RRQM_Home/TouchSocket/members) + +QQ + +[![NuGet(TouchSocket)](https://img.shields.io/github/stars/RRQM/TouchSocket?logo=github)](https://github.com/RRQM/TouchSocket) + +
+ +
+ +雄关漫道真如铁,而今迈步从头越。从头越,苍山如海,残阳如血。 + +
+ +中文 | [English](README.en.md) + +## 🎀描述 + +![Alt](https://repobeats.axiom.co/api/embed/7b543e0b31f0488b08dfd319fafca0044dfd1050.svg "Repobeats analytics image") + +【开源版】 +| 名称|地址 |描述| +|---|---|---| +|[![NuGet version (TouchSocket)](https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket)](https://www.nuget.org/packages/TouchSocket)|[Gitee](https://gitee.com/RRQM_Home/TouchSocket)
[Github](https://github.com/RRQM/TouchSocket)| TouchSocket这是一个轻量级的、支持插件的综合网络通信库。
基础通信功能包含Tcp、Udp、Ssl、Rpc、Http等。其中http
服务器支持WebSocket、静态网页、XmlRpc、WebApi、JsonRpc
等扩展插件。和自定义协议的TouchRpc,支持Ssl加密、异步调用、
权限管理、错误状态返回、服务回调、分布式调用等。在空载函数
执行时,10万次调用仅3.8秒,在不返回状态时,仅0.9秒。| +| [![NuGet version (TouchSocket.AspNetCore)](https://img.shields.io/nuget/v/TouchSocket.AspNetCore.svg?label=TouchSocket.AspNetCore)](https://www.nuget.org/packages/TouchSocket.AspNetCore)|[Gitee](https://gitee.com/RRQM_Home/TouchSocket)
[Github](https://github.com/RRQM/TouchSocket) | TouchSocket.AspNetCore是适用于AspNetCore的专属版本。| + +【企业版】 +| 名称|地址 |描述| +|---|---|---| +|[![NuGet version (TouchSocketPro)](https://img.shields.io/nuget/v/TouchSocketPro.svg?label=TouchSocketPro)](https://www.nuget.org/packages/TouchSocketPro)|[Gitee](https://gitee.com/RRQM_Home/TouchSocketPro)
[Github](https://github.com/RRQM/TouchSocketPro)| TouchSocketPro是TouchSocket的企业版,这在原有基础之上,
还有一些企业版功能,详情请看[企业版相关](https://www.yuque.com/rrqm/touchsocket/80696720a95e415d94c87fa03642513d)| +| [![NuGet version (TouchSocketPro.AspNetCore)](https://img.shields.io/nuget/v/TouchSocketPro.AspNetCore.svg?label=TouchSocketPro.AspNetCore)](https://www.nuget.org/packages/TouchSocketPro.AspNetCore)|[Gitee](https://gitee.com/RRQM_Home/TouchSocketPro)
[Github](https://github.com/RRQM/TouchSocketPro) | TouchSocketPro.AspNetCore是适用于AspNetCore的专属版本。| + +#### 特别声明 +TouchSocket项目已加入[dotNET China](https://gitee.com/dotnetchina) 组织。
+![dotnetchina](https://images.gitee.com/uploads/images/2021/0324/120117_2da9922c_416720.png "132645_21007ea0_974299.png") + + +## 🖥支持环境 +- .NET Framework4.5及以上。 +- .NET Core3.1及以上。 +- .NET Standard2.0及以上。 + +## 🥪支持框架 +- Console +- WPF +- Winform +- Blazor Server +- Xamarin +- MAUI +- Avalonia +- Mono +- Unity 3D(除WebGL) +- 其他(即所有C#系) + + +## 🌴TouchSocket特点速览 + +#### 传统IOCP和TouchSocket的IOCP模式 + +TouchSocket的IOCP和传统也不一样,就以微软官方示例为例,他是使用MemoryBuffer开辟一块内存,均分,然后给每个会话分配一个区接收,等收到数据后,再**复制**接收的数据,然后把复制的数据进行处理。而TouchSocket是每次接收之前,从内存池拿一个可用内存块,然后**直接用于接收**,等收到数据以后,直接就把这个内存块抛出处理,这样就避免了**复制操作**,虽然只是细小的设计,但是在传输**10w**次**64kb**的数据时,性能相差了**10倍**。 + +#### 数据处理适配器 + +相信大家都使用过其他的Socket产品,那么TouchSocket在设计时也是借鉴了其他产品的优秀设计理念,数据处理适配器就是其中之一,但和其他产品的设计不同的是,TouchSocket的适配器功能更加强大,易用,且灵活。它不仅可以提前解析数据包,还可以解析数据对象,可以随时替换,然后立即生效。例如:可以使用固定包头对数据进行预处理,从而解决**数据分包**、**粘包**的问题。也可以直接解析**HTTP**数据协议、WebSocket数据协议等。 + +#### 兼容性与适配 + +TouchSocket提供多种框架模型,能够完全兼容基于TCP、UDP协议的所有协议。例如:TcpService与TcpClient,其基础功能和Socket一模一样,只是增强了框架的**坚固性**和**并发性**,将**连接**和**接收数据**通过事件的形式抛出,让使用者能够更加友好的使用。 + +## 🔗联系作者 + +- [CSDN博客主页](https://blog.csdn.net/qq_40374647) +- [哔哩哔哩视频](https://space.bilibili.com/94253567) +- [源代码仓库主页](https://gitee.com/RRQM_Home) +- 交流QQ群:234762506 + +## 🌟说明文档 +- [ 文档首页 ](http://rrqm_home.gitee.io/touchsocket) + +## 👑功能导图 + +

+图片名称 +

+ +## ✨简单示例 + + **_以下仅以最简方式创建示例,更多详情请查看[说明文档](http://rrqm_home.gitee.io/touchsocket)。_** + + **【TcpService】** + +``` +TcpService service = new TcpService(); +service.Connecting = (client, e) => { };//有客户端正在连接 +service.Connected = (client, e) => { };//有客户端连接 +service.Disconnected = (client, e) => { };//有客户端断开连接 +service.Received = (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = byteBlock.ToString(); + Console.WriteLine($"已从{client.ID}接收到信息:{mes}"); + + client.Send(mes);//将收到的信息直接返回给发送方 + + //client.Send("id",mes);//将收到的信息返回给特定ID的客户端 + + var clients = service.GetClients(); + foreach (var targetClient in clients)//将收到的信息返回给在线的所有客户端。 + { + if (targetClient.ID != client.ID) + { + targetClient.Send(mes); + } + } +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) }))//同时监听两个地址 + .Start();//启动 +``` + + **【TcpClient】** +``` +TcpClient tcpClient = new TcpClient(); +tcpClient.Connected = (client, e) => { };//成功连接到服务器 +tcpClient.Disconnected = (client, e) => { };//从服务器断开连接,当连接不成功时不会触发。 +tcpClient.Received = (client, byteBlock, requestInfo) => +{ + //从服务器收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + Console.WriteLine($"接收到信息:{mes}"); +}; + +//声明配置 +TouchSocketConfig config = new TouchSocketConfig(); +config.SetRemoteIPHost(new IPHost("127.0.0.1:7789")) + .UsePlugin() + .SetBufferLength(1024 * 10); + +//载入配置 +tcpClient.Setup(config); +tcpClient.Connect(); +tcpClient.Send("RRQM"); +``` + + **【TcpClient 断线重连】** +在Config的插件配置中,首先得启用插件,然后使用重连插件即可。 + +``` +.UsePlugin() +.ConfigurePlugins(a=> +{ + a.UseReconnection(5, true, 1000); +}); +``` + + **【FixedHeaderPackageAdapter包模式】** + +该适配器主要解决TCP粘分包问题,数据格式采用简单而高效的“包头+数据体”的模式,其中包头支持: + +- Byte模式(1+n),一次性最大接收255字节的数据。 +- Ushort模式(2+n),一次最大接收65535字节。 +- Int模式(4+n),一次最大接收2G数据。 + +以上数据头均采用TouchSocketBitConverter的默认端模式(小端模式),使用者可以根据需求切换默认端模式。 + +``` +TouchSocketBitConverter.DefaultEndianType = EndianType.Little; +``` + + **【CustomFixedHeaderDataHandlingAdapter】** + +用户自定义固定包头适配器,主要帮助用户解决具有固定包头的数据帧信息。例如:下列数据格式,仅需要实现几个接口,就能完成解析,详细操作请参照API。 + +|1|1|1|**********| + + **【CustomUnfixedHeaderDataHandlingAdapter】** + +用户自定义不固定包头适配器,主要帮助用户解决具有包头不固定的数据帧信息。例如:最典型的HTTP数据包,其数据头和数据体由“\r\n”隔开,而数据头又因为请求者的请求信息的不同,头部数据也不固定,而数据体的长度,也是由数据头的ContentLength的值显式指定的,所以可以考虑使用CustomUnfixedHeaderDataHandlingAdapter解析,也是仅通过简单的开发,就能实现。 + +## 🧲应用场景模拟 +[场景入口](https://www.yuque.com/rrqm/touchsocket/wrwx9k) + +*** + +## 致谢 + +谢谢大家对TouchSocket的支持,如果还有其他问题,请提交Issue,或者加群QQ:234762506讨论。 + +## 支持作者 + +[支持入口](https://www.yuque.com/rrqm/touchsocket/a5199820843b324f025633fdeee44394) diff --git a/TouchSocket.sln b/TouchSocket.sln new file mode 100644 index 000000000..73684a8c7 --- /dev/null +++ b/TouchSocket.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33122.133 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchSocket", "src\TouchSocket\TouchSocket.csproj", "{37BF3CB2-9003-465D-A936-7373301FDA5C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchSocket.AspNetCore", "src\TouchSocket.AspNetCore\TouchSocket.AspNetCore.csproj", "{6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {37BF3CB2-9003-465D-A936-7373301FDA5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37BF3CB2-9003-465D-A936-7373301FDA5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37BF3CB2-9003-465D-A936-7373301FDA5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37BF3CB2-9003-465D-A936-7373301FDA5C}.Release|Any CPU.Build.0 = Release|Any CPU + {6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DB787235-A13A-4A3D-B5A8-5DFEB6511EEE} + EndGlobalSection +EndGlobal diff --git a/TouchSocketExample.sln b/TouchSocketExample.sln new file mode 100644 index 000000000..ca3559464 --- /dev/null +++ b/TouchSocketExample.sln @@ -0,0 +1,492 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32922.545 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tcp简单示例", "Tcp简单示例", "{FB46E926-0EEC-488C-B950-A16D2E7F694B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Udp简单示例", "Udp简单示例", "{F4D798A3-8D65-4750-9552-B02BCE081508}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Adapter简单示例", "Adapter简单示例", "{F8C07F29-7233-4FD3-A3DC-45963071E20A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugin简单示例", "Plugin简单示例", "{397AE2E0-1FB6-4B71-A888-328FF7FA05B4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Consul简单示例", "Consul简单示例", "{B405B0AE-6ECD-4586-B3D6-9D875073DFAF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NATService简单示例", "NATService简单示例", "{825D21FC-245C-4B6B-B237-E4ADEB2C98DC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ssl证书相关", "Ssl证书相关", "{4D592C10-4AF8-435E-9DB2-A718AB9BF9C4}" + ProjectSection(SolutionItems) = preProject + examples\Ssl证书相关\证书生成.zip = examples\Ssl证书相关\证书生成.zip + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdapterConsoleApp", "examples\Adapter简单示例\AdapterConsoleApp\AdapterConsoleApp.csproj", "{65823091-FE7C-4B96-96AB-1D4D09B45DA2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TouchRpc集群", "TouchRpc集群", "{DC9E894F-E65F-443E-9F4E-6FEDB46F06DC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinFormsApp", "examples\Consul集群示例\TouchRpc Consul集群\WinFormsApp\WinFormsApp.csproj", "{558B024C-981D-4288-99D2-5B6C0C30C427}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceConsoleApp", "examples\Consul集群示例\TouchRpc Consul集群\ServiceConsoleApp\ServiceConsoleApp.csproj", "{FF655439-DFFE-4BE4-AB76-BC84EE188C7F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tcp集群", "Tcp集群", "{82B05679-3A56-4E9A-BFA3-B68D29821B8A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsulConsoleApp", "examples\Consul集群示例\ConsulConsoleApp\ConsulConsoleApp.csproj", "{A9C4DF80-0A9F-4979-AB4B-201A5B573A61}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NATServiceConsoleApp", "examples\NAT简单示例\NATServiceConsoleApp\NATServiceConsoleApp.csproj", "{FF839E56-FD43-4CEF-9775-B440D6BA4099}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginConsoleApp", "examples\Plugin简单示例\PluginConsoleApp\PluginConsoleApp.csproj", "{A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceApp", "examples\Tcp简单示例\ServiceApp\ServiceApp.csproj", "{6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientApp", "examples\Tcp简单示例\ClientApp\ClientApp.csproj", "{0B7591F5-37C8-4570-ACEF-782CE3F12957}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UdpDemoApp", "examples\Udp简单示例\UdpDemoApp\UdpDemoApp.csproj", "{31026659-0E64-4344-A8E2-A3C5477E4A94}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JsonRpc简单示例", "JsonRpc简单示例", "{969A695E-BEB5-45B8-93D8-B31640FA495D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonRpcConsoleApp", "examples\JsonRpc简单示例\JsonRpcConsoleApp\JsonRpcConsoleApp.csproj", "{F9E0154E-2DFC-480F-9B3A-B30548C41DFD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Http简单示例", "Http简单示例", "{EFB33E23-9E98-4B85-99E4-865705D5ACD2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceConsoleApp", "examples\Http简单示例\ConsoleApp\ServiceConsoleApp.csproj", "{AF8A5195-E56B-41E6-85A2-83E501E69500}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebApi简单示例", "WebApi简单示例", "{5836A018-B0F3-4D6F-8C45-FC1E9C85D51A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApiServerApp", "examples\WebApi简单示例\WebApiServer\WebApiServerApp.csproj", "{725CF25C-F3F0-4833-A501-8FD8F3596837}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApiClientApp", "examples\WebApi简单示例\WebApiClientApp\WebApiClientApp.csproj", "{BF73D290-6C07-4EC6-8546-447F15B543C7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XmlRpc简单示例", "XmlRpc简单示例", "{94F46729-90A8-415A-92E0-2D996D3210B4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XmlRpcServerApp", "examples\XmlRpc简单示例\XmlRpcServerApp\XmlRpcServerApp.csproj", "{54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XmlRpcClientApp", "examples\XmlRpc简单示例\XmlRpcClientApp\XmlRpcClientApp.csproj", "{F933280F-F5C2-4145-B857-A70B921D940A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventBus简单示例", "EventBus简单示例", "{5E9585EE-934F-41B4-9ECA-FB0C55A155EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusServer", "examples\EventBus简单示例\EventBusServer\EventBusServer.csproj", "{A6358094-56E0-4DF3-BA95-319D676C0A04}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusClient", "examples\EventBus简单示例\EventBusClient\EventBusClient.csproj", "{30A64984-243D-4745-807E-B084BA51B968}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FileTransfer简单示例", "FileTransfer简单示例", "{24212B0A-8DAA-4AC3-BB5D-F3AC485EABA4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TouchRpc简单示例", "TouchRpc简单示例", "{54A8216A-AA96-4293-9285-D2173E1D2E69}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchRpcServerApp", "examples\TouchRpc简单示例\TouchRpcServerApp\TouchRpcServerApp.csproj", "{613B3E85-59DE-4314-9A3A-EEE7C03E207F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchRpcClientApp", "examples\TouchRpc简单示例\TouchRpcClientApp\TouchRpcClientApp.csproj", "{D367F50D-0B27-4B46-9872-695DC6B021BF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "基于AspNetCore的WebSocket协议", "基于AspNetCore的WebSocket协议", "{5C17B127-95DD-480C-BDCC-7FDF5E645B0C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchRpcWebApplication", "examples\TouchRpc简单示例\基于AspNetCore的WebSocket协议\TouchRpcWebApplication\TouchRpcWebApplication.csproj", "{35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WSTouchRpcClientConsoleApp", "examples\TouchRpc简单示例\基于AspNetCore的WebSocket协议\WSTouchRpcClientConsoleApp\WSTouchRpcClientConsoleApp.csproj", "{5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtocolServerConsoleApp", "examples\TouchRpc简单示例\ProtocolServerConsoleApp\ProtocolServerConsoleApp.csproj", "{571F2732-7E54-42A8-BEC6-B97B0A651059}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "控制台", "控制台", "{DB89FCB6-E4F9-4BD4-93F3-4E857741D749}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "examples\Tcp简单示例\ConsoleApp\ConsoleApp.csproj", "{71D8B6B2-09F3-4060-B073-A3F5D944C304}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSocket简单示例", "WebSocket简单示例", "{84D1227F-3419-4BCD-9331-8B61B2C19784}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSocketConsoleApp", "examples\WebSocket简单示例\WebSocketConsoleApp\WebSocketConsoleApp.csproj", "{5F9D5028-12C8-4819-9B8E-ACE017B63132}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WSFormClientApp", "examples\WebSocket简单示例\WSFormClientApp\WSFormClientApp.csproj", "{1B247610-9FAD-4434-BA15-B1DB1F71B7C5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileServiceGUI", "examples\FileTransfer简单示例\FileServiceGUI\FileServiceGUI.csproj", "{2017B959-1B58-453A-B65D-2F737E6B96DC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileClientGUI", "examples\FileTransfer简单示例\FileClientGUI\FileClientGUI.csproj", "{8BFDA2E0-E7B6-4592-86B8-53426A8C0848}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BlogsDemos", "BlogsDemos", "{EB38E883-88AF-4E4C-9DCD-FAEBD8A20968}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HeartbeatConsoleApp", "examples\BlogsDemos\HeartbeatConsoleApp\HeartbeatConsoleApp.csproj", "{06B4A342-2E42-4F66-A0FE-CD6110DDF980}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LimitNumberOfConnectionsConsoleApp", "examples\BlogsDemos\LimitNumberOfConnectionsConsoleApp\LimitNumberOfConnectionsConsoleApp.csproj", "{8452EA31-F7BB-4897-8881-F3EE3F82049A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThrottlingConsoleApp", "examples\BlogsDemos\ThrottlingConsoleApp\ThrottlingConsoleApp.csproj", "{DD7848E5-3489-454E-BF37-49B6FE4C7F01}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrafficCounterConsoleApp", "examples\BlogsDemos\TrafficCounterConsoleApp\TrafficCounterConsoleApp.csproj", "{82A783ED-11AD-407D-990B-A6AE9D557290}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UDP屏幕捕捉器", "UDP屏幕捕捉器", "{8B9374B5-42D7-48C9-84C7-A560167F0D47}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenUdpSender", "examples\Udp简单示例\UDP屏幕捕捉器\ScreenUdpSender\ScreenUdpSender.csproj", "{791D316B-41D7-4B19-A25B-A58EBEA4E04A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenUdpReceiver", "examples\Udp简单示例\UDP屏幕捕捉器\ScreenUdpReceiver\ScreenUdpReceiver.csproj", "{EDAA9CD3-1474-4588-9E3B-E970CED20F0F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "反向Rpc示例", "反向Rpc示例", "{5777979E-5737-46EF-9B0E-9C18FA7004B6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseRpcConsoleApp", "examples\TouchRpc简单示例\反向Rpc示例\ReverseRpcConsoleApp\ReverseRpcConsoleApp.csproj", "{D5738DF3-C8E8-4E21-98B2-0557F0392167}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "控制台", "控制台", "{FB0FA0CF-1657-48F7-B852-FBA818F1AE8A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileServiceConsoleApp", "examples\FileTransfer简单示例\FileClientApp\FileServiceConsoleApp\FileServiceConsoleApp.csproj", "{8C6EA0F4-78F6-4E5F-B633-848355B06331}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileClientConsoleApp", "examples\FileTransfer简单示例\FileClientConsoleApp\FileClientConsoleApp.csproj", "{EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "远程文件系统访问简单示例", "远程文件系统访问简单示例", "{1DE974CF-D77E-4E9B-B3F9-7E5A3F9C4A67}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerConsoleApp", "examples\远程文件系统访问简单示例\ServerConsoleApp\ServerConsoleApp.csproj", "{707CC6CD-17D0-4EC8-9CF7-D056F7740EC6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientWinFormsApp", "examples\远程文件系统访问简单示例\ClientWinFormsApp\ClientWinFormsApp.csproj", "{82E99507-C5AA-4AC0-A857-6294D5CF9FFA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BytePool简单示例", "BytePool简单示例", "{6D046723-8625-4D69-BD71-64E5F43B210A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BytePoolConsoleApp", "examples\BytePool简单示例\BytePoolConsoleApp\BytePoolConsoleApp.csproj", "{F5AA7892-A533-4603-959F-A990AE569C59}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unity3d简单示例", "Unity3d简单示例", "{59C3DFB0-C6E1-4F7E-AD9D-9857A4153A1E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnityServerConsoleApp", "examples\Unity3d简单示例\UnityServer\UnityServerConsoleApp\UnityServerConsoleApp.csproj", "{F645710B-4FE8-430C-9860-B289743CAE23}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AspNetCore", "AspNetCore", "{97C928E3-54D6-4FAE-A314-775BE9E25A14}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpServiceForWebApi", "examples\Tcp简单示例\AspNetCore\TcpServiceForWebApi\TcpServiceForWebApi.csproj", "{E629B642-AF9B-4FB6-AFE3-6258E2F0B953}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TLVWinFormsApp", "examples\Adapter简单示例\TLVWinFormsApp\TLVWinFormsApp.csproj", "{E72ADFB6-4AA5-4210-BC6B-A68927644526}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppMessenger简单示例", "AppMessenger简单示例", "{DFAE990A-30E8-4974-A130-D66E9B3486B7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinAppForAppMessenger", "examples\AppMessenger简单示例\WinAppForAppMessenger\WinAppForAppMessenger.csproj", "{66849ED5-C951-450A-8867-AE5FA8109FC3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PipelineConsoleApp", "examples\Adapter简单示例\PipelineConsoleApp\PipelineConsoleApp.csproj", "{D5892A0B-DE58-42C2-B5EE-E1C34745493B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Log4net日志注入", "Log4net日志注入", "{14C9DCF7-767F-48F5-956F-782161BA2420}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Log4netConsoleApp", "examples\Log4net日志注入\Log4netConsoleApp\Log4netConsoleApp.csproj", "{0E76C63C-66CC-43BE-A6AF-A7862E669C2F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "包序列化模式", "包序列化模式", "{55970A52-E1A6-493B-91C4-9F4EE3E888B6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageConsoleApp", "examples\包序列化模式\PackageConsoleApp\PackageConsoleApp.csproj", "{BDF15495-BC59-4A66-8643-F8166907B28E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdapterTesterConsoleApp", "examples\Adapter简单示例\AdapterTesterConsoleApp\AdapterTesterConsoleApp.csproj", "{BF997370-81F3-4DCA-81A3-AF7D9050ABB1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tcp命令行执行插件", "Tcp命令行执行插件", "{5B8D8451-E920-42E5-9F6A-D6D1238A24B4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpCommandLineConsoleApp", "examples\Tcp简单示例\Tcp命令行执行插件\TcpCommandLineConsoleApp\TcpCommandLineConsoleApp.csproj", "{15554D7C-32B3-48A2-9475-2364A721A1F7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AccessRestrictionsConsoleApp", "examples\BlogsDemos\AccessRestrictionsConsoleApp\AccessRestrictionsConsoleApp.csproj", "{0897A17C-8822-4E42-83BE-A59F21A4E5E2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DifferentProtocolConsoleApp", "examples\BlogsDemos\DifferentProtocolConsoleApp\DifferentProtocolConsoleApp.csproj", "{5BEF24DB-61B5-4615-A578-3BEB1F4FD1D8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "源代码生成代理", "源代码生成代理", "{32AE404F-B9EB-4793-A947-CACD58B2B5E2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneratorRpcProxyConsoleApp", "examples\TouchRpc简单示例\源代码生成代理\GeneratorRpcProxyConsoleApp\GeneratorRpcProxyConsoleApp.csproj", "{0AFDF908-C9A1-471D-ADEB-04B1002397DA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Udp组播、广播", "Udp组播、广播", "{ECB9C1D8-AB1D-4105-AF2F-BC9D14158BF3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UdpBroadcastConsoleApp", "examples\Udp简单示例\Udp组播、广播\UdpBroadcastConsoleApp\UdpBroadcastConsoleApp.csproj", "{C26AB687-63B1-4C4C-8FDC-B1CF182C9E92}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Rpc流式数据传输", "Rpc流式数据传输", "{F4BC22A9-7007-46B1-B168-DFB2A2E0EA24}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcStreamConsoleApp", "examples\TouchRpc简单示例\Rpc流式数据传输\RpcStreamConsoleApp\RpcStreamConsoleApp.csproj", "{23B63A76-3759-4522-AA7C-721B5098C822}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "序列化选择器", "序列化选择器", "{405C6B1D-CCFE-407A-9A96-3548C55B0D1F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerializationSelectorConsoleApp", "examples\TouchRpc简单示例\序列化选择器\SerializationSelectorConsoleApp\SerializationSelectorConsoleApp.csproj", "{B77AD280-A493-444F-BC86-DFE32F4FDA3E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SerializationSelectorClassLibrary", "examples\TouchRpc简单示例\序列化选择器\SerializationSelectorClassLibrary\SerializationSelectorClassLibrary.csproj", "{EB4DE5C1-A14A-456C-9473-78D39DED09A3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {65823091-FE7C-4B96-96AB-1D4D09B45DA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {65823091-FE7C-4B96-96AB-1D4D09B45DA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {65823091-FE7C-4B96-96AB-1D4D09B45DA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {65823091-FE7C-4B96-96AB-1D4D09B45DA2}.Release|Any CPU.Build.0 = Release|Any CPU + {558B024C-981D-4288-99D2-5B6C0C30C427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {558B024C-981D-4288-99D2-5B6C0C30C427}.Debug|Any CPU.Build.0 = Debug|Any CPU + {558B024C-981D-4288-99D2-5B6C0C30C427}.Release|Any CPU.ActiveCfg = Release|Any CPU + {558B024C-981D-4288-99D2-5B6C0C30C427}.Release|Any CPU.Build.0 = Release|Any CPU + {FF655439-DFFE-4BE4-AB76-BC84EE188C7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF655439-DFFE-4BE4-AB76-BC84EE188C7F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF655439-DFFE-4BE4-AB76-BC84EE188C7F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF655439-DFFE-4BE4-AB76-BC84EE188C7F}.Release|Any CPU.Build.0 = Release|Any CPU + {A9C4DF80-0A9F-4979-AB4B-201A5B573A61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A9C4DF80-0A9F-4979-AB4B-201A5B573A61}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A9C4DF80-0A9F-4979-AB4B-201A5B573A61}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A9C4DF80-0A9F-4979-AB4B-201A5B573A61}.Release|Any CPU.Build.0 = Release|Any CPU + {FF839E56-FD43-4CEF-9775-B440D6BA4099}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF839E56-FD43-4CEF-9775-B440D6BA4099}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF839E56-FD43-4CEF-9775-B440D6BA4099}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF839E56-FD43-4CEF-9775-B440D6BA4099}.Release|Any CPU.Build.0 = Release|Any CPU + {A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}.Release|Any CPU.Build.0 = Release|Any CPU + {6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}.Release|Any CPU.Build.0 = Release|Any CPU + {0B7591F5-37C8-4570-ACEF-782CE3F12957}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B7591F5-37C8-4570-ACEF-782CE3F12957}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B7591F5-37C8-4570-ACEF-782CE3F12957}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B7591F5-37C8-4570-ACEF-782CE3F12957}.Release|Any CPU.Build.0 = Release|Any CPU + {31026659-0E64-4344-A8E2-A3C5477E4A94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31026659-0E64-4344-A8E2-A3C5477E4A94}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31026659-0E64-4344-A8E2-A3C5477E4A94}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31026659-0E64-4344-A8E2-A3C5477E4A94}.Release|Any CPU.Build.0 = Release|Any CPU + {F9E0154E-2DFC-480F-9B3A-B30548C41DFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9E0154E-2DFC-480F-9B3A-B30548C41DFD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9E0154E-2DFC-480F-9B3A-B30548C41DFD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9E0154E-2DFC-480F-9B3A-B30548C41DFD}.Release|Any CPU.Build.0 = Release|Any CPU + {AF8A5195-E56B-41E6-85A2-83E501E69500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF8A5195-E56B-41E6-85A2-83E501E69500}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF8A5195-E56B-41E6-85A2-83E501E69500}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF8A5195-E56B-41E6-85A2-83E501E69500}.Release|Any CPU.Build.0 = Release|Any CPU + {725CF25C-F3F0-4833-A501-8FD8F3596837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {725CF25C-F3F0-4833-A501-8FD8F3596837}.Debug|Any CPU.Build.0 = Debug|Any CPU + {725CF25C-F3F0-4833-A501-8FD8F3596837}.Release|Any CPU.ActiveCfg = Release|Any CPU + {725CF25C-F3F0-4833-A501-8FD8F3596837}.Release|Any CPU.Build.0 = Release|Any CPU + {BF73D290-6C07-4EC6-8546-447F15B543C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF73D290-6C07-4EC6-8546-447F15B543C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF73D290-6C07-4EC6-8546-447F15B543C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF73D290-6C07-4EC6-8546-447F15B543C7}.Release|Any CPU.Build.0 = Release|Any CPU + {54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}.Release|Any CPU.Build.0 = Release|Any CPU + {F933280F-F5C2-4145-B857-A70B921D940A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F933280F-F5C2-4145-B857-A70B921D940A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F933280F-F5C2-4145-B857-A70B921D940A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F933280F-F5C2-4145-B857-A70B921D940A}.Release|Any CPU.Build.0 = Release|Any CPU + {A6358094-56E0-4DF3-BA95-319D676C0A04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6358094-56E0-4DF3-BA95-319D676C0A04}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6358094-56E0-4DF3-BA95-319D676C0A04}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6358094-56E0-4DF3-BA95-319D676C0A04}.Release|Any CPU.Build.0 = Release|Any CPU + {30A64984-243D-4745-807E-B084BA51B968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30A64984-243D-4745-807E-B084BA51B968}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30A64984-243D-4745-807E-B084BA51B968}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30A64984-243D-4745-807E-B084BA51B968}.Release|Any CPU.Build.0 = Release|Any CPU + {613B3E85-59DE-4314-9A3A-EEE7C03E207F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {613B3E85-59DE-4314-9A3A-EEE7C03E207F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {613B3E85-59DE-4314-9A3A-EEE7C03E207F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {613B3E85-59DE-4314-9A3A-EEE7C03E207F}.Release|Any CPU.Build.0 = Release|Any CPU + {D367F50D-0B27-4B46-9872-695DC6B021BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D367F50D-0B27-4B46-9872-695DC6B021BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D367F50D-0B27-4B46-9872-695DC6B021BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D367F50D-0B27-4B46-9872-695DC6B021BF}.Release|Any CPU.Build.0 = Release|Any CPU + {35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}.Release|Any CPU.Build.0 = Release|Any CPU + {5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}.Release|Any CPU.Build.0 = Release|Any CPU + {571F2732-7E54-42A8-BEC6-B97B0A651059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {571F2732-7E54-42A8-BEC6-B97B0A651059}.Debug|Any CPU.Build.0 = Debug|Any CPU + {571F2732-7E54-42A8-BEC6-B97B0A651059}.Release|Any CPU.ActiveCfg = Release|Any CPU + {571F2732-7E54-42A8-BEC6-B97B0A651059}.Release|Any CPU.Build.0 = Release|Any CPU + {71D8B6B2-09F3-4060-B073-A3F5D944C304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71D8B6B2-09F3-4060-B073-A3F5D944C304}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71D8B6B2-09F3-4060-B073-A3F5D944C304}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71D8B6B2-09F3-4060-B073-A3F5D944C304}.Release|Any CPU.Build.0 = Release|Any CPU + {5F9D5028-12C8-4819-9B8E-ACE017B63132}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F9D5028-12C8-4819-9B8E-ACE017B63132}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F9D5028-12C8-4819-9B8E-ACE017B63132}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F9D5028-12C8-4819-9B8E-ACE017B63132}.Release|Any CPU.Build.0 = Release|Any CPU + {1B247610-9FAD-4434-BA15-B1DB1F71B7C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B247610-9FAD-4434-BA15-B1DB1F71B7C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B247610-9FAD-4434-BA15-B1DB1F71B7C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B247610-9FAD-4434-BA15-B1DB1F71B7C5}.Release|Any CPU.Build.0 = Release|Any CPU + {2017B959-1B58-453A-B65D-2F737E6B96DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2017B959-1B58-453A-B65D-2F737E6B96DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2017B959-1B58-453A-B65D-2F737E6B96DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2017B959-1B58-453A-B65D-2F737E6B96DC}.Release|Any CPU.Build.0 = Release|Any CPU + {8BFDA2E0-E7B6-4592-86B8-53426A8C0848}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BFDA2E0-E7B6-4592-86B8-53426A8C0848}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BFDA2E0-E7B6-4592-86B8-53426A8C0848}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BFDA2E0-E7B6-4592-86B8-53426A8C0848}.Release|Any CPU.Build.0 = Release|Any CPU + {06B4A342-2E42-4F66-A0FE-CD6110DDF980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {06B4A342-2E42-4F66-A0FE-CD6110DDF980}.Debug|Any CPU.Build.0 = Debug|Any CPU + {06B4A342-2E42-4F66-A0FE-CD6110DDF980}.Release|Any CPU.ActiveCfg = Release|Any CPU + {06B4A342-2E42-4F66-A0FE-CD6110DDF980}.Release|Any CPU.Build.0 = Release|Any CPU + {8452EA31-F7BB-4897-8881-F3EE3F82049A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8452EA31-F7BB-4897-8881-F3EE3F82049A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8452EA31-F7BB-4897-8881-F3EE3F82049A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8452EA31-F7BB-4897-8881-F3EE3F82049A}.Release|Any CPU.Build.0 = Release|Any CPU + {DD7848E5-3489-454E-BF37-49B6FE4C7F01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD7848E5-3489-454E-BF37-49B6FE4C7F01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD7848E5-3489-454E-BF37-49B6FE4C7F01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD7848E5-3489-454E-BF37-49B6FE4C7F01}.Release|Any CPU.Build.0 = Release|Any CPU + {82A783ED-11AD-407D-990B-A6AE9D557290}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {82A783ED-11AD-407D-990B-A6AE9D557290}.Debug|Any CPU.Build.0 = Debug|Any CPU + {82A783ED-11AD-407D-990B-A6AE9D557290}.Release|Any CPU.ActiveCfg = Release|Any CPU + {82A783ED-11AD-407D-990B-A6AE9D557290}.Release|Any CPU.Build.0 = Release|Any CPU + {791D316B-41D7-4B19-A25B-A58EBEA4E04A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {791D316B-41D7-4B19-A25B-A58EBEA4E04A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {791D316B-41D7-4B19-A25B-A58EBEA4E04A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {791D316B-41D7-4B19-A25B-A58EBEA4E04A}.Release|Any CPU.Build.0 = Release|Any CPU + {EDAA9CD3-1474-4588-9E3B-E970CED20F0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDAA9CD3-1474-4588-9E3B-E970CED20F0F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDAA9CD3-1474-4588-9E3B-E970CED20F0F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDAA9CD3-1474-4588-9E3B-E970CED20F0F}.Release|Any CPU.Build.0 = Release|Any CPU + {D5738DF3-C8E8-4E21-98B2-0557F0392167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5738DF3-C8E8-4E21-98B2-0557F0392167}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5738DF3-C8E8-4E21-98B2-0557F0392167}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5738DF3-C8E8-4E21-98B2-0557F0392167}.Release|Any CPU.Build.0 = Release|Any CPU + {8C6EA0F4-78F6-4E5F-B633-848355B06331}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C6EA0F4-78F6-4E5F-B633-848355B06331}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C6EA0F4-78F6-4E5F-B633-848355B06331}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C6EA0F4-78F6-4E5F-B633-848355B06331}.Release|Any CPU.Build.0 = Release|Any CPU + {EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}.Release|Any CPU.Build.0 = Release|Any CPU + {707CC6CD-17D0-4EC8-9CF7-D056F7740EC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {707CC6CD-17D0-4EC8-9CF7-D056F7740EC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {707CC6CD-17D0-4EC8-9CF7-D056F7740EC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {707CC6CD-17D0-4EC8-9CF7-D056F7740EC6}.Release|Any CPU.Build.0 = Release|Any CPU + {82E99507-C5AA-4AC0-A857-6294D5CF9FFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {82E99507-C5AA-4AC0-A857-6294D5CF9FFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {82E99507-C5AA-4AC0-A857-6294D5CF9FFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {82E99507-C5AA-4AC0-A857-6294D5CF9FFA}.Release|Any CPU.Build.0 = Release|Any CPU + {F5AA7892-A533-4603-959F-A990AE569C59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5AA7892-A533-4603-959F-A990AE569C59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5AA7892-A533-4603-959F-A990AE569C59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5AA7892-A533-4603-959F-A990AE569C59}.Release|Any CPU.Build.0 = Release|Any CPU + {F645710B-4FE8-430C-9860-B289743CAE23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F645710B-4FE8-430C-9860-B289743CAE23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F645710B-4FE8-430C-9860-B289743CAE23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F645710B-4FE8-430C-9860-B289743CAE23}.Release|Any CPU.Build.0 = Release|Any CPU + {E629B642-AF9B-4FB6-AFE3-6258E2F0B953}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E629B642-AF9B-4FB6-AFE3-6258E2F0B953}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E629B642-AF9B-4FB6-AFE3-6258E2F0B953}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E629B642-AF9B-4FB6-AFE3-6258E2F0B953}.Release|Any CPU.Build.0 = Release|Any CPU + {E72ADFB6-4AA5-4210-BC6B-A68927644526}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E72ADFB6-4AA5-4210-BC6B-A68927644526}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E72ADFB6-4AA5-4210-BC6B-A68927644526}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E72ADFB6-4AA5-4210-BC6B-A68927644526}.Release|Any CPU.Build.0 = Release|Any CPU + {66849ED5-C951-450A-8867-AE5FA8109FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {66849ED5-C951-450A-8867-AE5FA8109FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {66849ED5-C951-450A-8867-AE5FA8109FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {66849ED5-C951-450A-8867-AE5FA8109FC3}.Release|Any CPU.Build.0 = Release|Any CPU + {D5892A0B-DE58-42C2-B5EE-E1C34745493B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5892A0B-DE58-42C2-B5EE-E1C34745493B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5892A0B-DE58-42C2-B5EE-E1C34745493B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5892A0B-DE58-42C2-B5EE-E1C34745493B}.Release|Any CPU.Build.0 = Release|Any CPU + {0E76C63C-66CC-43BE-A6AF-A7862E669C2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E76C63C-66CC-43BE-A6AF-A7862E669C2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E76C63C-66CC-43BE-A6AF-A7862E669C2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E76C63C-66CC-43BE-A6AF-A7862E669C2F}.Release|Any CPU.Build.0 = Release|Any CPU + {BDF15495-BC59-4A66-8643-F8166907B28E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDF15495-BC59-4A66-8643-F8166907B28E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDF15495-BC59-4A66-8643-F8166907B28E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDF15495-BC59-4A66-8643-F8166907B28E}.Release|Any CPU.Build.0 = Release|Any CPU + {BF997370-81F3-4DCA-81A3-AF7D9050ABB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF997370-81F3-4DCA-81A3-AF7D9050ABB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF997370-81F3-4DCA-81A3-AF7D9050ABB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF997370-81F3-4DCA-81A3-AF7D9050ABB1}.Release|Any CPU.Build.0 = Release|Any CPU + {15554D7C-32B3-48A2-9475-2364A721A1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15554D7C-32B3-48A2-9475-2364A721A1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15554D7C-32B3-48A2-9475-2364A721A1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15554D7C-32B3-48A2-9475-2364A721A1F7}.Release|Any CPU.Build.0 = Release|Any CPU + {0897A17C-8822-4E42-83BE-A59F21A4E5E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0897A17C-8822-4E42-83BE-A59F21A4E5E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0897A17C-8822-4E42-83BE-A59F21A4E5E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0897A17C-8822-4E42-83BE-A59F21A4E5E2}.Release|Any CPU.Build.0 = Release|Any CPU + {5BEF24DB-61B5-4615-A578-3BEB1F4FD1D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BEF24DB-61B5-4615-A578-3BEB1F4FD1D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BEF24DB-61B5-4615-A578-3BEB1F4FD1D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BEF24DB-61B5-4615-A578-3BEB1F4FD1D8}.Release|Any CPU.Build.0 = Release|Any CPU + {0AFDF908-C9A1-471D-ADEB-04B1002397DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AFDF908-C9A1-471D-ADEB-04B1002397DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AFDF908-C9A1-471D-ADEB-04B1002397DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AFDF908-C9A1-471D-ADEB-04B1002397DA}.Release|Any CPU.Build.0 = Release|Any CPU + {C26AB687-63B1-4C4C-8FDC-B1CF182C9E92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C26AB687-63B1-4C4C-8FDC-B1CF182C9E92}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C26AB687-63B1-4C4C-8FDC-B1CF182C9E92}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C26AB687-63B1-4C4C-8FDC-B1CF182C9E92}.Release|Any CPU.Build.0 = Release|Any CPU + {23B63A76-3759-4522-AA7C-721B5098C822}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23B63A76-3759-4522-AA7C-721B5098C822}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23B63A76-3759-4522-AA7C-721B5098C822}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23B63A76-3759-4522-AA7C-721B5098C822}.Release|Any CPU.Build.0 = Release|Any CPU + {B77AD280-A493-444F-BC86-DFE32F4FDA3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B77AD280-A493-444F-BC86-DFE32F4FDA3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B77AD280-A493-444F-BC86-DFE32F4FDA3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B77AD280-A493-444F-BC86-DFE32F4FDA3E}.Release|Any CPU.Build.0 = Release|Any CPU + {EB4DE5C1-A14A-456C-9473-78D39DED09A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB4DE5C1-A14A-456C-9473-78D39DED09A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB4DE5C1-A14A-456C-9473-78D39DED09A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB4DE5C1-A14A-456C-9473-78D39DED09A3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {65823091-FE7C-4B96-96AB-1D4D09B45DA2} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} + {DC9E894F-E65F-443E-9F4E-6FEDB46F06DC} = {B405B0AE-6ECD-4586-B3D6-9D875073DFAF} + {558B024C-981D-4288-99D2-5B6C0C30C427} = {DC9E894F-E65F-443E-9F4E-6FEDB46F06DC} + {FF655439-DFFE-4BE4-AB76-BC84EE188C7F} = {DC9E894F-E65F-443E-9F4E-6FEDB46F06DC} + {82B05679-3A56-4E9A-BFA3-B68D29821B8A} = {B405B0AE-6ECD-4586-B3D6-9D875073DFAF} + {A9C4DF80-0A9F-4979-AB4B-201A5B573A61} = {82B05679-3A56-4E9A-BFA3-B68D29821B8A} + {FF839E56-FD43-4CEF-9775-B440D6BA4099} = {825D21FC-245C-4B6B-B237-E4ADEB2C98DC} + {A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B} = {397AE2E0-1FB6-4B71-A888-328FF7FA05B4} + {6BEF15C2-29A2-4E57-8879-1B4AD0B4935E} = {FB46E926-0EEC-488C-B950-A16D2E7F694B} + {0B7591F5-37C8-4570-ACEF-782CE3F12957} = {FB46E926-0EEC-488C-B950-A16D2E7F694B} + {31026659-0E64-4344-A8E2-A3C5477E4A94} = {F4D798A3-8D65-4750-9552-B02BCE081508} + {F9E0154E-2DFC-480F-9B3A-B30548C41DFD} = {969A695E-BEB5-45B8-93D8-B31640FA495D} + {AF8A5195-E56B-41E6-85A2-83E501E69500} = {EFB33E23-9E98-4B85-99E4-865705D5ACD2} + {725CF25C-F3F0-4833-A501-8FD8F3596837} = {5836A018-B0F3-4D6F-8C45-FC1E9C85D51A} + {BF73D290-6C07-4EC6-8546-447F15B543C7} = {5836A018-B0F3-4D6F-8C45-FC1E9C85D51A} + {54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5} = {94F46729-90A8-415A-92E0-2D996D3210B4} + {F933280F-F5C2-4145-B857-A70B921D940A} = {94F46729-90A8-415A-92E0-2D996D3210B4} + {A6358094-56E0-4DF3-BA95-319D676C0A04} = {5E9585EE-934F-41B4-9ECA-FB0C55A155EF} + {30A64984-243D-4745-807E-B084BA51B968} = {5E9585EE-934F-41B4-9ECA-FB0C55A155EF} + {613B3E85-59DE-4314-9A3A-EEE7C03E207F} = {54A8216A-AA96-4293-9285-D2173E1D2E69} + {D367F50D-0B27-4B46-9872-695DC6B021BF} = {54A8216A-AA96-4293-9285-D2173E1D2E69} + {5C17B127-95DD-480C-BDCC-7FDF5E645B0C} = {54A8216A-AA96-4293-9285-D2173E1D2E69} + {35C3CCAE-2C39-4756-82CD-1E2AFE1FB527} = {5C17B127-95DD-480C-BDCC-7FDF5E645B0C} + {5FF19798-AD4B-4B45-BD0C-DE5271BEF63A} = {5C17B127-95DD-480C-BDCC-7FDF5E645B0C} + {571F2732-7E54-42A8-BEC6-B97B0A651059} = {54A8216A-AA96-4293-9285-D2173E1D2E69} + {DB89FCB6-E4F9-4BD4-93F3-4E857741D749} = {FB46E926-0EEC-488C-B950-A16D2E7F694B} + {71D8B6B2-09F3-4060-B073-A3F5D944C304} = {DB89FCB6-E4F9-4BD4-93F3-4E857741D749} + {5F9D5028-12C8-4819-9B8E-ACE017B63132} = {84D1227F-3419-4BCD-9331-8B61B2C19784} + {1B247610-9FAD-4434-BA15-B1DB1F71B7C5} = {84D1227F-3419-4BCD-9331-8B61B2C19784} + {2017B959-1B58-453A-B65D-2F737E6B96DC} = {24212B0A-8DAA-4AC3-BB5D-F3AC485EABA4} + {8BFDA2E0-E7B6-4592-86B8-53426A8C0848} = {24212B0A-8DAA-4AC3-BB5D-F3AC485EABA4} + {06B4A342-2E42-4F66-A0FE-CD6110DDF980} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968} + {8452EA31-F7BB-4897-8881-F3EE3F82049A} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968} + {DD7848E5-3489-454E-BF37-49B6FE4C7F01} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968} + {82A783ED-11AD-407D-990B-A6AE9D557290} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968} + {8B9374B5-42D7-48C9-84C7-A560167F0D47} = {F4D798A3-8D65-4750-9552-B02BCE081508} + {791D316B-41D7-4B19-A25B-A58EBEA4E04A} = {8B9374B5-42D7-48C9-84C7-A560167F0D47} + {EDAA9CD3-1474-4588-9E3B-E970CED20F0F} = {8B9374B5-42D7-48C9-84C7-A560167F0D47} + {5777979E-5737-46EF-9B0E-9C18FA7004B6} = {54A8216A-AA96-4293-9285-D2173E1D2E69} + {D5738DF3-C8E8-4E21-98B2-0557F0392167} = {5777979E-5737-46EF-9B0E-9C18FA7004B6} + {FB0FA0CF-1657-48F7-B852-FBA818F1AE8A} = {24212B0A-8DAA-4AC3-BB5D-F3AC485EABA4} + {8C6EA0F4-78F6-4E5F-B633-848355B06331} = {FB0FA0CF-1657-48F7-B852-FBA818F1AE8A} + {EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4} = {FB0FA0CF-1657-48F7-B852-FBA818F1AE8A} + {707CC6CD-17D0-4EC8-9CF7-D056F7740EC6} = {1DE974CF-D77E-4E9B-B3F9-7E5A3F9C4A67} + {82E99507-C5AA-4AC0-A857-6294D5CF9FFA} = {1DE974CF-D77E-4E9B-B3F9-7E5A3F9C4A67} + {F5AA7892-A533-4603-959F-A990AE569C59} = {6D046723-8625-4D69-BD71-64E5F43B210A} + {F645710B-4FE8-430C-9860-B289743CAE23} = {59C3DFB0-C6E1-4F7E-AD9D-9857A4153A1E} + {97C928E3-54D6-4FAE-A314-775BE9E25A14} = {FB46E926-0EEC-488C-B950-A16D2E7F694B} + {E629B642-AF9B-4FB6-AFE3-6258E2F0B953} = {97C928E3-54D6-4FAE-A314-775BE9E25A14} + {E72ADFB6-4AA5-4210-BC6B-A68927644526} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} + {66849ED5-C951-450A-8867-AE5FA8109FC3} = {DFAE990A-30E8-4974-A130-D66E9B3486B7} + {D5892A0B-DE58-42C2-B5EE-E1C34745493B} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} + {0E76C63C-66CC-43BE-A6AF-A7862E669C2F} = {14C9DCF7-767F-48F5-956F-782161BA2420} + {BDF15495-BC59-4A66-8643-F8166907B28E} = {55970A52-E1A6-493B-91C4-9F4EE3E888B6} + {BF997370-81F3-4DCA-81A3-AF7D9050ABB1} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} + {5B8D8451-E920-42E5-9F6A-D6D1238A24B4} = {FB46E926-0EEC-488C-B950-A16D2E7F694B} + {15554D7C-32B3-48A2-9475-2364A721A1F7} = {5B8D8451-E920-42E5-9F6A-D6D1238A24B4} + {0897A17C-8822-4E42-83BE-A59F21A4E5E2} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968} + {5BEF24DB-61B5-4615-A578-3BEB1F4FD1D8} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968} + {32AE404F-B9EB-4793-A947-CACD58B2B5E2} = {54A8216A-AA96-4293-9285-D2173E1D2E69} + {0AFDF908-C9A1-471D-ADEB-04B1002397DA} = {32AE404F-B9EB-4793-A947-CACD58B2B5E2} + {ECB9C1D8-AB1D-4105-AF2F-BC9D14158BF3} = {F4D798A3-8D65-4750-9552-B02BCE081508} + {C26AB687-63B1-4C4C-8FDC-B1CF182C9E92} = {ECB9C1D8-AB1D-4105-AF2F-BC9D14158BF3} + {F4BC22A9-7007-46B1-B168-DFB2A2E0EA24} = {54A8216A-AA96-4293-9285-D2173E1D2E69} + {23B63A76-3759-4522-AA7C-721B5098C822} = {F4BC22A9-7007-46B1-B168-DFB2A2E0EA24} + {405C6B1D-CCFE-407A-9A96-3548C55B0D1F} = {54A8216A-AA96-4293-9285-D2173E1D2E69} + {B77AD280-A493-444F-BC86-DFE32F4FDA3E} = {405C6B1D-CCFE-407A-9A96-3548C55B0D1F} + {EB4DE5C1-A14A-456C-9473-78D39DED09A3} = {405C6B1D-CCFE-407A-9A96-3548C55B0D1F} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DB787235-A13A-4A3D-B5A8-5DFEB6511EEE} + EndGlobalSection +EndGlobal diff --git a/examples/Adapter简单示例/AdapterConsoleApp/AdapterConsoleApp.csproj b/examples/Adapter简单示例/AdapterConsoleApp/AdapterConsoleApp.csproj new file mode 100644 index 000000000..0d491ba4f --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/AdapterConsoleApp.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0 + + + + + + + + Always + + + diff --git a/examples/Adapter简单示例/AdapterConsoleApp/MyBigFixedHeaderCustomDataHandlingAdapter.cs b/examples/Adapter简单示例/AdapterConsoleApp/MyBigFixedHeaderCustomDataHandlingAdapter.cs new file mode 100644 index 000000000..ed834b28f --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/MyBigFixedHeaderCustomDataHandlingAdapter.cs @@ -0,0 +1,50 @@ +using System; +using TouchSocket.Sockets; + +namespace AdapterConsoleApp +{ + /// + /// 模板解析“大数据固定包头”数据适配器 + /// + internal class MyBigFixedHeaderCustomDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter + { + public override int HeaderLength => throw new NotImplementedException(); + + public override bool CanSendRequestInfo => false; + + protected override MyBigFixedHeaderRequestInfo GetInstance() + { + return new MyBigFixedHeaderRequestInfo(); + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + } + + /// + /// 下列吗,没有实现逻辑,仅解释思路。 + /// + internal class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo + { + public long BodyLength => throw new NotImplementedException(); + + public void OnAppendBody(byte[] buffer, int offset, int length) + { + //在这里会一直追加数据体,用户自行实现数据的保存。 + } + + public bool OnFinished() + { + //触发该方法时,说明数据体接收完毕,返回true时,会触发Receive相关事件,否则不会。 + return true; + } + + public bool OnParsingHeader(byte[] header) + { + //解析头部 + return true; + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/AdapterConsoleApp/MyCustomBetweenAndDataHandlingAdapter.cs b/examples/Adapter简单示例/AdapterConsoleApp/MyCustomBetweenAndDataHandlingAdapter.cs new file mode 100644 index 000000000..b09c055e8 --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/MyCustomBetweenAndDataHandlingAdapter.cs @@ -0,0 +1,53 @@ +using System.Text; +using TouchSocket.Sockets; + +namespace AdapterConsoleApp +{ + internal class MyCustomBetweenAndDataHandlingAdapter : CustomBetweenAndDataHandlingAdapter + { + public MyCustomBetweenAndDataHandlingAdapter() + { + this.MinSize = 5;//表示,实际数据体不会小于5,例如“**12##12##”数据,解析后会解析成“12##12” + } + + public override byte[] StartCode => Encoding.UTF8.GetBytes("**");//可以为0长度字节,意味着没有起始标识。 + + public override byte[] EndCode => Encoding.UTF8.GetBytes("##");//必须为有效值。 + + public override bool CanSendRequestInfo => false; + + protected override MyBetweenAndRequestInfo GetInstance() + { + return new MyBetweenAndRequestInfo(); + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + } + + /// + /// 以**12##12##,Min=5为例。 + /// + internal class MyBetweenAndRequestInfo : IBetweenAndRequestInfo + { + public byte[] Body { get; private set; } + + public void OnParsingBody(byte[] body) + { + this.Body = body; + //这里的Body应该为12##12 + } + + public bool OnParsingEndCode(byte[] endCode) + { + return true;//该返回值决定,是否执行Receive + } + + public bool OnParsingStartCode(byte[] startCode) + { + return true; + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/AdapterConsoleApp/MyCustomDataHandlingAdapter.cs b/examples/Adapter简单示例/AdapterConsoleApp/MyCustomDataHandlingAdapter.cs new file mode 100644 index 000000000..a10e50736 --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/MyCustomDataHandlingAdapter.cs @@ -0,0 +1,89 @@ +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace AdapterConsoleApp +{ + /// + /// 用户自定义适配器 + /// + internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter + { + public override bool CanSendRequestInfo => false; + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref MyRequestInfo request, ref int tempCapacity) + { + //以下解析思路为一次性解析,不考虑缓存的临时对象。 + + if (byteBlock.CanReadLen < 3) + { + return FilterResult.Cache;//当头部都无法解析时,直接缓存 + } + + int pos = byteBlock.Pos;//记录初始游标位置,防止本次无法解析时,回退游标。 + + MyRequestInfo myRequestInfo = new MyRequestInfo(); + + byteBlock.Read(out byte[] header, 3);//填充header + + //因为第一个字节表示所有长度,而DataType、OrderType已经包含在了header里面。 + //所有只需呀再读取header[0]-2个长度即可。 + byte bodyLength = (byte)(header[0] - 2); + + if (bodyLength > byteBlock.CanReadLen) + { + //body数据不足。 + byteBlock.Pos = pos;//回退游标 + return FilterResult.Cache; + } + else + { + byteBlock.Read(out byte[] body, bodyLength);//填充body + + myRequestInfo.Header = header; + myRequestInfo.DataType = header[1]; + myRequestInfo.OrderType = header[2]; + myRequestInfo.Body = body; + request = myRequestInfo;//赋值ref + return FilterResult.Success;//返回成功 + } + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + } + + internal class MyRequestInfo : IRequestInfo + { + /// + /// 自定义属性,Body + /// + public byte[] Body { get; internal set; } + + /// + /// 自定义属性,Header + /// + public byte[] Header { get; internal set; } + + /// + /// 自定义属性,DataType + /// + public byte DataType { get; internal set; } + + /// + /// 自定义属性,OrderType + /// + public byte OrderType { get; internal set; } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/AdapterConsoleApp/MyFixedHeaderCustomDataHandlingAdapter.cs b/examples/Adapter简单示例/AdapterConsoleApp/MyFixedHeaderCustomDataHandlingAdapter.cs new file mode 100644 index 000000000..cd13a1700 --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/MyFixedHeaderCustomDataHandlingAdapter.cs @@ -0,0 +1,98 @@ +using TouchSocket.Sockets; + +namespace AdapterConsoleApp +{ + /// + /// 模板解析“固定包头”数据适配器 + /// + public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter + { + public MyFixedHeaderCustomDataHandlingAdapter() + { + this.MaxPackageSize = 1024; + } + + /// + /// 接口实现,指示固定包头长度 + /// + public override int HeaderLength => 3; + + public override bool CanSendRequestInfo => false; + + /// + /// 获取新实例 + /// + /// + protected override MyFixedHeaderRequestInfo GetInstance() + { + return new MyFixedHeaderRequestInfo(); + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + } + + public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo + { + private int bodyLength; + + /// + /// 接口实现,标识数据长度 + /// + public int BodyLength + { + get { return bodyLength; } + } + + private byte dataType; + + /// + /// 自定义属性,标识数据类型 + /// + public byte DataType + { + get { return dataType; } + } + + private byte orderType; + + /// + /// 自定义属性,标识指令类型 + /// + public byte OrderType + { + get { return orderType; } + } + + private byte[] body; + + /// + /// 自定义属性,标识实际数据 + /// + public byte[] Body + { + get { return body; } + } + + public bool OnParsingBody(byte[] body) + { + if (body.Length == this.bodyLength) + { + this.body = body; + return true; + } + return false; + } + + public bool OnParsingHeader(byte[] header) + { + //在该示例中,第一个字节表示后续的所有数据长度,但是header设置的是3,所以后续还应当接收length-2个长度。 + this.bodyLength = header[0] - 2; + this.dataType = header[1]; + this.orderType = header[2]; + return true; + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/AdapterConsoleApp/Program.cs b/examples/Adapter简单示例/AdapterConsoleApp/Program.cs new file mode 100644 index 000000000..5b4f5a6fc --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/Program.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace AdapterConsoleApp +{ + internal class Program + { + /// + /// Tcp内置适配器介绍,请看说明文档 + /// + /// + private static void Main(string[] args) + { + // 1.黏、分包问题使用内置适配器即可解决。 + //● 正常数据处理适配器(NormalDataHandlingAdapter) + //● 固定包头数据处理适配器(FixedHeaderPackageAdapter) + //● 固定长度数据处理适配器(FixedSizePackageAdapter) + //● 终止因子分割数据处理适配器(TerminatorPackageAdapter) + + ConsoleAction consoleAction = new ConsoleAction(); + consoleAction.OnException += ConsoleAction_OnException; + consoleAction.Add("0", "启动服务器测试适配器", StartTcpService); + consoleAction.Add("1", "原始适配器实现demo", TestRawDataHandlingAdapter); + consoleAction.Add("2", "SGCC适配器实现demo", TestSGCCCustomDataHandlingAdapter); + + consoleAction.ShowAll(); + while (true) + { + if (!consoleAction.Run(Console.ReadLine())) + { + Console.WriteLine("指令不正确。"); + } + } + } + + private static void StartTcpService() + { + TcpService service = new TcpService(); + service.Connected = (client, e) => { };//有客户端连接 + service.Disconnected = (client, e) => { };//有客户端断开连接 + service.Received = (client, byteBlock, requestInfo) => + { + //从客户端收到信息 + if (requestInfo is MyBetweenAndRequestInfo info) + { + Console.WriteLine(Encoding.UTF8.GetString(info.Body)); + } + }; + + service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + + .SetDataHandlingAdapter(() => { return new MyCustomBetweenAndDataHandlingAdapter(); }) + .SetThreadCount(10)) + .Start();//启动 + } + + private static void ConsoleAction_OnException(Exception obj) + { + Console.WriteLine(obj.Message); + } + + private static void TestRawDataHandlingAdapter() + { + for (int i = 0; i < 10; i++) + { + DataAdapterTester tester = DataAdapterTester.CreateTester(new RawDataHandlingAdapter(), new Random().Next(1, 1024));//用BufferLength模拟粘包,分包 + using ByteBlock block = new ByteBlock(); + block.Write((byte)1);//写入数据类型 这里并未写入数据长度,因为这个适配器在发送前会再封装一次。 + block.Write((byte)1);//写入数据指令 + byte[] buffer = new byte[100]; + new Random().NextBytes(buffer); + block.Write(buffer);//写入数据 + byte[] data = block.ToArray(); + + // 输出测试时间,用于衡量适配性能. + // 测试100次,限时2秒完成 + Console.WriteLine(tester.Run(data, 100, 100, 1000 * 2).ToString()); + } + } + + private static void TestSGCCCustomDataHandlingAdapter() + { + string[] lines = File.ReadAllLines("SGCC测试数据.txt"); + foreach (var item in lines) + { + DataAdapterTester tester = DataAdapterTester.CreateTester(new SGCCCustomDataHandlingAdapter(), new Random().Next(1, 1024));//用BufferLength模拟粘包,分包 + using ByteBlock block = new ByteBlock(); + + byte[] data = item.ByHexStringToBytes(" "); + // 输出测试时间,用于衡量适配性能. + // 测试100次,限时2秒完成 + Console.WriteLine(tester.Run(data, 100, 100, 1000 * 2).ToString()); + } + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/AdapterConsoleApp/RawDataHandlingAdapter.cs b/examples/Adapter简单示例/AdapterConsoleApp/RawDataHandlingAdapter.cs new file mode 100644 index 000000000..0677c0daa --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/RawDataHandlingAdapter.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace AdapterConsoleApp +{ + /// + /// 从原始适配器实现 + /// + internal class RawDataHandlingAdapter : DataHandlingAdapter + { + /// + /// 包剩余长度 + /// + private byte m_surPlusLength; + + /// + /// 临时包,此包仅当前实例储存 + /// + private ByteBlock m_tempByteBlock; + + /// + /// 是否支持拼接发送,为false的话可以不实现 + /// + public override bool CanSplicingSend => false; + + public override bool CanSendRequestInfo => false; + + /// + /// 设计原则:接收时,尽量不抛出异常。 + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + if (this.m_tempByteBlock == null)//如果没有临时包,则直接分包。 + { + SplitPackage(buffer, 0, r); + } + else + { + if (m_surPlusLength == r)//接收长度正好等于剩余长度,组合完数据以后直接处理数据。 + { + this.m_tempByteBlock.Write(buffer, 0, m_surPlusLength); + PreviewHandle(this.m_tempByteBlock); + this.m_tempByteBlock = null; + m_surPlusLength = 0; + } + else if (m_surPlusLength < r)//接收长度大于剩余长度,先组合包,然后处理包,然后将剩下的分包。 + { + this.m_tempByteBlock.Write(buffer, 0, m_surPlusLength); + PreviewHandle(this.m_tempByteBlock); + this.m_tempByteBlock = null; + SplitPackage(buffer, m_surPlusLength, r); + } + else//接收长度小于剩余长度,无法处理包,所以必须先组合包,然后等下次接收。 + { + this.m_tempByteBlock.Write(buffer, 0, r); + m_surPlusLength -= (byte)r; + } + } + } + + /// + /// 设计原则:发送时的异常,应当直接抛出,让发送者直接捕获 + /// + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + int dataLen = length - offset;//先获取需要发送的实际数据长度 + if (dataLen > byte.MaxValue)//超长判断 + { + throw new OverlengthException("发送数据太长。"); + } + ByteBlock byteBlock = new ByteBlock(64 * 1024);//从内存池申请内存块,因为此处数据绝不超过255,所以避免内存池碎片化,每次申请64K + //ByteBlock byteBlock = BytePool.GetByteBlock(dataLen+1);//实际写法。 + try + { + byteBlock.Write((byte)dataLen);//先写长度 + byteBlock.Write(buffer, offset, length);//再写数据 + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose();//释放内存块 + } + } + + protected override void PreviewSend(IList> transferBytes) + { + //暂时不实现。 + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + + protected override void Reset() + { + } + + /// + /// 处理数据 + /// + /// + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + this.GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose();//在框架里面将内存块释放 + } + } + + /// + /// 分解包 + /// + /// + /// + /// + private void SplitPackage(byte[] dataBuffer, int index, int r) + { + while (index < r) + { + byte length = dataBuffer[index]; + int recedSurPlusLength = r - index - 1; + if (recedSurPlusLength >= length) + { + ByteBlock byteBlock =new ByteBlock(length); + byteBlock.Write(dataBuffer, index + 1, length); + PreviewHandle(byteBlock); + m_surPlusLength = 0; + } + else//半包 + { + this.m_tempByteBlock = new ByteBlock(length); + m_surPlusLength = (byte)(length - recedSurPlusLength); + this.m_tempByteBlock.Write(dataBuffer, index + 1, recedSurPlusLength); + } + index = length + 1; + } + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/AdapterConsoleApp/SGCC测试数据.txt b/examples/Adapter简单示例/AdapterConsoleApp/SGCC测试数据.txt new file mode 100644 index 000000000..b44a21f0d --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/SGCC测试数据.txt @@ -0,0 +1 @@ +A5 5A 26 00 31 31 4D 32 30 30 30 30 30 30 30 30 30 30 30 30 30 09 C1 4A 27 EA 92 F4 33 33 1F 41 8F C2 03 42 00 00 20 41 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 93 73 96 \ No newline at end of file diff --git a/examples/Adapter简单示例/AdapterConsoleApp/国网输电i1标准版/SGCCCustomDataHandlingAdapter.cs b/examples/Adapter简单示例/AdapterConsoleApp/国网输电i1标准版/SGCCCustomDataHandlingAdapter.cs new file mode 100644 index 000000000..ee2ae7b80 --- /dev/null +++ b/examples/Adapter简单示例/AdapterConsoleApp/国网输电i1标准版/SGCCCustomDataHandlingAdapter.cs @@ -0,0 +1,144 @@ +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace AdapterConsoleApp +{ + /// + /// 国网输电i1标准版 + /// + internal class SGCCCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter + { + public override int HeaderLength => 30; + + public override bool CanSendRequestInfo => false; + + protected override SGCCRequestInfo GetInstance() + { + return new SGCCRequestInfo(); + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + } + + public class SGCCRequestInfo : IFixedHeaderRequestInfo + { + private byte[] m_sync; + private int m_bodyLength; + private byte[] m_cMDID; + private byte[] m_sample; + private byte[] m_cRC16; + + public int BodyLength { get => m_bodyLength; } + + /// + /// 报文头:5AA5 + /// + public byte[] Sync { get => m_sync; set => m_sync = value; } + + /// + /// 报文长度 + /// + public ushort PacketLength { get => (ushort)(this.m_bodyLength - 3); } + + /// + /// 状态监测装置ID(17位编码) + /// + public byte[] CMDID { get => m_cMDID; set => m_cMDID = value; } + + /// + /// 帧类型—参考附表C8-1相关含义 + /// + public byte FrameType { get; set; } + + /// + /// 报文类型—参考附表C8-2相关含义 + /// + public byte PacketType { get; set; } + + /// + /// 帧序列号(无符号整数) + /// + public byte FrameNo { get; set; } + + /// + /// 通道号—表示采集装置上的摄像机编号。如:一个装连接⒉部摄像机,则分别标号为1、2 + /// + public byte ChannelNo { get; set; } + + /// + /// 预置位号—即云台摄像所设置的预置位号,不带云台摄像机,预置位号为255 + /// + public byte PresettingNo { get; set; } + + /// + /// 总包数(无符号整数,取值范围:大于等于0) + /// + public ushort PacketNo { get; set; } + + /// + /// 子包包号(无符号整数,取值范围:大于等于0> + /// + public ushort SubpacketNo { get; set; } + + /// + /// 数据区 + /// + public byte[] Sample { get => m_sample; set => m_sample = value; } + + /// + /// 校验位 + /// + public byte[] CRC16 { get => m_cRC16; } + + /// + /// 报文尾:0x96 + /// + public byte End { get; set; } + + public bool OnParsingHeader(byte[] header) + { + if (header.Length == 30) + { + using (ByteBlock byteBlock = new ByteBlock(header)) + { + byteBlock.Pos = 0; + byteBlock.Read(out m_sync, 2); + + byte[] lenBuffer; + byteBlock.Read(out lenBuffer, 2); + + this.m_bodyLength = TouchSocketBitConverter.LittleEndian.ToUInt16(lenBuffer, 0) + 3 - 6;//先把crc校验和end都获取。 + byteBlock.Read(out m_cMDID, 17); + this.FrameType = (byte)byteBlock.ReadByte(); + this.PacketType = (byte)byteBlock.ReadByte(); + this.FrameNo = (byte)byteBlock.ReadByte(); + this.ChannelNo = (byte)byteBlock.ReadByte(); + this.PresettingNo = (byte)byteBlock.ReadByte(); + this.PacketNo = byteBlock.ReadUInt16(); + this.SubpacketNo = byteBlock.ReadUInt16(); + + return true; + } + } + return false; + } + + public bool OnParsingBody(byte[] body) + { + if (body.Length == this.BodyLength && body[^1] == 150) + { + using (ByteBlock byteBlock = new ByteBlock(body)) + { + byteBlock.Read(out this.m_sample, this.m_bodyLength - 3); + byteBlock.Read(out this.m_cRC16, 2); + this.End = (byte)byteBlock.ReadByte(); + } + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/AdapterConsoleApp/国网输电i1标准版/数据协议.png b/examples/Adapter简单示例/AdapterConsoleApp/国网输电i1标准版/数据协议.png new file mode 100644 index 000000000..a24a4ff78 Binary files /dev/null and b/examples/Adapter简单示例/AdapterConsoleApp/国网输电i1标准版/数据协议.png differ diff --git a/examples/Adapter简单示例/AdapterTesterConsoleApp/AdapterTesterConsoleApp.csproj b/examples/Adapter简单示例/AdapterTesterConsoleApp/AdapterTesterConsoleApp.csproj new file mode 100644 index 000000000..a0153c14d --- /dev/null +++ b/examples/Adapter简单示例/AdapterTesterConsoleApp/AdapterTesterConsoleApp.csproj @@ -0,0 +1,12 @@ + + + + Exe + net6.0 + enable + + + + + + diff --git a/examples/Adapter简单示例/AdapterTesterConsoleApp/Program.cs b/examples/Adapter简单示例/AdapterTesterConsoleApp/Program.cs new file mode 100644 index 000000000..a91c75d64 --- /dev/null +++ b/examples/Adapter简单示例/AdapterTesterConsoleApp/Program.cs @@ -0,0 +1,64 @@ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace AdapterTesterConsoleApp +{ + internal class Program + { + static void Main(string[] args) + { + ConsoleAction action = new ConsoleAction(); + action.OnException += Action_OnException; + action.Add("1", "测试Tcp适配器", TcpDataAdapterTester); + + action.ShowAll(); + while (true) + { + action.Run(Console.ReadLine()); + } + } + + private static void Action_OnException(Exception obj) + { + Console.WriteLine(obj.Message); + } + + static void TcpDataAdapterTester() + { + //Tcp适配器测试 + //bufferLength的作用是模拟tcp接收缓存区,例如: + + //发送数据为{0,1,2,3,4}时 + //当bufferLength=1时,会先接收一个字节,然后适配器判断无法解析,然后缓存,然后再接收下一个字节,直到成功解析。 + //该模式能很好的模拟网络很差的环境。 + //当bufferLength=8时,会先接收{0,1,2,3,4,0,1,2},然后适配器判断解析前五字节,然后缓存后三字节,然后再接收下一个续包,直到解析结束。 + + for (int bufferLength = 1; bufferLength < 1024 * 10; bufferLength += 1024) + { + bool isSuccess = true; + var data = new byte[] { 0, 1, 2, 3, 4 }; + DataAdapterTester tester = DataAdapterTester.CreateTester(new FixedHeaderPackageAdapter() + , bufferLength, (byteBlock, requestInfo) => + { + //此处就是接收,如果是自定义适配器,可以将requestInfo强制转换为实际对象,然后判断数据的确定性 + if (byteBlock.Len!=5||(!byteBlock.ToArray().SequenceEqual(data))) + { + isSuccess = false; + } + }); + + //data是发送的数据,因为此处使用的是固定包头适配器, + //发送前适配器会自动添加包头,所以,此处只发送数据即可。 + //如果测试的是自定义适配器,发送前没有封装的话,就需要自行构建发送数据。 + //随后的两个参数,10,10是测试次数,和期望次数,一般这两个值是相等的。 + //意为:本次数据将循环发送10次,且会接收10次。不然此处会一直阻塞。 + //最后一个参数是测试的最大超时时间。 + var time = tester.Run(data, 10, 10, 1000 * 10); + Thread.Sleep(1000); + Console.WriteLine($"测试结束,状态:{isSuccess},用时:{time}"); + } + Console.WriteLine("测试结束"); + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/PipelineConsoleApp/PipelineConsoleApp.csproj b/examples/Adapter简单示例/PipelineConsoleApp/PipelineConsoleApp.csproj new file mode 100644 index 000000000..cae093ede --- /dev/null +++ b/examples/Adapter简单示例/PipelineConsoleApp/PipelineConsoleApp.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/examples/Adapter简单示例/PipelineConsoleApp/Program.cs b/examples/Adapter简单示例/PipelineConsoleApp/Program.cs new file mode 100644 index 000000000..8f27396ad --- /dev/null +++ b/examples/Adapter简单示例/PipelineConsoleApp/Program.cs @@ -0,0 +1,53 @@ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace PipelineConsoleApp +{ + internal class Program + { + private static void Main(string[] args) + { + TcpService service = new TcpService(); + + service.Received = (client, byteBlock, requestInfo) => + { + if (requestInfo is Pipeline pipeline)//实际上Pipeline继承自Stream + { + //pipeline.ReadTimeout = 1000 * 60;//设置读取超时时间为60秒。 + //StreamReader streamReader = new StreamReader(pipeline);//所以可以直接用StreamReader构造 + //string? ss = streamReader.ReadLine();//会一直等换行,直到等到换行,才继续向下执行 + //Console.WriteLine(ss); + + while (true) + { + byte[] buffer = new byte[1024]; + int r = pipeline.Read(buffer); + var str = Encoding.UTF8.GetString(buffer, 0, r); + if (str.Contains("E")) + { + break; + } + pipeline.Write(Encoding.UTF8.GetBytes(str)); + Console.WriteLine(str); + } + } + //当Pipeline退出该事件方法时,会被自动释放,下次会投递新的Pipeline实例。 + // 如果里面还有未Read完的数据,下次会继续投递,如果想直接丢弃,则在此处直接调用Disopose即可。 + }; + + //声明配置 + var config = new TouchSocketConfig(); + config.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .SetDataHandlingAdapter(() => new PipelineDataHandlingAdapter());//配置适配器为Pipeline + + //载入配置 + service.Setup(config); + + //启动 + service.Start(); + + Console.ReadKey(); + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/TLVWinFormsApp/Form1.Designer.cs b/examples/Adapter简单示例/TLVWinFormsApp/Form1.Designer.cs new file mode 100644 index 000000000..8ea4e9efb --- /dev/null +++ b/examples/Adapter简单示例/TLVWinFormsApp/Form1.Designer.cs @@ -0,0 +1,189 @@ +namespace TLVWinFormsApp +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.listBox1 = new System.Windows.Forms.ListBox(); + this.button3 = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.numericUpDown1 = new System.Windows.Forms.NumericUpDown(); + this.button4 = new System.Windows.Forms.Button(); + this.button5 = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit(); + this.SuspendLayout(); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(61, 54); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(150, 46); + this.button1.TabIndex = 0; + this.button1.Text = "启动服务器"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // button2 + // + this.button2.Location = new System.Drawing.Point(249, 54); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(150, 46); + this.button2.TabIndex = 1; + this.button2.Text = "客户端连接"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // listBox1 + // + this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listBox1.FormattingEnabled = true; + this.listBox1.ItemHeight = 31; + this.listBox1.Location = new System.Drawing.Point(12, 160); + this.listBox1.Name = "listBox1"; + this.listBox1.Size = new System.Drawing.Size(1363, 283); + this.listBox1.TabIndex = 2; + // + // button3 + // + this.button3.Location = new System.Drawing.Point(1015, 54); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(150, 46); + this.button3.TabIndex = 3; + this.button3.Text = "发送"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(493, 62); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(56, 31); + this.label1.TabIndex = 4; + this.label1.Text = "Tag"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(671, 62); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(78, 31); + this.label2.TabIndex = 5; + this.label2.Text = "Value"; + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(770, 59); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(200, 38); + this.textBox1.TabIndex = 6; + // + // numericUpDown1 + // + this.numericUpDown1.Location = new System.Drawing.Point(555, 60); + this.numericUpDown1.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.numericUpDown1.Minimum = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.numericUpDown1.Name = "numericUpDown1"; + this.numericUpDown1.Size = new System.Drawing.Size(95, 38); + this.numericUpDown1.TabIndex = 7; + this.numericUpDown1.Value = new decimal(new int[] { + 10, + 0, + 0, + 0}); + // + // button4 + // + this.button4.Location = new System.Drawing.Point(1187, 54); + this.button4.Name = "button4"; + this.button4.Size = new System.Drawing.Size(150, 46); + this.button4.TabIndex = 8; + this.button4.Text = "Ping"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // button5 + // + this.button5.Location = new System.Drawing.Point(1015, 108); + this.button5.Name = "button5"; + this.button5.Size = new System.Drawing.Size(150, 46); + this.button5.TabIndex = 9; + this.button5.Text = "连续发送"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.button5_Click); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(14F, 31F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1387, 450); + this.Controls.Add(this.button5); + this.Controls.Add(this.button4); + this.Controls.Add(this.numericUpDown1); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.button3); + this.Controls.Add(this.listBox1); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Name = "Form1"; + this.Text = "Form1"; + ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button button1; + private Button button2; + private ListBox listBox1; + private Button button3; + private Label label1; + private Label label2; + private TextBox textBox1; + private NumericUpDown numericUpDown1; + private Button button4; + private Button button5; + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/TLVWinFormsApp/Form1.cs b/examples/Adapter简单示例/TLVWinFormsApp/Form1.cs new file mode 100644 index 000000000..2e127e6a6 --- /dev/null +++ b/examples/Adapter简单示例/TLVWinFormsApp/Form1.cs @@ -0,0 +1,124 @@ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TLVWinFormsApp +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + Control.CheckForIllegalCrossThreadCalls = false; + } + + private void ShowMsg(string msg) + { + this.listBox1.Items.Insert(0, msg); + } + + private readonly TcpService m_tcpService = new TcpService(); + + private void button1_Click(object sender, EventArgs e) + { + //յϢ¼ + m_tcpService.Received = (client, byteBlock, requestInfo) => + { + if (requestInfo is TLVDataFrame frame) + { + client.Logger.Info($"յ,Tag={frame.Tag},Len={frame.Length},Value={(frame.Value != null ? Encoding.UTF8.GetString(frame.Value) : string.Empty)}"); + } + }; + + TouchSocketConfig config = new TouchSocketConfig(); + config.SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .UsePlugin() + .ConfigureContainer(a => + { + a.SetSingletonLogger(new EasyLogger(this.ShowMsg)); + }) + .ConfigurePlugins(a => + { + a.Add()//ʹò൱ԶӦPing + .SetLengthType(FixedHeaderType.Int);//ֵֵ֧ͣSetMaxPackageSizeӰ졣 + }); + + // + m_tcpService.Setup(config); + + // + m_tcpService.Start(); + m_tcpService.Logger.Info("ɹ"); + } + + private readonly TcpClient m_client = new TcpClient(); + + private void button2_Click(object sender, EventArgs e) + { + m_client.Setup(new TouchSocketConfig() + .UsePlugin() + .SetMaxPackageSize(1024 * 1024 * 10) + .ConfigureContainer(a => + { + a.SetSingletonLogger(new EasyLogger(this.ShowMsg)); + }) + //.SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//ʹTLVPlugin˲ʡԡ + .ConfigurePlugins(a => + { + a.Add()//ʹò൱ԶӦPing + .SetLengthType(FixedHeaderType.Int);//ֵֵ֧ͣSetMaxPackageSizeӰ졣 + + a.Add>() + .SetTick(TimeSpan.FromSeconds(1)) + .SetActionForCheck((c) => + { + c.Logger.Info($"Զping{c.Ping()}"); + return true; + }); + }) + .SetRemoteIPHost(new IPHost("127.0.0.1:7789"))); + m_client.Connect(); + + m_client.Logger.Info("ӳɹ"); + } + + private void button3_Click(object sender, EventArgs e) + { + try + { + this.m_client?.Send(new ValueTLVDataFrame((ushort)this.numericUpDown1.Value, Encoding.UTF8.GetBytes(this.textBox1.Text))); + } + catch (Exception ex) + { + this.m_client.Logger.Exception(ex); + } + } + + private void button4_Click(object sender, EventArgs e) + { + try + { + m_client.Logger.Info($"ping={this.m_client?.Ping()}"); + } + catch (Exception ex) + { + this.m_client.Logger.Exception(ex); + } + } + + private void button5_Click(object sender, EventArgs e) + { + for (int i = 0; i < 100; i++) + { + try + { + this.m_client?.Send(new ValueTLVDataFrame((ushort)this.numericUpDown1.Value, Encoding.UTF8.GetBytes(i.ToString()))); + } + catch (Exception ex) + { + this.m_client?.Logger.Exception(ex); + } + } + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/TLVWinFormsApp/Form1.resx b/examples/Adapter简单示例/TLVWinFormsApp/Form1.resx new file mode 100644 index 000000000..f298a7be8 --- /dev/null +++ b/examples/Adapter简单示例/TLVWinFormsApp/Form1.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/examples/Adapter简单示例/TLVWinFormsApp/Program.cs b/examples/Adapter简单示例/TLVWinFormsApp/Program.cs new file mode 100644 index 000000000..1df540719 --- /dev/null +++ b/examples/Adapter简单示例/TLVWinFormsApp/Program.cs @@ -0,0 +1,26 @@ +using TouchSocket.Core; + +namespace TLVWinFormsApp +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + private static void Main() + { + try + { + Enterprise.ForTest(); + } + catch + { + } + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new Form1()); + } + } +} \ No newline at end of file diff --git a/examples/Adapter简单示例/TLVWinFormsApp/TLVWinFormsApp.csproj b/examples/Adapter简单示例/TLVWinFormsApp/TLVWinFormsApp.csproj new file mode 100644 index 000000000..6b9abb71d --- /dev/null +++ b/examples/Adapter简单示例/TLVWinFormsApp/TLVWinFormsApp.csproj @@ -0,0 +1,15 @@ + + + + WinExe + net6.0-windows + enable + true + enable + + + + + + + \ No newline at end of file diff --git a/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.Designer.cs b/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.Designer.cs new file mode 100644 index 000000000..1c9d7057c --- /dev/null +++ b/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.Designer.cs @@ -0,0 +1,39 @@ +namespace WinAppForAppMessenger +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Text = "Form1"; + } + + #endregion + } +} \ No newline at end of file diff --git a/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.cs b/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.cs new file mode 100644 index 000000000..9631ee4f5 --- /dev/null +++ b/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.cs @@ -0,0 +1,10 @@ +namespace WinAppForAppMessenger +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.resx b/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/examples/AppMessenger简单示例/WinAppForAppMessenger/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/examples/AppMessenger简单示例/WinAppForAppMessenger/Program.cs b/examples/AppMessenger简单示例/WinAppForAppMessenger/Program.cs new file mode 100644 index 000000000..37829d650 --- /dev/null +++ b/examples/AppMessenger简单示例/WinAppForAppMessenger/Program.cs @@ -0,0 +1,17 @@ +namespace WinAppForAppMessenger +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + private 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 Form1()); + } + } +} \ No newline at end of file diff --git a/examples/AppMessenger简单示例/WinAppForAppMessenger/WinAppForAppMessenger.csproj b/examples/AppMessenger简单示例/WinAppForAppMessenger/WinAppForAppMessenger.csproj new file mode 100644 index 000000000..b57c89e69 --- /dev/null +++ b/examples/AppMessenger简单示例/WinAppForAppMessenger/WinAppForAppMessenger.csproj @@ -0,0 +1,11 @@ + + + + WinExe + net6.0-windows + enable + true + enable + + + \ No newline at end of file diff --git a/examples/BlogsDemos/AccessRestrictionsConsoleApp/AccessRestrictionsConsoleApp.csproj b/examples/BlogsDemos/AccessRestrictionsConsoleApp/AccessRestrictionsConsoleApp.csproj new file mode 100644 index 000000000..cae093ede --- /dev/null +++ b/examples/BlogsDemos/AccessRestrictionsConsoleApp/AccessRestrictionsConsoleApp.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/examples/BlogsDemos/AccessRestrictionsConsoleApp/Program.cs b/examples/BlogsDemos/AccessRestrictionsConsoleApp/Program.cs new file mode 100644 index 000000000..214d40535 --- /dev/null +++ b/examples/BlogsDemos/AccessRestrictionsConsoleApp/Program.cs @@ -0,0 +1,131 @@ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace AccessRestrictionsConsoleApp +{ + internal class Program + { + /// + /// 实现黑白名单功能,博客 + /// + /// + static void Main(string[] args) + { + TcpService service = new TcpService(); + service.Received = (client, byteBlock, requestInfo) => + { + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + client.Logger.Info($"已从{client.ID}接收到信息:{mes}"); + }; + + service.Setup(new TouchSocketConfig()//载入配置 + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + a.RegisterSingleton();//注册访问限制实例,AccessRestrictions可自行实现,例如连接数据库做持久化等。 + }) + .ConfigurePlugins(a => + { + a.Add();//添加访问限制插件 + })) + .Start();//启动 + + service.Logger.Info("服务器成功启动"); + Console.ReadKey(); + } + } + + public class AccessRestrictionsPlugin : TcpPluginBase + { + private readonly IAccessRestrictions accessRestrictions; + + public AccessRestrictionsPlugin(IAccessRestrictions accessRestrictions) + { + this.accessRestrictions = accessRestrictions ?? throw new ArgumentNullException(nameof(accessRestrictions)); + } + protected override void OnConnecting(ITcpClientBase client, OperationEventArgs e) + { + if (client is ITcpClient) + { + //此处判断,如果该插件被添加在客户端,则不工作。 + return; + } + if (this.accessRestrictions.ExistsWhiteList(client.IP)) + { + //如果存在于白名单,直接返回,允许连接 + return; + } + if (this.accessRestrictions.ExistsBlackList(client.IP)) + { + //如果存在于黑名单,不允许连接 + e.IsPermitOperation = false; + e.Handled = true;//表示此处已经处理OnConnecting消息,其他插件不再路由投递。 + return; + } + base.OnConnecting(client, e); + } + } + + public interface IAccessRestrictions + { + bool AddWhiteList(string ip); + bool AddBlackList(string ip); + + bool RemoveWhiteList(string ip); + bool RemoveBlackList(string ip); + + bool ExistsWhiteList(string ip); + bool ExistsBlackList(string ip); + } + + public class AccessRestrictions : IAccessRestrictions + { + readonly List whiteListIP = new List(); + readonly List blackListIP = new List(); + public virtual bool AddBlackList(string ip) + { + if (blackListIP.Contains(ip)) + { + return true; + } + blackListIP.Add(ip); + return true; + } + + public virtual bool AddWhiteList(string ip) + { + if (whiteListIP.Contains(ip)) + { + return true; + } + whiteListIP.Add(ip); + return true; + } + + public virtual bool ExistsBlackList(string ip) + { + //实际上此处也可以用正则表达式 + return this.blackListIP.Contains(ip); + } + + public virtual bool ExistsWhiteList(string ip) + { + //实际上此处也可以用正则表达式 + return this.whiteListIP.Contains(ip); + } + + public virtual bool RemoveBlackList(string ip) + { + return this.blackListIP.Remove(ip); + } + + public virtual bool RemoveWhiteList(string ip) + { + return this.whiteListIP.Remove(ip); + } + } +} \ No newline at end of file diff --git a/examples/BlogsDemos/DifferentProtocolConsoleApp/DifferentProtocolConsoleApp.csproj b/examples/BlogsDemos/DifferentProtocolConsoleApp/DifferentProtocolConsoleApp.csproj new file mode 100644 index 000000000..cae093ede --- /dev/null +++ b/examples/BlogsDemos/DifferentProtocolConsoleApp/DifferentProtocolConsoleApp.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/examples/BlogsDemos/DifferentProtocolConsoleApp/Program.cs b/examples/BlogsDemos/DifferentProtocolConsoleApp/Program.cs new file mode 100644 index 000000000..118679a83 --- /dev/null +++ b/examples/BlogsDemos/DifferentProtocolConsoleApp/Program.cs @@ -0,0 +1,63 @@ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace DifferentProtocolConsoleApp +{ + /// + /// C# Tcp服务器实现多端口、多协议解析,博客 + /// + internal class Program + { + static void Main(string[] args) + { + TcpService service = new TcpService(); + service.Setup(new TouchSocketConfig()//载入配置 + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + }) + .ConfigurePlugins(a => + { + a.Add(); + })) + .Start();//启动 + + service.Logger.Info("服务器成功启动"); + Console.ReadKey(); + } + } + + /// + /// 此插件实现,按照不同端口,使用不同适配器。 + /// + /// 7789端口:使用"**"结尾的数据 + /// 7790端口:使用"##"结尾的数据 + /// + /// + class DifferentProtocolPlugin : TcpPluginBase + { + protected override void OnConnecting(ISocketClient client, OperationEventArgs e) + { + if (client.ServicePort == 7789) + { + client.SetDataHandlingAdapter(new TerminatorPackageAdapter("**")); + } + else + { + client.SetDataHandlingAdapter(new TerminatorPackageAdapter("##")); + } + base.OnConnecting(client, e); + } + + protected override void OnReceivedData(ISocketClient client, ReceivedDataEventArgs e) + { + //如果是自定义适配器,此处解析时,可以判断e.RequestInfo的类型 + + client.Logger.Info($"{client.GetInfo()}收到数据,服务器端口:{client.ServicePort},数据:{e.ByteBlock}"); + base.OnReceivedData(client, e); + } + } +} \ No newline at end of file diff --git a/examples/BlogsDemos/HeartbeatConsoleApp/HeartbeatConsoleApp.csproj b/examples/BlogsDemos/HeartbeatConsoleApp/HeartbeatConsoleApp.csproj new file mode 100644 index 000000000..96e64bbbf --- /dev/null +++ b/examples/BlogsDemos/HeartbeatConsoleApp/HeartbeatConsoleApp.csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + + + + + + diff --git a/examples/BlogsDemos/HeartbeatConsoleApp/Program.cs b/examples/BlogsDemos/HeartbeatConsoleApp/Program.cs new file mode 100644 index 000000000..eb04a0b9b --- /dev/null +++ b/examples/BlogsDemos/HeartbeatConsoleApp/Program.cs @@ -0,0 +1,254 @@ +using System; +using System.Text; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace HeartbeatConsoleApp +{ + internal class Program + { + /// + /// 示例心跳。 + /// 博客地址 + /// + /// + private static void Main(string[] args) + { + ConsoleAction consoleAction = new ConsoleAction(); + + //服务器 + TcpService service = new TcpService(); + service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .UsePlugin() + .SetDataHandlingAdapter(()=>new MyFixedHeaderDataHandlingAdapter()) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + })) + .Start();//启动 + service.Logger.Info("服务器成功启动"); + + //客户端 + TcpClient tcpClient = new TcpClient(); + tcpClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost(new IPHost("127.0.0.1:7789")) + .UsePlugin() + .SetDataHandlingAdapter(() => new MyFixedHeaderDataHandlingAdapter()) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + })); + tcpClient.Connect(); + tcpClient.Logger.Info("客户端成功连接"); + + consoleAction.OnException += ConsoleAction_OnException; + consoleAction.Add("1", "发送心跳", () => + { + tcpClient.Ping(); + }); + consoleAction.Add("2", "发送数据", () => + { + tcpClient.Send(new MyRequestInfo() + { + DataType = DataType.Data, + Data = Encoding.UTF8.GetBytes(Console.ReadLine()) + } + .PackageAsBytes()); + }); + consoleAction.ShowAll(); + while (true) + { + consoleAction.Run(Console.ReadLine()); + } + } + + private static void ConsoleAction_OnException(Exception obj) + { + Console.WriteLine(obj); + } + } + + #region 数据格式解析 + + internal class MyFixedHeaderDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter + { + public override int HeaderLength => 3; + + public override bool CanSendRequestInfo => false; + + protected override MyRequestInfo GetInstance() + { + return new MyRequestInfo(); + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + } + + internal class MyRequestInfo : IFixedHeaderRequestInfo + { + public DataType DataType { get; set; } + public byte[] Data { get; set; } + + public int BodyLength { get; private set; } + + public bool OnParsingBody(byte[] body) + { + if (body.Length == this.BodyLength) + { + this.Data = body; + return true; + } + return false; + } + + public bool OnParsingHeader(byte[] header) + { + if (header.Length == 3) + { + this.BodyLength = TouchSocketBitConverter.Default.ToUInt16(header, 0) - 1; + this.DataType = (DataType)header[2]; + return true; + } + return false; + } + + public void Package(ByteBlock byteBlock) + { + byteBlock.Write((ushort)((this.Data == null ? 0 : this.Data.Length) + 1)); + byteBlock.Write((byte)this.DataType); + if (Data != null) + { + byteBlock.Write(Data); + } + } + + public byte[] PackageAsBytes() + { + using ByteBlock byteBlock = new ByteBlock(); + this.Package(byteBlock); + return byteBlock.ToArray(); + } + + public override string ToString() + { + return $"数据类型={this.DataType},数据={(this.Data == null ? "null" : Encoding.UTF8.GetString(this.Data))}"; + } + } + + internal enum DataType : byte + { + Ping, + Pong, + Data + } + + #endregion 数据格式解析 + + /// + /// 一个心跳计数器扩展。 + /// + internal static class DependencyExtensions + { + public static readonly DependencyProperty HeartbeatTimerProperty = + DependencyProperty.Register("HeartbeatTimer", typeof(DependencyExtensions), null); + + public static bool Ping(this TClient client) where TClient : ITcpClientBase + { + try + { + client.Send(new MyRequestInfo() { DataType = DataType.Ping }.PackageAsBytes()); + return true; + } + catch (Exception ex) + { + client.Logger.Exception(ex); + } + + return false; + } + + public static bool Pong(this TClient client) where TClient : ITcpClientBase + { + try + { + client.Send(new MyRequestInfo() { DataType = DataType.Pong }.PackageAsBytes()); + return true; + } + catch (Exception ex) + { + client.Logger.Exception(ex); + } + + return false; + } + } + + internal class HeartbeatAndReceivePlugin : TcpPluginBase + { + private readonly int m_timeTick; + private readonly ILog logger; + + [DependencyInject(1000 * 5)] + public HeartbeatAndReceivePlugin(int timeTick, ILog logger) + { + this.m_timeTick = timeTick; + this.logger = logger; + } + + protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e) + { + if (client is ISocketClient) + { + return;//此处可判断,如果为服务器,则不用使用心跳。 + } + + if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer) + { + timer.Dispose(); + } + + client.SetValue(DependencyExtensions.HeartbeatTimerProperty, new Timer((o) => + { + client.Ping(); + }, null, 0, m_timeTick)); + + base.OnConnected(client, e); + } + + protected override void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + base.OnDisconnected(client, e); + if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer) + { + timer.Dispose(); + client.SetValue(DependencyExtensions.HeartbeatTimerProperty, null); + } + } + + protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + if (e.RequestInfo is MyRequestInfo myRequest) + { + this.logger.Info(myRequest.ToString()); + if (myRequest.DataType == DataType.Ping) + { + client.Pong(); + } + } + base.OnReceivedData(client, e); + } + } +} \ No newline at end of file diff --git a/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/LimitNumberOfConnectionsConsoleApp.csproj b/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/LimitNumberOfConnectionsConsoleApp.csproj new file mode 100644 index 000000000..87e69ed94 --- /dev/null +++ b/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/LimitNumberOfConnectionsConsoleApp.csproj @@ -0,0 +1,12 @@ + + + + Exe + net6.0 + + + + + + + diff --git a/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/Program.cs b/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/Program.cs new file mode 100644 index 000000000..e04919982 --- /dev/null +++ b/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/Program.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Concurrent; +using System.Text; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace LimitNumberOfConnectionsConsoleApp +{ + internal class Program + { + /// + /// 限制同一个IP的连接数量 + /// 博客地址 + /// + /// + private static void Main(string[] args) + { + TcpService service = new TcpService(); + service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + }) + .UsePlugin()) + .Start();//启动 + service.Logger.Info("服务器已启动"); + Console.ReadKey(); + } + } + + internal class Count + { + private int num; + + public int Num + { + get { return num; } + } + + public int Decrement() + { + return Interlocked.Decrement(ref num); + } + + public int Increment() + { + return Interlocked.Increment(ref num); + } + } + + internal class LimitNumberOfConnectionsPlugin : TcpPluginBase + { + private readonly ConcurrentDictionary m_ipToCount = new ConcurrentDictionary(); + + private readonly ILog m_logger; + + [DependencyInject(2)] + public LimitNumberOfConnectionsPlugin(int max, ILog logger) + { + this.Max = max; + this.m_logger = logger; + + logger.Info($"限制连接插件生效,同一IP限制{max}个连接"); + } + + public LimitNumberOfConnectionsPlugin(ILog logger) + { + this.m_logger = logger; + } + + public int Max { get; } + + protected override void OnConnecting(ITcpClientBase client, OperationEventArgs e) + { + Count count = m_ipToCount.GetOrAdd(client.IP, (s) => { return new Count(); }); + + if (count.Increment() > this.Max) + { + count.Decrement(); + e.IsPermitOperation = false;//表示不许连接 + e.Handled = true;//并且已经处理该消息。 + this.m_logger.Warning($"IP={client.IP}的客户端,连接数达到设置阈值。已拒绝连接。"); + return; + } + base.OnConnecting(client, e); + } + + protected override void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + if (m_ipToCount.TryGetValue(client.IP, out Count count)) + { + if (count.Decrement() == 0) + { + m_ipToCount.TryRemove(client.IP, out _); + } + } + base.OnDisconnected(client, e); + } + } +} \ No newline at end of file diff --git a/examples/BlogsDemos/ThrottlingConsoleApp/Program.cs b/examples/BlogsDemos/ThrottlingConsoleApp/Program.cs new file mode 100644 index 000000000..8aacd0847 --- /dev/null +++ b/examples/BlogsDemos/ThrottlingConsoleApp/Program.cs @@ -0,0 +1,84 @@ +using System; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace ThrottlingConsoleApp +{ + internal class Program + { + /// + /// 限制单个客户端的访问流量 + /// 博客连接 + /// + /// + private static void Main(string[] args) + { + TcpService service = new TcpService(); + service.Received = (client, byteBlock, requestInfo) => + { + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + client.Logger.Info($"已从{client.ID}接收到信息:{mes}"); + }; + + service.Setup(new TouchSocketConfig()//载入配置 + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + })) + .Start();//启动 + service.Logger.Info("服务器已启动"); + Console.ReadLine(); + } + } + + /// + /// 一个流量计数器扩展。 + /// + internal static class DependencyExtensions + { + public static readonly DependencyProperty FlowGateProperty = + DependencyProperty.Register("FlowGate", typeof(DependencyExtensions), null); + + public static void InitFlowGate(this IDependencyObject dependencyObject, int max) + { + dependencyObject.SetValue(FlowGateProperty, new FlowGate() { Maximum = max }); + } + + public static FlowGate GetFlowGate(this IDependencyObject dependencyObject) + { + return dependencyObject.GetValue(FlowGateProperty); + } + } + + public class MyThrottlingPlugin : TcpPluginBase + { + private readonly int m_max; + + [DependencyInject(10)] + public MyThrottlingPlugin(int max) + { + this.m_max = max; + this.Order = int.MaxValue;//提升优先级 + } + + protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e) + { + client.InitFlowGate(this.m_max);//初始化流量计数器。 + base.OnConnected(client, e); + } + + protected override void OnReceivingData(ITcpClientBase client, ByteBlockEventArgs e) + { + client.GetFlowGate().AddCheckWait(e.ByteBlock.Len); + base.OnReceivingData(client, e); + } + } +} \ No newline at end of file diff --git a/examples/BlogsDemos/ThrottlingConsoleApp/ThrottlingConsoleApp.csproj b/examples/BlogsDemos/ThrottlingConsoleApp/ThrottlingConsoleApp.csproj new file mode 100644 index 000000000..87e69ed94 --- /dev/null +++ b/examples/BlogsDemos/ThrottlingConsoleApp/ThrottlingConsoleApp.csproj @@ -0,0 +1,12 @@ + + + + Exe + net6.0 + + + + + + + diff --git a/examples/BlogsDemos/TrafficCounterConsoleApp/Program.cs b/examples/BlogsDemos/TrafficCounterConsoleApp/Program.cs new file mode 100644 index 000000000..d5992d37a --- /dev/null +++ b/examples/BlogsDemos/TrafficCounterConsoleApp/Program.cs @@ -0,0 +1,146 @@ +using System; +using System.Text; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TrafficCounterConsoleApp +{ + internal class Program + { + private static void Main(string[] args) + { + TcpService service = new TcpService(); + service.Received = (client, byteBlock, requestInfo) => + { + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + Console.WriteLine($"已从{client.ID}接收到信息:{mes}"); + client.Send(mes);//将收到的信息直接返回给发送方 + }; + + service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .SetMaxCount(1000) + .SetThreadCount(10) + .UsePlugin() + .ConfigurePlugins(a => + { + a.Add(new object[] { false });//此处可以添加插件 + }) + .ConfigureContainer(a => + { + a.AddConsoleLogger();//添加一个日志注入 + })) + .Start();//启动 + Timer timer = new Timer((s) => + { + var clients = service.GetClients(); + foreach (var item in clients) + { + item.Logger.Info($"发送流量:{item.GetSendTrafficCounter()}"); + item.Logger.Info($"接收流量:{item.GetReceivedTrafficCounter()}"); + } + }, null, 0, 1000); + + Console.ReadKey(); + } + } + + public class TrafficCounterPlugin : TcpPluginBase + { + public bool AutoRefresh { get; } + + [DependencyInject(true)] + public TrafficCounterPlugin(bool autoRefresh) + { + this.AutoRefresh = autoRefresh; + } + + protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e) + { + client.SetValue(TrafficCounterEx.AutoRefreshProperty, this.AutoRefresh); + if (this.AutoRefresh) + { + client.SetValue(TrafficCounterEx.AutoRefreshTimerProperty, new Timer((s) => + { + var countSend = client.GetValue(TrafficCounterEx.SendTempTrafficCounterProperty); + client.SetValue(TrafficCounterEx.SendTempTrafficCounterProperty, 0); + client.SetValue(TrafficCounterEx.SendTrafficCounterProperty, countSend); + + var countRev = client.GetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty); + client.SetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty, 0); + client.SetValue(TrafficCounterEx.ReceivedTrafficCounterProperty, countRev); + }, null, 0, 1000)); + } + + base.OnConnected(client, e); + } + + protected override void OnSending(ITcpClientBase client, SendingEventArgs e) + { + client.SetValue(TrafficCounterEx.SendTempTrafficCounterProperty, + e.Length + client.GetValue(TrafficCounterEx.SendTempTrafficCounterProperty)); + base.OnSending(client, e); + } + + protected override void OnReceivingData(ITcpClientBase client, ByteBlockEventArgs e) + { + client.SetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty, + e.ByteBlock.Len + +client.GetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty)); + base.OnReceivingData(client, e); + } + } + + public static class TrafficCounterEx + { + + public static readonly DependencyProperty SendTrafficCounterProperty = + DependencyProperty.Register("SendTrafficCounter", typeof(TrafficCounterEx), 0); + + public static readonly DependencyProperty SendTempTrafficCounterProperty = + DependencyProperty.Register("SendTempTrafficCounter", typeof(TrafficCounterEx), 0); + + public static readonly DependencyProperty ReceivedTrafficCounterProperty = DependencyProperty.Register("ReceivedTrafficCounter", typeof(TrafficCounterEx), 0); + + public static readonly DependencyProperty ReceivedTempTrafficCounterProperty = DependencyProperty.Register("ReceivedTempTrafficCounter", typeof(TrafficCounterEx), 0); + + public static readonly DependencyProperty AutoRefreshProperty = + DependencyProperty.Register("AutoRefresh", typeof(TrafficCounterEx), true); + + public static readonly DependencyProperty AutoRefreshTimerProperty = + DependencyProperty.Register("AutoRefreshTimer", typeof(TrafficCounterEx), null); + + public static int GetSendTrafficCounter(this DependencyObject dependencyObject) + { + if (dependencyObject.GetValue(AutoRefreshProperty)) + { + return dependencyObject.GetValue(SendTrafficCounterProperty); + } + else + { + var count = dependencyObject.GetValue(SendTempTrafficCounterProperty); + dependencyObject.SetValue(SendTempTrafficCounterProperty, 0); + + dependencyObject.SetValue(SendTrafficCounterProperty, count); + return count; + } + } + + public static int GetReceivedTrafficCounter(this DependencyObject dependencyObject) + { + if (dependencyObject.GetValue(AutoRefreshProperty)) + { + return dependencyObject.GetValue(ReceivedTrafficCounterProperty); + } + else + { + var count = dependencyObject.GetValue(ReceivedTempTrafficCounterProperty); + dependencyObject.SetValue(ReceivedTempTrafficCounterProperty, 0); + + dependencyObject.SetValue(ReceivedTrafficCounterProperty, count); + return count; + } + } + } +} \ No newline at end of file diff --git a/examples/BlogsDemos/TrafficCounterConsoleApp/TrafficCounterConsoleApp.csproj b/examples/BlogsDemos/TrafficCounterConsoleApp/TrafficCounterConsoleApp.csproj new file mode 100644 index 000000000..96e64bbbf --- /dev/null +++ b/examples/BlogsDemos/TrafficCounterConsoleApp/TrafficCounterConsoleApp.csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + + + + + + diff --git a/examples/BytePool简单示例/BytePoolConsoleApp/BytePoolConsoleApp.csproj b/examples/BytePool简单示例/BytePoolConsoleApp/BytePoolConsoleApp.csproj new file mode 100644 index 000000000..fd16ad4f0 --- /dev/null +++ b/examples/BytePool简单示例/BytePoolConsoleApp/BytePoolConsoleApp.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + + + + + diff --git a/examples/BytePool简单示例/BytePoolConsoleApp/Program.cs b/examples/BytePool简单示例/BytePoolConsoleApp/Program.cs new file mode 100644 index 000000000..c9aa85fbc --- /dev/null +++ b/examples/BytePool简单示例/BytePoolConsoleApp/Program.cs @@ -0,0 +1,66 @@ +using System; +using TouchSocket.Core; + +namespace BytePoolConsoleApp +{ + internal class Program + { + private static void Main(string[] args) + { + Console.ReadKey(); + + BytePool.Default.AddSizeKey(1024 * 1024); + //BytePool.AutoZero = true; + for (int i = 0; i < 5; i++) + { + byte[] data = BytePool.Default.GetByteCore(1024 * 10, true); + BytePool.Default.Recycle(data); + using (ByteBlock byteBlock = new ByteBlock(1024 * 10, true)) + { + //最重要:千万不要引用byteBlock.Buffer + byteBlock.Write(10); + byteBlock.Write('A'); + byteBlock.Write(100L); + byteBlock.Write(3.1415926); + byteBlock.Write("Hello TouchSocket"); + + var buffer = byteBlock.ToArray(); + + byteBlock.Position = 0; + + var p1 = byteBlock.ReadInt32(); + var p2 = byteBlock.ReadChar(); + var p3 = byteBlock.ReadInt64(); + var p4 = byteBlock.ReadDouble(); + var p5 = byteBlock.ReadString(); + } + } + + Console.ReadKey(); + } + + private static void Performance() + { + int count = 1000000; + TimeSpan timeSpan1 = TimeMeasurer.Run(() => + { + for (int i = 0; i < count; i++) + { + byte[] buffer = new byte[1024]; + } + }); + + TimeSpan timeSpan2 = TimeMeasurer.Run(() => + { + for (int i = 0; i < count; i++) + { + ByteBlock byteBlock = new ByteBlock(1024, true); + byteBlock.Dispose(); + } + }); + + Console.WriteLine($"直接实例化:{timeSpan1}"); + Console.WriteLine($"内存池实例化:{timeSpan2}"); + } + } +} \ No newline at end of file diff --git a/examples/Consul集群示例/ConsulConsoleApp/ConsulConsoleApp.csproj b/examples/Consul集群示例/ConsulConsoleApp/ConsulConsoleApp.csproj new file mode 100644 index 000000000..6c9cae735 --- /dev/null +++ b/examples/Consul集群示例/ConsulConsoleApp/ConsulConsoleApp.csproj @@ -0,0 +1,13 @@ + + + + Exe + net6.0 + + + + + + + + diff --git a/examples/Consul集群示例/ConsulConsoleApp/Program.cs b/examples/Consul集群示例/ConsulConsoleApp/Program.cs new file mode 100644 index 000000000..9e48e8e59 --- /dev/null +++ b/examples/Consul集群示例/ConsulConsoleApp/Program.cs @@ -0,0 +1,70 @@ +using Consul; +using System; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace ConsulConsoleApp +{ + internal class Program + { + private static void Main(string[] args) + { + TcpService service = new TcpService(); + service.Connecting = (client, e) => + { + service.Logger.Info("Connecting"); + };//有客户端正在连接 + service.Connected = (client, e) => { service.Logger.Info("Connected"); };//有客户端连接 + service.Disconnected = (client, e) => { service.Logger.Info("Disconnected"); };//有客户端断开连接 + service.Received = (client, byteBlock, requestInfo) => + { + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + client.Logger.Info($"已从{client.ID}接收到信息:{mes}"); + + //client.Send(mes);//将收到的信息直接返回给发送方 + }; + + service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + ) + .Start();//启动 + + RegisterConsul(7789); + Console.ReadKey(); + } + + /// + /// 注册Consul,使用该功能时,请先了解Consul,然后配置基本如下。 + /// + public static void RegisterConsul(int port) + { + var consulClient = new ConsulClient(p => { p.Address = new Uri($"http://127.0.0.1:8500"); });//请求注册的 Consul 地址 + //这里的这个ip 就是本机的ip,这个端口8500 这个是默认注册服务端口 + var httpCheck = new AgentServiceCheck() + { + DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册 + Interval = TimeSpan.FromSeconds(10), + //HTTP = $"http://127.0.0.1:{port}/api/Health",//健康检查地址 + TCP = $"127.0.0.1:{port}", + Timeout = TimeSpan.FromSeconds(5) + }; + + var registration = new AgentServiceRegistration() + { + Checks = new[] { httpCheck }, + ID = Guid.NewGuid().ToString(), + Name = "RRQM Tcp Service" + port, + Address = "127.0.0.1", + Port = port + }; + + consulClient.Agent.ServiceRegister(registration).Wait();//注册服务 + + //consulClient.Agent.ServiceDeregister(registration.ID).Wait();//registration.ID是guid + //当服务停止时需要取消服务注册,不然,下次启动服务时,会再注册一个服务。 + //但是,如果该服务长期不启动,那consul会自动删除这个服务,大约2,3分钟就会删了 + } + } +} \ No newline at end of file diff --git a/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/Program.cs b/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/Program.cs new file mode 100644 index 000000000..e906df1dd --- /dev/null +++ b/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/Program.cs @@ -0,0 +1,158 @@ +using Consul; +using System; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Http.WebSockets; +using TouchSocket.Rpc; +using TouchSocket.Rpc.JsonRpc; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Rpc.WebApi; +using TouchSocket.Rpc.XmlRpc; +using TouchSocket.Sockets; + +namespace ServiceConsoleApp +{ + internal class Program + { + private static void Main(string[] args) + { + Console.WriteLine("输入本地监听端口"); + int port = int.Parse(Console.ReadLine()); + + //此处直接建立HttpTouchRpcService。 + //此组件包含Http所有功能,可以承载JsonRpc、XmlRpc、WebSocket、TouchRpc等等。 + var service = new TouchSocketConfig() + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost(port) }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigureRpcStore(a => + { + a.RegisterServer(); + }) + .ConfigurePlugins(a => + { + a.UseWebSocket()//添加WebSocket功能 + .SetWSUrl("/ws"); + a.Add();//添加WebSocket业务数据接收插件 + a.Add();//添加WebSocket快捷实现,常规WS客户端发送文本“Add 10 20”即可得到30。 + a.Add().SetXmlRpcUrl("/xmlrpc"); + a.Add().SetJsonRpcUrl("/jsonrpc"); + a.Add(); + }) + .BuildWithHttpTouchRpcService(); + + service.Logger.Info("Http服务器已启动"); + service.Logger.Info($"WS插件已加载,使用 ws://127.0.0.1:{port}/ws 连接"); + service.Logger.Info("WS命令行插件已加载,使用WS发送文本“Add 10 20”获取答案"); + + service.Logger.Info($"jsonrpc插件已加载,使用 Http://127.0.0.1:{port}/jsonrpc +JsonRpc规范调用"); + service.Logger.Info($"xmlrpc插件已加载,使用 Http://127.0.0.1:{port}/xmlrpc +XmlRpc规范调用"); + service.Logger.Info("WebApi插件已加载"); + service.Logger.Info("RPC注册完成。"); + + RegisterConsul(port); + service.Logger.Info("Consul已成功注册"); + + while (Console.ReadKey().Key != ConsoleKey.Escape) + { + Console.WriteLine("按ESC键退出。"); + } + } + + /// + /// 注册Consul,使用该功能时,请先了解Consul,然后配置基本如下。 + /// + public static void RegisterConsul(int port) + { + var consulClient = new ConsulClient(p => { p.Address = new Uri($"http://127.0.0.1:8500"); });//请求注册的 Consul 地址 + //这里的这个ip 就是本机的ip,这个端口8500 这个是默认注册服务端口 + var httpCheck = new AgentServiceCheck() + { + DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册 + Interval = TimeSpan.FromSeconds(10),//间隔固定的时间访问一次,https://127.0.0.1:7789/api/Health + HTTP = $"http://127.0.0.1:{port}/api/Health",//健康检查地址 + Timeout = TimeSpan.FromSeconds(5) + }; + + var registration = new AgentServiceRegistration() + { + Checks = new[] { httpCheck }, + ID = Guid.NewGuid().ToString(), + Name = "RRQMService" + port, + Address = "127.0.0.1", + Port = port + }; + + consulClient.Agent.ServiceRegister(registration).Wait();//注册服务 + + //consulClient.Agent.ServiceDeregister(registration.ID).Wait();//registration.ID是guid + //当服务停止时需要取消服务注册,不然,下次启动服务时,会再注册一个服务。 + //但是,如果该服务长期不启动,那consul会自动删除这个服务,大约2,3分钟就会删了 + } + } + + internal class MyServer : RpcServer + { + [WebApi(HttpMethodType.GET)] + [XmlRpc] + [JsonRpc] + [TouchRpc] + public string SayHello(string name) + { + return $"{name},RRQM says hello to you."; + } + + /// + /// 健康检测 + /// + /// + [Router("/api/health")] + [WebApi(HttpMethodType.GET)] + public string Health() + { + return "ok"; + } + } + + /// + /// WS命令行执行 + /// + internal class MyWebSocketCommand : WSCommandLinePlugin + { + public MyWebSocketCommand(ILog logger) : base(logger) + { + } + + public int AddCommand(int a, int b) + { + return a + b; + } + } + + /// + /// WS收到数据等业务。 + /// + internal class MyWebSocketPlug : WebSocketPluginBase + { + protected override void OnHandshaked(ITcpClientBase client, HttpContextEventArgs e) + { + SocketClient socketClient = (SocketClient)client; + + client.Logger.Info($"WS客户端连接,ID={socketClient.ID},IPHost={client.IP}:{client.Port}"); + base.OnHandshaked(client, e); + } + + protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + if (e.DataFrame.Opcode == WSDataType.Text) + { + client.Logger.Info($"WS Msg={e.DataFrame.ToText()}"); + } + + base.OnHandleWSDataFrame(client, e); + } + } +} \ No newline at end of file diff --git a/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/ServiceConsoleApp.csproj b/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/ServiceConsoleApp.csproj new file mode 100644 index 000000000..6c9cae735 --- /dev/null +++ b/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/ServiceConsoleApp.csproj @@ -0,0 +1,13 @@ + + + + Exe + net6.0 + + + + + + + + diff --git a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.Designer.cs b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.Designer.cs new file mode 100644 index 000000000..29aead7e1 --- /dev/null +++ b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.Designer.cs @@ -0,0 +1,124 @@ + +namespace WinFormsApp +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listBox1 = new System.Windows.Forms.ListBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.button3 = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // listBox1 + // + this.listBox1.DisplayMember = "Service"; + this.listBox1.FormattingEnabled = true; + this.listBox1.ItemHeight = 17; + this.listBox1.Location = new System.Drawing.Point(13, 47); + this.listBox1.Name = "listBox1"; + this.listBox1.Size = new System.Drawing.Size(217, 395); + this.listBox1.TabIndex = 0; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(13, 18); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(217, 23); + this.button1.TabIndex = 1; + this.button1.Text = "获取所有服务"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // button2 + // + this.button2.Location = new System.Drawing.Point(475, 46); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.TabIndex = 2; + this.button2.Text = "TouchRpc"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(283, 46); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(171, 23); + this.textBox1.TabIndex = 3; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(236, 49); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(43, 17); + this.label1.TabIndex = 4; + this.label1.Text = "Name"; + // + // button3 + // + this.button3.Location = new System.Drawing.Point(556, 46); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(75, 23); + this.button3.TabIndex = 5; + this.button3.Text = "JsonRpc"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.button3); + this.Controls.Add(this.label1); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.listBox1); + this.Name = "Form1"; + this.Text = "JsonRpc"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ListBox listBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button button3; + } +} + diff --git a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.cs b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.cs new file mode 100644 index 000000000..1d6b6e3bf --- /dev/null +++ b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.cs @@ -0,0 +1,86 @@ +using Consul; +using System; +using System.Linq; +using System.Windows.Forms; +using TouchSocket.Core; +using TouchSocket.Rpc.JsonRpc; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace WinFormsApp +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + + private AgentService[] services; + + private async void button1_Click(object sender, EventArgs e) + { + var consulClient = new ConsulClient(x => x.Address = new Uri($"http://127.0.0.1:8500"));//请求注册的 Consul 地址 + var ret = await consulClient.Agent.Services(); + + services = ret.Response.Values.ToArray(); + this.listBox1.DataSource = services; + } + + private void button2_Click(object sender, EventArgs e) + { + if (this.listBox1.SelectedItem is AgentService agentService) + { + try + { + HttpTouchRpcClient client = new HttpTouchRpcClient(); + client.Setup(new TouchSocketConfig() + .SetRemoteIPHost($"{agentService.Address}:{agentService.Port}")); + client.Connect(); + + //直接调用时,第一个参数为服务名+方法名(必须全小写) + //第二个参数为调用配置参数,可设置调用超时时间,取消调用等功能。 + //后续参数为调用参数。 + string result = client.Invoke("myserver/sayhello", InvokeOption.WaitInvoke, textBox1.Text); + client.SafeDispose(); + MessageBox.Show(result); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + else + { + MessageBox.Show("请先选择一个服务器节点。"); + } + } + + private void button3_Click(object sender, EventArgs e) + { + if (this.listBox1.SelectedItem is AgentService agentService) + { + try + { + JsonRpcClient client = new JsonRpcClient(); + client.Setup(new TouchSocketConfig() + .SetJRPT(JRPT.Http) + .SetRemoteIPHost($"http://{agentService.Address}:{agentService.Port}/jsonrpc")); + client.Connect(); + + string result = client.Invoke("myserver/sayhello", InvokeOption.WaitInvoke, textBox1.Text); + client.SafeDispose(); + MessageBox.Show(result); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + else + { + MessageBox.Show("请先选择一个服务器节点。"); + } + } + } +} \ No newline at end of file diff --git a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.resx b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.resx new file mode 100644 index 000000000..f298a7be8 --- /dev/null +++ b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Program.cs b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Program.cs new file mode 100644 index 000000000..0af8b13d9 --- /dev/null +++ b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Program.cs @@ -0,0 +1,20 @@ +using System; +using System.Windows.Forms; + +namespace WinFormsApp +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + private static void Main() + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} \ No newline at end of file diff --git a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/WinFormsApp.csproj b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/WinFormsApp.csproj new file mode 100644 index 000000000..da14a7be5 --- /dev/null +++ b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/WinFormsApp.csproj @@ -0,0 +1,14 @@ + + + + WinExe + net6.0-windows + true + + + + + + + + \ No newline at end of file diff --git a/examples/EventBus简单示例/EventBusClient/EventBusClient.csproj b/examples/EventBus简单示例/EventBusClient/EventBusClient.csproj new file mode 100644 index 000000000..15147dcbf --- /dev/null +++ b/examples/EventBus简单示例/EventBusClient/EventBusClient.csproj @@ -0,0 +1,13 @@ + + + + WinExe + net6.0-windows + true + + + + + + + \ No newline at end of file diff --git a/examples/EventBus简单示例/EventBusClient/Form1.Designer.cs b/examples/EventBus简单示例/EventBusClient/Form1.Designer.cs new file mode 100644 index 000000000..fd5bae009 --- /dev/null +++ b/examples/EventBus简单示例/EventBusClient/Form1.Designer.cs @@ -0,0 +1,359 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.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首页:https://www.yuque.com/eo2w71/rrqm +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace EERPCClientDemo +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.button2 = new System.Windows.Forms.Button(); + this.checkBox3 = new System.Windows.Forms.CheckBox(); + this.checkBox2 = new System.Windows.Forms.CheckBox(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button3 = new System.Windows.Forms.Button(); + this.button4 = new System.Windows.Forms.Button(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.listBox1 = new System.Windows.Forms.ListBox(); + this.button5 = new System.Windows.Forms.Button(); + this.textBox4 = new System.Windows.Forms.TextBox(); + this.button6 = new System.Windows.Forms.Button(); + this.button7 = new System.Windows.Forms.Button(); + this.button8 = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.SuspendLayout(); + // + // button2 + // + this.button2.Location = new System.Drawing.Point(38, 121); + this.button2.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(75, 27); + this.button2.TabIndex = 14; + this.button2.Text = "刷新所有事件"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // checkBox3 + // + this.checkBox3.AutoSize = true; + this.checkBox3.Location = new System.Drawing.Point(423, 43); + this.checkBox3.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.checkBox3.Name = "checkBox3"; + this.checkBox3.Size = new System.Drawing.Size(80, 21); + this.checkBox3.TabIndex = 13; + this.checkBox3.Text = "Everyone"; + this.checkBox3.UseVisualStyleBackColor = true; + // + // checkBox2 + // + this.checkBox2.AutoSize = true; + this.checkBox2.Location = new System.Drawing.Point(355, 43); + this.checkBox2.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.checkBox2.Name = "checkBox2"; + this.checkBox2.Size = new System.Drawing.Size(68, 21); + this.checkBox2.TabIndex = 12; + this.checkBox2.Text = "Service"; + this.checkBox2.UseVisualStyleBackColor = true; + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Checked = true; + this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox1.Location = new System.Drawing.Point(285, 43); + this.checkBox1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(65, 21); + this.checkBox1.TabIndex = 11; + this.checkBox1.Text = "Owner"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // textBox2 + // + this.textBox2.Location = new System.Drawing.Point(77, 43); + this.textBox2.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(201, 23); + this.textBox2.TabIndex = 10; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(513, 43); + this.button1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 27); + this.button1.TabIndex = 9; + this.button1.Text = "发布事件"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(12, 412); + this.textBox1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(708, 102); + this.textBox1.TabIndex = 8; + // + // button3 + // + this.button3.Location = new System.Drawing.Point(15, 16); + this.button3.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(75, 27); + this.button3.TabIndex = 15; + this.button3.Text = "连接"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // button4 + // + this.button4.Location = new System.Drawing.Point(285, 89); + this.button4.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button4.Name = "button4"; + this.button4.Size = new System.Drawing.Size(75, 27); + this.button4.TabIndex = 17; + this.button4.Text = "订阅事件"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // textBox3 + // + this.textBox3.Location = new System.Drawing.Point(77, 89); + this.textBox3.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.textBox3.Name = "textBox3"; + this.textBox3.Size = new System.Drawing.Size(201, 23); + this.textBox3.TabIndex = 16; + // + // listBox1 + // + this.listBox1.FormattingEnabled = true; + this.listBox1.ItemHeight = 17; + this.listBox1.Location = new System.Drawing.Point(38, 152); + this.listBox1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.listBox1.Name = "listBox1"; + this.listBox1.Size = new System.Drawing.Size(201, 106); + this.listBox1.TabIndex = 18; + // + // button5 + // + this.button5.Location = new System.Drawing.Point(600, 152); + this.button5.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button5.Name = "button5"; + this.button5.Size = new System.Drawing.Size(75, 27); + this.button5.TabIndex = 20; + this.button5.Text = "触发事件"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.button5_Click); + // + // textBox4 + // + this.textBox4.Location = new System.Drawing.Point(247, 152); + this.textBox4.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.textBox4.Name = "textBox4"; + this.textBox4.Size = new System.Drawing.Size(332, 23); + this.textBox4.TabIndex = 19; + // + // button6 + // + this.button6.Location = new System.Drawing.Point(600, 43); + this.button6.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button6.Name = "button6"; + this.button6.Size = new System.Drawing.Size(75, 27); + this.button6.TabIndex = 21; + this.button6.Text = "取消发布"; + this.button6.UseVisualStyleBackColor = true; + this.button6.Click += new System.EventHandler(this.button6_Click); + // + // button7 + // + this.button7.Location = new System.Drawing.Point(371, 89); + this.button7.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button7.Name = "button7"; + this.button7.Size = new System.Drawing.Size(75, 27); + this.button7.TabIndex = 22; + this.button7.Text = "取消订阅"; + this.button7.UseVisualStyleBackColor = true; + this.button7.Click += new System.EventHandler(this.button7_Click); + // + // button8 + // + this.button8.Location = new System.Drawing.Point(365, 381); + this.button8.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.button8.Name = "button8"; + this.button8.Size = new System.Drawing.Size(75, 27); + this.button8.TabIndex = 23; + this.button8.Text = "清空"; + this.button8.UseVisualStyleBackColor = true; + this.button8.Click += new System.EventHandler(this.button8_Click); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 377); + this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(32, 17); + this.label2.TabIndex = 24; + this.label2.Text = "日志"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(31, 45); + this.label4.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(44, 17); + this.label4.TabIndex = 25; + this.label4.Text = "事件名"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(31, 91); + this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(44, 17); + this.label1.TabIndex = 26; + this.label1.Text = "事件名"; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Location = new System.Drawing.Point(15, 48); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(709, 320); + this.tabControl1.TabIndex = 27; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.textBox2); + this.tabPage1.Controls.Add(this.label1); + this.tabPage1.Controls.Add(this.button1); + this.tabPage1.Controls.Add(this.label4); + this.tabPage1.Controls.Add(this.checkBox1); + this.tabPage1.Controls.Add(this.checkBox2); + this.tabPage1.Controls.Add(this.checkBox3); + this.tabPage1.Controls.Add(this.button7); + this.tabPage1.Controls.Add(this.button2); + this.tabPage1.Controls.Add(this.button6); + this.tabPage1.Controls.Add(this.textBox3); + this.tabPage1.Controls.Add(this.button5); + this.tabPage1.Controls.Add(this.button4); + this.tabPage1.Controls.Add(this.textBox4); + this.tabPage1.Controls.Add(this.listBox1); + this.tabPage1.Location = new System.Drawing.Point(4, 26); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(701, 290); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "EventBus"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // tabPage2 + // + this.tabPage2.Location = new System.Drawing.Point(4, 26); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(701, 290); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "RPC"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(752, 547); + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.button8); + this.Controls.Add(this.button3); + this.Controls.Add(this.label2); + this.Controls.Add(this.textBox1); + this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.Name = "Form1"; + this.Text = "Form1"; + this.Load += new System.EventHandler(this.Form1_Load); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button2; + private System.Windows.Forms.CheckBox checkBox3; + private System.Windows.Forms.CheckBox checkBox2; + private System.Windows.Forms.CheckBox checkBox1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.ListBox listBox1; + private System.Windows.Forms.Button button5; + private System.Windows.Forms.TextBox textBox4; + private System.Windows.Forms.Button button6; + private System.Windows.Forms.Button button7; + private System.Windows.Forms.Button button8; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabPage2; + } +} + diff --git a/examples/EventBus简单示例/EventBusClient/Form1.cs b/examples/EventBus简单示例/EventBusClient/Form1.cs new file mode 100644 index 000000000..4f048b5f8 --- /dev/null +++ b/examples/EventBus简单示例/EventBusClient/Form1.cs @@ -0,0 +1,181 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.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首页:https://www.yuque.com/eo2w71/rrqm +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Windows.Forms; +using TouchSocket.Core; +using TouchSocket.Rpc; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace EERPCClientDemo +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + + public void ShowMsg(string msg) + { + this.Invoke((Action)(delegate () { this.textBox1.AppendText(msg + "\r\n"); })); + } + + private TcpTouchRpcClient tcpRpcClient; + + private void button3_Click(object sender, EventArgs e) + { + this.tcpRpcClient = new TcpTouchRpcClient(); + this.tcpRpcClient.Disconnected = TcpRpcClient_Disconnected; + tcpRpcClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .ConfigureRpcStore(a => + { + a.RegisterServer(); + })) + .Connect(1000 * 100); + this.button3.Enabled = false; + this.Text = this.tcpRpcClient.ID; + ShowMsg("连接成功"); + } + + private void TcpRpcClient_Disconnected(ITcpClientBase client, DisconnectEventArgs e) + { + ShowMsg("已断开连接"); + } + + private void button1_Click(object sender, EventArgs e) + { + try + { + AccessType accessType = AccessType.Owner; + if (this.checkBox1.Checked) + { + accessType = accessType | AccessType.Owner; + } + if (this.checkBox2.Checked) + { + accessType = accessType | AccessType.Service; + } + if (this.checkBox3.Checked) + { + accessType = accessType | AccessType.Everyone; + } + this.tcpRpcClient.PublishEvent(this.textBox2.Text, accessType); + ShowMsg("发布成功"); + } + catch (Exception ex) + { + ShowMsg(ex.Message); + } + } + + private void button2_Click(object sender, EventArgs e) + { + string[] events = this.tcpRpcClient.GetAllEvents(); + + this.listBox1.Items.Clear(); + this.listBox1.Items.AddRange(events); + } + + private void button4_Click(object sender, EventArgs e) + { + try + { + this.tcpRpcClient.SubscribeEvent(this.textBox3.Text, SubscribeEvent); + this.ShowMsg($"订阅成功"); + } + catch (Exception ex) + { + ShowMsg(ex.Message); + } + } + + private void SubscribeEvent(EventSender eventSender, string arg) + { + this.ShowMsg($"从{eventSender.RaiseSourceType}收到通知事件{eventSender.EventName},信息:{arg}"); + } + + private void button5_Click(object sender, EventArgs e) + { + try + { + if (listBox1.SelectedItem is string eventName) + { + this.tcpRpcClient.RaiseEvent(eventName, this.textBox4.Text); + ShowMsg("触发成功"); + } + else + { + ShowMsg("请先选择事件"); + } + } + catch (Exception ex) + { + ShowMsg(ex.Message); + } + } + + private void button6_Click(object sender, EventArgs e) + { + try + { + this.tcpRpcClient.UnpublishEvent(this.textBox2.Text); + ShowMsg("取消发布成功"); + } + catch (Exception ex) + { + ShowMsg(ex.Message); + } + } + + private void button7_Click(object sender, EventArgs e) + { + try + { + this.tcpRpcClient.UnsubscribeEvent(this.textBox3.Text); + ShowMsg("取消订阅成功"); + } + catch (Exception ex) + { + ShowMsg(ex.Message); + } + } + + private void button8_Click(object sender, EventArgs e) + { + this.textBox1.Clear(); + } + + private void Form1_Load(object sender, EventArgs e) + { + try + { + Enterprise.ForTest(); + } + catch (Exception ex) + { + this.ShowMsg("正在试用企业版功能,1小时后失效。"); + } + } + } + + internal class ThisRpcServer : RpcServer + { + [TouchRpc(true)] + public DateTime GetDataTime() + { + return DateTime.Now; + } + } +} \ No newline at end of file diff --git a/examples/EventBus简单示例/EventBusClient/Form1.resx b/examples/EventBus简单示例/EventBusClient/Form1.resx new file mode 100644 index 000000000..f298a7be8 --- /dev/null +++ b/examples/EventBus简单示例/EventBusClient/Form1.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/examples/EventBus简单示例/EventBusClient/Program.cs b/examples/EventBus简单示例/EventBusClient/Program.cs new file mode 100644 index 000000000..18fa46345 --- /dev/null +++ b/examples/EventBus简单示例/EventBusClient/Program.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.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首页:https://www.yuque.com/eo2w71/rrqm +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Windows.Forms; + +namespace EERPCClientDemo +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + private static void Main() + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + new Form1().Show(); + Application.Run(new Form1()); + } + } +} \ No newline at end of file diff --git a/examples/EventBus简单示例/EventBusServer/EventBusServer.csproj b/examples/EventBus简单示例/EventBusServer/EventBusServer.csproj new file mode 100644 index 000000000..399881540 --- /dev/null +++ b/examples/EventBus简单示例/EventBusServer/EventBusServer.csproj @@ -0,0 +1,12 @@ + + + + WinExe + net6.0-windows + true + + + + + + \ No newline at end of file diff --git a/examples/EventBus简单示例/EventBusServer/Form1.Designer.cs b/examples/EventBus简单示例/EventBusServer/Form1.Designer.cs new file mode 100644 index 000000000..97df9b544 --- /dev/null +++ b/examples/EventBus简单示例/EventBusServer/Form1.Designer.cs @@ -0,0 +1,459 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.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首页:https://www.yuque.com/eo2w71/rrqm +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace EERPCServiceDemo +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.checkBox2 = new System.Windows.Forms.CheckBox(); + this.checkBox3 = new System.Windows.Forms.CheckBox(); + this.button2 = new System.Windows.Forms.Button(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.button3 = new System.Windows.Forms.Button(); + this.listBox1 = new System.Windows.Forms.ListBox(); + this.button4 = new System.Windows.Forms.Button(); + this.textBox4 = new System.Windows.Forms.TextBox(); + this.button5 = new System.Windows.Forms.Button(); + this.button6 = new System.Windows.Forms.Button(); + this.listBox2 = new System.Windows.Forms.ListBox(); + this.checkBox4 = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label6 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.button7 = new System.Windows.Forms.Button(); + this.label3 = new System.Windows.Forms.Label(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.button8 = new System.Windows.Forms.Button(); + this.button9 = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.SuspendLayout(); + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(500, 765); + this.textBox1.Margin = new System.Windows.Forms.Padding(4); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(1220, 409); + this.textBox1.TabIndex = 1; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(788, 95); + this.button1.Margin = new System.Windows.Forms.Padding(4); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(150, 49); + this.button1.TabIndex = 2; + this.button1.Text = "发布事件"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // textBox2 + // + this.textBox2.Location = new System.Drawing.Point(110, 100); + this.textBox2.Margin = new System.Windows.Forms.Padding(4); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(204, 38); + this.textBox2.TabIndex = 3; + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Checked = true; + this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox1.Location = new System.Drawing.Point(326, 100); + this.checkBox1.Margin = new System.Windows.Forms.Padding(4); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(123, 35); + this.checkBox1.TabIndex = 4; + this.checkBox1.Text = "Owner"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // checkBox2 + // + this.checkBox2.AutoSize = true; + this.checkBox2.Location = new System.Drawing.Point(466, 100); + this.checkBox2.Margin = new System.Windows.Forms.Padding(4); + this.checkBox2.Name = "checkBox2"; + this.checkBox2.Size = new System.Drawing.Size(128, 35); + this.checkBox2.TabIndex = 5; + this.checkBox2.Text = "Service"; + this.checkBox2.UseVisualStyleBackColor = true; + // + // checkBox3 + // + this.checkBox3.AutoSize = true; + this.checkBox3.Location = new System.Drawing.Point(620, 100); + this.checkBox3.Margin = new System.Windows.Forms.Padding(4); + this.checkBox3.Name = "checkBox3"; + this.checkBox3.Size = new System.Drawing.Size(152, 35); + this.checkBox3.TabIndex = 6; + this.checkBox3.Text = "Everyone"; + this.checkBox3.UseVisualStyleBackColor = true; + // + // button2 + // + this.button2.Location = new System.Drawing.Point(186, 346); + this.button2.Margin = new System.Windows.Forms.Padding(4); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(150, 49); + this.button2.TabIndex = 7; + this.button2.Text = "刷新所有事件"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // textBox3 + // + this.textBox3.Location = new System.Drawing.Point(108, 157); + this.textBox3.Margin = new System.Windows.Forms.Padding(4); + this.textBox3.Name = "textBox3"; + this.textBox3.Size = new System.Drawing.Size(204, 38); + this.textBox3.TabIndex = 8; + // + // button3 + // + this.button3.Location = new System.Drawing.Point(324, 153); + this.button3.Margin = new System.Windows.Forms.Padding(4); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(150, 49); + this.button3.TabIndex = 9; + this.button3.Text = "订阅事件"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // listBox1 + // + this.listBox1.FormattingEnabled = true; + this.listBox1.ItemHeight = 31; + this.listBox1.Location = new System.Drawing.Point(66, 416); + this.listBox1.Margin = new System.Windows.Forms.Padding(4); + this.listBox1.Name = "listBox1"; + this.listBox1.Size = new System.Drawing.Size(1106, 159); + this.listBox1.TabIndex = 10; + // + // button4 + // + this.button4.Location = new System.Drawing.Point(324, 215); + this.button4.Margin = new System.Windows.Forms.Padding(4); + this.button4.Name = "button4"; + this.button4.Size = new System.Drawing.Size(150, 49); + this.button4.TabIndex = 12; + this.button4.Text = "触发事件"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // textBox4 + // + this.textBox4.Location = new System.Drawing.Point(108, 219); + this.textBox4.Margin = new System.Windows.Forms.Padding(4); + this.textBox4.Name = "textBox4"; + this.textBox4.Size = new System.Drawing.Size(204, 38); + this.textBox4.TabIndex = 11; + // + // button5 + // + this.button5.Location = new System.Drawing.Point(488, 153); + this.button5.Margin = new System.Windows.Forms.Padding(4); + this.button5.Name = "button5"; + this.button5.Size = new System.Drawing.Size(150, 49); + this.button5.TabIndex = 13; + this.button5.Text = "取消订阅"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.button5_Click); + // + // button6 + // + this.button6.Location = new System.Drawing.Point(946, 95); + this.button6.Margin = new System.Windows.Forms.Padding(4); + this.button6.Name = "button6"; + this.button6.Size = new System.Drawing.Size(150, 49); + this.button6.TabIndex = 14; + this.button6.Text = "取消发布"; + this.button6.UseVisualStyleBackColor = true; + this.button6.Click += new System.EventHandler(this.button6_Click); + // + // listBox2 + // + this.listBox2.FormattingEnabled = true; + this.listBox2.ItemHeight = 31; + this.listBox2.Location = new System.Drawing.Point(12, 47); + this.listBox2.Margin = new System.Windows.Forms.Padding(4); + this.listBox2.Name = "listBox2"; + this.listBox2.Size = new System.Drawing.Size(472, 1120); + this.listBox2.TabIndex = 15; + // + // checkBox4 + // + this.checkBox4.AutoSize = true; + this.checkBox4.Checked = true; + this.checkBox4.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox4.Location = new System.Drawing.Point(24, 49); + this.checkBox4.Margin = new System.Windows.Forms.Padding(4); + this.checkBox4.Name = "checkBox4"; + this.checkBox4.Size = new System.Drawing.Size(166, 35); + this.checkBox4.TabIndex = 16; + this.checkBox4.Text = "服务器操作"; + this.checkBox4.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(66, 352); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(110, 31); + this.label1.TabIndex = 17; + this.label1.Text = "事件列表"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(500, 705); + this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(62, 31); + this.label2.TabIndex = 18; + this.label2.Text = "日志"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label6); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.checkBox4); + this.groupBox1.Controls.Add(this.textBox2); + this.groupBox1.Controls.Add(this.button1); + this.groupBox1.Controls.Add(this.checkBox1); + this.groupBox1.Controls.Add(this.button4); + this.groupBox1.Controls.Add(this.button6); + this.groupBox1.Controls.Add(this.textBox4); + this.groupBox1.Controls.Add(this.checkBox2); + this.groupBox1.Controls.Add(this.button5); + this.groupBox1.Controls.Add(this.checkBox3); + this.groupBox1.Controls.Add(this.textBox3); + this.groupBox1.Controls.Add(this.button3); + this.groupBox1.Location = new System.Drawing.Point(66, 49); + this.groupBox1.Margin = new System.Windows.Forms.Padding(4); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Padding = new System.Windows.Forms.Padding(4); + this.groupBox1.Size = new System.Drawing.Size(1106, 283); + this.groupBox1.TabIndex = 19; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "操作"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(14, 222); + this.label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(62, 31); + this.label6.TabIndex = 19; + this.label6.Text = "参数"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(14, 159); + this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(86, 31); + this.label5.TabIndex = 18; + this.label5.Text = "事件名"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(14, 100); + this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(86, 31); + this.label4.TabIndex = 17; + this.label4.Text = "事件名"; + // + // button7 + // + this.button7.Location = new System.Drawing.Point(1570, 708); + this.button7.Margin = new System.Windows.Forms.Padding(4); + this.button7.Name = "button7"; + this.button7.Size = new System.Drawing.Size(150, 49); + this.button7.TabIndex = 17; + this.button7.Text = "清空"; + this.button7.UseVisualStyleBackColor = true; + this.button7.Click += new System.EventHandler(this.button7_Click); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 9); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(134, 31); + this.label3.TabIndex = 20; + this.label3.Text = "客户端列表"; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Location = new System.Drawing.Point(498, 47); + this.tabControl1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(1222, 647); + this.tabControl1.TabIndex = 21; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.groupBox1); + this.tabPage1.Controls.Add(this.button2); + this.tabPage1.Controls.Add(this.listBox1); + this.tabPage1.Controls.Add(this.label1); + this.tabPage1.Location = new System.Drawing.Point(8, 45); + this.tabPage1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.tabPage1.Size = new System.Drawing.Size(1206, 594); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "EventBus"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.button9); + this.tabPage2.Controls.Add(this.button8); + this.tabPage2.Location = new System.Drawing.Point(8, 45); + this.tabPage2.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.tabPage2.Size = new System.Drawing.Size(1206, 594); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "RPC"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // button8 + // + this.button8.Location = new System.Drawing.Point(24, 33); + this.button8.Name = "button8"; + this.button8.Size = new System.Drawing.Size(262, 46); + this.button8.TabIndex = 0; + this.button8.Text = "从客户端获取时间"; + this.button8.UseVisualStyleBackColor = true; + this.button8.Click += new System.EventHandler(this.button8_Click); + // + // button9 + // + this.button9.Location = new System.Drawing.Point(304, 33); + this.button9.Name = "button9"; + this.button9.Size = new System.Drawing.Size(262, 46); + this.button9.TabIndex = 1; + this.button9.Text = "从服务器获取时间"; + this.button9.UseVisualStyleBackColor = true; + this.button9.Click += new System.EventHandler(this.button9_Click); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(14F, 31F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1739, 1196); + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.label3); + this.Controls.Add(this.button7); + this.Controls.Add(this.listBox2); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label2); + this.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.Name = "Form1"; + this.Text = "Form1"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage1.PerformLayout(); + this.tabPage2.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.CheckBox checkBox1; + private System.Windows.Forms.CheckBox checkBox2; + private System.Windows.Forms.CheckBox checkBox3; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.ListBox listBox1; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.TextBox textBox4; + private System.Windows.Forms.Button button5; + private System.Windows.Forms.Button button6; + private System.Windows.Forms.ListBox listBox2; + private System.Windows.Forms.CheckBox checkBox4; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button button7; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.Button button8; + private System.Windows.Forms.Button button9; + } +} + diff --git a/examples/EventBus简单示例/EventBusServer/Form1.cs b/examples/EventBus简单示例/EventBusServer/Form1.cs new file mode 100644 index 000000000..4216ec2c4 --- /dev/null +++ b/examples/EventBus简单示例/EventBusServer/Form1.cs @@ -0,0 +1,334 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.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首页:https://www.yuque.com/eo2w71/rrqm +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Diagnostics; +using System.Windows.Forms; +using TouchSocket.Core; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace EERPCServiceDemo +{ + public partial class Form1 : Form + { + public Form1() + { + this.InitializeComponent(); + this.Load += this.Form1_Load; + } + + private void Form1_Load(object sender, EventArgs e) + { + try + { + Enterprise.ForTest(); + } + catch (Exception ex) + { + this.ShowMsg("正在试用企业版功能,1小时后失效。"); + } + + Control.CheckForIllegalCrossThreadCalls = false; + this.tcpRpcService = new TcpTouchRpcService(); + this.tcpRpcService.Connected = this.TcpRpcParser_Connected; + this.tcpRpcService.Disconnected = this.TcpRpcParser_Disconnected; + + var config = new TouchSocketConfig(); + config.SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .UsePlugin() + .ConfigurePlugins(a => + { + a.Add>() + .SetHandshaking(this.TcpRpcParser_Handshaking) + .SetHandshaked(this.TcpRpcParser_Handshaked); + }); + + this.tcpRpcService.Setup(config).Start(); + this.ShowMsg("服务器已启动"); + } + + private void TcpRpcParser_Handshaking(TcpTouchRpcSocketClient client, VerifyOptionEventArgs e) + { + Debug.WriteLine("Handshaking"); + } + + private void TcpRpcParser_Connected(TcpTouchRpcSocketClient client, TouchSocketEventArgs e) + { + Debug.WriteLine("Connected"); + } + + private void TcpRpcParser_Disconnected(TcpTouchRpcSocketClient client, TouchSocketEventArgs e) + { + lock (this) + { + this.listBox2.Items.Remove(client.ID); + } + } + + private void TcpRpcParser_Handshaked(TcpTouchRpcSocketClient client, TouchSocketEventArgs e) + { + Debug.WriteLine("Handshaked"); + this.listBox2.Items.Add(client.ID); + } + + public void ShowMsg(string msg) + { + this.Invoke((Action)(delegate () { this.textBox1.AppendText(msg + "\r\n"); })); + } + + private TcpTouchRpcService tcpRpcService; + + private void button1_Click(object sender, EventArgs e) + { + try + { + AccessType accessType = AccessType.Owner; + if (this.checkBox1.Checked) + { + accessType = accessType | AccessType.Owner; + } + if (this.checkBox2.Checked) + { + accessType = accessType | AccessType.Service; + } + if (this.checkBox3.Checked) + { + accessType = accessType | AccessType.Everyone; + } + if (this.checkBox4.Checked) + { + this.tcpRpcService.PublishEvent(this.textBox2.Text, accessType); + this.ShowMsg("发布成功"); + } + else if (this.listBox2.SelectedItem is string id) + { + if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient)) + { + socketClient.PublishEvent(this.textBox2.Text, accessType); + this.ShowMsg("发布成功"); + } + else + { + this.ShowMsg("没有找到对应客户端"); + } + } + else + { + this.ShowMsg("请选择一个客户端ID"); + } + } + catch (Exception ex) + { + this.ShowMsg(ex.Message); + } + } + + private void button2_Click(object sender, EventArgs e) + { + string[] events = this.tcpRpcService.GetAllEvents(); + + this.listBox1.Items.Clear(); + this.listBox1.Items.AddRange(events); + } + + private void button3_Click(object sender, EventArgs e) + { + try + { + if (this.checkBox4.Checked) + { + this.tcpRpcService.SubscribeEvent(this.textBox3.Text, this.SubscribeEvent); + this.ShowMsg("订阅成功"); + } + else if (this.listBox2.SelectedItem is string id) + { + if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient)) + { + socketClient.SubscribeEvent(this.textBox3.Text, this.SubscribeEvent); + this.ShowMsg("订阅成功"); + } + else + { + this.ShowMsg("没有找到对应客户端"); + } + } + else + { + this.ShowMsg("请选择一个客户端ID"); + } + } + catch (Exception ex) + { + this.ShowMsg(ex.Message); + } + } + + private void SubscribeEvent(EventSender eventSender, string arg) + { + this.ShowMsg($"从{eventSender.RaiseSourceType}收到通知事件{eventSender.EventName},信息:{arg}"); + } + + private void button4_Click(object sender, EventArgs e) + { + try + { + if (this.listBox1.SelectedItem is string eventName) + { + if (this.checkBox4.Checked) + { + this.tcpRpcService.RaiseEvent(eventName, this.textBox4.Text); + this.ShowMsg("触发成功"); + } + else if (this.listBox2.SelectedItem is string id) + { + if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient)) + { + socketClient.RaiseEvent(eventName, this.textBox4.Text); + this.ShowMsg("触发成功"); + } + else + { + this.ShowMsg("没有找到对应客户端"); + } + } + else + { + this.ShowMsg("请选择一个客户端ID"); + } + } + else + { + this.ShowMsg("请先选择事件"); + } + } + catch (Exception ex) + { + this.ShowMsg(ex.Message); + } + } + + private void button5_Click(object sender, EventArgs e) + { + try + { + if (this.checkBox4.Checked) + { + this.tcpRpcService.UnsubscribeEvent(this.textBox3.Text); + this.ShowMsg("取消订阅成功"); + } + else if (this.listBox2.SelectedItem is string id) + { + if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient)) + { + socketClient.UnsubscribeEvent(this.textBox3.Text); + this.ShowMsg("取消订阅成功"); + } + else + { + this.ShowMsg("没有找到对应客户端"); + } + } + else + { + this.ShowMsg("请选择一个客户端ID"); + } + } + catch (Exception ex) + { + this.ShowMsg(ex.Message); + } + } + + private void button6_Click(object sender, EventArgs e) + { + try + { + if (this.checkBox4.Checked) + { + this.tcpRpcService.UnpublishEvent(this.textBox2.Text); + this.ShowMsg("取消发布成功"); + } + else if (this.listBox2.SelectedItem is string id) + { + if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient)) + { + socketClient.UnpublishEvent(this.textBox2.Text); + this.ShowMsg("取消发布成功"); + } + else + { + this.ShowMsg("没有找到对应客户端"); + } + } + else + { + this.ShowMsg("请选择一个客户端ID"); + } + } + catch (Exception ex) + { + this.ShowMsg(ex.Message); + } + } + + private void button7_Click(object sender, EventArgs e) + { + this.textBox1.Clear(); + } + + private bool TryGetSelectedClient(out TcpTouchRpcSocketClient socketClient) + { + if (this.listBox2.SelectedItem is string id) + { + if (this.tcpRpcService.TryGetSocketClient(id, out socketClient)) + { + return true; + } + else + { + this.ShowMsg("没有找到对应客户端"); + return false; + } + } + else + { + this.ShowMsg("请选择一个客户端ID"); + } + + socketClient = null; + return false; + } + + private void button8_Click(object sender, EventArgs e) + { + if (this.TryGetSelectedClient(out TcpTouchRpcSocketClient client)) + { + var time = client.Invoke("GetDataTime", default); + this.ShowMsg(time.ToString()); + } + } + + private void button9_Click(object sender, EventArgs e) + { + if (this.listBox2.SelectedItem is string id) + { + var time = this.tcpRpcService.Invoke(id, "GetDataTime", default); + this.ShowMsg(time.ToString()); + } + else + { + this.ShowMsg("请选择一个客户端ID"); + } + } + } +} \ No newline at end of file diff --git a/examples/EventBus简单示例/EventBusServer/Form1.resx b/examples/EventBus简单示例/EventBusServer/Form1.resx new file mode 100644 index 000000000..f298a7be8 --- /dev/null +++ b/examples/EventBus简单示例/EventBusServer/Form1.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/examples/EventBus简单示例/EventBusServer/Program.cs b/examples/EventBus简单示例/EventBusServer/Program.cs new file mode 100644 index 000000000..2937e134f --- /dev/null +++ b/examples/EventBus简单示例/EventBusServer/Program.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.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首页:https://www.yuque.com/eo2w71/rrqm +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Windows.Forms; + +namespace EERPCServiceDemo +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + private static void Main() + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} \ No newline at end of file diff --git a/examples/FileTransfer简单示例/FileClientApp/FileServiceConsoleApp/FileServiceConsoleApp.csproj b/examples/FileTransfer简单示例/FileClientApp/FileServiceConsoleApp/FileServiceConsoleApp.csproj new file mode 100644 index 000000000..1e67d9a4a --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientApp/FileServiceConsoleApp/FileServiceConsoleApp.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + + + + + diff --git a/examples/FileTransfer简单示例/FileClientApp/FileServiceConsoleApp/Program.cs b/examples/FileTransfer简单示例/FileClientApp/FileServiceConsoleApp/Program.cs new file mode 100644 index 000000000..e69a36dcd --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientApp/FileServiceConsoleApp/Program.cs @@ -0,0 +1,63 @@ +using System; +using TouchSocket.Core; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace FileServiceConsoleApp +{ + internal class Program + { + private static void Main(string[] args) + { + var service = new TouchSocketConfig()//配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .UsePlugin() + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + a.Add(); + }) + .SetVerifyToken("File")//连接验证口令。 + .BuildWithTcpTouchRpcService();//此处build相当于new TcpTouchRpcService,然后Setup,然后Start。 + service.Logger.Info("服务器成功启动"); + Console.ReadKey(); + } + } + + internal class MyPlugin : TouchRpcPluginBase + { + protected override void OnFileTransfering(TcpTouchRpcSocketClient client, FileOperationEventArgs e) + { + //有可能是上传,也有可能是下载 + client.Logger.Info($"有客户端请求传输文件,ID={client.ID},请求类型={e.TransferType},请求文件名={e.ResourcePath}"); + base.OnFileTransfering(client, e); + } + + protected override void OnFileTransfered(TcpTouchRpcSocketClient client, FileTransferStatusEventArgs e) + { + //传输结束,但是不一定成功,需要从e.Result判断状态。 + client.Logger.Info($"客户端传输文件结束,ID={client.ID},请求类型={e.TransferType},文件名={e.ResourcePath},请求状态={e.Result}"); + base.OnFileTransfered(client, e); + } + + protected override void OnHandshaked(TcpTouchRpcSocketClient client, VerifyOptionEventArgs e) + { + client.Logger.Info($"有客户端成功验证,ID={client.ID}"); + base.OnHandshaked(client, e); + } + } + + internal class MyTcpPlugin : TcpPluginBase + { + protected override void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + client.Logger.Info($"有客户端断开,ID={((TcpTouchRpcSocketClient)client).ID}"); + base.OnDisconnected(client, e); + } + } +} \ No newline at end of file diff --git a/examples/FileTransfer简单示例/FileClientConsoleApp/FileClientConsoleApp.csproj b/examples/FileTransfer简单示例/FileClientConsoleApp/FileClientConsoleApp.csproj new file mode 100644 index 000000000..1e67d9a4a --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientConsoleApp/FileClientConsoleApp.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + + + + + diff --git a/examples/FileTransfer简单示例/FileClientConsoleApp/Program.cs b/examples/FileTransfer简单示例/FileClientConsoleApp/Program.cs new file mode 100644 index 000000000..719cdb755 --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientConsoleApp/Program.cs @@ -0,0 +1,65 @@ +using System; +using TouchSocket.Core; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace FileClientConsoleApp +{ + internal class Program + { + private static void Main(string[] args) + { + TcpTouchRpcClient client = new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("File") + .UsePlugin() + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }) + .ConfigurePlugins(a => + { + a.UseTouchRpcHeartbeat(); + }) + .BuildWithTcpTouchRpcClient(); + + client.Logger.Info("连接成功"); + + Metadata metadata = new Metadata();//传递到服务器的元数据 + metadata.Add("1", "1"); + metadata.Add("2", "2"); + + FileOperator fileOperator = new FileOperator()//实例化本次传输的控制器,用于获取传输进度、速度、状态等。 + { + Flags = TransferFlags.BreakpointResume,//尝试断点续传,使用断点续传时,会验证MD5值 + SavePath = $@"Windows.iso",//保存路径 + ResourcePath = @"D:\System\Windows.iso",//请求路径 + Metadata= metadata//传递到服务器的元数据 + }; + + fileOperator.Timeout = TimeSpan.FromSeconds(60);//当传输大文件,且启用断点续传时,服务器可能会先计算MD5,而延时响应,所以需要设置超时时间。 + + //此处的作用相当于Timer,定时每秒输出当前的传输进度和速度。 + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) => + { + if (fileOperator.Result.ResultCode != ResultCode.Default) + { + loop.Dispose(); + } + + client.Logger.Info($"进度:{fileOperator.Progress},速度:{fileOperator.Speed()}"); + }); + + loopAction.RunAsync(); + + + + //此方法会阻塞,直到传输结束,也可以使用PullFileAsync + IResult result = client.PullFile(fileOperator); + + client.Logger.Info(result.ToString()); + Console.ReadKey(); + } + } +} \ No newline at end of file diff --git a/examples/FileTransfer简单示例/FileClientGUI/App.xaml b/examples/FileTransfer简单示例/FileClientGUI/App.xaml new file mode 100644 index 000000000..1ce0c746e --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientGUI/App.xaml @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/examples/FileTransfer简单示例/FileClientGUI/App.xaml.cs b/examples/FileTransfer简单示例/FileClientGUI/App.xaml.cs new file mode 100644 index 000000000..8d4bb8e0a --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientGUI/App.xaml.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Windows; + +namespace FileClientGUI +{ + /// + /// App.xaml 的交互逻辑 + /// + public partial class App : Application + { + } +} \ No newline at end of file diff --git a/examples/FileTransfer简单示例/FileClientGUI/AssemblyInfo.cs b/examples/FileTransfer简单示例/FileClientGUI/AssemblyInfo.cs new file mode 100644 index 000000000..1d2612478 --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientGUI/AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] \ No newline at end of file diff --git a/examples/FileTransfer简单示例/FileClientGUI/FileClientGUI.csproj b/examples/FileTransfer简单示例/FileClientGUI/FileClientGUI.csproj new file mode 100644 index 000000000..8372008bd --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientGUI/FileClientGUI.csproj @@ -0,0 +1,25 @@ + + + + WinExe + net6.0-windows + true + + + + + + + + + + + + + + + + + + + diff --git a/examples/FileTransfer简单示例/FileClientGUI/MainWindow.xaml b/examples/FileTransfer简单示例/FileClientGUI/MainWindow.xaml new file mode 100644 index 000000000..1fb01f118 --- /dev/null +++ b/examples/FileTransfer简单示例/FileClientGUI/MainWindow.xaml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + TouchSocket文档更新日志

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+ + + + \ No newline at end of file diff --git a/handbook/build/assets/css/styles.24cd5811.css b/handbook/build/assets/css/styles.24cd5811.css new file mode 100644 index 000000000..c1a116928 --- /dev/null +++ b/handbook/build/assets/css/styles.24cd5811.css @@ -0,0 +1 @@ +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#25c2a0;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#46cbae;--ifm-color-primary-lighter:#66d4bd;--ifm-color-primary-lightest:#92e0d0;--ifm-code-font-size:95%;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child,.system-window pre{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after,.searchBarContainer_NW3z.searchIndexLoading_EJ1f .searchBarLoadingRing_YnHq{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area.breadcrumbs__link[href]:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.TouchSocket-contributor-item img,.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.content_knG7 a,.hitFooter_E9YW a,.suggestion_fB_2.cursor_eG29 mark{text-decoration:underline}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;pointer-events:none;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.collapsibleContent_i85q>:last-child,.footer__items,.searchResultItem_U687>h2{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.TouchSocket-banner-item,.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}#nprogress,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{-webkit-appearance:none;appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-duration:.25s;transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-duration:.1s;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}.docusaurus-highlight-code-line{background-color:#484d5b;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#docusaurus-base-url-issue-banner-container,.docSidebarContainer_b6E3,.hideAction_vcyE>svg,.sidebarLogo_isFc,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.searchBar_RVTs .dropdownMenu_qbY6{background:var(--search-local-modal-background,#f5f6f7);border-radius:6px;box-shadow:var(--search-local-modal-shadow,inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64);left:auto!important;margin-top:8px;padding:var(--search-local-spacing,12px);position:relative;right:0!important;width:var(--search-local-modal-width,560px)}html[data-theme=dark] .searchBar_RVTs .dropdownMenu_qbY6{background:var(--search-local-modal-background,var(--ifm-background-color));box-shadow:var(--search-local-modal-shadow,inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309)}.searchBar_RVTs .dropdownMenu_qbY6 .suggestion_fB_2{align-items:center;background:var(--search-local-hit-background,#fff);border-radius:4px;box-shadow:var(--search-local-hit-shadow,0 1px 3px 0 #d4d9e1);color:var(--search-local-hit-color,#444950);cursor:pointer;display:flex;flex-direction:row;height:var(--search-local-hit-height,56px);padding:0 var(--search-local-spacing,12px);width:100%}.hitTree_kk6K,.noResults_l6Q3{align-items:center;display:flex}html[data-theme=dark] .dropdownMenu_qbY6 .suggestion_fB_2{background:var(--search-local-hit-background,var(--ifm-color-emphasis-100));box-shadow:var(--search-local-hit-shadow,none);color:var(--search-local-hit-color,var(--ifm-font-color-base))}.searchBar_RVTs .dropdownMenu_qbY6 .suggestion_fB_2:not(:last-child){margin-bottom:4px}.searchBar_RVTs .dropdownMenu_qbY6 .suggestion_fB_2.cursor_eG29{background-color:var(--search-local-highlight-color,var(--ifm-color-primary))}.hitFooter_E9YW a,.hitIcon_a7Zy,.hitPath_ieM4,.hitTree_kk6K,.noResultsIcon_EBY5{color:var(--search-local-muted-color,#969faf)}html[data-theme=dark] .hitIcon_a7Zy,html[data-theme=dark] .hitPath_ieM4,html[data-theme=dark] .hitTree_kk6K,html[data-theme=dark] .noResultsIcon_EBY5{color:var(--search-local-muted-color,var(--ifm-color-secondary-darkest))}.hitTree_kk6K>svg{height:var(--search-local-hit-height,56px);opacity:.5;width:24px}.hitIcon_a7Zy,.hitTree_kk6K>svg{stroke-width:var(--search-local-icon-stroke-width,1.4)}.hitAction_NqkB,.hitIcon_a7Zy{height:20px;width:20px}.hitWrapper_sAK8{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;margin:0 8px;overflow-x:hidden;width:80%}.hitWrapper_sAK8 mark{background:none;color:var(--search-local-highlight-color,var(--ifm-color-primary))}.hitTitle_vyVt{font-size:.9em}.hitPath_ieM4{font-size:.75em}.hitPath_ieM4,.hitTitle_vyVt{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.noResults_l6Q3{flex-direction:column;justify-content:center;padding:var(--search-local-spacing,12px) 0}.noResultsIcon_EBY5{margin-bottom:var(--search-local-spacing,12px)}.hitFooter_E9YW{font-size:.85em;margin-top:var(--search-local-spacing,12px);text-align:center}.cursor_eG29 .hideAction_vcyE>svg,.tocCollapsibleContent_vkbj a{display:block}.suggestion_fB_2.cursor_eG29,.suggestion_fB_2.cursor_eG29 .hitIcon_a7Zy,.suggestion_fB_2.cursor_eG29 .hitPath_ieM4,.suggestion_fB_2.cursor_eG29 .hitTree_kk6K,.suggestion_fB_2.cursor_eG29 mark{color:var(--search-local-hit-active-color,var(--ifm-color-white))!important}.searchBarContainer_NW3z{margin-left:16px}.searchBarContainer_NW3z .searchBarLoadingRing_YnHq{display:none;left:10px;position:absolute;top:6px}.searchBarContainer_NW3z .searchClearButton_qk4g{background:none;border:none;line-height:1rem;padding:0;position:absolute;right:.8rem;top:50%;transform:translateY(-50%)}.navbar__search{position:relative}.searchIndexLoading_EJ1f .navbar__search-input{background-image:none}.searchHintContainer_Pkmr{align-items:center;display:flex;gap:4px;height:100%;justify-content:center;pointer-events:none;position:absolute;right:10px;top:0}.searchHint_iIMx{background-color:var(--ifm-navbar-search-input-background-color);border:1px solid var(--ifm-color-emphasis-500);box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-500);color:var(--ifm-navbar-search-input-placeholder-color)}.loadingRing_RJI3{display:inline-block;height:20px;opacity:var(--search-local-loading-icon-opacity,.5);position:relative;width:20px}.loadingRing_RJI3 div{animation:1.2s cubic-bezier(.5,0,.5,1) infinite a;border:2px solid var(--search-load-loading-icon-color,var(--ifm-navbar-search-input-color));border-color:var(--search-load-loading-icon-color,var(--ifm-navbar-search-input-color)) #0000 #0000 #0000;border-radius:50%;box-sizing:border-box;display:block;height:16px;margin:2px;position:absolute;width:16px}.loadingRing_RJI3 div:first-child{animation-delay:-.45s}.loadingRing_RJI3 div:nth-child(2){animation-delay:-.3s}.loadingRing_RJI3 div:nth-child(3){animation-delay:-.15s}@keyframes a{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.label_p8vM{align-items:center;border-radius:3px;color:#fff;display:inline-flex;font-size:12px;line-height:normal;margin-left:-3px;margin-right:6px;padding:4px 6px;vertical-align:middle}.icon_knQK{margin-right:4px}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.searchQueryInput_CFBF{background:var(--ifm-background-color);border:var(--ifm-global-border-width) solid var(--ifm-color-content-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-font-color-base);font-size:var(--ifm-font-size-base);margin-bottom:1rem;padding:.5rem;width:100%}.searchResultItem_U687{border-bottom:1px solid #dfe3e8;padding:1rem 0}.searchResultItemPath_uIbk{color:var(--ifm-color-content-secondary);font-size:.8rem;margin:.5rem 0 0}.searchResultItemSummary_oZHr{font-style:italic;margin:.5rem 0 0}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.docsWrapper_BCFX{display:flex;flex:1 0 auto}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity .2s ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:.15s;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;list-style:none;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.containsTaskList_mC6p{list-style:none}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.TouchSocket-banner{align-items:center;background-color:#211b50;color:#fff;padding:4rem 2rem}.TouchSocket-banner-container{display:flex;justify-content:space-between;margin:0 auto;max-width:1140px}.TouchSocket-banner-project{font-size:1.5em;font-weight:700}.TouchSocket-banner-description{-webkit-text-fill-color:#0000;-webkit-background-clip:text;background-clip:text;background-image:linear-gradient(81deg,#8759ff,#3fc4fe,#42ffac);font-size:2.2em;font-weight:700;line-height:1.25;margin:24px 0}.TouchSocket-banner-spec{font-family:Muli;font-size:1em;font-weight:500;line-height:1.33;opacity:.7;padding:0}.TouchSocket-banner-spec li{list-style:none;margin-bottom:1em;padding-left:1em;position:relative}.TouchSocket-banner-spec li:before{background-color:#8759ff;content:"";height:4px;left:0;position:absolute;top:.5em;width:4px}.TouchSocket-support-platform{color:#fff;font-family:Muli;font-size:.85em;font-weight:500;line-height:2;margin-top:3em;opacity:.6}.TouchSocket-support-icons{display:flex;margin-top:12px}.TouchSocket-support-icons span{margin-right:20px}.TouchSocket-get-start,.TouchSocket-try-demo{background:#8759ff;border-radius:2em;color:#fff;display:inline-block;line-height:1.5;margin-top:4em;min-width:145px;padding:8px 32px;position:relative;text-align:center;text-decoration:none;white-space:nowrap}.TouchSocket-try-demo{background-color:#21b091;margin-left:20px}.TouchSocket-get-start:hover{background:#8759ffe6}.TouchSocket-try-demo:hover{opacity:.9}.TouchSocket-banner-item .system-window{width:34rem}.TouchSocket-get-start:hover,.TouchSocket-try-demo:hover{color:#fff;text-decoration:none}.system-top-bar{background-image:linear-gradient(90deg,#8859ff33,#3fc4fe33 90%,#42ffac33);padding:.25em 1em}.system-top-bar-circle{border-radius:50%;display:inline-block;filter:brightness(100%);height:.5em;margin-left:.3em;width:.5em}.system-window{--ifm-leading:0;background:#211b50;border-radius:1em;overflow:hidden;padding:0;width:95%}.system-window iframe{border-radius:unset}.blue-accent{--uni-border-color:#3fbbfe;--uni-box-shadow-color:#3fbbfe1a;--ifm-menu-color-active:#3fbbfe}.preview-border{border:1px solid #3fbbfe;box-shadow:0 6px 58px 0 #3fbbfe1a}.TouchSocket-content{margin-bottom:4em;margin-top:4em;text-align:center}.TouchSocket-small-title{color:#412a94;font-family:Muli;font-size:1em;font-weight:600;letter-spacing:1px;opacity:.6}.TouchSocket-big-title.dark,.TouchSocket-contributor-item.dark a,.TouchSocket-log-number span.dark,.TouchSocket-remark-p p.dark,.TouchSocket-small-title.dark{color:#f5f6f7}.TouchSocket-big-title{color:#412a94;font-family:Poppins;font-size:2em;font-weight:700;line-height:1.31;margin-bottom:2em}.TouchSocket-gitee-log{display:flex;flex-wrap:nowrap;justify-content:center}.TouchSocket-log-item{box-sizing:border-box;height:173px;margin-right:65px;position:relative;width:260px}.TouchSocket-log-jiao{background:#fff;border-right:1px dashed #a795e8;border-top:1px dashed #a795e8;height:100px;position:absolute;right:-6px;top:-6px;width:100px}.TouchSocket-log-jiao.dark{background:#18191a}.TouchSocket-log-item:last-child{margin-right:0}.TouchSocket-log-number{align-items:center;display:flex;flex-direction:column;height:100%;justify-content:center;position:relative;width:100%;z-index:2}.TouchSocket-log-number div{font-size:3em;font-weight:700}.TouchSocket-log-number span{color:#1c1e21;font-family:Poppins,sans-serif;font-stretch:normal;font-style:normal;letter-spacing:normal;line-height:normal}.TouchSocket-remark{display:flex;justify-content:center}.TouchSocket-remark-item{border-image-slice:1;border-image-source:linear-gradient(var(--uni-border-gradient-degrees),#8759ff,#3fc4fe 51%,#42ffac);border-style:solid;border-width:6px;height:100%;margin:2em;max-width:320px;padding:4em 2em}.TouchSocket-remark-item:first-child{--uni-border-gradient-degrees:41deg;border-right:0;border-top:0}.TouchSocket-remark-item:nth-child(2){--uni-border-gradient-degrees:100deg;border:0}.TouchSocket-remark-item:last-child{--uni-border-gradient-degrees:221deg;border-bottom:0;border-left:0}.TouchSocket-remark-p{height:150px}.TouchSocket-remark-p h1{font-size:24px}.TouchSocket-remark-p p,.TouchSocket-who-des p{font-family:Muli;font-size:1em;line-height:1.75;opacity:.8}.TouchSocket-remark-p p{color:#474747;text-align:center}.TouchSocket-whouse{align-items:center;background-color:#412a94!important;color:#fff;display:flex;padding:5rem 0}.TouchSocket-who-custom{align-items:center;background-color:#fff;box-sizing:border-box;color:#723cff;display:flex;flex-wrap:wrap;justify-content:flex-end;min-height:500px;padding:6rem;text-align:right;width:60%}.TouchSocket-custom-img{color:#0000;margin-left:3em;text-decoration:none}.TouchSocket-who-des{box-sizing:border-box;padding:0 5rem}.TouchSocket-who-des p{color:#fff;margin-bottom:.8em}.footer{background-color:#211b50!important}.TouchSocket-links{margin:4em;text-align:center}.TouchSocket-links-content a{display:inline-block;font-size:20px;font-weight:600;margin:0 1em}.TouchSocket-contributors,.TouchSocket-proccesson{margin:4em 0;text-align:center}#dotnet-china{height:100px}.TouchSocket-contributor-item{background-color:#f3f3f3;border-radius:4px;box-shadow:4px 3px 16px -3px #0009;box-sizing:border-box;color:#333;display:inline-block;height:170px;margin:10px 5px;overflow:hidden;padding:10px;position:relative;text-align:center;width:130px}.TouchSocket-contributor-extra{background-color:#412a94;border-radius:4px;color:#fff;font-size:12px;padding:2px 5px;position:absolute;right:0;text-align:left;top:-9px}.TouchSocket-contributor-item a{color:#333;display:block;font-size:10pt;font-weight:700;text-decoration:none}.TouchSocket-contributor-item div{margin-top:10px}.TouchSocket-contributor-item.dark{background:#333}.TouchSocket-get-start-btn{display:flex;position:relative}.TouchSocket-version{color:#ff0;font-size:16px;position:absolute;right:0;top:-10px;z-index:10}.TouchSocket-wzi,.TouchSocket-wzi-title b{font-family:Arial,Helvetica,sans-serif;font-size:20px}.TouchSocket-bifa{background-position:50%;background-repeat:no-repeat;background-size:cover;color:#fff;display:flex;flex-direction:row-reverse;justify-content:center;padding:100px 0}.TouchSocket-wzi{border-left:1px solid #8993b480;height:320px;letter-spacing:10px;padding:25px;writing-mode:vertical-lr}.TouchSocket-wzi span{color:#44bcfe;font-weight:500}.TouchSocket-wzi-title{align-items:center;background:0 0/8px 8px #4472c4;background-image:linear-gradient(#5b80d4 1px,#0000 0),linear-gradient(90deg,#5b80d4 1px,#0000 0);display:flex;font-size:22px;font-weight:500;height:320px;letter-spacing:12px;margin-left:40px;width:84px;writing-mode:vertical-lr}.TouchSocket-wzi-title b{letter-spacing:2px;margin:20px 0;writing-mode:horizontal-tb}.navbar{background-color:#211b50}.navbar__brand,.navbar__items,.navbar__link{color:#fff}.navbar__link--active,.navbar__link:hover{color:#ff0}.menu__list-item .navbar__link--active,.menu__list-item .navbar__link:hover{color:#743dff}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);-webkit-clip-path:inset(0);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_Xe31{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media screen and (max-width:1024px){.TouchSocket-banner-container{flex-direction:column;justify-content:unset}.TouchSocket-get-start-btn{text-align:center}#dotnet-china{height:45px}.TouchSocket-banner-item .system-window{margin-top:3rem;width:100%}.TouchSocket-gitee-log{align-items:center;flex-direction:column;flex-wrap:unset;justify-content:center;padding:20px}.TouchSocket-log-item{height:173px;margin-right:0;margin-top:25px;width:100%}.TouchSocket-big-title{margin-bottom:1em}.TouchSocket-remark,.TouchSocket-whouse{flex-direction:column}.TouchSocket-whouse{padding-bottom:1em}.TouchSocket-who-des{padding-bottom:2em;padding-top:1em}.TouchSocket-remark-item{border:none;margin:0;max-width:unset;padding-bottom:0;width:100%}.TouchSocket-custom-img{margin-bottom:2em;margin-left:0}.TouchSocket-custom-img img{max-width:unset}.TouchSocket-who-custom{align-items:center;justify-content:center;text-align:center;width:100%}.TouchSocket-contributors{margin:4em 0}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media not (max-width:996px){.searchBar_RVTs.searchBarLeft_MXDe .dropdownMenu_qbY6{left:0!important;right:auto!important}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.navbar__search-input:not(:focus){width:2rem}.searchBar_RVTs .dropdownMenu_qbY6{max-width:calc(100vw - var(--ifm-navbar-padding-horizontal)*2);width:var(--search-local-modal-width-sm,340px)}.searchBarContainer_NW3z:not(.focused_OWtg) .searchClearButton_qk4g,.searchHintContainer_Pkmr{display:none}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/handbook/build/assets/images/consoleaction-1-d9e1a3f9f1a42d751e1d5e0605714a2c.gif b/handbook/build/assets/images/consoleaction-1-d9e1a3f9f1a42d751e1d5e0605714a2c.gif new file mode 100644 index 000000000..3e24d573d Binary files /dev/null and b/handbook/build/assets/images/consoleaction-1-d9e1a3f9f1a42d751e1d5e0605714a2c.gif differ diff --git a/handbook/build/assets/images/createhttpservice-1-4b8f923700c533fb1182b7775268246c.png b/handbook/build/assets/images/createhttpservice-1-4b8f923700c533fb1182b7775268246c.png new file mode 100644 index 000000000..c6a6e3c54 Binary files /dev/null and b/handbook/build/assets/images/createhttpservice-1-4b8f923700c533fb1182b7775268246c.png differ diff --git a/handbook/build/assets/images/createtcpservice-1-f7dd6a219c3c152c78ccf0cf84066439.png b/handbook/build/assets/images/createtcpservice-1-f7dd6a219c3c152c78ccf0cf84066439.png new file mode 100644 index 000000000..dc7300f00 Binary files /dev/null and b/handbook/build/assets/images/createtcpservice-1-f7dd6a219c3c152c78ccf0cf84066439.png differ diff --git a/handbook/build/assets/images/createtcpservice-2-005d50c69d09a71156030539fb5bf7f6.png b/handbook/build/assets/images/createtcpservice-2-005d50c69d09a71156030539fb5bf7f6.png new file mode 100644 index 000000000..7f3fcc503 Binary files /dev/null and b/handbook/build/assets/images/createtcpservice-2-005d50c69d09a71156030539fb5bf7f6.png differ diff --git a/handbook/build/assets/images/customdatahandlingadapter-1-0aec7ea38e0dd3113fa927cec2861066.png b/handbook/build/assets/images/customdatahandlingadapter-1-0aec7ea38e0dd3113fa927cec2861066.png new file mode 100644 index 000000000..b1d189ed0 Binary files /dev/null and b/handbook/build/assets/images/customdatahandlingadapter-1-0aec7ea38e0dd3113fa927cec2861066.png differ diff --git a/handbook/build/assets/images/dataforwarding-1-700ae9bd774c6299f265e8106362a702.png b/handbook/build/assets/images/dataforwarding-1-700ae9bd774c6299f265e8106362a702.png new file mode 100644 index 000000000..b59df3df8 Binary files /dev/null and b/handbook/build/assets/images/dataforwarding-1-700ae9bd774c6299f265e8106362a702.png differ diff --git a/handbook/build/assets/images/donate-1-bc856a7a46e2b61db3ff9356d8210962.png b/handbook/build/assets/images/donate-1-bc856a7a46e2b61db3ff9356d8210962.png new file mode 100644 index 000000000..da3686d2e Binary files /dev/null and b/handbook/build/assets/images/donate-1-bc856a7a46e2b61db3ff9356d8210962.png differ diff --git a/handbook/build/assets/images/engineertoolbox-1-f4ef22b000dfa103a5211d15e8591fae.jpg b/handbook/build/assets/images/engineertoolbox-1-f4ef22b000dfa103a5211d15e8591fae.jpg new file mode 100644 index 000000000..e716e8475 Binary files /dev/null and b/handbook/build/assets/images/engineertoolbox-1-f4ef22b000dfa103a5211d15e8591fae.jpg differ diff --git a/handbook/build/assets/images/engineertoolbox-2-4adfa904169e408a00e38870aa82a0c4.jpg b/handbook/build/assets/images/engineertoolbox-2-4adfa904169e408a00e38870aa82a0c4.jpg new file mode 100644 index 000000000..3253d4595 Binary files /dev/null and b/handbook/build/assets/images/engineertoolbox-2-4adfa904169e408a00e38870aa82a0c4.jpg differ diff --git a/handbook/build/assets/images/engineertoolbox-3-e6f715f5501aebfc7fd7dec0b21bff0f.jpg b/handbook/build/assets/images/engineertoolbox-3-e6f715f5501aebfc7fd7dec0b21bff0f.jpg new file mode 100644 index 000000000..4f79f1092 Binary files /dev/null and b/handbook/build/assets/images/engineertoolbox-3-e6f715f5501aebfc7fd7dec0b21bff0f.jpg differ diff --git a/handbook/build/assets/images/enterprise-1-b2ffe369f19088bca3f0671679bad11d.jpg b/handbook/build/assets/images/enterprise-1-b2ffe369f19088bca3f0671679bad11d.jpg new file mode 100644 index 000000000..1973cf479 Binary files /dev/null and b/handbook/build/assets/images/enterprise-1-b2ffe369f19088bca3f0671679bad11d.jpg differ diff --git a/handbook/build/assets/images/filesynchronization-1-d586ade9a477965b397c0387e95f9fbe.png b/handbook/build/assets/images/filesynchronization-1-d586ade9a477965b397c0387e95f9fbe.png new file mode 100644 index 000000000..afbb6d214 Binary files /dev/null and b/handbook/build/assets/images/filesynchronization-1-d586ade9a477965b397c0387e95f9fbe.png differ diff --git a/handbook/build/assets/images/generateproxy-1-163d930232955088abd9e846f68067d1.png b/handbook/build/assets/images/generateproxy-1-163d930232955088abd9e846f68067d1.png new file mode 100644 index 000000000..d35238bc9 Binary files /dev/null and b/handbook/build/assets/images/generateproxy-1-163d930232955088abd9e846f68067d1.png differ diff --git a/handbook/build/assets/images/ilog-1-cfa95e95bee4088509c9c35784bca442.png b/handbook/build/assets/images/ilog-1-cfa95e95bee4088509c9c35784bca442.png new file mode 100644 index 000000000..bb07cacb3 Binary files /dev/null and b/handbook/build/assets/images/ilog-1-cfa95e95bee4088509c9c35784bca442.png differ diff --git a/handbook/build/assets/images/ilog-2-715cd211ac8ac352a6e44fd2ac11f6ee.png b/handbook/build/assets/images/ilog-2-715cd211ac8ac352a6e44fd2ac11f6ee.png new file mode 100644 index 000000000..324b73cd6 Binary files /dev/null and b/handbook/build/assets/images/ilog-2-715cd211ac8ac352a6e44fd2ac11f6ee.png differ diff --git a/handbook/build/assets/images/ipackage-1-2f48a97c1a2568b875aab9b5a51de765.png b/handbook/build/assets/images/ipackage-1-2f48a97c1a2568b875aab9b5a51de765.png new file mode 100644 index 000000000..a732995a2 Binary files /dev/null and b/handbook/build/assets/images/ipackage-1-2f48a97c1a2568b875aab9b5a51de765.png differ diff --git a/handbook/build/assets/images/jsonserialize-1-a32327fa8972eacb38ae1e5930655a90.png b/handbook/build/assets/images/jsonserialize-1-a32327fa8972eacb38ae1e5930655a90.png new file mode 100644 index 000000000..9a107177c Binary files /dev/null and b/handbook/build/assets/images/jsonserialize-1-a32327fa8972eacb38ae1e5930655a90.png differ diff --git a/handbook/build/assets/images/jsonserialize-2-c45920c130f4a3cedcaad54fb9d8a389.png b/handbook/build/assets/images/jsonserialize-2-c45920c130f4a3cedcaad54fb9d8a389.png new file mode 100644 index 000000000..0565b38db Binary files /dev/null and b/handbook/build/assets/images/jsonserialize-2-c45920c130f4a3cedcaad54fb9d8a389.png differ diff --git a/handbook/build/assets/images/remotemonitoring-2-5c74840e35ae767d7cf69f547a67de94.gif b/handbook/build/assets/images/remotemonitoring-2-5c74840e35ae767d7cf69f547a67de94.gif new file mode 100644 index 000000000..097618946 Binary files /dev/null and b/handbook/build/assets/images/remotemonitoring-2-5c74840e35ae767d7cf69f547a67de94.gif differ diff --git a/handbook/build/assets/images/remotemonitoring-3-a3933fd43dae5dbd36a20de2a4eab122.gif b/handbook/build/assets/images/remotemonitoring-3-a3933fd43dae5dbd36a20de2a4eab122.gif new file mode 100644 index 000000000..c8d786049 Binary files /dev/null and b/handbook/build/assets/images/remotemonitoring-3-a3933fd43dae5dbd36a20de2a4eab122.gif differ diff --git a/handbook/build/assets/images/remotemonitoring-4-6f88f3a5b775c025524a73109d71a925.gif b/handbook/build/assets/images/remotemonitoring-4-6f88f3a5b775c025524a73109d71a925.gif new file mode 100644 index 000000000..055f89d54 Binary files /dev/null and b/handbook/build/assets/images/remotemonitoring-4-6f88f3a5b775c025524a73109d71a925.gif differ diff --git a/handbook/build/assets/images/remotemonitoring-5-34a53f7476270e9d9624009686d1d365.gif b/handbook/build/assets/images/remotemonitoring-5-34a53f7476270e9d9624009686d1d365.gif new file mode 100644 index 000000000..e11b88e2d Binary files /dev/null and b/handbook/build/assets/images/remotemonitoring-5-34a53f7476270e9d9624009686d1d365.gif differ diff --git a/handbook/build/assets/images/remotemonitoring-6-1cf6a6a157babffbaa8a15e2d8cf26a0.gif b/handbook/build/assets/images/remotemonitoring-6-1cf6a6a157babffbaa8a15e2d8cf26a0.gif new file mode 100644 index 000000000..2af03f1c2 Binary files /dev/null and b/handbook/build/assets/images/remotemonitoring-6-1cf6a6a157babffbaa8a15e2d8cf26a0.gif differ diff --git a/handbook/build/assets/images/remotestreamaccess-1-9ac54f0c1895cfe875a59449dc1db695.gif b/handbook/build/assets/images/remotestreamaccess-1-9ac54f0c1895cfe875a59449dc1db695.gif new file mode 100644 index 000000000..b7d8db21c Binary files /dev/null and b/handbook/build/assets/images/remotestreamaccess-1-9ac54f0c1895cfe875a59449dc1db695.gif differ diff --git a/handbook/build/assets/images/serializationselector-1-d45835b7e936897b4e5403f61565f668.png b/handbook/build/assets/images/serializationselector-1-d45835b7e936897b4e5403f61565f668.png new file mode 100644 index 000000000..e6ac69c3d Binary files /dev/null and b/handbook/build/assets/images/serializationselector-1-d45835b7e936897b4e5403f61565f668.png differ diff --git a/handbook/build/assets/images/startguide-1-ee9268f00fb23eec237bb5bf587216f3.png b/handbook/build/assets/images/startguide-1-ee9268f00fb23eec237bb5bf587216f3.png new file mode 100644 index 000000000..7d3ad3a60 Binary files /dev/null and b/handbook/build/assets/images/startguide-1-ee9268f00fb23eec237bb5bf587216f3.png differ diff --git a/handbook/build/assets/images/startguide-2-a43c6e900d91b577547b8fd8c6e9c610.png b/handbook/build/assets/images/startguide-2-a43c6e900d91b577547b8fd8c6e9c610.png new file mode 100644 index 000000000..bdf0131ac Binary files /dev/null and b/handbook/build/assets/images/startguide-2-a43c6e900d91b577547b8fd8c6e9c610.png differ diff --git a/handbook/build/assets/images/startguide-3-9733695ccab25c40b67c0aee41a950b2.png b/handbook/build/assets/images/startguide-3-9733695ccab25c40b67c0aee41a950b2.png new file mode 100644 index 000000000..24240cda9 Binary files /dev/null and b/handbook/build/assets/images/startguide-3-9733695ccab25c40b67c0aee41a950b2.png differ diff --git a/handbook/build/assets/images/startguide-4-e7a71340ebdf1e1e203cdccf0c48c466.png b/handbook/build/assets/images/startguide-4-e7a71340ebdf1e1e203cdccf0c48c466.png new file mode 100644 index 000000000..221ba949a Binary files /dev/null and b/handbook/build/assets/images/startguide-4-e7a71340ebdf1e1e203cdccf0c48c466.png differ diff --git a/handbook/build/assets/images/startguide-5-7a6e55e24a82130b5a31a1079ad955ae.png b/handbook/build/assets/images/startguide-5-7a6e55e24a82130b5a31a1079ad955ae.png new file mode 100644 index 000000000..6a81f5305 Binary files /dev/null and b/handbook/build/assets/images/startguide-5-7a6e55e24a82130b5a31a1079ad955ae.png differ diff --git a/handbook/build/assets/images/startguide-6-5ab3345890708d617b5bf98d105c52ae.png b/handbook/build/assets/images/startguide-6-5ab3345890708d617b5bf98d105c52ae.png new file mode 100644 index 000000000..3a85f739f Binary files /dev/null and b/handbook/build/assets/images/startguide-6-5ab3345890708d617b5bf98d105c52ae.png differ diff --git a/handbook/build/assets/images/startguide-7-57368c4a979c819f89d3d89d066a8a9a.png b/handbook/build/assets/images/startguide-7-57368c4a979c819f89d3d89d066a8a9a.png new file mode 100644 index 000000000..bd0c1b668 Binary files /dev/null and b/handbook/build/assets/images/startguide-7-57368c4a979c819f89d3d89d066a8a9a.png differ diff --git a/handbook/build/assets/images/startguide-8-c7cdec8201782abee3e623b2ca9f0f15.png b/handbook/build/assets/images/startguide-8-c7cdec8201782abee3e623b2ca9f0f15.png new file mode 100644 index 000000000..f2f2f7395 Binary files /dev/null and b/handbook/build/assets/images/startguide-8-c7cdec8201782abee3e623b2ca9f0f15.png differ diff --git a/handbook/build/assets/images/startguide-9-c2c31ae92c23dc68759264df69273c84.png b/handbook/build/assets/images/startguide-9-c2c31ae92c23dc68759264df69273c84.png new file mode 100644 index 000000000..6b4cb70b5 Binary files /dev/null and b/handbook/build/assets/images/startguide-9-c2c31ae92c23dc68759264df69273c84.png differ diff --git a/handbook/build/assets/images/upgrade-1-6b82b0abeb6cf5bcaf6aca07f67ad2aa.png b/handbook/build/assets/images/upgrade-1-6b82b0abeb6cf5bcaf6aca07f67ad2aa.png new file mode 100644 index 000000000..7ed97fbed Binary files /dev/null and b/handbook/build/assets/images/upgrade-1-6b82b0abeb6cf5bcaf6aca07f67ad2aa.png differ diff --git a/handbook/build/assets/images/upgrade-2-e69c2951e8df8d2c064b1990fb4ca3ba.png b/handbook/build/assets/images/upgrade-2-e69c2951e8df8d2c064b1990fb4ca3ba.png new file mode 100644 index 000000000..e887f5c39 Binary files /dev/null and b/handbook/build/assets/images/upgrade-2-e69c2951e8df8d2c064b1990fb4ca3ba.png differ diff --git a/handbook/build/assets/images/upgrade-3-69fbf6d003e3a06604cf5aaf4689fe9e.png b/handbook/build/assets/images/upgrade-3-69fbf6d003e3a06604cf5aaf4689fe9e.png new file mode 100644 index 000000000..f6bf023c8 Binary files /dev/null and b/handbook/build/assets/images/upgrade-3-69fbf6d003e3a06604cf5aaf4689fe9e.png differ diff --git a/handbook/build/assets/images/upgrade-4-2d7db90014741755af54830e9ffc187d.png b/handbook/build/assets/images/upgrade-4-2d7db90014741755af54830e9ffc187d.png new file mode 100644 index 000000000..4f4b108f6 Binary files /dev/null and b/handbook/build/assets/images/upgrade-4-2d7db90014741755af54830e9ffc187d.png differ diff --git a/handbook/build/assets/images/upgrade-5-fe66cc273eb92e8ceed0135da45a3a1c.png b/handbook/build/assets/images/upgrade-5-fe66cc273eb92e8ceed0135da45a3a1c.png new file mode 100644 index 000000000..dd2298cd5 Binary files /dev/null and b/handbook/build/assets/images/upgrade-5-fe66cc273eb92e8ceed0135da45a3a1c.png differ diff --git a/handbook/build/assets/images/upgrade-6-4e52667e8ec250b8e2c5a9acf63eaaf2.png b/handbook/build/assets/images/upgrade-6-4e52667e8ec250b8e2c5a9acf63eaaf2.png new file mode 100644 index 000000000..c79cd6e7b Binary files /dev/null and b/handbook/build/assets/images/upgrade-6-4e52667e8ec250b8e2c5a9acf63eaaf2.png differ diff --git a/handbook/build/assets/images/webdataforwarding-1-669ef575ba0422c1a8881c07203101e9.gif b/handbook/build/assets/images/webdataforwarding-1-669ef575ba0422c1a8881c07203101e9.gif new file mode 100644 index 000000000..55d9ca5ca Binary files /dev/null and b/handbook/build/assets/images/webdataforwarding-1-669ef575ba0422c1a8881c07203101e9.gif differ diff --git a/handbook/build/assets/js/01fa1a8d.1831ff50.js b/handbook/build/assets/js/01fa1a8d.1831ff50.js new file mode 100644 index 000000000..d61ec771c --- /dev/null +++ b/handbook/build/assets/js/01fa1a8d.1831ff50.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9035],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>m});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(r),m=a,k=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return r?n.createElement(k,i(i({ref:t},s),{},{components:r})):n.createElement(k,i({ref:t},s))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=u;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>p});var n=r(7462),a=(r(7294),r(3905));const o={id:"terminatorpackageadapter",title:"\u7ec8\u6b62\u56e0\u5b50\u5206\u5272\u6570\u636e\u5904\u7406\u9002\u914d\u5668"},i=void 0,c={unversionedId:"terminatorpackageadapter",id:"terminatorpackageadapter",title:"\u7ec8\u6b62\u56e0\u5b50\u5206\u5272\u6570\u636e\u5904\u7406\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/terminatorpackageadapter.mdx",sourceDirName:".",slug:"/terminatorpackageadapter",permalink:"/touchsocket/docs/terminatorpackageadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/terminatorpackageadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675577572,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"terminatorpackageadapter",title:"\u7ec8\u6b62\u56e0\u5b50\u5206\u5272\u6570\u636e\u5904\u7406\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u56fa\u5b9a\u957f\u5ea6\u6570\u636e\u5904\u7406\u9002\u914d\u5668",permalink:"/touchsocket/docs/fixedsizepackageadapter"},next:{title:"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668",permalink:"/touchsocket/docs/datahandleadapter"}},l={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2}],s={toc:p};function d(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u7ec8\u6b62\u56e0\u5b50\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u662f\u901a\u8fc7",(0,a.kt)("strong",{parentName:"p"},"\u7279\u6b8a\u5b57\u7b26\u6216\u6570\u503c"),"\u7684\u65b9\u5f0f\uff0c\u6765\u8fbe\u5230\u5904\u7406\u7c98\u5305\u3001\u5206\u5305\u7684\u76ee\u7684\u3002\u53ef\u968f\u610f\u8bbe\u7f6e\u5206\u5272\u56e0\u5b50\u7684\u503c\uff0c\u4ee5\u53ca\u7f16\u7801\u65b9\u5f0f\u3002\u4e0d\u4ec5\u5982\u6b64\uff0c\u8fd8\u6709\u5f02\u5e38\u6570\u636e\u8bbe\u7f6e\uff0c\u5728\u8fbe\u5230\u8bbe\u5b9a\u503c\u65f6\uff0c\u5982\u679c\u8fd8\u6ca1\u6709\u53d1\u73b0\u5206\u5272\u56e0\u5b50\uff0c\u5219\u629b\u5f03\u6570\u636e\u3002\u5176\u7a33\u5b9a\u6027\u4ec5\u6b21\u4e8e\u56fa\u5b9a\u5305\u5934\uff0c\u4e14\u4f7f\u7528\u573a\u666f\u4e5f\u6bd4\u8f83\u5e7f\u6cdb\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u6700\u9002\u7528\u4e8e\u5b57\u7b26\u4e32\u7c7b\uff08Json\uff0cXml\u7b49\uff09\u7684\u4fe1\u606f\u4ea4\u4e92\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u7b97\u6cd5\u7b80\u5355\uff0c\u975e\u5e38\u5bb9\u6613\u5b9e\u73b0\u8de8\u8bed\u8a00\u3001\u8de8\u6846\u67b6\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u53d1\u9001\u666e\u901a\u6d41\u6570\u636e\u65f6\uff0c\u6709\u5f88\u5c0f\u7684\u6982\u7387\u53d1\u751f\u63d0\u524d\u7ec8\u6b62\u7684\u60c5\u51b5\uff08\u53ef\u8bbe\u7f6e\u590d\u6742\u7ec8\u6b62\u56e0\u5b50\u6765\u89e3\u51b3\uff09\u3002")),(0,a.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002\u4e0b\u5217\u4ee5\u670d\u52a1\u5668\u4e3a\u4f8b\u3002"),(0,a.kt)("p",null,"\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e\uff0c\u540c\u65f6\u6307\u5b9a\u6570\u636e\u7684\u957f\u5ea6\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684ByteBlock\u8bfb\u53d6\u6570\u636e\uff08\u6ce8\u610f\uff1a\u6570\u636e\u957f\u5ea6\u662fbyteBlock.Len\uff09\u3002")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{10}","{10}":!0},'TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u5ba2\u6237\u7aef\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(()=> { return new TerminatorPackageAdapter("\\r\\n"); }))//\u914d\u7f6e\u7ec8\u6b62\u5b57\u7b26\u9002\u914d\u5668\uff0c\u4ee5\\r\\n\u7ed3\u5c3e\u3002\n .Start();//\u542f\u52a8\n')),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u7ec8\u6b62\u56e0\u5b50\u4e0d\u4f1a\u4fdd\u7559\u5728\u6570\u636e\u4e2d\uff0c\u7528\u6237\u53ef\u901a\u8fc7ReserveTerminatorCode\u5c5e\u6027\uff0c\u8bbe\u4e3atrue\uff0c\u6765\u4fdd\u7559\u7ec8\u6b62\u56e0\u5b50\u3002")),(0,a.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"\u63a5\u6536\u7684\u6570\u636e\u957f\u5ea6\u662fbyteBlock.Len\uff0c\u800c\u4e0d\u662fbyteBlock.Buffer.Length\u3002")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u8be5\u9002\u914d\u5668\uff0c\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/04ff01fb.f73cf086.js b/handbook/build/assets/js/04ff01fb.f73cf086.js new file mode 100644 index 000000000..6fd91130d --- /dev/null +++ b/handbook/build/assets/js/04ff01fb.f73cf086.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1586],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var l=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,l)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var o=l.createContext({}),s=function(e){var t=l.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=s(e.components);return l.createElement(o.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},d=l.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=s(n),k=a,v=d["".concat(o,".").concat(k)]||d[k]||u[k]||r;return n?l.createElement(v,i(i({ref:t},p),{},{components:n})):l.createElement(v,i({ref:t},p))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=d;var c={};for(var o in t)hasOwnProperty.call(t,o)&&(c[o]=t[o]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var s=2;s{n.d(t,{Z:()=>F});var l=n(7294),a=n(7462);const r=(e,t,n)=>e?"string"==typeof e?e:e[t]||n:n,i={display:"block"},c=e=>{let{size:t,color:n,style:c,...o}=e;const s=c?{...i,...c}:i;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),l.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:r(n,0,"#333333")}))};c.defaultProps={size:18};const o=c,s={display:"block"},p=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...s,...i}:s;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:r(n,0,"#333333")}),l.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:r(n,1,"#333333")}))};p.defaultProps={size:18};const u=p,d={display:"block"},k=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...d,...i}:d;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:r(n,0,"#333333")}),l.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:r(n,1,"#333333")}),l.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:r(n,2,"#333333")}))};k.defaultProps={size:18};const v=k,g={display:"block"},m=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...g,...i}:g;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:r(n,0,"#333333")}))};m.defaultProps={size:18};const h=m,y={display:"block"},S=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...y,...i}:y;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:r(n,0,"#333333")}))};S.defaultProps={size:18};const f=S,C={display:"block"},N=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...C,...i}:C;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:r(n,0,"#333333")}),l.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:r(n,1,"#333333")}),l.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:r(n,2,"#333333")}))};N.defaultProps={size:18};const b=N,P={display:"block"},T=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...P,...i}:P;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:r(n,0,"#333333")}),l.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:r(n,1,"#333333")}))};T.defaultProps={size:18};const I=T,w={display:"block"},B=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...w,...i}:w;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:r(n,0,"#333333")}),l.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:r(n,1,"#333333")}))};B.defaultProps={size:18};const z=B,E={display:"block"},x=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...E,...i}:E;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:r(n,0,"#333333")}),l.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:r(n,1,"#333333")}))};x.defaultProps={size:18};const D=x,M={display:"block"},O=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...M,...i}:M;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:r(n,0,"#333333")}))};O.defaultProps={size:18};const H=O,L={display:"block"},A=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...L,...i}:L;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:r(n,0,"#333333")}))};A.defaultProps={size:18};const R=A,U={display:"block"},Z=e=>{let{size:t,color:n,style:i,...c}=e;const o=i?{...U,...i}:U;return l.createElement("svg",(0,a.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},c),l.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:r(n,0,"#333333")}))};Z.defaultProps={size:18};const j=Z,q=e=>{let{name:t,...n}=e;switch(t){case"youhua":return l.createElement(o,n);case"dayi":return l.createElement(u,n);case"shengji":return l.createElement(v,n);case"tiaozheng":return l.createElement(h,n);case"gengxin":return l.createElement(f,n);case"wendang":return l.createElement(b,n);case"shanchu":return l.createElement(I,n);case"bug":return l.createElement(z,n);case"xinzeng":return l.createElement(D,n);case"fuwu":return l.createElement(H,n);case"down":return l.createElement(R,n);case"up":return l.createElement(j,n)}return null},G="label_p8vM",V="icon_knQK";function F(e){const{children:t}=e,n={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return l.createElement("label",{className:G,title:t,style:{backgroundColor:n[t].bgColor}},l.createElement(q,{name:n[t].icon,color:"white",size:14,className:V})," ",t)}},4748:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>c,default:()=>d,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var l=n(7462),a=(n(7294),n(3905)),r=n(510);const i={id:"createtcpservice",title:"\u521b\u5efaTcpService"},c=void 0,o={unversionedId:"createtcpservice",id:"createtcpservice",title:"\u521b\u5efaTcpService",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/createtcpservice.mdx",sourceDirName:".",slug:"/createtcpservice",permalink:"/touchsocket/docs/createtcpservice",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createtcpservice.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675609832,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"createtcpservice",title:"\u521b\u5efaTcpService"},sidebar:"docs",previous:{title:"\u5176\u4ed6\u76f8\u5173\u529f\u80fd\u7c7b",permalink:"/touchsocket/docs/othercore"},next:{title:"\u521b\u5efaTcpClient",permalink:"/touchsocket/docs/createtcpclient"}},s={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4ea7\u54c1\u5e94\u7528\u573a\u666f",id:"\u4e09\u4ea7\u54c1\u5e94\u7528\u573a\u666f",level:2},{value:"\u56db\u3001\u670d\u52a1\u5668\u67b6\u6784",id:"\u56db\u670d\u52a1\u5668\u67b6\u6784",level:2},{value:"\u4e94\u3001\u53ef\u914d\u7f6e\u9879",id:"\u4e94\u53ef\u914d\u7f6e\u9879",level:2},{value:"SetBufferLength",id:"setbufferlength",level:4},{value:"SetMaxPackageSize",id:"setmaxpackagesize",level:4},{value:"SetThreadCount",id:"setthreadcount",level:4},{value:"SetGetDefaultNewID",id:"setgetdefaultnewid",level:4},{value:"SetListenIPHosts",id:"setlisteniphosts",level:4},{value:"SetServerName",id:"setservername",level:4},{value:"SetBacklogProperty",id:"setbacklogproperty",level:4},{value:"SetMaxCount",id:"setmaxcount",level:4},{value:"SetReceiveType",id:"setreceivetype",level:4},{value:"UsePlugin",id:"useplugin",level:4},{value:"SetServiceSslOption",id:"setservicessloption",level:4},{value:"UseNoDelay",id:"usenodelay",level:4},{value:"UseDelaySender",id:"usedelaysender",level:4},{value:"UseReuseAddress",id:"usereuseaddress",level:4},{value:"SetRemoteIPHost",id:"setremoteiphost",level:4},{value:"SetClientSslOption",id:"setclientssloption",level:4},{value:"SetKeepAliveValue",id:"setkeepalivevalue",level:4},{value:"SetBindIPHost",id:"setbindiphost",level:4},{value:"UseDelaySender",id:"usedelaysender-1",level:4},{value:"UseNoDelay",id:"usenodelay-1",level:4},{value:"UseBroadcast",id:"usebroadcast",level:4},{value:"\u516d\u3001\u652f\u6301\u63d2\u4ef6",id:"\u516d\u652f\u6301\u63d2\u4ef6",level:2},{value:"\u4e03\u3001\u521b\u5efaTcpService",id:"\u4e03\u521b\u5efatcpservice",level:2},{value:"7.1 \u7b80\u5355\u521b\u5efa",id:"71-\u7b80\u5355\u521b\u5efa",level:3},{value:"7.2 \u6cdb\u578b\u521b\u5efa",id:"72-\u6cdb\u578b\u521b\u5efa",level:3},{value:"\u516b\u3001\u63a5\u6536\u6570\u636e",id:"\u516b\u63a5\u6536\u6570\u636e",level:2},{value:"8.1 Received\u59d4\u6258\u5904\u7406",id:"81-received\u59d4\u6258\u5904\u7406",level:3},{value:"8.2 \u91cd\u5199SocketClient\u5904\u7406",id:"82-\u91cd\u5199socketclient\u5904\u7406",level:3},{value:"8.3 \u63d2\u4ef6\u5904\u7406 \u63a8\u8350",id:"83-\u63d2\u4ef6\u5904\u7406-\u63a8\u8350",level:3},{value:"\u4e5d\u3001AspNetCore\u4e2d\u521b\u5efa",id:"\u4e5daspnetcore\u4e2d\u521b\u5efa",level:2},{value:"\u5341\u3001\u53d1\u9001\u6570\u636e",id:"\u5341\u53d1\u9001\u6570\u636e",level:2},{value:"10.1 \u5982\u4f55\u83b7\u53d6SocketClient\uff1f",id:"101-\u5982\u4f55\u83b7\u53d6socketclient",level:3},{value:"10.2 \u53d1\u9001",id:"102-\u53d1\u9001",level:3},{value:"10.3 \u901a\u8fc7TcpService\u53d1\u9001",id:"103-\u901a\u8fc7tcpservice\u53d1\u9001",level:3}],u={toc:p};function d(e){let{components:t,...i}=e;return(0,a.kt)("wrapper",(0,l.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"TcpService\u662fTcp\u7cfb\u670d\u52a1\u5668\u57fa\u7c7b\uff0c\u5b83\u4e0d\u53c2\u4e0e\u5b9e\u9645\u7684\u6570\u636e\u4ea4\u4e92\uff0c\u53ea\u662f\u914d\u7f6e\u3001\u6fc0\u6d3b\u3001\u7ba1\u7406\u3001\u6ce8\u9500\u3001\u91cd\u5efa",(0,a.kt)("strong",{parentName:"p"},"SocketClient"),"\u7c7b\u5b9e\u4f8b\u3002\u800c",(0,a.kt)("strong",{parentName:"p"},"SocketClient"),"\u662f\u5f53",(0,a.kt)("strong",{parentName:"p"},"TcpClient\uff08\u5ba2\u6237\u7aef\uff09"),"\u6210\u529f\u8fde\u63a5\u670d\u52a1\u5668\u4ee5\u540e\uff0c\u7531\u670d\u52a1\u5668\u65b0\u5efa\u7684\u4e00\u4e2a\u5b9e\u4f8b\u7c7b\uff0c\u540e\u7eed\u7684\u6240\u6709\u901a\u4fe1\uff0c\u4e5f\u90fd\u662f\u901a\u8fc7\u8be5\u5b9e\u4f8b\u5b8c\u6210\u7684\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u7b80\u5355\u6613\u7528\u3002"),(0,a.kt)("li",{parentName:"ul"},"IOCP\u591a\u7ebf\u7a0b\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u5185\u5b58\u6c60\u652f\u6301"),(0,a.kt)("li",{parentName:"ul"},"\u9ad8\u6027\u80fd\uff08\u5b9e\u6d4b\u670d\u52a1\u5668\u5355\u5ba2\u6237\u7aef\u5355\u7ebf\u7a0b\uff0c\u6bcf\u79d2\u53ef\u63a5\u6536200w\u67618\u5b57\u8282\u7684\u4fe1\u606f\uff0c\u63a5\u6536\u6570\u636e\u6d41\u91cf\u53ef\u8fbe2.5GB/s\uff09\u3002"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"\u591a\u5730\u5740\u76d1\u542c"),"\uff08\u53ef\u4ee5\u4e00\u6b21\u6027\u76d1\u542c\u591a\u4e2aIP\u53ca\u7aef\u53e3\uff09"),(0,a.kt)("li",{parentName:"ul"},"\u9002\u914d\u5668\u9884\u5904\u7406\uff0c\u4e00\u952e\u5f0f\u89e3\u51b3",(0,a.kt)("strong",{parentName:"li"},"\u5206\u5305"),"\u3001",(0,a.kt)("strong",{parentName:"li"},"\u7c98\u5305"),"\u3001\u5bf9\u8c61\u89e3\u6790(\u5982HTTP\uff0cJson)\u7b49\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u8d85\u7b80\u5355\u7684\u540c\u6b65\u53d1\u9001\u3001\u5f02\u6b65\u53d1\u9001\u3001\u63a5\u6536\u7b49\u64cd\u4f5c\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u57fa\u4e8e\u59d4\u6258\u3001\u63d2\u4ef6\u9a71\u52a8\uff0c\u8ba9\u6bcf\u4e00\u6b65\u90fd\u80fd\u6267\u884cAOP\u3002")),(0,a.kt)("h2",{id:"\u4e09\u4ea7\u54c1\u5e94\u7528\u573a\u666f"},"\u4e09\u3001\u4ea7\u54c1\u5e94\u7528\u573a\u666f"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u6240\u6709Tcp\u57fa\u7840\u4f7f\u7528\u573a\u666f\uff1a\u53ef\u8de8\u5e73\u53f0\u3001\u8de8\u8bed\u8a00\u4f7f\u7528\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u81ea\u5b9a\u4e49\u534f\u8bae\u89e3\u6790\u573a\u666f\uff1a\u53ef\u89e3\u6790\u4efb\u610f\u6570\u636e\u683c\u5f0f\u7684TCP\u6570\u636e\u62a5\u6587\u3002")),(0,a.kt)("h2",{id:"\u56db\u670d\u52a1\u5668\u67b6\u6784"},"\u56db\u3001\u670d\u52a1\u5668\u67b6\u6784"),(0,a.kt)("p",null,"\u670d\u52a1\u5668\u5728\u6536\u5230",(0,a.kt)("strong",{parentName:"p"},"\u65b0\u5ba2\u6237\u7aef\u8fde\u63a5"),"\u65f6\uff0c\u4f1a\u521b\u5efa\u4e00\u4e2aSocketClient\u7684\u6d3e\u751f\u7c7b\u5b9e\u4f8b\uff0c\u4e0e\u5ba2\u6237\u7aefTcpClient\u4e00\u4e00\u5bf9\u5e94\uff0c\u540e\u7eed\u7684\u6570\u636e\u901a\u4fe1\u5747\u7531\u6b64\u5b9e\u4f8b\u8d1f\u8d23\u3002"),(0,a.kt)("p",null,"SocketClient\u5728Service\u91cc\u9762\u4ee5\u5b57\u5178\u6620\u5c04\u3002ID\u4e3a\u952e\uff0cSocketClient\u672c\u8eab\u4e3a\u503c\u3002"),(0,a.kt)("img",{src:n(9544).Z,width:"500"}),(0,a.kt)("h2",{id:"\u4e94\u53ef\u914d\u7f6e\u9879"},"\u4e94\u3001\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("details",null,(0,a.kt)("summary",null,"\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("div",null,(0,a.kt)("h4",{id:"setbufferlength"},"SetBufferLength"),(0,a.kt)("p",null,"\u53d1\u9001\u3001\u63a5\u6536\u7f13\u5b58\u5bb9\u91cf\uff08\u5355\u4f4d\uff1abyte\uff09\uff0c\u9ed8\u8ba41024\xd764\u3002\u8bbe\u7f6e\u5efa\u8bae\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5982\u679c\u6570\u636e\u5305\u8f83\u5c0f\uff0c\u5efa\u8bae10k\u5de6\u53f3\u7684\u503c\u3002\u66f4\u52a0\u8282\u7ea6\u5185\u5b58\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u5982\u679c\u6570\u636e\u5305\u8f83\u5927\uff0c\u4f8b\u5982\u6587\u4ef6\u4f20\u8f93\u7b49\uff0c\u5efa\u8bae64k\uff0c\u751a\u81f3\u66f4\u5927\u7684\u503c\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u8be5\u503c\u867d\u7136\u65e0\u4e0a\u9650\uff0c\u4f46\u662f\u4e00\u822c\u4e0d\u8981\u8d85\u8fc71Mb\uff0c\u4e0d\u7136\u4e0d\u4ec5\u6ca1\u610f\u4e49\uff0c\u8fd8\u5f88\u6d6a\u8d39")),(0,a.kt)("h4",{id:"setmaxpackagesize"},"SetMaxPackageSize"),(0,a.kt)("p",null,"\u6570\u636e\u5305\u6700\u5927\u503c\uff08\u5355\u4f4d\uff1abyte\uff09\uff0c\u9ed8\u8ba41024\xd71024\xd710\u3002\u8be5\u503c\u4f1a\u5728\u9002\u5f53\u65f6\u95f4\uff0c\u76f4\u63a5\u4f5c\u7528DataHandlingAdapter.MaxPackageSize\u3002 "),(0,a.kt)("h4",{id:"setthreadcount"},"SetThreadCount"),(0,a.kt)("p",null,"\u591a\u7ebf\u7a0b\u6570\u91cf\u3002\u8be5\u503c\u5728Auto\u6a21\u5f0f\u4e0b\u6307\u793a\u7ebf\u7a0b\u6c60\u7684\u6700\u5c11\u7ebf\u7a0b\u6570\u91cf\u548cIO\u7ebf\u7a0b\u6570\u91cf\u3002"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u5efa\u8bae\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5f02\u6b65\u5904\u7406\u63a5\u6536\u6570\u636e\uff0c\u6b64\u65f6\u7ebf\u7a0b\u6570\u91cf\u8bbe\u7f6e\u4e3a\u5185\u6838\u7ebf\u7a0b\u5de6\u53f3\u7684\u503c\u5373\u53ef\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u540c\u6b65\u5904\u7406\u63a5\u6536\u6570\u636e\uff0c\u6b64\u65f6\u5e94\u5f53\u8003\u8651\u4e24\u4e2a\u56e0\u7d20\u3002\u8be5\u64cd\u4f5c\u662f\u5426\u4e3a\u8017\u65f6\u64cd\u4f5c\uff0c\u5982\u679c\u662f\uff0c\u5219\u8be5\u503c\u5728\u5141\u8bb8\u8303\u56f4\u5185\uff0c\u5e94\u5f53\u8bbe\u7f6e\u66f4\u53ef\u80fd\u5927\u7684\u503c\u3002\u5982\u679c\u4e0d\u662f\uff0c\u5219\u8bbe\u7f6e\u4e3a\u5185\u6838\u7ebf\u7a0b\u5de6\u53f3\u7684\u503c\u5373\u53ef\u3002")),(0,a.kt)("h4",{id:"setgetdefaultnewid"},"SetGetDefaultNewID"),(0,a.kt)("p",null,"\u914d\u7f6e\u521d\u59cbID\u7684\u5206\u914d\u7b56\u7565"),(0,a.kt)("h4",{id:"setlisteniphosts"},"SetListenIPHosts"),(0,a.kt)("p",null,"\u76d1\u542cIP\u548c\u7aef\u53e3\u53f7\u7ec4\uff0c\u53ef\u4ee5\u4e00\u6b21\u6027\u8bbe\u7f6e\u591a\u4e2a\u5730\u5740\u3002 "),(0,a.kt)("h4",{id:"setservername"},"SetServerName"),(0,a.kt)("p",null,"\u670d\u52a1\u5668\u6807\u8bc6\u540d\u79f0\uff0c\u65e0\u5b9e\u9645\u4f7f\u7528\u610f\u4e49\u3002"),(0,a.kt)("h4",{id:"setbacklogproperty"},"SetBacklogProperty"),(0,a.kt)("p",null,"Tcp\u534a\u8fde\u63a5\u6302\u8d77\u8fde\u63a5\u961f\u5217\u7684\u6700\u5927\u957f\u5ea6\u3002\u9ed8\u8ba4\u4e3a30 "),(0,a.kt)("h4",{id:"setmaxcount"},"SetMaxCount"),(0,a.kt)("p",null,"\u6700\u5927\u53ef\u8fde\u63a5\u6570\uff0c\u9ed8\u8ba4\u4e3a10000 "),(0,a.kt)("h4",{id:"setreceivetype"},"SetReceiveType"),(0,a.kt)("p",null,"\u63a5\u6536\u7c7b\u578b\u3002"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"AUTO\uff1a\u81ea\u52a8\u63a5\u6536\u6a21\u5f0f\u3002"),(0,a.kt)("li",{parentName:"ul"},"None\uff1a\u4e0d\u6295\u9012IO\u63a5\u6536\u7533\u8bf7\uff0c\u7528\u6237\u53ef\u901a\u8fc7GetStream\uff0c\u83b7\u53d6\u5230\u6d41\u4ee5\u540e\uff0c\u81ea\u5df1\u5904\u7406\u63a5\u6536\u3002\u6ce8\u610f\uff1a\u8fde\u63a5\u7aef\u4e0d\u4f1a\u611f\u77e5\u4e3b\u52a8\u65ad\u5f00\u3002")),(0,a.kt)("h4",{id:"useplugin"},"UsePlugin"),(0,a.kt)("p",null,"\u662f\u5426\u542f\u7528\u63d2\u4ef6\u3002\u5728\u542f\u7528\u65f6\u6216\u8bb8\u4f1a\u5e26\u6765\u4e00\u70b9\u70b9\u6027\u80fd\u635f\u8017\uff0c\u57fa\u672c\u4e0a\u4e0d\u662f\u5343\u4e07\u6570\u636e\u4ea4\u4e92\u6839\u672c\u4e0d\u503c\u4e00\u63d0\u3002"),(0,a.kt)("h4",{id:"setservicessloption"},"SetServiceSslOption"),(0,a.kt)("p",null,"Ssl\u914d\u7f6e\uff0c\u4e3aNull\u65f6\u5219\u4e0d\u542f\u7528\u3002 "),(0,a.kt)("h4",{id:"usenodelay"},"UseNoDelay"),(0,a.kt)("p",null,"\u8bbe\u7f6eSocket\u7684NoDelay\u5c5e\u6027\uff0c\u9ed8\u8ba4false\u3002 "),(0,a.kt)("h4",{id:"usedelaysender"},"UseDelaySender"),(0,a.kt)("p",null,"\u4f7f\u7528\u5ef6\u8fdf\u53d1\u9001\u3002\u4f17\u6240\u5468\u77e5\uff0ctcp\u6570\u636e\u62a5\u6587\u4e3a\u4e86\u53d1\u9001\u6548\u7387\uff0c\u4f1a\u9ed8\u8ba4\u542f\u7528",(0,a.kt)("strong",{parentName:"p"},"\u5ef6\u8fdf\u7b97\u6cd5"),"\u3002\u4f46\u662f\u8fd9\u79cd\u8bbe\u7f6e\uff0c\u53ea\u80fd\u4e00\u5b9a\u7a0b\u5ea6\u7684\u7f13\u89e3\u5c0f\u6570\u636e\u53d1\u9001\u6548\u7387\u4f4e\u7684\u95ee\u9898\uff0c\u56e0\u4e3a\u5b83\u4e3a\u4e86\u4fdd\u8bc1\u591a\u7ebf\u7a0b\u53d1\u9001\u7684\u6709\u5e8f\u6027\uff0c\u5728send\u51fd\u6570\u4e2d\u8bbe\u7f6e\u4e86\u7ebf\u7a0b\u540c\u6b65\uff0c\u6240\u4ee5\u8bf4\uff0c\u6bcf\u8c03\u7528\u4e00\u6b21send\uff0c\u5b9e\u9645\u4e0a\u90fd\u662f\u5de8\u5927\u7684\u6027\u80fd\u6d88\u8017\uff08\u6b64\u5904\u7528iocp\u53d1\u9001\u4ea6\u7136\uff09\u3002\u6240\u4ee5\uff0c\u8981\u89e3\u51b3\u8be5\u95ee\u9898\uff0c \u6700\u7ec8\u8fd8\u662f\u8981\u5c06\u5c0f\u6570\u636e\uff0c\u7ec4\u5408\u6210\u5927\u6570\u636e\uff0c\u8fd9\u6837\u624d\u80fd\u66f4\u9ad8\u6548\u7387\u7684\u53d1\u9001\u3002\u6240\u4ee5\uff0cDelaySender\u6b63\u662f\u8d1f\u8d23\u6b64\u7c7b\u5de5\u4f5c\u7684\u3002"),(0,a.kt)("p",null,"\u4f7f\u7528DelaySender\uff0c\u4f1a\u4e00\u5b9a\u7a0b\u5ea6\u7684\u964d\u4f4e\u53d1\u9001\u7684\u53ca\u65f6\u6027\uff0c\u4f46\u662f\u964d\u4f4e\u7a0b\u5ea6\u5e76\u4e0d\u9ad8\uff0c\u7b80\u5355\u6765\u8bf4\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5982\u679c\u4e00\u4e2a\u5305\u5927\u4e8e512kb\uff0c\u5219\u4e0d\u4f1a\u5ef6\u8fdf\uff0c\u76f4\u63a5\u53d1\u9001\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u5982\u679c\u53d1\u9001\u7b2c\u4e00\u4e2a\u5305\uff0c\u4e0e\u7b2c\u4e8c\u4e2a\u5305\u7684\u65f6\u95f4\u95f4\u9694\u5c0f\u4e8e\u4e00\u4e2a\u7ebf\u7a0b\u6c60\u7ebf\u7a0b\u8c03\u5ea6\u7684\u65f6\u95f4\uff08\u8fd9\u4e2a\u65f6\u95f4\u6781\u77ed\uff0c\u4e00\u822c\u6765\u8bf4\u4f1a\u572810",(0,a.kt)("strong",{parentName:"li"},"\u5fae\u79d2"),"\u5de6\u53f3\uff09\uff0c\u5219\u4f1a\u5c06\u8fd9\u4e24\u4e2a\u5305\u538b\u7f29\u4e3a\u4e00\u4e2a\u5305\u53d1\u9001\u3002")),(0,a.kt)("h4",{id:"usereuseaddress"},"UseReuseAddress"),(0,a.kt)("p",null,"\u542f\u7528\u7aef\u53e3\u590d\u7528\u3002\u8be5\u914d\u7f6e\u53ef\u5728\u670d\u52a1\u5668\u3001\u6216\u5ba2\u6237\u7aef\u5728\u76d1\u542c\u7aef\u53e3\u65f6\uff0c\u8fd0\u884c\u76d1\u542c\u540c\u4e00\u4e2a\u7aef\u53e3\u3002\u53ef\u4ee5\u4e00\u5b9a\u7a0b\u5ea6\u7f13\u89e3\u7aef\u53e3\u6765\u4e0d\u53ca\u91ca\u653e\u7684\u95ee\u9898\u3002"),(0,a.kt)("h4",{id:"setremoteiphost"},"SetRemoteIPHost"),(0,a.kt)("p",null,"\u94fe\u63a5\u5230\u7684\u8fdc\u7a0bIPHost\uff0c\u652f\u6301\u57df\u540d\u3002\u652f\u6301\u7c7b\u578b\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u4f7f\u7528IP&Port\uff0c\u4f20\u5165\u5f62\u5982\uff1a127.0.0.1:7789\u7684\u5b57\u7b26\u4e32\u5373\u53ef\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u4f7f\u7528\u57df\u540d\uff0c\u5fc5\u987b\u5305\u542b\u534f\u8bae\u7c7b\u578b\uff0c\u5f62\u5982\uff1a",(0,a.kt)("a",{parentName:"li",href:"http://baidu.com%E6%88%96%E8%80%85https://baidu.com:80"},"http://baidu.com\u6216\u8005https://baidu.com:80"))),(0,a.kt)("h4",{id:"setclientssloption"},"SetClientSslOption"),(0,a.kt)("p",null,"\u5ba2\u6237\u7aefSsl\u914d\u7f6e\uff0c\u4e3aNull\u65f6\u5219\u4e0d\u542f\u7528\u3002\n\u6ce8\u610f\uff0c\u5f53RemoteIPHost\u4f7f\u7528https\u3001wss\u7684\u57df\u540d\u65f6\uff0c\u8be5\u914d\u7f6e\u4f1a\u4f7f\u7528\u7cfb\u7edf\u9ed8\u8ba4\u914d\u7f6e\u751f\u6548\u3002"),(0,a.kt)("h4",{id:"setkeepalivevalue"},"SetKeepAliveValue"),(0,a.kt)("p",null,"\u4e3aSocket\u8bbe\u7f6e\u7684\u5c5e\u6027\u3002\n\u6ce8\u610f\uff1a\u8be5\u914d\u7f6e\u4ec5\u5728window\u5e73\u53f0\u751f\u6548\u3002"),(0,a.kt)("h4",{id:"setbindiphost"},"SetBindIPHost"),(0,a.kt)("p",null,"\u7ed1\u5b9a\u7aef\u53e3\u3002"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u5728UdpSessionBase\u4e2d\u8868\u793a\u672c\u5730\u76d1\u542c\u5730\u5740"),(0,a.kt)("li",{parentName:"ul"},"\u5728TcpClient\u4e2d\u8868\u793a\u56fa\u5b9a\u5ba2\u6237\u7aef\u7aef\u53e3\u53f7\u3002")),(0,a.kt)("h4",{id:"usedelaysender-1"},"UseDelaySender"),(0,a.kt)("p",null,"\u4f7f\u7528\u5ef6\u8fdf\u53d1\u9001\u3002\u4f17\u6240\u5468\u77e5\uff0ctcp\u6570\u636e\u62a5\u6587\u4e3a\u4e86\u53d1\u9001\u6548\u7387\uff0c\u4f1a\u9ed8\u8ba4\u542f\u7528\u5ef6\u8fdf\u7b97\u6cd5\u3002\u4f46\u662f\u8fd9\u79cd\u8bbe\u7f6e\uff0c\u53ea\u80fd\u4e00\u5b9a\u7a0b\u5ea6\u7684\u7f13\u89e3\u5c0f\u6570\u636e\u53d1\u9001\u6548\u7387\u4f4e\u7684\u95ee\u9898\uff0c\u56e0\u4e3a\u5b83\u4e3a\u4e86\u4fdd\u8bc1\u591a\u7ebf\u7a0b\u53d1\u9001\u7684\u6709\u5e8f\u6027\uff0c\u5728send\u51fd\u6570\u4e2d\u8bbe\u7f6e\u4e86\u7ebf\u7a0b\u540c\u6b65\uff0c\u6240\u4ee5\u8bf4\uff0c\u6bcf\u8c03\u7528\u4e00\u6b21send\uff0c\u5b9e\u9645\u4e0a\u90fd\u662f\u5de8\u5927\u7684\u6027\u80fd\u6d88\u8017\uff08\u6b64\u5904\u7528iocp\u53d1\u9001\u4ea6\u7136\uff09\u3002\u6240\u4ee5\uff0c\u8981\u89e3\u51b3\u8be5\u95ee\u9898\uff0c \u6700\u7ec8\u8fd8\u662f\u8981\u5c06\u5c0f\u6570\u636e\uff0c\u7ec4\u5408\u6210\u5927\u6570\u636e\uff0c\u8fd9\u6837\u624d\u80fd\u66f4\u9ad8\u6548\u7387\u7684\u53d1\u9001\u3002\u6240\u4ee5\uff0cDelaySender\u6b63\u662f\u8d1f\u8d23\u6b64\u7c7b\u5de5\u4f5c\u7684\u3002"),(0,a.kt)("p",null,"\u4f7f\u7528DelaySender\uff0c\u4f1a\u4e00\u5b9a\u7a0b\u5ea6\u7684\u964d\u4f4e\u53d1\u9001\u7684\u53ca\u65f6\u6027\uff0c\u4f46\u662f\u964d\u4f4e\u7a0b\u5ea6\u5e76\u4e0d\u9ad8\uff0c\u7b80\u5355\u6765\u8bf4\uff1a"),(0,a.kt)("p",null,"\u5982\u679c\u4e00\u4e2a\u5305\u5927\u4e8e512kb\uff0c\u5219\u4e0d\u4f1a\u5ef6\u8fdf\uff0c\u76f4\u63a5\u53d1\u9001\u3002\n\u5982\u679c\u53d1\u9001\u7b2c\u4e00\u4e2a\u5305\uff0c\u4e0e\u7b2c\u4e8c\u4e2a\u5305\u7684\u65f6\u95f4\u95f4\u9694\u5c0f\u4e8e\u4e00\u4e2a\u7ebf\u7a0b\u6c60\u7ebf\u7a0b\u8c03\u5ea6\u7684\u65f6\u95f4\uff08\u8fd9\u4e2a\u65f6\u95f4\u6781\u77ed\uff0c\u4e00\u822c\u6765\u8bf4\u4f1a\u572810\u5fae\u79d2\u5de6\u53f3\uff09\uff0c\u5219\u4f1a\u5c06\u8fd9\u4e24\u4e2a\u5305\u538b\u7f29\u4e3a\u4e00\u4e2a\u5305\u53d1\u9001\u3002"),(0,a.kt)("h4",{id:"usenodelay-1"},"UseNoDelay"),(0,a.kt)("p",null,"\u8bbe\u7f6eSocket\u7684NoDelay\u5c5e\u6027\uff0c\u9ed8\u8ba4false\u3002"),(0,a.kt)("h4",{id:"usebroadcast"},"UseBroadcast"),(0,a.kt)("p",null,"\u8be5\u503c\u6307\u5b9a\u53ef\u4ee5\u53d1\u9001\u6216\u63a5\u6536\u5e7f\u64ad\u6570\u636e\u5305\u3002"))),(0,a.kt)("h2",{id:"\u516d\u652f\u6301\u63d2\u4ef6"},"\u516d\u3001\u652f\u6301\u63d2\u4ef6"),(0,a.kt)("p",null,"\u652f\u6301",(0,a.kt)("strong",{parentName:"p"},"ITcpPlugin"),"\u63a5\u53e3\uff0c\u6216\u8005\u7ee7\u627f\u81ea",(0,a.kt)("strong",{parentName:"p"},"TcpPluginBase"),"\u7c7b\uff0c\u91cd\u5199\u76f8\u5e94\u65b9\u6cd5\u5373\u53ef\u3002"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"\u63d2\u4ef6\u65b9\u6cd5"),(0,a.kt)("th",{parentName:"tr",align:null},"\u529f\u80fd"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnConnecting"),(0,a.kt)("td",{parentName:"tr",align:null},"\u6b64\u65f6Socket\u5b9e\u9645\u4e0a\u5df2\u7ecf\u5b8c\u6210\u8fde\u63a5\uff0c\u4f46\u662f\u5e76\u6ca1\u6709\u542f\u52a8\u63a5\u6536\uff0c\u7136\u540e\u89e6\u53d1\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnConnected"),(0,a.kt)("td",{parentName:"tr",align:null},"\u540c\u610f\u8fde\u63a5\uff0c\u4e14\u6210\u529f\u542f\u52a8\u63a5\u6536\u540e\u89e6\u53d1")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnDisconnecting"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u5ba2\u6237\u7aef\u4e3b\u52a8\u8c03\u7528Close\u65f6\u89e6\u53d1")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnDisconnected"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u5ba2\u6237\u7aef\u65ad\u5f00\u8fde\u63a5\u540e\u89e6\u53d1")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnReceivingData"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u6536\u5230\u539f\u59cb\u6570\u636e\u65f6\u89e6\u53d1\uff0c\u6240\u6709\u7684\u6570\u636e\u5747\u5728ByteBlock\u91cc\u9762\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnReceivedData"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u6536\u5230\u9002\u914d\u5668\u6570\u636e\u65f6\u89e6\u53d1\uff0c\u6839\u636e\u9002\u914d\u5668\u7c7b\u578b\uff0c\u6570\u636e\u53ef\u80fd\u5728ByteBlock\u6216\u8005IRequestInfo\u91cc\u9762\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnSendingData"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u5373\u5c06\u53d1\u9001\u6570\u636e\u65f6\uff0c\u8c03\u7528\u8be5\u65b9\u6cd5\u5728\u9002\u914d\u5668\u4e4b\u540e\uff0c\u63a5\u4e0b\u6765\u5373\u4f1a\u53d1\u9001\u6570\u636e\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnIDChanged"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53SocketClient\u7684ID\u53d1\u751f\u6539\u53d8\u65f6\u89e6\u53d1\u3002")))),(0,a.kt)("h2",{id:"\u4e03\u521b\u5efatcpservice"},"\u4e03\u3001\u521b\u5efaTcpService"),(0,a.kt)("h3",{id:"71-\u7b80\u5355\u521b\u5efa"},"7.1 \u7b80\u5355\u521b\u5efa"),(0,a.kt)("p",null,"\u76f4\u63a5\u521d\u59cb\u5316TcpService\uff0c\u4f1a\u4f7f\u7528\u9ed8\u8ba4\u7684",(0,a.kt)("strong",{parentName:"p"},"SocketClient"),"\u3002\n\u7b80\u5355\u7684\u5904\u7406\u903b\u8f91\u53ef\u901a\u8fc7",(0,a.kt)("strong",{parentName:"p"},"Connecting"),"\u3001",(0,a.kt)("strong",{parentName:"p"},"Connected"),"\u3001",(0,a.kt)("strong",{parentName:"p"},"Received"),"\u7b49\u59d4\u6258\u76f4\u63a5\u5b9e\u73b0\u3002"),(0,a.kt)("p",null,"\u4ee3\u7801\u5982\u4e0b\uff1a"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpService service = new TcpService();\nservice.Connecting = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u6b63\u5728\u8fde\u63a5\nservice.Connected = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u6210\u529f\u8fde\u63a5\nservice.Disconnected = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u65ad\u5f00\u8fde\u63a5\nservice.Received = (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u5ba2\u6237\u7aef\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n client.Logger.Info($"\u5df2\u4ece{client.ID}\u63a5\u6536\u5230\u4fe1\u606f\uff1a{mes}");\n\n client.Send(mes);//\u5c06\u6536\u5230\u7684\u4fe1\u606f\u76f4\u63a5\u8fd4\u56de\u7ed9\u53d1\u9001\u65b9\n\n //client.Send("id",mes);//\u5c06\u6536\u5230\u7684\u4fe1\u606f\u8fd4\u56de\u7ed9\u7279\u5b9aID\u7684\u5ba2\u6237\u7aef\n\n var ids = service.GetIDs();\n foreach (var clientId in ids)//\u5c06\u6536\u5230\u7684\u4fe1\u606f\u8fd4\u56de\u7ed9\u5728\u7ebf\u7684\u6240\u6709\u5ba2\u6237\u7aef\u3002\n {\n if (clientId != client.ID)//\u4e0d\u7ed9\u81ea\u5df1\u53d1\n {\n service.Send(clientId, mes);\n }\n }\n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .ConfigureContainer(a =>//\u5bb9\u5668\u7684\u914d\u7f6e\u987a\u5e8f\u5e94\u8be5\u5728\u6700\u524d\u9762\n {\n a.AddConsoleLogger();//\u6dfb\u52a0\u4e00\u4e2a\u63a7\u5236\u53f0\u65e5\u5fd7\u6ce8\u5165\uff08\u6ce8\u610f\uff1a\u5728maui\u4e2d\u63a7\u5236\u53f0\u65e5\u5fd7\u4e0d\u53ef\u7528\uff09\n })\n .ConfigurePlugins(a =>\n {\n //a.Add();//\u6b64\u5904\u53ef\u4ee5\u6dfb\u52a0\u63d2\u4ef6\n }))\n .Start();//\u542f\u52a8\n')),(0,a.kt)("h3",{id:"72-\u6cdb\u578b\u521b\u5efa"},"7.2 \u6cdb\u578b\u521b\u5efa"),(0,a.kt)("p",null,"\u901a\u8fc7\u6cdb\u578b\u521b\u5efa\u670d\u52a1\u5668\uff0c\u53ef\u4ee5\u5b9e\u73b0\u5f88\u591a\u6709\u610f\u601d\uff0c\u4e14\u80fd",(0,a.kt)("strong",{parentName:"p"},"\u91cd\u5199"),"\u4e00\u4e9b\u6709\u7528\u7684\u529f\u80fd\u3002\u4e0b\u9762\u5c31\u6f14\u793a\uff0c\u5982\u4f55\u901a\u8fc7\u6cdb\u578b\u521b\u5efa\u670d\u52a1\u5668\u3002"),(0,a.kt)("p",null,"\u4ee3\u7801\u5982\u4e0b\uff1a"),(0,a.kt)("p",null,"\uff081\uff09\u5efa\u7acbSocketClient\u7ee7\u627f\u7c7b\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MySocketClient : SocketClient\n{\n protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)\n {\n //\u6b64\u5904\u903b\u8f91\u5355\u7ebf\u7a0b\u5904\u7406\u3002\n\n //\u6b64\u5904\u5904\u7406\u6570\u636e\uff0c\u529f\u80fd\u76f8\u5f53\u4e8eReceived\u59d4\u6258\u3002\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n Console.WriteLine($"\u5df2\u63a5\u6536\u5230\u4fe1\u606f\uff1a{mes}");\n }\n}\n')),(0,a.kt)("p",null,"\uff082\uff09\u5efa\u7acbTcpService\u7ee7\u627f\u7c7b\u3002\u5b9e\u9645\u4e0a\u5982\u679c\u4e1a\u52a1\u4e0d\u6d89\u53ca\u670d\u52a1\u5668\u914d\u7f6e\u7684\u8bdd\uff0c\u53ef\u4ee5\u7701\u7565\u8be5\u6b65\u9aa4\uff0c\u4f7f\u7528",(0,a.kt)("strong",{parentName:"p"},"TcpService\u7684\u6cdb\u578b"),"\u76f4\u63a5\u521b\u5efa\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyService : TcpService\n{\n protected override void LoadConfig(TouchSocketConfig config)\n {\n //\u6b64\u5904\u52a0\u8f7d\u914d\u7f6e\uff0c\u7528\u6237\u53ef\u4ee5\u4ece\u914d\u7f6e\u4e2d\u83b7\u53d6\u914d\u7f6e\u9879\u3002\n base.LoadConfig(config);\n }\n\n protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e)\n {\n //\u6b64\u5904\u903b\u8f91\u4f1a\u591a\u7ebf\u7a0b\u5904\u7406\u3002\n\n \n //e.ID:\u5bf9\u65b0\u8fde\u63a5\u7684\u5ba2\u6237\u7aef\u8fdb\u884cID\u521d\u59cb\u5316\uff0c\u4f8b\u5982\u53ef\u4ee5\u8bbe\u7f6e\u4e3a\u5176IP\u5730\u5740\u3002\n //e.IsPermitOperation:\u6307\u793a\u662f\u5426\u5141\u8bb8\u8be5\u5ba2\u6237\u7aef\u94fe\u63a5\u3002\n base.OnConnecting(socketClient, e);\n }\n}\n\n")),(0,a.kt)("p",null,"\uff083\uff09\u521b\u5efa\u670d\u52a1\u5668\uff08\u5305\u542bMyService\uff09\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'MyService service = new MyService();\nservice.Connecting = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u6b63\u5728\u8fde\u63a5\nservice.Connected = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u6210\u529f\u8fde\u63a5\nservice.Disconnected = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u65ad\u5f00\u8fde\u63a5\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .ConfigureContainer(a =>//\u5bb9\u5668\u7684\u914d\u7f6e\u987a\u5e8f\u5e94\u8be5\u5728\u6700\u524d\u9762\n {\n a.UseConsoleLogger();//\u6dfb\u52a0\u4e00\u4e2a\u63a7\u5236\u53f0\u65e5\u5fd7\u6ce8\u5165\uff08\u6ce8\u610f\uff1a\u5728maui\u4e2d\u63a7\u5236\u53f0\u65e5\u5fd7\u4e0d\u53ef\u7528\uff09\n })\n .ConfigurePlugins(a =>\n {\n //a.Add();//\u6b64\u5904\u53ef\u4ee5\u6dfb\u52a0\u63d2\u4ef6\n }))\n .Start();//\u542f\u52a8\n')),(0,a.kt)("p",null,"\uff084\uff09\u521b\u5efa\u670d\u52a1\u5668\uff08\u4e0d\u542bMyService\uff09\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpService service = new TcpService();\nservice.Connecting = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u6b63\u5728\u8fde\u63a5\nservice.Connected = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u6210\u529f\u8fde\u63a5\nservice.Disconnected = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u65ad\u5f00\u8fde\u63a5\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .ConfigureContainer(a =>//\u5bb9\u5668\u7684\u914d\u7f6e\u987a\u5e8f\u5e94\u8be5\u5728\u6700\u524d\u9762\n {\n a.UseConsoleLogger();//\u6dfb\u52a0\u4e00\u4e2a\u63a7\u5236\u53f0\u65e5\u5fd7\u6ce8\u5165\uff08\u6ce8\u610f\uff1a\u5728maui\u4e2d\u63a7\u5236\u53f0\u65e5\u5fd7\u4e0d\u53ef\u7528\uff09\n })\n .ConfigurePlugins(a =>\n {\n //a.Add();//\u6b64\u5904\u53ef\u4ee5\u6dfb\u52a0\u63d2\u4ef6\n }))\n .Start();//\u542f\u52a8\n')),(0,a.kt)("admonition",{title:"\u5efa\u8bae",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u7531\u4e0a\u8ff0\u4ee3\u7801\u53ef\u4ee5\u770b\u51fa\uff0c\u901a\u8fc7\u7ee7\u627f\uff0c\u53ef\u4ee5\u66f4\u52a0\u7075\u6d3b\u7684\u5b9e\u73b0\u6269\u5c55\u3002\u4f46\u5b9e\u9645\u4e0a\uff0c\u5f88\u591a\u4e1a\u52a1\u6211\u4eec\u5e0c\u671b\u5927\u5bb6\u80fd\u901a\u8fc7\u63d2\u4ef6\u5b8c\u6210\u3002")),(0,a.kt)("h2",{id:"\u516b\u63a5\u6536\u6570\u636e"},"\u516b\u3001\u63a5\u6536\u6570\u636e"),(0,a.kt)("p",null,"\u5728TcpService\u4e2d\uff0c\u63a5\u6536\u6570\u636e\u7684\u65b9\u5f0f\u6709\u5f88\u591a\u79cd\u3002\u591a\u79cd\u65b9\u5f0f\u53ef\u4ee5\u7ec4\u5408\u4f7f\u7528\u3002"),(0,a.kt)("h3",{id:"81-received\u59d4\u6258\u5904\u7406"},"8.1 Received\u59d4\u6258\u5904\u7406"),(0,a.kt)("p",null,"\u5f53\u4f7f\u7528TcpService\uff08\u975e\u6cdb\u578b\uff09\u521b\u5efa\u670d\u52a1\u5668\u65f6\uff0c\u5185\u90e8\u5df2\u7ecf\u5b9a\u4e49\u597d\u4e86\u4e00\u4e2a\u5916\u7f6e\u59d4\u6258Received\uff0c\u53ef\u4ee5\u901a\u8fc7\u8be5\u59d4\u6258\u76f4\u63a5\u63a5\u6536\u6570\u636e\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpService service = new TcpService();\nservice.Received = (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u5ba2\u6237\u7aef\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n client.Logger.Info($"\u5df2\u4ece{client.ID}\u63a5\u6536\u5230\u4fe1\u606f\uff1a{mes}");\n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .ConfigureContainer(a =>//\u5bb9\u5668\u7684\u914d\u7f6e\u987a\u5e8f\u5e94\u8be5\u5728\u6700\u524d\u9762\n {\n a.UseConsoleLogger();//\u6dfb\u52a0\u4e00\u4e2a\u63a7\u5236\u53f0\u65e5\u5fd7\u6ce8\u5165\uff08\u6ce8\u610f\uff1a\u5728maui\u4e2d\u63a7\u5236\u53f0\u65e5\u5fd7\u4e0d\u53ef\u7528\uff09\n }))\n .Start();//\u542f\u52a8\n')),(0,a.kt)("h3",{id:"82-\u91cd\u5199socketclient\u5904\u7406"},"8.2 \u91cd\u5199SocketClient\u5904\u7406"),(0,a.kt)("p",null,"\u6b63\u59826.2\u6240\u793a\uff0c\u53ef\u4ee5\u76f4\u63a5\u5728MySocketClient\u7684\u91cd\u5199",(0,a.kt)("strong",{parentName:"p"},"HandleReceivedData"),"\u4e2d\u76f4\u63a5\u5904\u7406\u6570\u636e\u3002"),(0,a.kt)("h3",{id:"83-\u63d2\u4ef6\u5904\u7406-\u63a8\u8350"},"8.3 \u63d2\u4ef6\u5904\u7406 ",(0,a.kt)(r.Z,{mdxType:"Tag"},"\u63a8\u8350")),(0,a.kt)("p",null,"\u6309\u7167TouchSocket\u7684\u8bbe\u8ba1\u7406\u5ff5\uff0c\u4f7f\u7528\u63d2\u4ef6\u5904\u7406\u6570\u636e\uff0c\u662f\u4e00\u9879\u975e\u5e38\u7b80\u5355\uff0c\u4e14\u9ad8\u5ea6\u89e3\u8026\u7684\u65b9\u5f0f\u3002\u6b65\u9aa4\u5982\u4e0b\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u670d\u52a1\u5668\u914d\u7f6e\u542f\u7528\u63d2\u4ef6\uff08UsePlugin\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u65b0\u5efa\u63d2\u4ef6\u7c7b"),(0,a.kt)("li",{parentName:"ol"},"\u6dfb\u52a0\u63d2\u4ef6")),(0,a.kt)("p",null,"\u4ee3\u7801\u5982\u4e0b\uff1a"),(0,a.kt)("p",null,"\uff081\uff09\u58f0\u660e\u63d2\u4ef6"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyPlugin : TcpPluginBase\n{\n public MyPlugin()\n {\n this.Order = 0;//\u6b64\u503c\u8868\u793a\u63d2\u4ef6\u7684\u6267\u884c\u987a\u5e8f\uff0c\u5f53\u591a\u4e2a\u63d2\u4ef6\u5e76\u5b58\u65f6\uff0c\u8be5\u503c\u8d8a\u5927\uff0c\u8d8a\u5728\u524d\u6267\u884c\u3002\n }\n \n protected override void OnReceivedData(SocketClient client, ReceivedDataEventArgs e)\n {\n //\u8fd9\u91cc\u5904\u7406\u6570\u636e\u63a5\u6536\n //\u6839\u636e\u9002\u914d\u5668\u7c7b\u578b\uff0ce.ByteBlock\u4e0ee.RequestInfo\u4f1a\u5448\u73b0\u4e0d\u540c\u7684\u503c\uff0c\u5177\u4f53\u770b\u6587\u6863=\u300b\u9002\u914d\u5668\u90e8\u5206\u3002\n ByteBlock byteBlock = e.ByteBlock;\n IRequestInfo requestInfo = e.RequestInfo;\n\n //e.Handled = true;//\u8868\u793a\u8be5\u6570\u636e\u5df2\u7ecf\u88ab\u672c\u63d2\u4ef6\u5904\u7406\uff0c\u65e0\u9700\u518d\u6295\u9012\u5230\u5176\u4ed6\u63d2\u4ef6\u3002\n base.OnReceivedData(client, e);\n }\n}\n")),(0,a.kt)("p",null,"\uff082\uff09\u521b\u5efa\u4f7f\u7528\u63d2\u4ef6\u5904\u7406\u7684\u670d\u52a1\u5668"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpService service = new TcpService();\nservice.Setup(new TouchSocketConfig()\n .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })\n .UsePlugin()\n .ConfigureContainer(a=>\n {\n a.UseConsoleLogger();\n })\n .ConfigurePlugins(a => \n {\n a.Add();\n }))\n .Start();\n')),(0,a.kt)("h2",{id:"\u4e5daspnetcore\u4e2d\u521b\u5efa"},"\u4e5d\u3001AspNetCore\u4e2d\u521b\u5efa"),(0,a.kt)("p",null,"\u9996\u5148\u5efa\u8bae\u5b89\u88c5",(0,a.kt)("inlineCode",{parentName:"p"},"TouchSocket.AspNetCore"),"\u6216\u8005",(0,a.kt)("inlineCode",{parentName:"p"},"TouchSocketPro.AspNetCore"),"\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u91cc\u9762\u6709\u5f88\u591a\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528\u7684\u6ce8\u5165\u9879\u3002"),(0,a.kt)("admonition",{title:"\u5efa\u8bae",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u5728\u5b89\u88c5",(0,a.kt)("inlineCode",{parentName:"p"},"TouchSocket.AspNetCore"),"\u6216\u8005",(0,a.kt)("inlineCode",{parentName:"p"},"TouchSocketPro.AspNetCore"),"\u7684\u540c\u65f6\uff0c\u6700\u597d\u4e5f\u5b89\u88c5",(0,a.kt)("inlineCode",{parentName:"p"},"TouchSocket"),"\u6216\u8005",(0,a.kt)("inlineCode",{parentName:"p"},"TouchSocketPro"),"\u3002\u8fd9\u6837\u66f4\u65b0\u4e5f\u5373\u65f6\u4e00\u4e9b\u3002")),(0,a.kt)("p",null,"\u5728AspNetCore\u4e2d\u4f7f\u7528TcpService\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u4e0d\u5e94\u8be5"),"\u50cf\u666e\u901a\u7aef\u4e00\u6837\uff0c\u8ba2\u9605Received\u3002\u5e94\u8be5\u662f\u901a\u8fc7",(0,a.kt)("strong",{parentName:"p"},"\u63d2\u4ef6"),"\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u6ce8\u5165"),"\u7b49\u65b9\u5f0f\u5b9e\u73b0\u3002\u6b65\u9aa4\u5982\u4e0b\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u6ce8\u5165TcpService\uff0c\u5e76\u505a\u597d\u914d\u7f6e\uff08\u548c\u5e38\u89c4\u670d\u52a1\u5668\u914d\u7f6e\u4e00\u6837\uff09\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u65b0\u5efa\u63d2\u4ef6\uff0c\u5904\u7406\u6536\u5230\u7684\u6570\u636e\u3002")),(0,a.kt)("p",null,"\u4ee3\u7801\u5982\u4e0b\uff1a"),(0,a.kt)("p",null,"\uff081\uff09\u58f0\u660e\u63d2\u4ef6"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyTcpPlugin : TcpPluginBase\n{\n private ILogger m_logger;\n\n public MyTcpPlugin(ILogger logger)\n {\n this.m_logger = logger;\n }\n\n protected override void OnConnected(SocketClient client, TouchSocketEventArgs e)\n {\n m_logger.LogInformation("\u5ba2\u6237\u7aef\u8fde\u63a5");\n base.OnConnected(client, e);\n }\n\n protected override void OnReceivedData(SocketClient client, ReceivedDataEventArgs e)\n {\n //\u8fd9\u91cc\u5904\u7406\u6570\u636e\u63a5\u6536\n //\u6839\u636e\u9002\u914d\u5668\u7c7b\u578b\uff0ce.ByteBlock\u4e0ee.RequestInfo\u4f1a\u5448\u73b0\u4e0d\u540c\u7684\u503c\uff0c\u5177\u4f53\u770b\u6587\u6863=\u300b\u9002\u914d\u5668\u90e8\u5206\u3002\n ByteBlock byteBlock = e.ByteBlock;\n IRequestInfo requestInfo = e.RequestInfo;\n }\n}\n')),(0,a.kt)("p",null,"\uff082\uff09\u6ce8\u5165\u670d\u52a1"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public void ConfigureServices(IServiceCollection services)\n{\n var tcpService = services.AddTcpService(config =>\n {\n config.SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .UsePlugin()\n .UseAspNetCoreContainer(services)\n .ConfigurePlugins(a =>\n {\n a.Add();//\u6b64\u63d2\u4ef6\u5c31\u53ef\u4ee5\u5904\u7406\u63a5\u6536\u6570\u636e\n });\n });\n}\n\n")),(0,a.kt)("p",null,"\u7136\u540e\u5728\u4efb\u610f\u5730\u65b9\uff0c\u4e5f\u53ef\u83b7\u5f97\u670d\u52a1\u3002"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"image.png",src:n(2127).Z,width:"1170",height:"480"})),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u6b64\u65f6\uff0cTcpService\u4e0e\u6574\u4e2aAspNetCore\u662f\u5171\u4eabIOC\u5bb9\u5668\u7684\u3002\u5373\uff1aTcpService\u4e2d\u7684\u4efb\u4f55\u5730\u65b9\uff08\u4f8b\u5982\uff1a\u63d2\u4ef6\uff09\u4e5f\u80fd\u83b7\u5f97AspNetCore\u5df2\u6ce8\u518c\u7684\u670d\u52a1\u3002")),(0,a.kt)("h2",{id:"\u5341\u53d1\u9001\u6570\u636e"},"\u5341\u3001\u53d1\u9001\u6570\u636e"),(0,a.kt)("p",null,"\u6309\u7167\u67b6\u6784\u56fe\uff0c\u6bcf\u4e2a\u5ba2\u6237\u7aef\u6210\u529f\u8fde\u63a5\u540e\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u6d3e\u751f\u81ea",(0,a.kt)("strong",{parentName:"p"},"SocketClient"),"\u7684\u5b9e\u4f8b\uff0c\u901a\u8fc7",(0,a.kt)("strong",{parentName:"p"},"\u8be5\u5b9e\u4f8b"),"\u5373\u53ef\u5c06\u6570\u636e\u53d1\u9001\u81f3",(0,a.kt)("strong",{parentName:"p"},"\u5ba2\u6237\u7aef"),"\u3002"),(0,a.kt)("h3",{id:"101-\u5982\u4f55\u83b7\u53d6socketclient"},"10.1 \u5982\u4f55\u83b7\u53d6SocketClient\uff1f"),(0,a.kt)("p",null,"\uff081\uff09\u76f4\u63a5\u83b7\u53d6\u6240\u6709\u5728\u7ebf\u5ba2\u6237\u7aef"),(0,a.kt)("p",null,"\u901a\u8fc7",(0,a.kt)("inlineCode",{parentName:"p"},"service.GetClients"),"\u65b9\u6cd5\uff0c\u83b7\u53d6\u5f53\u524d\u5728\u7ebf\u7684\u6240\u6709\u5ba2\u6237\u7aef\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"SocketClient[] socketClients = service.GetClients();\n")),(0,a.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"\u7531\u4e8eSocketClient\u7684\u751f\u547d\u5468\u671f\u662f\u7531\u6846\u67b6\u63a7\u5236\u7684\uff0c\u6240\u4ee5\u6700\u597d\u5c3d\u91cf\u4e0d\u8981\u76f4\u63a5\u5f15\u7528\u8be5\u5b9e\u4f8b\uff0c\u53ef\u4ee5\u5f15\u7528SocketClient.ID\uff0c\u7136\u540e\u518d\u901a\u8fc7\u670d\u52a1\u5668\u67e5\u627e\u3002")),(0,a.kt)("p",null,"\uff082\uff09\u901a\u8fc7ID\u83b7\u53d6"),(0,a.kt)("p",null,"\u5148\u8c03\u7528",(0,a.kt)("inlineCode",{parentName:"p"},"service.GetIDs"),"\u65b9\u6cd5\uff0c\u83b7\u53d6\u5f53\u524d\u5728\u7ebf\u7684\u6240\u6709\u5ba2\u6237\u7aef\u7684ID\uff0c\u7136\u540e\u9009\u62e9\u9700\u8981\u7684ID\uff0c\u901a\u8fc7TryGetSocketClient\u65b9\u6cd5\uff0c\u83b7\u53d6\u5230\u60f3\u8981\u7684\u5ba2\u6237\u7aef\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"string[] ids = service.GetIDs();\nif (service.TryGetSocketClient(ids[0], out SocketClient socketClient))\n{\n}\n")),(0,a.kt)("h3",{id:"102-\u53d1\u9001"},"10.2 \u53d1\u9001"),(0,a.kt)("p",null,"\u3010\u540c\u6b65\u53d1\u9001\u3011"),(0,a.kt)("p",null,"SocketClient\u5df2\u7ecf\u5185\u7f6e\u4e86\u4e09\u79cd\u540c\u6b65\u53d1\u9001\u65b9\u6cd5\uff0c\u76f4\u63a5\u8c03\u7528\u5c31\u53ef\u4ee5\u53d1\u9001\uff0c\u5982\u679c\u53d1\u9001\u5931\u8d25\uff0c\u5219\u4f1a\u7acb\u5373\u629b\u51fa\u5f02\u5e38\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public virtual void Send(byte[] buffer);\npublic virtual void Send(ByteBlock byteBlock);\npublic virtual void Send(byte[] buffer, int offset, int length);\n")),(0,a.kt)("p",null,"\u3010\u5f02\u6b65\u53d1\u9001\u3011"),(0,a.kt)("p",null,"TcpClient\u5df2\u7ecf\u5185\u7f6e\u4e86\u4e09\u79cd\u5f02\u6b65\u53d1\u9001\u65b9\u6cd5\uff0c\u76f4\u63a5\u8c03\u7528\u5c31\u53ef\u4ee5\u53d1\u9001\u3002\u5982\u679c\u53d1\u9001\u5931\u8d25\uff0cawait\u5c31\u4f1a\u89e6\u53d1\u5f02\u5e38\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public virtual Task SendAsync(byte[] buffer);\npublic virtual Task SendAsync(ByteBlock byteBlock);\npublic virtual Task SendAsync(byte[] buffer, int offset, int length);\n")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u901a\u8fc7\u4e0a\u8ff0\u65b9\u6cd5\u53d1\u9001\u7684\u6570\u636e\uff0c\u90fd\u4f1a\u7ecf\u8fc7",(0,a.kt)("strong",{parentName:"p"},"\u9002\u914d\u5668"),"\uff0c\u5982\u679c\u60f3\u8981\u76f4\u63a5\u53d1\u9001\uff0c\u8bf7\u4f7f\u7528",(0,a.kt)("strong",{parentName:"p"},"DefaultSend"),"\u3002")),(0,a.kt)("h3",{id:"103-\u901a\u8fc7tcpservice\u53d1\u9001"},"10.3 \u901a\u8fc7TcpService\u53d1\u9001"),(0,a.kt)("p",null,"\u901a\u8fc7ID\u53d1\u9001\u6570\u636e\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public virtual void Send(string id, ByteBlock byteBlock);\npublic virtual void Send(string id, byte[] buffer, int offset, int length);\npublic virtual void Send(string id, byte[] buffer);\npublic virtual Task SendAsync(string id, ByteBlock byteBlock);\npublic virtual Task SendAsync(string id, byte[] buffer, int offset, int length);\npublic virtual Task SendAsync(string id, byte[] buffer);\n")))}d.isMDXComponent=!0},9544:(e,t,n)=>{n.d(t,{Z:()=>l});const l=n.p+"assets/images/createtcpservice-2-005d50c69d09a71156030539fb5bf7f6.png"},2127:(e,t,n)=>{n.d(t,{Z:()=>l});const l=n.p+"assets/images/createtcpservice-1-f7dd6a219c3c152c78ccf0cf84066439.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/0654e75d.8db102f4.js b/handbook/build/assets/js/0654e75d.8db102f4.js new file mode 100644 index 000000000..4a764d5d2 --- /dev/null +++ b/handbook/build/assets/js/0654e75d.8db102f4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7987],{5745:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-pages","id":"default"}')}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/078d73b8.4dc736f8.js b/handbook/build/assets/js/078d73b8.4dc736f8.js new file mode 100644 index 000000000..880fd7617 --- /dev/null +++ b/handbook/build/assets/js/078d73b8.4dc736f8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[4018],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=p(e,["components","mdxType","originalType","parentName"]),u=c(n),m=a,f=u["".concat(l,".").concat(m)]||u[m]||s[m]||i;return n?r.createElement(f,o(o({ref:t},d),{},{components:n})):r.createElement(f,o({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p.mdxType="string"==typeof e?e:a,o[1]=p;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>s,frontMatter:()=>i,metadata:()=>p,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const i={id:"pipelinedatahandlingadapter",title:"Pipeline\u6570\u636e\u9002\u914d\u5668"},o=void 0,p={unversionedId:"pipelinedatahandlingadapter",id:"pipelinedatahandlingadapter",title:"Pipeline\u6570\u636e\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/pipelinedatahandlingadapter.mdx",sourceDirName:".",slug:"/pipelinedatahandlingadapter",permalink:"/touchsocket/docs/pipelinedatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/pipelinedatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675586056,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"pipelinedatahandlingadapter",title:"Pipeline\u6570\u636e\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u6a21\u677f\u89e3\u6790\u201c\u533a\u95f4\u6570\u636e\u201d\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/custombetweenanddatahandlingadapter"},next:{title:"\u4e09\u5143\u7ec4\u7f16\u7801\uff08TLV\uff09\u9002\u914d\u5668",permalink:"/touchsocket/docs/tlvdatahandlingadapter"}},l={},c=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4f7f\u7528",id:"\u4e8c\u4f7f\u7528",level:2}],d={toc:c};function s(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"Pipeline\u9002\u914d\u5668\uff0c\u662f\u7ed3\u5408IOCP\u4e0e\u7ba1\u9053\u6a21\u578b\u7ed3\u5408\u7684\u4ea7\u7269\u3002\u529f\u80fd\u7c7b\u4f3c\u4e8eNetworkStream\uff0c\u4f46\u4e0e\u4e4b\u4e0d\u540c\u7684\u662f\uff0cPipeline\u6bcf\u5f53\u6709\u6570\u636e\u5230\u8fbe\u65f6\uff0c\u4f1a\u5148\u89e6\u53d1\u4e00\u4e2a\u4e8b\u4ef6\uff08OnReveived\uff09\uff0c\u7136\u540e\u7528\u6237\u5728\u4e8b\u4ef6\u4e2d\u53ef\u65e0\u9650\u5236\u7684Read\u6216Write\u6570\u636e\u3002\u5982\u679c\u672c\u6b21\u63a5\u6536\u5b8c\u6210\uff0c\u53ef\u9000\u51fa\u63a5\u6536\u3002\u5f53\u4e0b\u4e00\u6bb5\u6570\u636e\u62b5\u8fbe\u65f6\uff0c\u4f1a\u518d\u6b21\u901a\u77e5\u63a5\u6536\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u4f7f\u7528"},"\u4e8c\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u4e0b\u5217\u793a\u4f8b\u4ee3\u7801\u5b9e\u73b0\uff0c\u5f53\u8bfb\u5230\u6362\u884c\u65f6\uff0c\u7ed3\u675f\u672c\u6b21\u63a5\u6536\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpService service = new TcpService();\n\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n if (requestInfo is Pipeline pipeline)//\u5b9e\u9645\u4e0aPipeline\u7ee7\u627f\u81eaStream\n {\n pipeline.ReadTimeout = 1000 * 60;//\u8bbe\u7f6e\u8bfb\u53d6\u8d85\u65f6\u65f6\u95f4\u4e3a60\u79d2\u3002\n StreamReader streamReader = new StreamReader(pipeline);//\u6240\u4ee5\u53ef\u4ee5\u76f4\u63a5\u7528StreamReader\u6784\u9020\n string ss = streamReader.ReadLine();//\u4f1a\u4e00\u76f4\u7b49\u6362\u884c\uff0c\u76f4\u5230\u7b49\u5230\u6362\u884c\uff0c\u624d\u7ee7\u7eed\u5411\u4e0b\u6267\u884c\n Console.WriteLine(ss);\n }\n //\u5f53Pipeline\u9000\u51fa\u8be5\u4e8b\u4ef6\u65b9\u6cd5\u65f6\uff0c\u4f1a\u88ab\u81ea\u52a8\u91ca\u653e\uff0c\u4e0b\u6b21\u4f1a\u6295\u9012\u65b0\u7684Pipeline\u5b9e\u4f8b\u3002\n // \u5982\u679c\u91cc\u9762\u8fd8\u6709\u672aRead\u5b8c\u7684\u6570\u636e\uff0c\u4e0b\u6b21\u4f1a\u7ee7\u7eed\u6295\u9012,\u5982\u679c\u60f3\u76f4\u63a5\u4e22\u5f03\uff0c\u5219\u5728\u6b64\u5904\u76f4\u63a5\u8c03\u7528Disopose\u5373\u53ef\u3002\n \n};\n\n//\u58f0\u660e\u914d\u7f6e\nvar config = new TouchSocketConfig();\nconfig.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .SetDataHandlingAdapter(() => new PipelineDataHandlingAdapter());//\u914d\u7f6e\u9002\u914d\u5668\u4e3aPipeline\n\n//\u8f7d\u5165\u914d\u7f6e\nservice.Setup(config);\n\n//\u542f\u52a8\nservice.Start();\n\n')),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u521b\u5efa\u7684\u9002\u914d\u5668\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/09a85799.29e58d80.js b/handbook/build/assets/js/09a85799.29e58d80.js new file mode 100644 index 000000000..29c14d953 --- /dev/null +++ b/handbook/build/assets/js/09a85799.29e58d80.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9541],{3905:(e,n,t)=>{t.d(n,{Zo:()=>m,kt:()=>d});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=r.createContext({}),p=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},m=function(e){var n=p(e.components);return r.createElement(l.Provider,{value:n},e.children)},u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},s=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,m=c(e,["components","mdxType","originalType","parentName"]),s=p(t),d=a,g=s["".concat(l,".").concat(d)]||s[d]||u[d]||o;return t?r.createElement(g,i(i({ref:n},m),{},{components:t})):r.createElement(g,i({ref:n},m))}));function d(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=s;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var p=2;p{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>p});var r=t(7462),a=(t(7294),t(3905));const o={id:"tcpcommandlineplugin",title:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6"},i=void 0,c={unversionedId:"tcpcommandlineplugin",id:"tcpcommandlineplugin",title:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/tcpcommandlineplugin.mdx",sourceDirName:".",slug:"/tcpcommandlineplugin",permalink:"/touchsocket/docs/tcpcommandlineplugin",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/tcpcommandlineplugin.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"tcpcommandlineplugin",title:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6"},sidebar:"docs",previous:{title:"\u65ad\u7ebf\u91cd\u8fde",permalink:"/touchsocket/docs/reconnection"},next:{title:"\u5fc3\u8df3\u8bbe\u8ba1",permalink:"/touchsocket/docs/heartbeat"}},l={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u521b\u5efa\u5feb\u6377\u6267\u884c\u63d2\u4ef6",id:"\u4e8c\u521b\u5efa\u5feb\u6377\u6267\u884c\u63d2\u4ef6",level:2},{value:"\u4e09\u3001\u521b\u5efa\u670d\u52a1\u5668",id:"\u4e09\u521b\u5efa\u670d\u52a1\u5668",level:2},{value:"\u56db\u3001\u8c03\u7528",id:"\u56db\u8c03\u7528",level:2}],m={toc:p};function u(e){let{components:n,...t}=e;return(0,a.kt)("wrapper",(0,r.Z)({},m,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"TcpCommandLinePlugin"),"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6\uff0c\u662f\u7528\u4e8eTCP\u7684\u5feb\u6377\u4e8b\u52a1\u5b9e\u73b0\u3002\u8be5\u7c7b\u662f\u62bd\u8c61\u7c7b\uff0c\u5fc5\u987b\u901a\u8fc7\u7ee7\u627f\uff0c\u5728\u7ee7\u627f\u7c7b\u4e2d\uff0c\u58f0\u660e\u7684\u5177\u7684",(0,a.kt)("strong",{parentName:"p"},"\u516c\u5171\u7684"),"\u4e14\u540d\u79f0\u4ee5",(0,a.kt)("strong",{parentName:"p"},"Command"),"\u7ed3\u5c3e\u7684\u65b9\u6cd5\uff0c\u5747\u53ef\u88ab\u5feb\u6377\u6267\u884c\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u521b\u5efa\u5feb\u6377\u6267\u884c\u63d2\u4ef6"},"\u4e8c\u3001\u521b\u5efa\u5feb\u6377\u6267\u884c\u63d2\u4ef6"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'/// \n/// \u547d\u4ee4\u6267\u884c\u63d2\u4ef6\u3002\u65b9\u6cd5\u5fc5\u987b\u4ee5Command\u7ed3\u5c3e\u3002\n/// \nclass MyCommandLinePlugin : TcpCommandLinePlugin\n{\n private readonly ILog logger;\n\n public MyCommandLinePlugin(ILog logger) : base(logger)\n {\n this.ReturnException = true;//\u8868\u793a\u6267\u884c\u5f02\u5e38\u7684\u65f6\u5019\uff0c\u662f\u5426\u8fd4\u56de\u5f02\u5e38\u4fe1\u606f\n this.logger = logger;\n }\n\n /// \n /// \u52a0\u6cd5\n /// \n /// \n /// \n /// \n public int AddCommand(int a, int b)\n {\n this.logger.Info($"\u6267\u884c{nameof(AddCommand)}");\n return a + b;\n }\n\n /// \n /// \u4e58\u6cd5\uff0c\u5e76\u4e14\u83b7\u53d6\u8c03\u7528\u8005\u4fe1\u606f\n /// \n /// \n /// \n /// \n /// \n public int MULCommand(ISocketClient socketClient,int a, int b)\n {\n this.logger.Info($"{socketClient.IP}:{socketClient.Port}\u6267\u884c{nameof(MULCommand)}");\n return a * b;\n }\n\n /// \n /// \u6d4b\u8bd5\u5f02\u5e38\n /// \n /// \n public void ExcCommand()\n {\n throw new Exception("\u6211\u5f02\u5e38\u4e86");\n }\n}\n')),(0,a.kt)("h2",{id:"\u4e09\u521b\u5efa\u670d\u52a1\u5668"},"\u4e09\u3001\u521b\u5efa\u670d\u52a1\u5668"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpService service = new TcpService();\n\nvar config = new TouchSocketConfig();\nconfig.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) }) //\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .SetDataHandlingAdapter(() =>\n {\n //return new TerminatorPackageAdapter(1024, "\\r\\n");//\u547d\u4ee4\u884c\u4e2d\u4f7f\u7528\\r\\n\u7ed3\u5c3e \n return new NormalDataHandlingAdapter();//\u4ea6\u6216\u8005\u7701\u7565\\r\\n\uff0c\u4f46\u6b64\u65f6\u8c03\u7528\u65b9\u4e0d\u80fd\u9ad8\u901f\u8c03\u7528\uff0c\u4f1a\u7c98\u5305\n })\n .UsePlugin()\n .ConfigureContainer(a => \n {\n a.AddConsoleLogger();\n })\n .ConfigurePlugins(a =>\n {\n a.Add();\n });\n\n//\u8f7d\u5165\u914d\u7f6e\nservice.Setup(config);\n\n//\u542f\u52a8\nservice.Start();\n\nservice.Logger.Info("\u670d\u52a1\u5668\u6210\u529f\u542f\u52a8\u3002");\nservice.Logger.Info("\u4f7f\u7528\uff1a\u201cAdd 10 20\u201d\u6d4b\u8bd5");\nservice.Logger.Info("\u4f7f\u7528\uff1a\u201cMUL 10 20\u201d\u6d4b\u8bd5");\nservice.Logger.Info("\u4f7f\u7528\uff1a\u201cExc\u201d\u6d4b\u8bd5\u5f02\u5e38");\n')),(0,a.kt)("h2",{id:"\u56db\u8c03\u7528"},"\u56db\u3001\u8c03\u7528"),(0,a.kt)("p",null,"\u4e0a\u8ff0\u5feb\u6377\u6267\u884c\u63d2\u4ef6\uff0c\u5373\u53ef\u88ab\u666e\u901atcp\u5ba2\u6237\u7aef\uff0c\u6216cmd/telnet\u7b49\u4fbf\u6377\u8c03\u7528\u3002"),(0,a.kt)("p",null,"\u8c03\u7528\u6570\u636e\u683c\u5f0f\uff1a"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"Add 10 20 /r/n")," ",(0,a.kt)("strong",{parentName:"p"},"/r/n"),"\u975e\u5fc5\u987b\uff0c\u4f46\u662f\u5f53\u9002\u914d\u5668\u9009\u4e3a",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/terminatorpackageadapter"},"\u7ec8\u6b62\u5b57\u7b26\u5206\u5272\u9002\u914d\u5668"),"\u65f6\uff0c\u5219\u5fc5\u987b\u3002\u4e0d\u7136\uff0c\u5219\u4e0d\u53ef\u8fde\u7eed\u8c03\u7528\uff0c\u4f1a\u7c98\u5305\u3002"),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u8c03\u7528\u7684\u53c2\u6570\u4e5f\u652f\u6301\u81ea\u5b9a\u4e49\u5b9e\u4f53\u7c7b\uff0c\u5c4a\u65f6\u8695\u98df\u4f7f\u7528Json\u6570\u636e\u683c\u5f0f\u5373\u53ef\u3002")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/0a7a9b32.6d442850.js b/handbook/build/assets/js/0a7a9b32.6d442850.js new file mode 100644 index 000000000..c84abbc79 --- /dev/null +++ b/handbook/build/assets/js/0a7a9b32.6d442850.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7162],{3905:(e,t,n)=>{n.d(t,{Zo:()=>k,kt:()=>d});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},k=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},s=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,k=l(e,["components","mdxType","originalType","parentName"]),s=c(n),d=o,m=s["".concat(p,".").concat(d)]||s[d]||u[d]||a;return n?r.createElement(m,i(i({ref:t},k),{},{components:n})):r.createElement(m,i({ref:t},k))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=s;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l.mdxType="string"==typeof e?e:o,i[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const a={id:"rpcoption",title:"\u8c03\u7528\u914d\u7f6e"},i=void 0,l={unversionedId:"rpcoption",id:"rpcoption",title:"\u8c03\u7528\u914d\u7f6e",description:"\u4e00\u3001\u8c03\u7528\u53cd\u9988\u7c7b\u578b",source:"@site/docs/rpcoption.mdx",sourceDirName:".",slug:"/rpcoption",permalink:"/touchsocket/docs/rpcoption",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/rpcoption.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675696587,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"rpcoption",title:"\u8c03\u7528\u914d\u7f6e"},sidebar:"docs",previous:{title:"Rpc\u5927\u6570\u636e\u6d41\u5f0f\u4f20\u8f93",permalink:"/touchsocket/docs/rpcstream"},next:{title:"\u5e8f\u5217\u5316\u9009\u62e9\u5668",permalink:"/touchsocket/docs/serializationselector"}},p={},c=[{value:"\u4e00\u3001\u8c03\u7528\u53cd\u9988\u7c7b\u578b",id:"\u4e00\u8c03\u7528\u53cd\u9988\u7c7b\u578b",level:2},{value:"1.1 \u4f7f\u7528",id:"11-\u4f7f\u7528",level:3},{value:"\u4e8c\u3001\u8c03\u7528\u8d85\u65f6\u8bbe\u7f6e",id:"\u4e8c\u8c03\u7528\u8d85\u65f6\u8bbe\u7f6e",level:2},{value:"2.1 \u8ba1\u65f6\u5668\u8bbe\u7f6e",id:"21-\u8ba1\u65f6\u5668\u8bbe\u7f6e",level:3},{value:"2.2 \u4efb\u52a1\u53d6\u6d88",id:"22-\u4efb\u52a1\u53d6\u6d88",level:3},{value:"2.3 \u670d\u52a1\u4efb\u52a1\u53d6\u6d88",id:"23-\u670d\u52a1\u4efb\u52a1\u53d6\u6d88",level:3}],k={toc:c};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},k,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8c03\u7528\u53cd\u9988\u7c7b\u578b"},"\u4e00\u3001\u8c03\u7528\u53cd\u9988\u7c7b\u578b"),(0,o.kt)("p",null,"RPC\u5728\u8c03\u7528\u65f6\uff0c\u7684\u8c03\u7528\u72b6\u6001\u6709\u4e09\u79cd\u72b6\u6001\u53ef\u9009\uff0c\u5206\u522b\u4e3a\uff1a",(0,o.kt)("inlineCode",{parentName:"p"},"OnlySend"),"\u3001",(0,o.kt)("inlineCode",{parentName:"p"},"WaitSend"),"\u3001",(0,o.kt)("inlineCode",{parentName:"p"},"WaitInvoke"),"\u3002\u533a\u522b\u662f\uff1a"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"OnlySend"),(0,o.kt)("th",{parentName:"tr",align:null},"WaitSend"),(0,o.kt)("th",{parentName:"tr",align:null},"WaitInvoke"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"\u4ec5\u53d1\u9001RPC\u8bf7\u6c42\uff0c\u5728TCP\u5e95\u5c42\u534f\u8bae\u4e0b\uff0c\u80fd\u4fdd\u8bc1\u53d1\u9001\u6210\u529f\uff0c\u4f46\u662f\u4e0d\u53cd\u9988\u670d\u52a1\u5668",(0,o.kt)("strong",{parentName:"td"},"\u4efb\u4f55\u72b6\u6001"),"\uff0c\u4e5f\u4e0d\u4f1a\u53d6\u5f97",(0,o.kt)("strong",{parentName:"td"},"\u8fd4\u56de\u503c"),"\u3001",(0,o.kt)("strong",{parentName:"td"},"\u5f02\u5e38"),"\u7b49\u4fe1\u606f\u3002\u5728UDP\u5e95\u5c42\u534f\u8bae\u4e0b\uff0c\u4e0d\u4fdd\u8bc1\u53d1\u9001\u6210\u529f\uff0c\u4ec5\u4ec5\u662f\u5177\u6709\u8bf7\u6c42\u52a8\u4f5c\u800c\u5df2\u3002"),(0,o.kt)("td",{parentName:"tr",align:null},"\u53d1\u9001RPC\u8bf7\u6c42\uff0c\u5e76\u4e14\u7b49\u5f85\u6536\u5230\u72b6\u6001\u8fd4\u56de\uff0c\u80fd\u4fdd\u8bc1RPC\u8bf7\u6c42\u987a\u5229\u5230\u8fbe\u670d\u52a1\uff0c\u4f46\u662f\u4e0d\u80fd\u5f97\u77e5RPC\u670d\u52a1\u662f\u5426\u6210\u529f\u6267\u884c\uff0c\u4e5f\u4e0d\u4f1a\u53d6\u5f97",(0,o.kt)("strong",{parentName:"td"},"\u8fd4\u56de\u503c"),"\u3001",(0,o.kt)("strong",{parentName:"td"},"\u5f02\u5e38"),"\u7b49\u4fe1\u606f"),(0,o.kt)("td",{parentName:"tr",align:null},"\u53d1\u9001RPC\u8bf7\u6c42\uff0c\u4e14\u8fd4\u56de\u6240\u6709\u4fe1\u606f\uff0c\u5305\u62ec\u662f\u5426\u6210\u529f\u8c03\u7528\uff0c\u6267\u884c\u540e\u7684",(0,o.kt)("strong",{parentName:"td"},"\u8fd4\u56de\u503c"),"\u6216",(0,o.kt)("strong",{parentName:"td"},"\u5f02\u5e38"),"\u7b49\u4fe1\u606f\u3002")))),(0,o.kt)("h3",{id:"11-\u4f7f\u7528"},"1.1 \u4f7f\u7528"),(0,o.kt)("p",null,"\u540c\u6837\u7684\uff0c\u5728InvokeOption\u4e2d\u53ef\u4ee5\u76f4\u63a5\u8d4b\u503c\u4f7f\u7528\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'InvokeOption invokeOption = new InvokeOption();\ninvokeOption.FeedbackType = FeedbackType.WaitInvoke;\n//invokeOption.FeedbackType = FeedbackType.OnlySend;\n//invokeOption.FeedbackType = FeedbackType.WaitSend;\nstring returnString = client.Invoke("TestOne", invokeOption, "10");\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},(0,o.kt)("em",{parentName:"strong"},"\u6ce8\u610f\uff1a\u5047\u5982IInvokeOption\u4f7f\u7528\u7684\u662fInvokeOption\u7684\u8bdd\uff0c\u5728new\u7684\u65f6\u5019\uff0c\u5e94\u8be5\u5bf9\u5176\u4ed6\u53c2\u6570\u4e5f\u8fdb\u884c\u8bbe\u7f6e\uff08\u56e0\u4e3a\u5b83\u662f\u7ed3\u6784\u4f53\uff09\u3002"))),(0,o.kt)("h2",{id:"\u4e8c\u8c03\u7528\u8d85\u65f6\u8bbe\u7f6e"},"\u4e8c\u3001\u8c03\u7528\u8d85\u65f6\u8bbe\u7f6e"),(0,o.kt)("p",null,"\u8c03\u7528RPC\uff0c\u4e0d\u80fd\u65e0\u9650\u5236\u7b49\u5f85\uff0c\u5fc5\u987b\u8981\u6709\u8ba1\u65f6\u5668\uff0c\u6216\u8005\u4efb\u52a1\u53d6\u6d88\u7684\u529f\u80fd\u3002 ",(0,o.kt)("a",{name:"bt54x"})),(0,o.kt)("h3",{id:"21-\u8ba1\u65f6\u5668\u8bbe\u7f6e"},"2.1 \u8ba1\u65f6\u5668\u8bbe\u7f6e"),(0,o.kt)("p",null,"\u76f4\u63a5\u5bf9",(0,o.kt)("inlineCode",{parentName:"p"},"InvokeOption"),"\u7684",(0,o.kt)("inlineCode",{parentName:"p"},"Timeout")," \u5c5e\u6027\u8d4b\u503c\u5373\u53ef\uff0c\u5355\u4f4d\u4e3a",(0,o.kt)("inlineCode",{parentName:"p"},"\u6beb\u79d2"),"\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'InvokeOption invokeOption = new InvokeOption();\ninvokeOption.Timeout = 1000 * 10;//10\u79d2\u540e\u65e0\u53cd\u5e94\uff0c\u5219\u629b\u51faRRQMTimeoutException\u5f02\u5e38\nstring returnString = client.Invoke("TestOne", invokeOption, "10");\n')),(0,o.kt)("h3",{id:"22-\u4efb\u52a1\u53d6\u6d88"},"2.2 \u4efb\u52a1\u53d6\u6d88"),(0,o.kt)("p",null,"\u5728RPC\u8c03\u7528\u65f6\uff0c\u8ba1\u65f6\u5668\u662f\u4e00\u4e2a\u597d\u7684\u9009\u62e9\uff0c\u4f46\u662f\u8fd8\u4e0d\u591f\u5b8c\u7f8e\uff0c\u6709\u65f6\u5019\u6211\u4eec\u5e0c\u671b\u80fd\u624b\u52a8\u7ec8\u7ed3\u67d0\u4e2a\u8c03\u7528\u4efb\u52a1\u3002\u8fd9\u65f6\u5019\uff0c\u8ba1\u65f6\u5668\u5c31\u4e0d\u582a\u91cd\u4efb\uff0c\u9700\u8981\u80fd\u4e3b\u52a8\u53d6\u6d88\u4efb\u52a1\u7684\u529f\u80fd\u3002\u719f\u6089.net\u7684\u5c0f\u4f19\u4f34\u90fd\u77e5\u9053\uff0cCancellationToken\u662f\u5177\u5907\u8fd9\u4e2a\u529f\u80fd\u7684\u3002\u540c\u6837\u7684\uff0c\u53ea\u9700\u8981\u5bf9",(0,o.kt)("inlineCode",{parentName:"p"},"InvokeOption"),"\u7684",(0,o.kt)("inlineCode",{parentName:"p"},"CancellationToken")," \u8d4b\u503c\u5373\u53ef\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'InvokeOption invokeOption = new InvokeOption();\nCancellationTokenSource tokenSource = new CancellationTokenSource();\ninvokeOption.CancellationToken = tokenSource.Token;\n//tokenSource.Cancel();//\u8c03\u7528\u65f6\u53d6\u6d88\u4efb\u52a1\nstring returnString = client.Invoke("TestOne", invokeOption, "10");\n')),(0,o.kt)("h3",{id:"23-\u670d\u52a1\u4efb\u52a1\u53d6\u6d88"},"2.3 \u670d\u52a1\u4efb\u52a1\u53d6\u6d88"),(0,o.kt)("p",null,"\u5b9e\u9645\u4e0a7.2\u7684\u53d6\u6d88\u4efb\u52a1\uff0c\u4ec5\u4ec5\u80fd\u5b9e\u73b0\u8ba9\u5ba2\u6237\u7aef\u53d6\u6d88\u8bf7\u6c42\uff0c\u4f46\u662f\u670d\u52a1\u5668\u5e76\u4e0d\u77e5\u9053\uff0c\u5982\u679c\u60f3\u8ba9\u670d\u52a1\u5668\u4e5f\u611f\u77e5\u4efb\u52a1\u6d88\u606f\uff0c\u5c31\u5fc5\u987b\u4f9d\u6258\u4e8e\u8c03\u7528\u4e0a\u4e0b\u6587\u3002"),(0,o.kt)("p",null,"\u6b64\u5904\u7684\u53d6\u6d88\uff0c\u6709\u53ef\u80fd\u662f\u8c03\u7528\u8005\u4e3b\u52a8\u53d6\u6d88\u3002\u4e5f\u6709\u53ef\u80fd\u662f\u8c03\u7528\u8005\u5df2\u7ecf\u6389\u7ebf\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'public class ElapsedTimeRpcServer : ServerProvider\n{\n [Description("\u6d4b\u8bd5\u53ef\u53d6\u6d88\u7684\u8c03\u7528")]\n [RRQMRPC(MethodFlags.IncludeCallContext)]\n public bool DelayInvoke(ICallContext serverCallContext,int tick)//\u540c\u6b65\u670d\u52a1\n {\n for (int i = 0; i < tick; i++)\n {\n Thread.Sleep(100);\n if (serverCallContext.TokenSource.IsCancellationRequested)\n {\n Console.WriteLine("\u5ba2\u6237\u7aef\u5df2\u7ecf\u53d6\u6d88\u8be5\u4efb\u52a1\uff01");\n return false;//\u5b9e\u9645\u4e0a\u5728\u53d6\u6d88\u65f6\uff0c\u5ba2\u6237\u7aef\u5f97\u4e0d\u5230\u8be5\u503c\n }\n }\n return true;\n }\n}\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/0afce4d0.ddd32fea.js b/handbook/build/assets/js/0afce4d0.ddd32fea.js new file mode 100644 index 000000000..f8c601031 --- /dev/null +++ b/handbook/build/assets/js/0afce4d0.ddd32fea.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2996],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>p});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},A={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},i=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,s=e.originalType,l=e.parentName,d=u(e,["components","mdxType","originalType","parentName"]),i=c(n),p=a,m=i["".concat(l,".").concat(p)]||i[p]||A[p]||s;return n?r.createElement(m,o(o({ref:t},d),{},{components:n})):r.createElement(m,o({ref:t},d))}));function p(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=n.length,o=new Array(s);o[0]=i;var u={};for(var l in t)hasOwnProperty.call(t,l)&&(u[l]=t[l]);u.originalType=e,u.mdxType="string"==typeof e?e:a,o[1]=u;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>A,frontMatter:()=>s,metadata:()=>u,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const s={id:"customdatahandlingadapter",title:"\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668"},o=void 0,u={unversionedId:"customdatahandlingadapter",id:"customdatahandlingadapter",title:"\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/customdatahandlingadapter.mdx",sourceDirName:".",slug:"/customdatahandlingadapter",permalink:"/touchsocket/docs/customdatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/customdatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675660193,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"customdatahandlingadapter",title:"\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668",permalink:"/touchsocket/docs/datahandleadapter"},next:{title:"\u6a21\u677f\u89e3\u6790\u201c\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/customfixedheaderdatahandlingadapter"}},l={},c=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u8fd0\u884c\u903b\u8f91",id:"\u4e8c\u8fd0\u884c\u903b\u8f91",level:2},{value:"\u4e09\u3001\u7279\u70b9",id:"\u4e09\u7279\u70b9",level:2},{value:"\u56db\u3001\u4f7f\u7528",id:"\u56db\u4f7f\u7528",level:2}],d={toc:c};function A(e){let{components:t,...s}=e;return(0,a.kt)("wrapper",(0,r.Z)({},d,s,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u548c\u539f\u59cb\u9002\u914d\u5668\u76f8\u6bd4\uff0c\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668\uff08",(0,a.kt)("strong",{parentName:"p"},"CustomDataHandlingAdapter"),"\uff09\u7b80\u5355\u5f88\u591a\u3002\u56e0\u4e3a\u4ed6\u53ea\u9700\u8981\u8003\u8651\u63a5\u4e0b\u6765\u5982\u4f55\u5904\u7406\u5373\u53ef\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u8fd0\u884c\u903b\u8f91"},"\u4e8c\u3001\u8fd0\u884c\u903b\u8f91"),(0,a.kt)("img",{src:n(8992).Z,width:"700"}),(0,a.kt)("p",null,"\u8fd4\u56de\u6307\u4ee4\u7c7b\u578b\uff1a"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"FilterResult.Cache\uff1a\u5c06ByteBlock\u4e2d\u7684\uff0c\u4eceByteBlock.Pos\u5230\u7ed3\u675f\u7684\u6240\u6709\u6570\u636e\u8fdb\u884c\u7f13\u5b58\uff0c\u7528\u4e8e\u548c\u4e0b\u6b21\u63a5\u6536\u6570\u636e\u505a\u62fc\u63a5\u3002"),(0,a.kt)("li",{parentName:"ul"},"FilterResult.Success\uff1a\u5b8c\u6210\u672c\u6b21\u6570\u636e\u89e3\u6790\uff0c\u5411Received\u6295\u9012IRequestInfo\u5bf9\u8c61\u3002\u5728\u8fd4\u56de\u4e4b\u524d\uff0c\u8bf7\u4e00\u5b9a\u786e\u4fdd\u5df2\u7ecf\u4fee\u6539ByteBlock.Pos\u5c5e\u6027\u3002\u4e0d\u7136\u4f1a\u53d1\u751f\u65e0\u9650\u5faa\u73af\u7684\u5371\u9669\u60c5\u51b5\u3002"),(0,a.kt)("li",{parentName:"ul"},"FilterResult.GoOn\uff1a\u5c06ByteBlock.Pos\u81f3\u7ed3\u675f\u7684\u6570\u636e\u91cd\u65b0\u6295\u9012\uff0c\u6240\u4ee5\u5728\u8fd4\u56de\u4e4b\u524d\uff0c\u8bf7\u4e00\u5b9a\u786e\u4fdd\u5df2\u7ecf\u4fee\u6539ByteBlock.Pos\u5c5e\u6027\uff0c\u81f3\u5c11\u5df2\u7ecf\u9012\u589e\u4e00\u4f4d\u3002\u4e0d\u7136\u4f1a\u53d1\u751f\u65e0\u9650\u5faa\u73af\u7684\u5371\u9669\u60c5\u51b5\u3002")),(0,a.kt)("admonition",{title:"\u6ce8\u610f",type:"danger"},(0,a.kt)("p",{parentName:"admonition"},"\u8fd4\u56deSuccess\u6216\u8005GoOn\u6307\u4ee4\u65f6\uff0c\u8bf7\u4e00\u5b9a\u786e\u4fdd\u5df2\u7ecf\u4fee\u6539ByteBlock.Pos\u5c5e\u6027\uff0c\u81f3\u5c11\u5df2\u7ecf\u9012\u589e\u4e00\u4f4d\u3002\u4e0d\u7136\u4f1a\u53d1\u751f\u65e0\u9650\u5faa\u73af\u7684\u5371\u9669\u60c5\u51b5\u3002")),(0,a.kt)("h2",{id:"\u4e09\u7279\u70b9"},"\u4e09\u3001\u7279\u70b9"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u66f4\u52a0\u81ea\u7531\u5ea6\u7684\u64cd\u4f5c\u6570\u636e\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u80fd\u591f\u7b80\u5355\u7684\u7f13\u5b58\u4e0d\u80fd\u89e3\u6790\u7684\u6570\u636e\u3002")),(0,a.kt)("h2",{id:"\u56db\u4f7f\u7528"},"\u56db\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u8fd8\u662f\u4ee5\u4e0b\u5217\u6570\u636e\u4e3a\u4f8b\uff1a"),(0,a.kt)("img",{src:n(3718).Z}),(0,a.kt)("p",null,"\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u5b9e\u73b0IRequestInfo\u63a5\u53e3\uff0c\u6b64\u5bf9\u8c61\u5373\u4e3a\u5b58\u50a8\u6570\u636e\u7684\u5b9e\u4f53\u7c7b\uff0c\u53ef\u5728\u6b64\u7c7b\u4e2d\u58f0\u660e\u4e00\u4e9b\u5c5e\u6027\uff0c\u4ee5\u5907\u4f7f\u7528\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u7ee7\u627fCustomDataHandlingAdapter\uff0c\u5e76\u4e14\u4ee5\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u4f5c\u4e3a\u6cdb\u578b\u3002\u5e76\u5b9e\u73b0\u5bf9\u5e94\u62bd\u8c61\u65b9\u6cd5\u3002"),(0,a.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684RequestInfo\u5bf9\u8c61\uff0c\u5f3a\u8f6c\u4e3a\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u578b\uff0c\u7136\u540e\u8bfb\u53d6\u5176\u5c5e\u6027\u503c\uff0c\u4ee5\u5907\u4f7f\u7528\u3002")),(0,a.kt)("p",null,"\u3010\u5b9a\u4e49\u9002\u914d\u5668\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter\n{\n\n /// \n /// \u7b5b\u9009\u89e3\u6790\u6570\u636e\u3002\u5b9e\u4f8b\u5316\u7684TRequest\u4f1a\u4e00\u76f4\u4fdd\u5b58\uff0c\u76f4\u81f3\u89e3\u6790\u6210\u529f\uff0c\u6216\u624b\u52a8\u6e05\u9664\u3002\n /// \u5f53\u4e0d\u6ee1\u8db3\u89e3\u6790\u6761\u4ef6\u65f6\uff0c\u8bf7\u8fd4\u56de\uff0c\u6b64\u65f6\u4f1a\u4fdd\u5b58\u7684\u6570\u636e\n /// \u5f53\u6570\u636e\u90e8\u5206\u5f02\u5e38\u65f6\uff0c\u8bf7\u79fb\u52a8\u5230\u6307\u5b9a\u4f4d\u7f6e\uff0c\u7136\u540e\u8fd4\u56de\n /// \u5f53\u5b8c\u5168\u6ee1\u8db3\u89e3\u6790\u6761\u4ef6\u65f6\uff0c\u8bf7\u8fd4\u56de\u6700\u540e\u5c06\u79fb\u81f3\u6307\u5b9a\u4f4d\u7f6e\u3002\n /// \n /// \u5b57\u8282\u5757\n /// \u662f\u5426\u4e3a\u4e0a\u6b21\u9057\u7559\u5bf9\u8c61\uff0c\u5f53\u8be5\u53c2\u6570\u4e3aTrue\u65f6\uff0crequest\u4e5f\u5c06\u662f\u4e0a\u6b21\u5b9e\u4f8b\u5316\u7684\u5bf9\u8c61\u3002\n /// \u5bf9\u8c61\u3002\n /// \u7f13\u5b58\u5bb9\u91cf\u6307\u5bfc\uff0c\u6307\u793a\u5f53\u9700\u8981\u7f13\u5b58\u65f6\uff0c\u5e94\u8be5\u7533\u8bf7\u591a\u5927\u7684\u5185\u5b58\u3002\n /// \n protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref MyRequestInfo request, ref int tempCapacity)\n {\n //\u4ee5\u4e0b\u89e3\u6790\u601d\u8def\u4e3a\u4e00\u6b21\u6027\u89e3\u6790\uff0c\u4e0d\u8003\u8651\u7f13\u5b58\u7684\u4e34\u65f6\u5bf9\u8c61\u3002\n\n if (byteBlock.CanReadLen < 3)\n {\n return FilterResult.Cache;//\u5f53\u5934\u90e8\u90fd\u65e0\u6cd5\u89e3\u6790\u65f6\uff0c\u76f4\u63a5\u7f13\u5b58\n }\n\n int pos = byteBlock.Pos;//\u8bb0\u5f55\u521d\u59cb\u6e38\u6807\u4f4d\u7f6e\uff0c\u9632\u6b62\u672c\u6b21\u65e0\u6cd5\u89e3\u6790\u65f6\uff0c\u56de\u9000\u6e38\u6807\u3002\n\n MyRequestInfo myRequestInfo = new MyRequestInfo();\n\n //\u6b64\u64cd\u4f5c\u5b9e\u9645\u4e0a\u6709\u4e24\u4e2a\u4f5c\u7528\uff0c\n //1.\u586b\u5145header\n //2.\u5c06byteBlock.Pos\u9012\u589e3\u7684\u957f\u5ea6\u3002\n byteBlock.Read(out byte[] header, 3);//\u586b\u5145header\n\n //\u56e0\u4e3a\u7b2c\u4e00\u4e2a\u5b57\u8282\u8868\u793a\u6240\u6709\u957f\u5ea6\uff0c\u800cDataType\u3001OrderType\u5df2\u7ecf\u5305\u542b\u5728\u4e86header\u91cc\u9762\u3002\n //\u6240\u6709\u53ea\u9700\u5440\u518d\u8bfb\u53d6header[0]-2\u4e2a\u957f\u5ea6\u5373\u53ef\u3002\n byte bodyLength = (byte)(header[0] - 2);\n\n if (bodyLength > byteBlock.CanReadLen)\n {\n //body\u6570\u636e\u4e0d\u8db3\u3002\n byteBlock.Pos = pos;//\u56de\u9000\u6e38\u6807\n return FilterResult.Cache;\n }\n else\n {\n //\u6b64\u64cd\u4f5c\u5b9e\u9645\u4e0a\u6709\u4e24\u4e2a\u4f5c\u7528\uff0c\n //1.\u586b\u5145body\n //2.\u5c06byteBlock.Pos\u9012\u589ebodyLength\u7684\u957f\u5ea6\u3002\n byteBlock.Read(out byte[] body, bodyLength);\n\n myRequestInfo.Header = header;\n myRequestInfo.DataType = header[1];\n myRequestInfo.OrderType = header[2];\n myRequestInfo.Body = body;\n request = myRequestInfo;//\u8d4b\u503cref\n return FilterResult.Success;//\u8fd4\u56de\u6210\u529f\n }\n }\n}\n\ninternal class MyRequestInfo : IRequestInfo\n{\n /// \n /// \u81ea\u5b9a\u4e49\u5c5e\u6027,Body\n /// \n public byte[] Body { get; internal set; }\n\n /// \n /// \u81ea\u5b9a\u4e49\u5c5e\u6027,Header\n /// \n public byte[] Header { get; internal set; }\n\n /// \n /// \u81ea\u5b9a\u4e49\u5c5e\u6027,DataType\n /// \n public byte DataType { get; internal set; }\n\n /// \n /// \u81ea\u5b9a\u4e49\u5c5e\u6027,OrderType\n /// \n public byte OrderType { get; internal set; }\n}\n')),(0,a.kt)("p",null,"\u3010\u63a5\u6536\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u63a5\u6536\u4fe1\u606f\uff0c\u5728CustomDataHandlingAdapter\u6d3e\u751f\u7684\u9002\u914d\u5668\u4e2d\uff0cbyteBlock\u5c06\u4e3anull\uff0crequestInfo\u5c06\u4e3a\u9002\u914d\u5668\u5b9a\u4e49\u7684\u6cdb\u578b\n if (requestInfo is MyRequestInfo myRequestInfo)\n {\n //\u6b64\u5904\u53ef\u4ee5\u5904\u7406MyRequestInfo\u7684\u76f8\u5173\u4fe1\u606f\u4e86\u3002\n string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);\n }\n \n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(() => { return new MyCustomDataHandlingAdapter(); }))//\u914d\u7f6e\u9002\u914d\u5668\n .Start();//\u542f\u52a8\n")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u521b\u5efa\u7684\u9002\u914d\u5668\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}A.isMDXComponent=!0},8992:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/customdatahandlingadapter-1-0aec7ea38e0dd3113fa927cec2861066.png"},3718:(e,t,n)=>{n.d(t,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA7MAAAEECAMAAADNkJO5AAAAzFBMVEX////v7+7n5+fc3NyZ2ev/fib29PS15xwAAADtHCT9/fynp6fFxcXV1dW4/f+enp76+PgHC2aRkZHOzs67u7ug5vja4ufbkTqysrJ/f3/u8jmIiIj//9/k///8qcb5cjH73//+/7zvX6y377H7p1X/8ZzP+f//znfd6e3zu//x//+86HLW6iT/3Zj/iniEhIS72+8EUqPC8+H0Nm3/lZ3993Lb/v9mFwC3ZgD7v9//jzH/2LT/qyb3SiQnCiCRZjrtHFBYkcNmt//JkWZqAa6EAAAQQ0lEQVR42uydC1viOB9HS7koUbEO4u66yE1uIrIdUXeNl3Xe/f7f6U3SizrqSDOgzXDO6FCQOM/TX07+SVodzwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgJWyCQCfBs4C4CwA4CwA4CzAWjlbtcQ0LmXGNCsvjnn/BsAvBc4C4CzOAuAszgLgLADO4iwAzuIsAM4C4CzOAuAszgLgLADO4iwAzuIsAM4C4CzOAuAszgLgLADO4iwAzuIsAM7iLOAszgLgLM4C4CzOAs7iLADO4iwAzuIs4CzOAuAszgLgbLm/V5M4Czhr4+xor/YTzqrWFs7e/Lu5V6POAs5aOGvssXbWtM7srGq1ibOAszbOxvZYOhu3zuasvPnbfA1nAWczO5vaY+Vs2jpjnT2739wr/YazgLPZnU3tsXI2bZ3V2b1SuYyzgLM2zu6VqlVrZ0d76q/3nZVPPh/BWcBZ233j335mDypjnZUvnE1txlnA2Rw6S50FnMVZyMp/f3y7av53v3n/NeRk4Oz7zkqc/Wz+2dzrRnv+9//jbODsK87K8osdKJz9XGe//n3/rbjzr75Qx+nA2R/UWfnS2UefcfYDnY1dVQcUWpxlPeuEs5GqZ/eb3zgdOLuAsxJnP3s9G02J1ar2K6cDZ793Vr4+PcbZT13PDnEWZ39YZyVz45zV2Sucxdn358Zv3bsY3wmFsx9ZZ3EWZ9mDYm4Mv6yz8omzEmc/d258j7M4+/rP9VBnmRvjrGN1Vr65GYWzOIuzrv2uVImznzY3xlmcXWjfWFJnqbM462ydlTgLOJs3ZyX/jwDgrKt1Vj47eDZbxlnA2Rw5K8s/XsxSZwFn+T+2AHDWxtn3K6zEWcDZvNdZSZ0FnHVvbvzd7ynHWcDZXF3rkaxnAWcdvdYjXy+5OAs4y74xAM4uy9mXNx/jLOBs7uuspM4CzuZ1D0q+uw2Fs4Czuayz8q2Ki7OAs9xTAYCzP3Pv4mveSpwFnOV3ywDg7FJ+Fo89KMBZJ+usxFnAWXeclW/Ki7OAs3n+fVCSOgs4+56zAPAp4CwAzgIAzgIAzgKsi7NLQOg/C+LpD5uBxQMAAAAAAAAAgF+TapVzQOrgVHjW8ZH7OqYOeQjPMj67hvQVt1MHh9Oza0lfwVlwylk6C87CUtKr4iypg1PhVT8qd/qK46mDw+lVf8JZOgvOgiPO0llwFpYTnkV8OLuOqYPD6dm1pK/gLDjlLJ0FZ2FZ4VletMHZ9Uod8pFe+rD63OkrbqcOzjubtSUDPM7CMiZJVjc62DtLZ3E3dcjLgGthkV3uOOt26uC8s1lbMsDjLCw1veqHOEtncTd1yE942S2yyh1nHU8dHE7PriUDPM6CU87SWXAWlhBe9eUxzpI65H7AzWiRXe4463bq4LyzWVsywOMsLG+SlNEie2fpLO6mDvkacLPv/2bOHWfdTh2cdzZrSwZ4nIVlTpIyWWTvLJ3F3dQhbwNuBovscsdZt1MH553N2pIBHmfBQWfpLDgLS1vYeJYXbXB2TVKH/A24C6dnlzvOup06OO9s1pYM8DgLS58kLbotZO8sncXd1CGPA+6CFtnljrNupw7OO5u1JQM8zsLyJ0kLWmTvLJ3F3dQhnwPu4vu/mXPHWbdTB+edzdqSAR5nYSmzpFduJrTZAF7QWTqLu6lDfsL7/ofjFr3QmjF3nHU8dXA4PbuWDPA4C045S2fBWVhefDbLWZxds9QhVxFmXVva5I6zrqcOzqeXtSUDPM6CW87SWXAWcBZwlvRwltQBZ+ksOAs4CzhLejhL6oCzdBacBZwFnCU9nCV1zgnO0llwFnAWcBZwltSJAWfpLDgLOAs4CzhL6sSAs3QWnAWcBZwFnAViwFmcxVnAWcBZwFkgBpzFWZwFnAWcBZwFYiA9nMVZwFnAWcBZIAbSw1mcBZwFnAWcBWIgPZzFWcBZwFnAWSAG0sNZUoccpfcMnCV1+IWdzdoSZ3EWHHSWzoKzgLOAs2sbn4ezpA7kjrMADPAAAAAAAAAAAAAAAABribhpNedB/2TU08/OeqIdXXY58UT7RL8UfUF/7aHD6QLIgbT963m/5fVPIme9tjFT+1o+Eepg7uun6SXUHmcM4JOVNSq2jI/t6sP8aZ0Vo2pL6DcphZXLIhI7Jqh5B1eFWqVhnjS8cclQ8yqloTceeiIcqkNNo9BQb03aDVre6NrzmrIc1e3bi+j1kex4/Y7XVQ+jsuZi1GrOSGilNKdD/TA9j54eHnNKXJBWzO56Qb8XdOcVkdZZI+r1XVJVyw9JnW09tvRr4bjhFWra6iDUmioOap5XaEzGQxE2JuqbhFeVhlAf4dFTZ7WS19HT21Y//p6jC68vuuXrwPO6M2+k3oazK6U7vVLOmo8rkTh7uRFzesQZyutIe3c9H/Vm80D56g16YtbRq9q4uCb6ll+pswVTQ8NQF9IDfRTVWW2u8A6GUSdQrqpCrD7GSZ29VbqOjK+DC11tlbD9i2jw8HSdjXoTzn4Eg9Pm9FxV2kHsp7hUzsbHA5zNLe1Oc97sTWadUUvZqufH1XienGKEbUdHTxmrUqpqahBembnxMDLvoJTSiI/D53VWFVODngR3tLkDdXhbTmnFxzj7AXNjXWEPTWE9Ng+nqbMTTk9uY5vr4jbqtU+ad9Ve86GjKq4QgQjUejYurMGs88qk+qA2HjfG4VGgJsHCOKuPTHFVsjailuHkuzrrnT1Or2/VodDSmkWtmhbfls0X9WvU2ZVzGM+Cj/Wi1ixlmRu7UWdNVRVNtajV+8bdudmUeugIvW/cnQdG64eztOQ+VtlhEB4NjwrDSqjdLMV7UHqOfKRWuXr7SamqhRVmjpzW2fLszJTRmXg6csjyTM+N9VK35d1ea2c9gbMrHq9Ppxvnyt1zpavehkrmxspd5sb55Ww+ad4pO81VnJveWa9/olaWevWq1rPBzdwsL3uBrsbNu9azpgdDtXKtNMY1octqONRVNdmfMhNlXWD1pwhLjeQrUik50N9H+9iPZ8OJmv1IY+2r+uyW5QUBrQ5xudGcjqfH09PjeAP5MHJWr2thwZO4UzA9vf7jdxUretbp6/LlJ7VK+DuRLPWs/2hX19lR9USqQjvotVuzqM5qZ/vzjnG539N7VerFp0scs1ZtTJSvE32tR4RRoR0+Xc9Gm1U14T0pqWo9O3gUtWlq7LWusynRjrLejxL0iRUyPdeqdk+F8nQQO3t4msyNN44DTtH7BLtGPP+vVMRifFTfenxX5Yt+tfCHOqWVPwtJt97ZNw/F/YzDRFvf3jSaT7SZ7epFbyLNrRQdNVuOLs6OqtfzrpkWd5/dUxGEV2pJqx50CQ3CQNVb5Vi0E1UpxXNhP9U30V1oZ5M663VluTNoJ51j1I8Lrt6EMhJTZ1fKYMPE1Z0OL49VQJcbp1fmQC9uBQPmQs7WTZ0tJLVS1Hei6ultPXNW35pU2FXntLKrS65fPCj6O9vF5MEv1isZzY32mMSzyvZeaGrGW2pUSjW/caTqrN8oJNd6KiW9mVyK10PC1FnxRp1VE+DEy5E66qbT5PS6D6yszib1VKj58bnQVfZYTYsra3BvhSjubxf9yJLC9u/qWNeNSrFe3yn6UR2s+NvBK2XQ39/a2o7fsr+7u1Xc2lXs73xRx7tf9Mv1P+vmloUv28+cFcIv/O776q+DYtGr/7+d822RIgfCeFdKS8gfE5Lckrb1hYhynMNFFn1xcN//c11V0j3TepyrB4os9YAz0jvdy+70L89TlZptraHPnp9C2fjROfrxP/bvT95ZS0ympd/unjz/8Ac8HzXunQRmofTDdc/2bLR/P/3r5LOD1Y+zB/VxZ/jpn8NiZ1hWo/2BeiH7OTID9Va6xHaw+uLN5fH3jSmurtbgxSLLGqvn/zMy4LJz0YUwTJGPzQQbzyf2GrAw5HIqMIIUPT+B2YxoWF2dztvxdB4fI2/W1qphQv1wROvaIutGiz+5CBzjF3b46D5GcXjq9cn+y7Q1dv0Kenl5dm9fvJfsc3n/St6TT29eXu5HB/k6W/EoXbZ1MyrPZtkB22gMtcZkOS+3JmJlh4WME74Ts7BFGveuGYwPGrewQFrCut/6xu53vHE3YIPhJaLymjBOuBoqQor8bY1RHlTf7rTDTt8+u79IGcsm+/by6vLomYXuByWBq0xw0w5rE5+dzgqhcXrcYKbiG7MpO6HSkCXCtgNZyMZ47f3iqGYBEYrHOzCIHgjBZK5ZeU1Arlz7KQQXD0BAZEDvRdU3taDYaF9f7j+x3b6+zH3Zy5tj1OIRMxvW3S2dsYzXLcHuzC4YE3sqV7T4GbOFLZLyVkPJbMMHepYvc7q2wI9c8vboPObY5IsWi7yEVl+LufnsEjYphgvGbvRuVH1TD+rd9Fqh015kdhE5Iz96n7U+nyrNEgzZo1rd3RIiMrNgJTzfmLXSVYrRMq91sfwSNlWufU2rYQor41g9CflmBfbqnUWSL0osFrO++WwJIUldWdegd6Pq/9zKR3v/sVdXycfTj4iucW4FOvssuCI+yyG5nJgVAgVF9su7Zdlw8VykenBbvWrgWCRS+zjAnXwixtBgAU9EcPhsar0WZLIVWZXqQWY/W6uwxRakDj357GR2Eee8zkbQZhcUi5YH6GlujsJ6G2OaS14Uc92kN1ymoVuHufTCrMfY7qbPWsgdrWFoXVdkVaqvB4oQv4wSENCBvfksY8TMWg619eSzDhYjrSfPRur2HlTCL7u+IwEL8dbm+SLMkGVTB9ZFelszircMHGyS75u2jVWqByQtplnYXtu1VnrGR99YmlSchEn6S56uzKbgF1MM+YDU9hZUKnWdCodJlzbScJJoPMvZWMcclB2FLu2jGlKHWL4+KrEq1UMyZR/OX9EeU06U/bWeTTkyxKPuTIi3HpTMF/qcS9m6m7RT9N7ZKVcmfcKubc4bajNV42qYWXAubs61uEUXJ8vJuJxddK4Gp++KSvXfIizidSlmMUSzWytaqmPfJ7V+J+l2YGnCrfqlgvTZgC/kjQS3ccBNn6XZd7IBS5iX5igts4sGEsD4x4+yGrSNy9wxPkWY9V1Rqb4WjgsCmdi5kkw1GCCo3Un1asCYkvvIsHt/F08dK2jFJD4nTCyxZ5hReDA7Tbrc2swt4N6In58RSLHZFIKsF/zNuws275vDRplVqb4mG2LuaxzNn1Rz3tZcZSd2FKZ5jkiU3S/NeuoyW47GW18namF1SSYgEyUiStNnbZ5h29LWLFe++watMJvcZsaklFzYS8GbjoJamVWpHqIWDO0z8HaB7xkdJCPJdlrwYLvnIYyjnjV9rATswU5Gl0sbR4kNmYO02dP2dYSqterlEwpBmVWpfpbaYcNZfNbGLqiGuDY7K95hu9iNX49P25m8d5zYi+s+QKXMqlQ/rTY+5pX3jtOwbB+Po2mgmyCVcO1dmcNnycMcPvv+Py+jUql+bBbXX4FKpVKpVCqVSqVSqVQqlUqlUqlUKpVKpVL9qvoHFd+Yldt1J+4AAAAASUVORK5CYII="}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/0b8ef44c.49139891.js b/handbook/build/assets/js/0b8ef44c.49139891.js new file mode 100644 index 000000000..2a2614efa --- /dev/null +++ b/handbook/build/assets/js/0b8ef44c.49139891.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9750],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),i=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},s=function(e){var t=i(e.components);return n.createElement(l.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=p(e,["components","mdxType","originalType","parentName"]),u=i(r),d=o,f=u["".concat(l,".").concat(d)]||u[d]||m[d]||a;return r?n.createElement(f,c(c({ref:t},s),{},{components:r})):n.createElement(f,c({ref:t},s))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=u;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p.mdxType="string"==typeof e?e:o,c[1]=p;for(var i=2;i{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>m,frontMatter:()=>a,metadata:()=>p,toc:()=>i});var n=r(7462),o=(r(7294),r(3905));const a={id:"xmlrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},c=void 0,p={unversionedId:"xmlrpcdescription",id:"xmlrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",description:"XmlRpc\u662f\u901a\u7528\u7684\u5de5\u4f5c\u5728Internet\u4e0a\u7684RPC\u3002\u4e00\u4e2aXML-RPC\u6d88\u606f\u5c31\u662f\u4e00\u4e2a\u8bf7\u6c42\u4f53\u4e3axml\u7684http-post\u8bf7\u6c42\uff0c\u88ab\u8c03\u7528\u7684\u65b9\u6cd5\u5728\u670d\u52a1\u5668\u7aef\u6267\u884c\u5e76\u5c06\u6267\u884c\u7ed3\u679c\u4ee5xml\u683c\u5f0f\u7f16\u7801\u540e\u8fd4\u56de\u3002\u8fd9\u4e0e\u7f16\u7a0b\u8bed\u8a00\u65e0\u5173\uff0c\u4e0e\u64cd\u4f5c\u7cfb\u7edf\u65e0\u5173\u3002\u5728RRQM\u4e2d\u5c01\u88c5\u4e86\u524d\u540e\u7aef\uff0c\u4f7f\u5176\u4f7f\u7528\u66f4\u52a0\u65b9\u4fbf\u3001\u9ad8\u6548\u3002",source:"@site/docs/xmlrpcdescription.mdx",sourceDirName:".",slug:"/xmlrpcdescription",permalink:"/touchsocket/docs/xmlrpcdescription",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/xmlrpcdescription.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238253,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"xmlrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},sidebar:"docs",previous:{title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1",permalink:"/touchsocket/docs/calljsonrpc"},next:{title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",permalink:"/touchsocket/docs/xmlrpcservice"}},l={},i=[{value:"\u7279\u70b9\uff1a",id:"\u7279\u70b9",level:2},{value:"\u793a\u4f8b\u4ee3\u7801",id:"\u793a\u4f8b\u4ee3\u7801",level:2}],s={toc:i};function m(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"XmlRpc\u662f",(0,o.kt)("strong",{parentName:"p"},"\u901a\u7528"),"\u7684\u5de5\u4f5c\u5728",(0,o.kt)("strong",{parentName:"p"},"Internet"),"\u4e0a\u7684RPC\u3002\u4e00\u4e2aXML-RPC\u6d88\u606f\u5c31\u662f\u4e00\u4e2a\u8bf7\u6c42\u4f53\u4e3axml\u7684",(0,o.kt)("strong",{parentName:"p"},"http-post"),"\u8bf7\u6c42\uff0c\u88ab\u8c03\u7528\u7684\u65b9\u6cd5\u5728\u670d\u52a1\u5668\u7aef\u6267\u884c\u5e76\u5c06\u6267\u884c\u7ed3\u679c\u4ee5xml\u683c\u5f0f\u7f16\u7801\u540e\u8fd4\u56de\u3002\u8fd9\u4e0e",(0,o.kt)("strong",{parentName:"p"},"\u7f16\u7a0b\u8bed\u8a00\u65e0\u5173"),"\uff0c\u4e0e",(0,o.kt)("strong",{parentName:"p"},"\u64cd\u4f5c\u7cfb\u7edf\u65e0\u5173"),"\u3002\u5728RRQM\u4e2d\u5c01\u88c5\u4e86",(0,o.kt)("strong",{parentName:"p"},"\u524d\u540e\u7aef"),"\uff0c\u4f7f\u5176\u4f7f\u7528\u66f4\u52a0\u65b9\u4fbf\u3001\u9ad8\u6548\u3002"),(0,o.kt)("a",{name:"C6IwW"}),(0,o.kt)("h2",{id:"\u7279\u70b9"},"\u7279\u70b9\uff1a"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"\u5f02\u5e38\u53cd\u9988")," \u3002"),(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301\u81ea\u5b9a\u4e49\u7c7b\u578b\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301\u7c7b\u578b\u5d4c\u5957\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301Web\u7b49\u8c03\u7528\u3002")),(0,o.kt)("a",{name:"y57dN"}),(0,o.kt)("h2",{id:"\u793a\u4f8b\u4ee3\u7801"},"\u793a\u4f8b\u4ee3\u7801"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://gitee.com/RRQM_Home/RRQMBox/tree/master/%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3%E7%A4%BA%E4%BE%8B/XmlRpc%E7%A4%BA%E4%BE%8B"},"XmlRpc\u793a\u4f8b")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/0c2b5d1a.6d37bd6a.js b/handbook/build/assets/js/0c2b5d1a.6d37bd6a.js new file mode 100644 index 000000000..ab3abad07 --- /dev/null +++ b/handbook/build/assets/js/0c2b5d1a.6d37bd6a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9925],{3905:(e,t,r)=>{r.d(t,{Zo:()=>i,kt:()=>m});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},i=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=l(e,["components","mdxType","originalType","parentName"]),d=s(r),m=a,y=d["".concat(p,".").concat(m)]||d[m]||u[m]||o;return r?n.createElement(y,c(c({ref:t},i),{},{components:r})):n.createElement(y,c({ref:t},i))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l.mdxType="string"==typeof e?e:a,c[1]=l;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const o={id:"othercore",title:"\u5176\u4ed6\u76f8\u5173\u529f\u80fd\u7c7b"},c=void 0,l={unversionedId:"othercore",id:"othercore",title:"\u5176\u4ed6\u76f8\u5173\u529f\u80fd\u7c7b",description:"\u4e00\u3001Crc\u8ba1\u7b97",source:"@site/docs/othercore.mdx",sourceDirName:".",slug:"/othercore",permalink:"/touchsocket/docs/othercore",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/othercore.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"othercore",title:"\u5176\u4ed6\u76f8\u5173\u529f\u80fd\u7c7b"},sidebar:"docs",previous:{title:"\u5305\u5e8f\u5217\u5316\u6a21\u5f0f",permalink:"/touchsocket/docs/ipackage"},next:{title:"\u521b\u5efaTcpService",permalink:"/touchsocket/docs/createtcpservice"}},p={},s=[{value:"\u4e00\u3001Crc\u8ba1\u7b97",id:"\u4e00crc\u8ba1\u7b97",level:2},{value:"\u4e8c\u3001\u65f6\u95f4\u6d4b\u91cf\u5668\uff08TimeMeasurer\uff09",id:"\u4e8c\u65f6\u95f4\u6d4b\u91cf\u5668timemeasurer",level:2},{value:"\u4e09\u3001MD5\u8ba1\u7b97",id:"\u4e09md5\u8ba1\u7b97",level:2},{value:"\u56db\u300116\u8fdb\u5236\u76f8\u5173",id:"\u56db16\u8fdb\u5236\u76f8\u5173",level:2},{value:"\u4e94\u3001\u96ea\u82b1ID\u751f\u6210",id:"\u4e94\u96ea\u82b1id\u751f\u6210",level:2},{value:"\u516d\u3001\u6570\u636e\u538b\u7f29",id:"\u516d\u6570\u636e\u538b\u7f29",level:2}],i={toc:s};function u(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},i,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00crc\u8ba1\u7b97"},"\u4e00\u3001Crc\u8ba1\u7b97"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"TouchSocket"),"\u4ece\u7f51\u4e0a\u641c\u96c6\u4e86Crc1-23\u7684\u8ba1\u7b97\u65b9\u6cd5\u3002\u5e76\u5c01\u88c5\u5728\u4e86Crc\u7c7b\u4e2d\u3002\n\u4ee5\u6700\u5e38\u7528\u7684Crc16\u4e3a\u4f8b\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"byte[] data = new byte[10];\nbyte[] result = Crc.Crc16(data, 0, data.Length);\n")),(0,a.kt)("h2",{id:"\u4e8c\u65f6\u95f4\u6d4b\u91cf\u5668timemeasurer"},"\u4e8c\u3001\u65f6\u95f4\u6d4b\u91cf\u5668\uff08TimeMeasurer\uff09"),(0,a.kt)("p",null,"\u529f\u80fd\uff1a\u5c01\u88c5\u7684Stopwatch\uff0c\u6d4b\u91cf\u8fd0\u884cAction\u7684\u65f6\u95f4\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"TimeSpan timeSpan = TimeMeasurer.Run(() =>\n {\n Thread.Sleep(1000);\n });\n\n")),(0,a.kt)("h2",{id:"\u4e09md5\u8ba1\u7b97"},"\u4e09\u3001MD5\u8ba1\u7b97"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'string str = MD5.GetMD5Hash("TouchSocket");\nbool b = MD5.VerifyMD5Hash("TouchSocket",str);\n')),(0,a.kt)("h2",{id:"\u56db16\u8fdb\u5236\u76f8\u5173"},"\u56db\u300116\u8fdb\u5236\u76f8\u5173"),(0,a.kt)("p",null,"\u3010\u5c0616\u8fdb\u5236\u7684\u5b57\u7b26\u8f6c\u6362\u4e3a\u6570\u7ec4\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"}," public static byte[] ByHexStringToBytes(this string hexString, string splite = default)\n")),(0,a.kt)("p",null,"\u3010\u5c0616\u8fdb\u5236\u7684\u5b57\u7b26\u8f6c\u6362\u4e3aint32\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"}," public static int ByHexStringToInt32(this string hexString)\n")),(0,a.kt)("h2",{id:"\u4e94\u96ea\u82b1id\u751f\u6210"},"\u4e94\u3001\u96ea\u82b1ID\u751f\u6210"),(0,a.kt)("p",null,"\u96ea\u82b1ID\uff0c\u4f1a\u751f\u6210long\u7c7b\u578b\u7684\u4e0d\u91cd\u590dID\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"SnowflakeIDGenerator generator = new SnowflakeIDGenerator(4);\nlong id=generator.NextID();\n")),(0,a.kt)("h2",{id:"\u516d\u6570\u636e\u538b\u7f29"},"\u516d\u3001\u6570\u636e\u538b\u7f29"),(0,a.kt)("p",null,"\u5185\u90e8\u5c01\u88c5\u4e86Gzip\u7684\u538b\u7f29\u3002\u4f7f\u7528\u9759\u6001\u65b9\u6cd5\u5373\u53ef\u5b8c\u6210\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"\nbyte[] data = new byte[1024];\nnew Random().NextBytes(data);\n\nusing (ByteBlock byteBlock=new ByteBlock())\n{\n GZip.Compress(byteBlock,data,0,data.Length);//\u538b\u7f29\n var decompressData2 = GZip.Decompress(byteBlock.ToArray());//\u89e3\u538b\n}\n\n\n")),(0,a.kt)("p",null,"\u538b\u7f29\u63a5\u53e3\n\u5185\u90e8\u8fd8\u5b9a\u4e49\u4e86\u4e00\u4e2aIDataCompressor\u7684\u538b\u7f29\u63a5\u53e3\u3002\u76ee\u7684\u662f\u4e3a\u4e86\u5411\u6210\u719f\u6846\u67b6\u4f20\u9012\u538b\u7f29\u65b9\u6cd5\uff08\u4f8b\u5982TcpClient\uff09\u3002\n\u9ed8\u8ba4\u914d\u5907\u4e86\u4e00\u4e2aGZipDataCompressor\u3002\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528\u3002\u5f53\u7136\u5927\u5bb6\u53ef\u4ee5\u81ea\u7531\u6269\u5c55\u5176\u4ed6\u538b\u7f29\u65b9\u6cd5\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyDataCompressor : IDataCompressor\n{\n public byte[] Compress(ArraySegment data)\n {\n //\u6b64\u5904\u5b9e\u73b0\u538b\u7f29\n throw new NotImplementedException();\n }\n\n public byte[] Decompress(ArraySegment data)\n {\n //\u6b64\u5904\u5b9e\u73b0\u538b\u7f29\n throw new NotImplementedException();\n }\n}\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/0fc86718.7a7ab966.js b/handbook/build/assets/js/0fc86718.7a7ab966.js new file mode 100644 index 000000000..62fb51d75 --- /dev/null +++ b/handbook/build/assets/js/0fc86718.7a7ab966.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2903],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=o.createContext({}),s=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=s(e.components);return o.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(n),f=r,m=d["".concat(i,".").concat(f)]||d[f]||u[f]||c;return n?o.createElement(m,a(a({ref:t},p),{},{components:n})):o.createElement(m,a({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,a=new Array(c);a[0]=d;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l.mdxType="string"==typeof e?e:r,a[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>a,default:()=>u,frontMatter:()=>c,metadata:()=>l,toc:()=>s});var o=n(7462),r=(n(7294),n(3905));const c={id:"consoleaction",title:"\u63a7\u5236\u53f0\u884c\u4e3a"},a=void 0,l={unversionedId:"consoleaction",id:"consoleaction",title:"\u63a7\u5236\u53f0\u884c\u4e3a",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/consoleaction.mdx",sourceDirName:".",slug:"/consoleaction",permalink:"/touchsocket/docs/consoleaction",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/consoleaction.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"consoleaction",title:"\u63a7\u5236\u53f0\u884c\u4e3a"},sidebar:"docs",previous:{title:"\u5185\u5b58\u6c60",permalink:"/touchsocket/docs/bytepool"},next:{title:"\u5927\u5c0f\u7aef\u8f6c\u6362\u5668",permalink:"/touchsocket/docs/touchsocketbitconverter"}},i={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4f7f\u7528",id:"\u4e8c\u4f7f\u7528",level:2},{value:"\u4e09\u3001\u6548\u679c\u56fe",id:"\u4e09\u6548\u679c\u56fe",level:2}],p={toc:s};function u(e){let{components:t,...c}=e;return(0,r.kt)("wrapper",(0,o.Z)({},p,c,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"\u8fd9\u662f\u4e00\u4e2a\u5f88\u7b80\u5355\u7684\u63a7\u5236\u53f0\u547d\u4ee4\u5668\uff0c\u91cd\u8981\u4f5c\u7528\u5c31\u662f\u5f88\u65b9\u4fbf\u7684\u5b9e\u73b0\u63a7\u5236\u53f0\u63a7\u5236\u3002"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Nuget Package\uff1a"),(0,r.kt)("a",{parentName:"p",href:"https://www.nuget.org/packages/TouchSocket/"},"TouchSocket")),(0,r.kt)("h2",{id:"\u4e8c\u4f7f\u7528"},"\u4e8c\u3001\u4f7f\u7528"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'ConsoleAction consoleAction = new ConsoleAction("h|help|?");//\u8bbe\u7f6e\u5e2e\u52a9\u547d\u4ee4\nconsoleAction.OnException += ConsoleAction_OnException;//\u8ba2\u9605\u6267\u884c\u5f02\u5e38\u8f93\u51fa\n\n//\u4e0b\u5217\u7684ShareProxy\uff0cStopShareProxy\uff0cGetAll\u5747\u4e3a\u65e0\u53c2\u6570\u7684\u65b9\u6cd5\nconsoleAction.Add("sp|shareProxy", "\u5206\u4eab\u4ee3\u7406", ShareProxy);//\u793a\u4f8b\u547d\u4ee4\nconsoleAction.Add("ssp|stopShareProxy", "\u505c\u6b62\u5206\u4eab\u4ee3\u7406", StopShareProxy);//\u793a\u4f8b\u547d\u4ee4\nconsoleAction.Add("ga|getAll", "\u83b7\u53d6\u6240\u6709\u5ba2\u6237\u7aef\u4fe1\u606f", GetAll);//\u793a\u4f8b\u547d\u4ee4\nconsoleAction.ShowAll();\nwhile (true)\n{\n if (!consoleAction.Run(Console.ReadLine()))\n {\n Console.WriteLine("\u547d\u4ee4\u4e0d\u6b63\u786e\uff0c\u8bf7\u8f93\u5165\u201ch|help|?\u201d\u83b7\u5f97\u5e2e\u52a9\u3002");\n }\n}\n')),(0,r.kt)("h2",{id:"\u4e09\u6548\u679c\u56fe"},"\u4e09\u3001\u6548\u679c\u56fe"),(0,r.kt)("p",null,(0,r.kt)("img",{src:n(1382).Z,width:"974",height:"515"})))}u.isMDXComponent=!0},1382:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/consoleaction-1-d9e1a3f9f1a42d751e1d5e0605714a2c.gif"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/11f9f480.1f045afd.js b/handbook/build/assets/js/11f9f480.1f045afd.js new file mode 100644 index 000000000..a78ae827b --- /dev/null +++ b/handbook/build/assets/js/11f9f480.1f045afd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2671],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>d});var r=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=r.createContext({}),l=function(e){var n=r.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(c.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=l(t),d=o,g=m["".concat(c,".").concat(d)]||m[d]||p[d]||a;return t?r.createElement(g,i(i({ref:n},u),{},{components:t})):r.createElement(g,i({ref:n},u))}));function d(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=m;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s.mdxType="string"==typeof e?e:o,i[1]=s;for(var l=2;l{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var r=t(7462),o=(t(7294),t(3905));const a={id:"wscommandlineplugin",title:"WSCommandLinePlugin"},i=void 0,s={unversionedId:"wscommandlineplugin",id:"wscommandlineplugin",title:"WSCommandLinePlugin",description:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6\u5ba2\u6237\u7aef\u3001\u670d\u52a1\u5668\u5747\u652f\u6301",source:"@site/docs/wscommandlineplugin.mdx",sourceDirName:".",slug:"/wscommandlineplugin",permalink:"/touchsocket/docs/wscommandlineplugin",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/wscommandlineplugin.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"wscommandlineplugin",title:"WSCommandLinePlugin"},sidebar:"docs",previous:{title:"\u521b\u5efaWebSocket\u5ba2\u6237\u7aef",permalink:"/touchsocket/docs/createwebsocketclient"},next:{title:"\u57fa\u4e8eWS\u7684JsonRpc",permalink:"/touchsocket/docs/wsjsonrpc"}},c={},l=[{value:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6\u5ba2\u6237\u7aef\u3001\u670d\u52a1\u5668\u5747\u652f\u6301",id:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6\u5ba2\u6237\u7aef\u670d\u52a1\u5668\u5747\u652f\u6301",level:2}],u={toc:l};function p(e){let{components:n,...t}=e;return(0,o.kt)("wrapper",(0,r.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6\u5ba2\u6237\u7aef\u670d\u52a1\u5668\u5747\u652f\u6301"},"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6\u5ba2\u6237\u7aef\u3001\u670d\u52a1\u5668\u5747\u652f\u6301"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"WSCommandLinePlugin"),"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6\uff0c\u662f\u7528\u4e8e",(0,o.kt)("strong",{parentName:"p"},"WebSocket"),"\u7684\u5feb\u6377\u4e8b\u52a1\u5b9e\u73b0\uff0c\u8ba9WS\u5728",(0,o.kt)("strong",{parentName:"p"},"Text"),"\u6587\u672c\u4e2d\uff0c\u7528\u6700\u7b80\u5355\u7684\u6587\u5b57\u6d88\u606f\u5373\u53ef\u5b8c\u6210\u76f8\u5173\u4e8b\u52a1\u7684\u6267\u884c\u3002\u8be5\u7c7b\u662f\u62bd\u8c61\u7c7b\uff0c\u5fc5\u987b\u901a\u8fc7\u7ee7\u627f\uff0c\u5728\u7ee7\u627f\u7c7b\u4e2d\uff0c\u58f0\u660e\u7684\u5177\u7684",(0,o.kt)("strong",{parentName:"p"},"\u516c\u5171\u7684"),"\u4e14\u540d\u79f0\u4ee5",(0,o.kt)("strong",{parentName:"p"},"Command"),"\u7ed3\u5c3e\u7684\u65b9\u6cd5\uff0c\u5747\u53ef\u88ab\u5feb\u6377\u6267\u884c\u3002"),(0,o.kt)("p",null,"\u4f8b\u5982\uff1a\u4e0b\u5217\u63d2\u4ef6\uff0c\u5373\u53ef\u88ab\u666e\u901aWS\u5ba2\u6237\u7aef\uff0c\u6216\u670d\u52a1\u5668\u4fbf\u6377\u8c03\u7528\u3002"),(0,o.kt)("p",null,"\u8c03\u7528\u6570\u636e\u683c\u5f0f\uff1a\n",(0,o.kt)("inlineCode",{parentName:"p"},"Add 10 20"),"\u652f\u6301Json\u6570\u636e\u683c\u5f0f"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new HttpService();\n\nvar config = new TouchSocketConfig();\nconfig.UsePlugin()\n .SetReceiveType(ReceiveType.Auto)\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigureContainer(a=> \n {\n a.SetSingletonLogger();\n })\n .ConfigurePlugins(a=> \n {\n a.Add();//\u6dfb\u52a0WebSocket\u529f\u80fd\n a.Add();//\u6dfb\u52a0WS\u547d\u4ee4\u884c\u4e8b\u52a1\u3002\n });\n\nservice.Setup(config)\n .Start();\nservice.Logger.Message("Http\u670d\u52a1\u5668\u5df2\u542f\u52a8");\nservice.Logger.Message("WS\u8bbf\u95ee\uff1aws://127.0.0.1:7789/ws");\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'/// \n/// \u547d\u4ee4\u884c\u63d2\u4ef6\u3002\n/// \u58f0\u660e\u7684\u65b9\u6cd5\u5fc5\u987b\u4ee5"Command"\u7ed3\u5c3e\uff0c\u652f\u6301json\u5b57\u7b26\u4e32\uff0c\u53c2\u6570\u4e4b\u95f4\u7a7a\u683c\u9694\u5f00\u3002\n/// \nclass MyWSCommandLinePlugin : WSCommandLinePlugin\n{\n public int AddCommand(int a, int b)\n {\n return a + b;\n }\n\n public SumClass SumCommand(SumClass sumClass)\n {\n sumClass.Sum = sumClass.A + sumClass.B;\n return sumClass;\n }\n}\nclass SumClass\n{\n public int A { get; set; }\n public int B { get; set; }\n public int Sum { get; set; }\n\n}\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/11fc8f46.7090702e.js b/handbook/build/assets/js/11fc8f46.7090702e.js new file mode 100644 index 000000000..ba21e5f41 --- /dev/null +++ b/handbook/build/assets/js/11fc8f46.7090702e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1317],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),d=p(r),f=o,m=d["".concat(l,".").concat(f)]||d[f]||u[f]||a;return r?n.createElement(m,c(c({ref:t},s),{},{components:r})):n.createElement(m,c({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>i,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const a={id:"tcpother",title:"\u5176\u4ed6\u573a\u666f\u5e94\u7528"},c=void 0,i={unversionedId:"tcpother",id:"tcpother",title:"\u5176\u4ed6\u573a\u666f\u5e94\u7528",description:"- C# TCP\u5982\u4f55\u9650\u5236\u5355\u4e2a\u5ba2\u6237\u7aef\u7684\u8bbf\u95ee\u6d41\u91cf",source:"@site/docs/tcpother.mdx",sourceDirName:".",slug:"/tcpother",permalink:"/touchsocket/docs/tcpother",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/tcpother.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"tcpother",title:"\u5176\u4ed6\u573a\u666f\u5e94\u7528"},sidebar:"docs",previous:{title:"\u5fc3\u8df3\u8bbe\u8ba1",permalink:"/touchsocket/docs/heartbeat"},next:{title:"\u521b\u5efaUdpSession",permalink:"/touchsocket/docs/createudpsession"}},l={},p=[],s={toc:p};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://blog.csdn.net/qq_40374647/article/details/125496769"},"C# TCP\u5982\u4f55\u9650\u5236\u5355\u4e2a\u5ba2\u6237\u7aef\u7684\u8bbf\u95ee\u6d41\u91cf")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://blog.csdn.net/qq_40374647/article/details/125390655"},"C# Tcp\u670d\u52a1\u5668\u5982\u4f55\u9650\u5236\u540c\u4e00\u4e2aIP\u7684\u8fde\u63a5\u6570\u91cf\uff1f")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://blog.csdn.net/qq_40374647/article/details/128640132"},"C# \u5b9e\u73b0\u4e3aTcp\u670d\u52a1\u5668\u8bbe\u8ba1\u8bbf\u95ee\u9ed1\u540d\u5355\u3001\u767d\u540d\u5355")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://blog.csdn.net/qq_40374647/article/details/128641766"},"C# Tcp\u670d\u52a1\u5668\u5b9e\u73b0\u591a\u7aef\u53e3\u3001\u591a\u534f\u8bae\u89e3\u6790"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/13b149a4.a34a836b.js b/handbook/build/assets/js/13b149a4.a34a836b.js new file mode 100644 index 000000000..7ec5ee0ff --- /dev/null +++ b/handbook/build/assets/js/13b149a4.a34a836b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9911],{3905:(e,t,n)=>{n.d(t,{Zo:()=>i,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function p(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):p(p({},t),e)),n},i=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,s=e.originalType,c=e.parentName,i=o(e,["components","mdxType","originalType","parentName"]),d=l(n),m=a,g=d["".concat(c,".").concat(m)]||d[m]||u[m]||s;return n?r.createElement(g,p(p({ref:t},i),{},{components:n})):r.createElement(g,p({ref:t},i))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=n.length,p=new Array(s);p[0]=d;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o.mdxType="string"==typeof e?e:a,p[1]=o;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>l});var r=n(7462),a=(n(7294),n(3905));const s={id:"appmessenger",title:"\u5e94\u7528\u4fe1\u4f7f"},p=void 0,o={unversionedId:"appmessenger",id:"appmessenger",title:"\u5e94\u7528\u4fe1\u4f7f",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/appmessenger.mdx",sourceDirName:".",slug:"/appmessenger",permalink:"/touchsocket/docs/appmessenger",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/appmessenger.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675229490,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"appmessenger",title:"\u5e94\u7528\u4fe1\u4f7f"},sidebar:"docs",previous:{title:"\u65e5\u5fd7\u8bb0\u5f55\u5668",permalink:"/touchsocket/docs/ilog"},next:{title:"\u9ad8\u6027\u80fd\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316",permalink:"/touchsocket/docs/fastbinaryformatter"}},c={},l=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4f7f\u7528",id:"\u4e8c\u4f7f\u7528",level:2}],i={toc:l};function u(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},i,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u5e94\u7528\u4fe1\u4f7f\u662f\u5728\u8fdb\u7a0b\u5185\u7684\uff0c\u884c\u4f7f\u6ce8\u518c\u548c\u89e6\u53d1\u529f\u80fd\u7684\u7ec4\u4ef6\u3002\u53ef",(0,a.kt)("strong",{parentName:"p"},"\u4ee3\u66ff\u4e8b\u4ef6"),"\uff0c\u53ef",(0,a.kt)("strong",{parentName:"p"},"\u8de8\u8d8a\u7a0b\u5e8f\u96c6"),"\uff0c\u53ef",(0,a.kt)("strong",{parentName:"p"},"\u4f9d\u8d56\u5012\u7f6e"),"\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u4f7f\u7528"},"\u4e8c\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u3010\u58f0\u660e\u4e3b\u4f53\u3011\n\u5b9e\u73b0IMessage\u63a5\u53e3\uff0c\u7136\u540e\u589e\u52a0AppMessage\u6807\u8bb0\u7684\u516c\u5171\u65b9\u6cd5\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MessageObject : IMessage\n{\n\n [AppMessage]\n public int Add(int a, int b)\n {\n return a + b;\n }\n\n [AppMessage]\n public int Sub(int a, int b)\n {\n return a - b;\n }\n}\n\n")),(0,a.kt)("p",null,"\u3010\u6ce8\u518c\u3011\n\u4e0b\u5217\u6f14\u793a\u65f6\uff0c\u662f\u65b0\u5b9e\u4f8b\u5316\u7684AppMessenger\uff0c\u5b9e\u9645\u4e0a\uff0c\u7528\u6237\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528AppMessenger.Default\u9ed8\u8ba4\u5b9e\u4f8b\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"AppMessenger appMessenger = new AppMessenger();\nappMessenger.Register();\n")),(0,a.kt)("p",null,"\u3010\u89e6\u53d1\u3011\n\u89e6\u53d1\u65f6\uff0c\u6cdb\u578b\u7c7b\u578b\uff0c\u5373\u65f6\u8fd4\u56de\u503c\u7c7b\u578b\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'int add = appMessenger.Send("Add", 20, 10);\nAssert.Equal(30,add);\n\nint sub = appMessenger.Send("Sub", 20, 10);\nAssert.Equal(10, sub);\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/17443a98.2fd798c5.js b/handbook/build/assets/js/17443a98.2fd798c5.js new file mode 100644 index 000000000..da97304b9 --- /dev/null +++ b/handbook/build/assets/js/17443a98.2fd798c5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1965],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>g});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),d=c(n),g=a,k=d["".concat(p,".").concat(g)]||d[g]||u[g]||l;return n?r.createElement(k,o(o({ref:t},s),{},{components:n})):r.createElement(k,o({ref:t},s))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,o=new Array(l);o[0]=d;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:a,o[1]=i;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>l,metadata:()=>i,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const l={id:"transferfile",title:"\u4f20\u8f93\u6587\u4ef6"},o=void 0,i={unversionedId:"transferfile",id:"transferfile",title:"\u4f20\u8f93\u6587\u4ef6",description:"\u6f14\u793a\uff1a \u53ef\u4ee5\u770b\u5230\uff0c\u4e0b\u56fe\u6b63\u5728\u4e0a\u4f20\u4e00\u4e2aWindow\u7684\u7cfb\u7edf\u955c\u50cf\u6587\u4ef6\uff0c\u5927\u7ea64.2Gb\uff0c\u4f20\u8f93\u901f\u5ea6\u5df2\u8fbe\u5230800Mb/s\uff0cGC\u57fa\u672c\u4e0a\u6ca1\u6709\u91ca\u653e\uff0c\u6027\u80fd\u975e\u5e38\u5f3a\u608d\uff08\u4e2d\u95f4\u6709\u7a0d\u5fae\u505c\u987f\uff0c\u56e0\u4e3a\u7a0b\u5e8f\u5728\u83b7\u53d6\u6587\u4ef6MD5\u503c\uff09\u3002",source:"@site/docs/transferfile.mdx",sourceDirName:".",slug:"/transferfile",permalink:"/touchsocket/docs/transferfile",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/transferfile.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"transferfile",title:"\u4f20\u8f93\u6587\u4ef6"},sidebar:"docs",previous:{title:"\u751f\u6210\u3001\u83b7\u53d6\u4ee3\u7406",permalink:"/touchsocket/docs/generateproxy"},next:{title:"\u5c0f\u6587\u4ef6\u4f20\u8f93",permalink:"/touchsocket/docs/smallfiletransfer"}},p={},c=[{value:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f",id:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f",level:2},{value:"\u670d\u52a1\u67b6\u6784",id:"\u670d\u52a1\u67b6\u6784",level:2},{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001Pull\u6587\u4ef6",id:"\u4e8cpull\u6587\u4ef6",level:2},{value:"\u793a\u4f8b\u4ee3\u7801\uff1a",id:"\u793a\u4f8b\u4ee3\u7801",level:3},{value:"\u4e09\u3001Push\u6587\u4ef6",id:"\u4e09push\u6587\u4ef6",level:2},{value:"\u56db\u3001\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6",id:"\u56db\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6",level:2}],s={toc:c};function u(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u6f14\u793a\uff1a")," \u53ef\u4ee5\u770b\u5230\uff0c\u4e0b\u56fe\u6b63\u5728\u4e0a\u4f20\u4e00\u4e2aWindow\u7684\u7cfb\u7edf\u955c\u50cf\u6587\u4ef6\uff0c\u5927\u7ea64.2Gb\uff0c\u4f20\u8f93\u901f\u5ea6\u5df2\u8fbe\u5230800Mb/s\uff0cGC\u57fa\u672c\u4e0a\u6ca1\u6709\u91ca\u653e\uff0c\u6027\u80fd\u975e\u5e38\u5f3a\u608d\uff08\u4e2d\u95f4\u6709\u7a0d\u5fae\u505c\u987f\uff0c\u56e0\u4e3a\u7a0b\u5e8f\u5728\u83b7\u53d6\u6587\u4ef6MD5\u503c\uff09\u3002"),(0,a.kt)("a",{name:"h6l2a"}),(0,a.kt)("h2",{id:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f"},"\u4ea7\u54c1\u5e94\u7528\u573a\u666f"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u5e38\u89c4C/S\u5e94\u7528\u4f7f\u7528\u573a\u666f\uff1a\u5f00\u53d1\u4f7f\u7528\u975e\u5e38\u65b9\u4fbf\uff0c\u8fde\u63a5\u9a8c\u8bc1\uff0c\u6570\u636e\u4e1a\u52a1\uff0c\u6587\u4ef6\u4f20\u8f93\u7b49\u4e00\u7cfb\u5217\u529f\u80fd\u5b8c\u5168\u96c6\u6210\u3002"),(0,a.kt)("li",{parentName:"ul"},"Unity\u6e38\u620f\u573a\u666f\uff1a\u6027\u80fd\u5353\u8d8a\uff0c\u529f\u80fd\u4e30\u5bcc\uff0c\u4f7f\u7528\u65b9\u4fbf\u3002 ",(0,a.kt)("a",{name:"h50Dz"}))),(0,a.kt)("h2",{id:"\u670d\u52a1\u67b6\u6784"},"\u670d\u52a1\u67b6\u6784"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u5176\u4f20\u8f93\u67b6\u6784\u662f\u57fa\u4e8eChannel\u5de5\u4f5c\u7684\u3002\u6240\u4ee5\u5f53\u5728\u540c\u4e00\u65f6\u95f4\uff0c\u53ef\u8fdb\u884c\u591a\u4e2a\u4f20\u8f93\u5e76\u884c\uff0c\u4e14\u6570\u636e\u4e92\u4e0d\u5f71\u54cd\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u5728\u6587\u4ef6\u4f20\u8f93\u65f6\uff0c\u6bcf\u4e2a\u8fde\u63a5\u7aef\u548c\u670d\u52a1\u5668\u5747\u662f\u5e73\u7b49\u6743\u5229\u7684\uff0c\u6240\u4ee5RRQM\u5c06\u5176\u547d\u540d\u4e3a\u5bf9\u70b9\u3002\u4efb\u610f\u4e24\u4e2a\u5bf9\u70b9\u4e4b\u95f4\u5747\u53efPull\uff08\u62c9\u53d6\u6216\u4e0b\u8f7d\uff09\u6216Push\uff08\u63a8\u9001\u6216\u4e0a\u4f20\uff09\u6587\u4ef6\uff0c\u4f8b\u5982\u4e0b\u56fe\u4e2d\uff0cClient1\u3001SocketClient1\u3001Client2\u3001SocketClient2\u56db\u4e2a\u4e92\u76f8\u4e3a\u5bf9\u70b9\uff0c\u5747\u53ef\u81ea\u7531\u4f20\u8f93\u6587\u4ef6\u3002")),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u6587\u4ef6\u4f20\u8f93\u662f\u6bcf\u4e2a\u6846\u67b6\u90fd\u9700\u8981\u7684\u529f\u80fd\uff0c\u4e5f\u662f\u68c0\u9a8c\u4e00\u4e2a\u6846\u67b6\u6027\u80fd\u7684\u975e\u5e38\u91cd\u8981\u7684\u6307\u6807\u3002"),(0,a.kt)("p",null,"TouchRpc\u5f00\u8f9f\u4e86\u5bf9\u70b9\u6587\u4ef6\u4f20\u8f93\u3002\u5373\uff0c\u5f53\u5ba2\u6237\u7aef\u8fde\u63a5\u670d\u52a1\u5668\u4ee5\u540e\uff0c\u4e24\u8005\u53ef\u4ee5\u4efb\u610f\uff0c\u968f\u65f6\u7684\u4e92\u76f8\u53d1\u9001\u6587\u4ef6\u3002\u4e0d\u4ec5\u5982\u6b64\uff0c\u5373\u4f7f\u662f\u5ba2\u6237\u7aef\u4e4b\u95f4\uff0c\u53ef\u4ee5\u53d1\u9001\u6587\u4ef6\u3002"),(0,a.kt)("p",null,"\u4e0b\u5217\u793a\u4f8b\u4ec5\u6f14\u793a\u7531",(0,a.kt)("strong",{parentName:"p"},"TcpTouchRpcClient"),"\u5230",(0,a.kt)("strong",{parentName:"p"},"TcpTouchRpcService"),"\uff08\u5b9e\u9645\u4e0a\u662f",(0,a.kt)("strong",{parentName:"p"},"TcpTouchRpcSocketClient"),"\uff09\u7684\u64cd\u4f5c\u3002"),(0,a.kt)("p",null,"\u5bf9\u70b9\u4e4b\u95f4\u53ef\u4ee5\u4efb\u610fpull\uff08\u62c9\u53d6\uff09\u3001push\uff08\u63a8\u9001\uff09\u6587\u4ef6\u3002",(0,a.kt)("strong",{parentName:"p"},"\u63a5\u6536\u5bf9\u70b9"),"\u53ef\u4ee5\u8ba2\u9605",(0,a.kt)("strong",{parentName:"p"},"FileTransfering"),"\u548c",(0,a.kt)("strong",{parentName:"p"},"FileTransfered"),"\u4e8b\u4ef6\uff0c\u6765\u83b7\u53d6\u76f8\u5173\u4fe1\u606f\uff0c\u53d1\u8d77\u5bf9\u70b9\u76f4\u63a5\u901a\u8fc7\u4f20\u8f93\u63a7\u5236\u5668\u6216\u8fd4\u56de\u503c\u83b7\u53d6\u4f20\u8f93\u4fe1\u606f\u3002"),(0,a.kt)("p",null,"\u503c\u5f97\u6ce8\u610f\u7684\u662f\uff0c",(0,a.kt)("strong",{parentName:"p"},"FileTransfered"),"\u4e8b\u4ef6\u7684\u89e6\u53d1\u5e76",(0,a.kt)("strong",{parentName:"p"},"\u4e0d\u610f\u5473\u7740\u5b8c\u6210\u4f20\u8f93"),"\uff0c\u5177\u4f53\u7ed3\u679c\u8fd8\u8981\u901a\u8fc7",(0,a.kt)("strong",{parentName:"p"},"Result"),"\u5c5e\u6027\u503c\u8fdb\u884c\u5224\u65ad\u3002 ",(0,a.kt)("a",{name:"sKmQe"})),(0,a.kt)("h2",{id:"\u4e8cpull\u6587\u4ef6"},"\u4e8c\u3001Pull\u6587\u4ef6"),(0,a.kt)("p",null,"\u7531",(0,a.kt)("strong",{parentName:"p"},"TcpTouchRpcClient"),"\u5411",(0,a.kt)("strong",{parentName:"p"},"TcpTouchRpcService"),"\u53d1\u8d77Pull\u8bf7\u6c42\u65f6\uff0c\u76f8\u5f53\u4e8e\u7531\u5ba2\u6237\u7aef\u4ece\u670d\u52a1\u5668\u4e0b\u8f7d\u6587\u4ef6\u3002"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u54cd\u5e94\u6d41\u7a0b\uff1a")),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u53d1\u8d77Pull\u8bf7\u6c42\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u63a5\u6536\u5bf9\u70b9\uff08\u5373\u6b64\u5904\u7684\u670d\u52a1\u5668\uff09\u89e6\u53d1",(0,a.kt)("strong",{parentName:"li"},"FileTransfering"),"\u4e8b\u4ef6\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u8fd4\u56de\u6587\u4ef6\u4fe1\u606f\uff0c\u7136\u540e\u68c0\u9a8c\u662f\u5426\u7eed\u4f20\u7b49\uff0c\u7136\u540e\u5f00\u59cb\u63a5\u6536\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u63a5\u6536\u5b8c\u6210\u6216\u5f02\u5e38\u3002"),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"\u63a5\u6536\u5bf9\u70b9"),"\u89e6\u53d1",(0,a.kt)("strong",{parentName:"li"},"FileTransfered"),"\u4e8b\u4ef6\u3002"),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"\u53d1\u8d77\u5bf9\u70b9"),"\u51fd\u6570\u8fd4\u56de\uff0c\u63a7\u5236\u5668\u72b6\u6001\u6539\u53d8\u3002")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u5177\u4f53\u8bf7\u6c42\uff1a")),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"\u8bf7\u6c42\u53c2\u6570"),(0,a.kt)("th",{parentName:"tr",align:null},"\u53c2\u6570\u5c5e\u6027"),(0,a.kt)("th",{parentName:"tr",align:null},"\u8bf7\u6c42\u53c2\u6570\u5c5e\u6027\u63cf\u8ff0")))),(0,a.kt)("p",null,"| ",(0,a.kt)("strong",{parentName:"p"},"FileOperator\uff1a"),"FileOperator\u662f\u672c\u6b21\u4f20\u8f93\u7684\u8bf7\u6c42\u64cd\u4f5c\u5668\uff0c\u4e3b\u8981\u7528\u4e8e\u83b7\u53d6\u4f20\u8f93\u8fdb\u5ea6\u3001\u901f\u5ea6\u3001\u72b6\u6001\u4ee5\u53ca\u53d6\u6d88\u4f20\u8f93\u7b49\u64cd\u4f5c\u3002",(0,a.kt)("strong",{parentName:"p"},"\u63a5\u6536\u65b9\u7684\u63a7\u5236\u5668\u4eceFileTransfering\u4e8b\u4ef6\u7684\u53c2\u6570e\u4e2d\u83b7\u5f97\u3002")),(0,a.kt)("p",null,"| ResourcePath | ResourcePath\u5c5e\u6027\u4e3a\u8bf7\u6c42\u6587\u4ef6\u5728\u63a5\u6536\u5bf9\u70b9\u7684\u8def\u5f84\uff0c\u5f53\u8be5\u503c\u4e3a\u76f8\u5bf9\u8def\u5f84\u65f6\uff0c\u4f1a\u4e0e\u63a5\u6536\u5bf9\u70b9\u7684RootPath\u7ec4\u5408\u8def\u5f84\u3002\u5f53\u4e3a\u7edd\u5bf9\u8def\u5f84\u65f6\uff0c\u5219\u4f1a\u76f4\u63a5\u8bbf\u95ee\u8def\u5f84\u6587\u4ef6",(0,a.kt)("strong",{parentName:"p"},"\uff08\u6b64\u65f6\u5982\u679c\u4e0d\u5728\u5bf9\u70b9\u8bbe\u7f6e\u6761\u4ef6\uff0c\u5219\u6709\u53ef\u80fd\u4f1a\u6709\u6587\u4ef6\u5b89\u5168\u9690\u60a3\uff0c\u8bbe\u7f6e\u8be6\u60c5"),(0,a.kt)("a",{parentName:"p",href:"https://www.yuque.com/eo2w71/rrqm/motlw5#zZBRq"},"\u94fe\u63a5"),(0,a.kt)("strong",{parentName:"p"},"\uff09"),"\u3002 |\n| | SavePath | SavePath\u5c5e\u6027\u662f\u53d1\u8d77\u5bf9\u70b9\u672c\u5730\u7684\u4fdd\u5b58\u8def\u5f84\u3002 |\n| | Flags | \u53ef\u901a\u8fc7\u53e0\u52a0\u4f4d\u57df\u7684\u5f62\u5f0f\uff0c\u5c1d\u8bd5\u65ad\u70b9\u7eed\u4f20\u3002 |\n| | CompletedLength | \u5df2\u5b8c\u6210\u6d41\u957f\u5ea6\u3002 |\n| | Speed \u51fd\u6570 | \u4ece\u4e0a\u6b21\u83b7\u53d6\u5230\u6b64\u6b21\u83b7\u5f97\u7684\u901f\u5ea6\u3002\u4e00\u822c\u8bf7\u6bcf\u79d2\u949f\u8c03\u7528\u4e00\u6b21\u83b7\u53d6\u901f\u5ea6\u503c\u3002 |\n| | Progress | \u4f20\u8f93\u8fdb\u5ea6\uff0c\u8303\u56f40-1\u3002 |\n| | Result | \u83b7\u53d6\u4f20\u8f93\u72b6\u6001\u4ee5\u53ca\u72b6\u6001\u4fe1\u606f\u3002\u5f53ResultCode\u4e3aDefault\u65f6\uff0c\u610f\u5473\u7740\u4f20\u8f93\u6b63\u5728\u8fdb\u884c\u3002 |\n| | Token | CancellationToken\u7c7b\u578b\u7684\u53ef\u53d6\u6d88\u4ee4\u7bad\u3002 |\n| | Metadata | string\u7c7b\u578b\u7684\u952e\u503c\u5bf9\uff0c\u7528\u4e8e\u548c\u63a5\u6536\u65b9\u4ea4\u4e92\u6570\u636e\u3002 |"),(0,a.kt)("a",{name:"JeQp8"}),(0,a.kt)("h3",{id:"\u793a\u4f8b\u4ee3\u7801"},"\u793a\u4f8b\u4ee3\u7801\uff1a"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u3010\u670d\u52a1\u5668\u3011")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new TouchSocketConfig()//\u914d\u7f6e\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .UsePlugin()\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n a.AddFileLogger();\n })\n .ConfigurePlugins(a =>\n {\n a.Add();\n })\n .SetVerifyToken("File")//\u8fde\u63a5\u9a8c\u8bc1\u53e3\u4ee4\u3002\n .BuildWithTcpTouchRpcService();//\u6b64\u5904build\u76f8\u5f53\u4e8enew TcpTouchRpcService\uff0c\u7136\u540eSetup\uff0c\u7136\u540eStart\u3002\nservice.Logger.Info("\u670d\u52a1\u5668\u6210\u529f\u542f\u52a8");\n')),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'class MyPlugin : TouchRpcPluginBase\n{\n protected override void OnFileTransfering(TcpTouchRpcSocketClient client, FileOperationEventArgs e)\n {\n e.IsPermitOperation = true;//\u8fd0\u884c\u64cd\u4f5c\n\n //\u6709\u53ef\u80fd\u662f\u4e0a\u4f20\uff0c\u4e5f\u6709\u53ef\u80fd\u662f\u4e0b\u8f7d\n client.Logger.Info($"\u6709\u5ba2\u6237\u7aef\u8bf7\u6c42\u4f20\u8f93\u6587\u4ef6\uff0cID={client.ID}\uff0c\u8bf7\u6c42\u7c7b\u578b={e.TransferType}\uff0c\u8bf7\u6c42\u6587\u4ef6\u540d={e.ResourcePath}");\n }\n\n protected override void OnFileTransfered(TcpTouchRpcSocketClient client, FileTransferStatusEventArgs e)\n {\n //\u4f20\u8f93\u7ed3\u675f\uff0c\u4f46\u662f\u4e0d\u4e00\u5b9a\u6210\u529f\uff0c\u9700\u8981\u4ecee.Result\u5224\u65ad\u72b6\u6001\u3002\n client.Logger.Info($"\u5ba2\u6237\u7aef\u4f20\u8f93\u6587\u4ef6\u7ed3\u675f\uff0cID={client.ID}\uff0c\u8bf7\u6c42\u7c7b\u578b={e.TransferType}\uff0c\u6587\u4ef6\u540d={e.ResourcePath}\uff0c\u8bf7\u6c42\u72b6\u6001={e.Result}");\n }\n\n protected override void OnHandshaked(TcpTouchRpcSocketClient client, VerifyOptionEventArgs e)\n {\n client.Logger.Info($"\u6709\u5ba2\u6237\u7aef\u6210\u529f\u9a8c\u8bc1\uff0cID={client.ID}");\n }\n\n protected override void OnDisconnected(TcpTouchRpcSocketClient client, ClientDisconnectedEventArgs e)\n {\n client.Logger.Info($"\u6709\u5ba2\u6237\u7aef\u65ad\u5f00\uff0cID={client.ID}");\n base.OnDisconnected(client, e);\n }\n}\n')),(0,a.kt)("p",null,"\u3010\u5ba2\u6237\u7aef\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClient client = new TouchSocketConfig()\n .SetRemoteIPHost("127.0.0.1:7789")\n .SetVerifyToken("File")\n .UsePlugin()\n .ConfigureContainer(a => \n {\n a.AddConsoleLogger();\n a.AddFileLogger();\n })\n .ConfigurePlugins(a =>\n {\n a.UseTouchRpcHeartbeat();\n })\n .BuildWithTcpTouchRpcClient();\n\nclient.Logger.Info("\u8fde\u63a5\u6210\u529f");\n\nMetadata metadata = new Metadata();//\u4f20\u9012\u5230\u670d\u52a1\u5668\u7684\u5143\u6570\u636e\nmetadata.Add("1", "1");\nmetadata.Add("2", "2");\n\nFileOperator fileOperator = new FileOperator()//\u5b9e\u4f8b\u5316\u672c\u6b21\u4f20\u8f93\u7684\u63a7\u5236\u5668\uff0c\u7528\u4e8e\u83b7\u53d6\u4f20\u8f93\u8fdb\u5ea6\u3001\u901f\u5ea6\u3001\u72b6\u6001\u7b49\u3002\n{\n Flags = TransferFlags.BreakpointResume,//\u5c1d\u8bd5\u65ad\u70b9\u7eed\u4f20\uff0c\u4f7f\u7528\u65ad\u70b9\u7eed\u4f20\u65f6\uff0c\u4f1a\u9a8c\u8bc1MD5\u503c\n SavePath = $@"Windows.iso",//\u4fdd\u5b58\u8def\u5f84\n ResourcePath = @"D:\\System\\Windows.iso",//\u8bf7\u6c42\u8def\u5f84\n Metadata= metadata//\u4f20\u9012\u5230\u670d\u52a1\u5668\u7684\u5143\u6570\u636e\n};\n\nfileOperator.Timeout = TimeSpan.FromSeconds(60);//\u5f53\u4f20\u8f93\u5927\u6587\u4ef6\uff0c\u4e14\u542f\u7528\u65ad\u70b9\u7eed\u4f20\u65f6\uff0c\u670d\u52a1\u5668\u53ef\u80fd\u4f1a\u5148\u8ba1\u7b97MD5\uff0c\u800c\u5ef6\u65f6\u54cd\u5e94\uff0c\u6240\u4ee5\u9700\u8981\u8bbe\u7f6e\u8d85\u65f6\u65f6\u95f4\u3002\n\n//\u6b64\u5904\u7684\u4f5c\u7528\u76f8\u5f53\u4e8eTimer\uff0c\u5b9a\u65f6\u6bcf\u79d2\u8f93\u51fa\u5f53\u524d\u7684\u4f20\u8f93\u8fdb\u5ea6\u548c\u901f\u5ea6\u3002\nLoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>\n{\n if (fileOperator.Result.ResultCode != ResultCode.Default)\n {\n loop.Dispose();\n }\n\n client.Logger.Info($"\u8fdb\u5ea6\uff1a{fileOperator.Progress}\uff0c\u901f\u5ea6\uff1a{fileOperator.Speed()}");\n});\n\nloopAction.RunAsync();\n\n\n\n//\u6b64\u65b9\u6cd5\u4f1a\u963b\u585e\uff0c\u76f4\u5230\u4f20\u8f93\u7ed3\u675f\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528PullFileAsync\nIResult result = client.PullFile(fileOperator);\n\nclient.Logger.Info(result.ToString());\n')),(0,a.kt)("a",{name:"qZvBF"}),(0,a.kt)("h2",{id:"\u4e09push\u6587\u4ef6"},"\u4e09\u3001Push\u6587\u4ef6"),(0,a.kt)("p",null,"Push\u548cPull\u64cd\u4f5c\u4e00\u81f4\uff0c\u4ec5\u9700\u8981\u5728\u6700\u540e\u8c03\u7528PushFile\u5373\u53ef\u3002"),(0,a.kt)("a",{name:"VRKlH"}),(0,a.kt)("h2",{id:"\u56db\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6"},"\u56db\u3001\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6"),(0,a.kt)("p",null,"\u8be5\u529f\u80fd\u652f\u6301\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6\uff0c\u4f7f\u7528\u65b9\u6cd5\u57fa\u672c\u4e00\u81f4\uff0c\u53ea\u9700\u8981\u989d\u5916\u589e\u52a0\u76ee\u6807Id\u5373\u53ef\u3002"),(0,a.kt)("p",null,"\u6b64\u5916\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u4e5f\u9700\u8981\u540c\u610f\u8def\u7531\u3002\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u4f7f\u7528\u8be5\u65b9\u5f0f\u6587\u4ef6\u4f20\u8f93\u65f6\uff0c\u8fd8\u4f1a\u53d1\u8d77\u901a\u9053\u8def\u7531\uff0c\u6240\u4ee5\uff0c\u9700\u8981\u5141\u8bb8\u7684\u8def\u7531\u5e94\u8be5\u8fd8\u989d\u5916\u589e\u52a0",(0,a.kt)("strong",{parentName:"p"},"\u901a\u9053\u7c7b\u578b"),"\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"internal class MyTouchRpcPlugin : TouchRpcPluginBase\n{\n protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)\n {\n if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile||e.RouterType== RouteType.CreateChannel)\n {\n e.IsPermitOperation = true;\n }\n base.OnRouting(client, e);\n }\n}\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/177fd31f.ede3771d.js b/handbook/build/assets/js/177fd31f.ede3771d.js new file mode 100644 index 000000000..7e0961cda --- /dev/null +++ b/handbook/build/assets/js/177fd31f.ede3771d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8300],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),m=c(n),d=a,b=m["".concat(p,".").concat(d)]||m[d]||u[d]||o;return n?r.createElement(b,i(i({ref:t},l),{},{components:n})):r.createElement(b,i({ref:t},l))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={id:"webapiservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1"},i=void 0,s={unversionedId:"webapiservice",id:"webapiservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",description:"\u5b9a\u4e49\u670d\u52a1",source:"@site/docs/webapiservice.mdx",sourceDirName:".",slug:"/webapiservice",permalink:"/touchsocket/docs/webapiservice",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/webapiservice.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"webapiservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1"},sidebar:"docs",previous:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/webapidescription"},next:{title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1",permalink:"/touchsocket/docs/callwebapi"}},p={},c=[{value:"\u5b9a\u4e49\u670d\u52a1",id:"\u5b9a\u4e49\u670d\u52a1",level:2},{value:"\u521b\u5efa\u7b80\u5355\u670d\u52a1\u5668",id:"\u521b\u5efa\u7b80\u5355\u670d\u52a1\u5668",level:2}],l={toc:c};function u(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u5b9a\u4e49\u670d\u52a1"},"\u5b9a\u4e49\u670d\u52a1"),(0,a.kt)("p",null,"\u5728",(0,a.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u7aef\u4e2d\u65b0\u5efa\u4e00\u4e2a\u7c7b\uff0c\u7ee7\u627f\u4e8e",(0,a.kt)("strong",{parentName:"p"},"RpcServer"),"\u7c7b\uff08\u6216\u5b9e\u73b0IRpcServer\uff09\uff0c\u7136\u540e\u5728\u8be5\u7c7b\u4e2d\u5199",(0,a.kt)("strong",{parentName:"p"},"\u516c\u5171\u65b9\u6cd5"),"\uff0c\u5e76\u7528",(0,a.kt)("strong",{parentName:"p"},"WebApi"),"\u5c5e\u6027\u6807\u7b7e\u6807\u8bb0\uff0c\u5982\u679c\u65b9\u6cd5\u6709",(0,a.kt)("strong",{parentName:"p"},"\u91cd\u8f7d"),"\uff0c\u9700\u8981\u91cd\u65b0\u6307\u5b9a",(0,a.kt)("strong",{parentName:"p"},"\u51fd\u6570\u952e"),"\u3002"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u652f\u6301\u4ee3\u7406\u751f\u6210",(0,a.kt)("strong",{parentName:"li"},"\u6ce8\u91ca"),"\u3002")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'public class ApiServer : RpcServer\n{\n [Router("[api]/[action]ab")]//\u6b64\u8def\u7531\u4f1a\u4ee5"/Server/Sumab"\u5b9e\u73b0\n [WebApi(HttpMethodType.GET)]\n public int Sum(int a, int b)\n {\n return a + b;\n }\n\n [WebApi(HttpMethodType.POST)]\n public int TestPost(MyClass myClass)\n {\n return myClass.A + myClass.B;\n }\n\n /// \n /// \u4f7f\u7528\u8c03\u7528\u4e0a\u4e0b\u6587\uff0c\u54cd\u5e94\u6587\u4ef6\u4e0b\u8f7d\u3002\n /// \n /// \n [WebApi(HttpMethodType.GET, MethodFlags = MethodFlags.IncludeCallContext)]\n public Task DownloadFile(IWebApiCallContext callContext, string id)\n {\n if (id == "rrqm")\n {\n callContext.HttpContext.Response.FromFile(@"D:\\System\\Windows.iso", callContext.HttpContext.Request);\n return Task.FromResult("ok");\n }\n return Task.FromResult("id\u4e0d\u6b63\u786e\u3002");\n }\n}\n\npublic class MyClass\n{\n public int A { get; set; }\n public int B { get; set; }\n}\n')),(0,a.kt)("a",{name:"lHhEB"}),(0,a.kt)("h2",{id:"\u521b\u5efa\u7b80\u5355\u670d\u52a1\u5668"},"\u521b\u5efa\u7b80\u5355\u670d\u52a1\u5668"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},' HttpService service = new HttpService();\n service.Setup(new TouchSocketConfig()\n .UsePlugin()\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigureContainer(a =>\n {\n a.SetSingletonLogger();//\u6ce8\u518c\u4e00\u4e2a\u65e5\u5fd7\n })\n .ConfigureRpcStore(a =>\n {\n a.RegisterServer();//\u6ce8\u518c\u670d\u52a1\n })\n .ConfigurePlugins(a =>\n {\n a.Add();//\u6dfb\u52a0\u652f\u6301WebApi\u7684\u63d2\u4ef6\u3002\u6b64\u5904\u53ef\u80fd\u9700\u8981using TouchSocket.Core.Plugins;\n }))\n .Start();\n\n Console.WriteLine("\u4ee5\u4e0b\u8fde\u63a5\u7528\u4e8e\u6d4b\u8bd5webApi");\n Console.WriteLine($"\u4f7f\u7528\uff1ahttp://127.0.0.1:7789/ApiServer/Sum?a=10&b=20");\n\n Console.ReadKey();\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/17896441.fc5f7a42.js b/handbook/build/assets/js/17896441.fc5f7a42.js new file mode 100644 index 000000000..1c38473a4 --- /dev/null +++ b/handbook/build/assets/js/17896441.fc5f7a42.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7918],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>p});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),i=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=i(e.components);return a.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,d=c(e,["components","mdxType","originalType","parentName"]),u=i(n),p=l,v=u["".concat(s,".").concat(p)]||u[p]||m[p]||r;return n?a.createElement(v,o(o({ref:t},d),{},{components:n})):a.createElement(v,o({ref:t},d))}));function p(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,o=new Array(r);o[0]=u;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c.mdxType="string"==typeof e?e:l,o[1]=c;for(var i=2;i{n.r(t),n.d(t,{default:()=>Ae});var a=n(7294),l=n(1944),r=n(902);const o=a.createContext(null);function c(e){let{children:t,content:n}=e;const l=function(e){return(0,a.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(n);return a.createElement(o.Provider,{value:l},t)}function s(){const e=(0,a.useContext)(o);if(null===e)throw new r.i6("DocProvider");return e}function i(){const{metadata:e,frontMatter:t,assets:n}=s();return a.createElement(l.d,{title:e.title,description:e.description,keywords:t.keywords,image:n.image??t.image})}var d=n(6010),m=n(7524),u=n(7462),p=n(5999),v=n(9960);function f(e){const{permalink:t,title:n,subLabel:l,isNext:r}=e;return a.createElement(v.Z,{className:(0,d.Z)("pagination-nav__link",r?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},l&&a.createElement("div",{className:"pagination-nav__sublabel"},l),a.createElement("div",{className:"pagination-nav__label"},n))}function b(e){const{previous:t,next:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,p.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages navigation",description:"The ARIA label for the docs pagination"})},t&&a.createElement(f,(0,u.Z)({},t,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),n&&a.createElement(f,(0,u.Z)({},n,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function h(){const{metadata:e}=s();return a.createElement(b,{previous:e.previous,next:e.next})}var g=n(2263),E=n(143),L=n(5281),N=n(373),k=n(4477);const y={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(p.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(p.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function _(e){const t=y[e.versionMetadata.banner];return a.createElement(t,e)}function x(e){let{versionLabel:t,to:n,onClick:l}=e;return a.createElement(p.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:a.createElement("b",null,a.createElement(v.Z,{to:n,onClick:l},a.createElement(p.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function T(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:l}}=(0,g.Z)(),{pluginId:r}=(0,E.gA)({failfast:!0}),{savePreferredVersionName:o}=(0,N.J)(r),{latestDocSuggestion:c,latestVersionSuggestion:s}=(0,E.Jo)(r),i=c??(m=s).docs.find((e=>e.id===m.mainDocId));var m;return a.createElement("div",{className:(0,d.Z)(t,L.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},a.createElement("div",null,a.createElement(_,{siteTitle:l,versionMetadata:n})),a.createElement("div",{className:"margin-top--md"},a.createElement(x,{versionLabel:s.label,to:i.path,onClick:()=>o(s.name)})))}function Z(e){let{className:t}=e;const n=(0,k.E)();return n.banner?a.createElement(T,{className:t,versionMetadata:n}):null}function C(e){let{className:t}=e;const n=(0,k.E)();return n.badge?a.createElement("span",{className:(0,d.Z)(t,L.k.docs.docVersionBadge,"badge badge--secondary")},a.createElement(p.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label}},"Version: {versionLabel}")):null}function w(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n}=e;return a.createElement(p.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:a.createElement("b",null,a.createElement("time",{dateTime:new Date(1e3*t).toISOString()},n))}}," on {date}")}function O(e){let{lastUpdatedBy:t}=e;return a.createElement(p.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:a.createElement("b",null,t)}}," by {user}")}function H(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n,lastUpdatedBy:l}=e;return a.createElement("span",{className:L.k.common.lastUpdated},a.createElement(p.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?a.createElement(w,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:l?a.createElement(O,{lastUpdatedBy:l}):""}},"Last updated{atDate}{byUser}"),!1)}const U="iconEdit_Z9Sw";function A(e){let{className:t,...n}=e;return a.createElement("svg",(0,u.Z)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,d.Z)(U,t),"aria-hidden":"true"},n),a.createElement("g",null,a.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function M(e){let{editUrl:t}=e;return a.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:L.k.common.editThisPage},a.createElement(A,null),a.createElement(p.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}const P="tag_zVej",j="tagRegular_sFm0",B="tagWithCount_h2kH";function I(e){let{permalink:t,label:n,count:l}=e;return a.createElement(v.Z,{href:t,className:(0,d.Z)(P,l?B:j)},n,l&&a.createElement("span",null,l))}const S="tags_jXut",D="tag_QGVx";function V(e){let{tags:t}=e;return a.createElement(a.Fragment,null,a.createElement("b",null,a.createElement(p.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),a.createElement("ul",{className:(0,d.Z)(S,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:n}=e;return a.createElement("li",{key:n,className:D},a.createElement(I,{label:t,permalink:n}))}))))}const R="lastUpdated_vwxv";function F(e){return a.createElement("div",{className:(0,d.Z)(L.k.docs.docFooterTagsRow,"row margin-bottom--sm")},a.createElement("div",{className:"col"},a.createElement(V,e)))}function z(e){let{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:l,formattedLastUpdatedAt:r}=e;return a.createElement("div",{className:(0,d.Z)(L.k.docs.docFooterEditMetaRow,"row")},a.createElement("div",{className:"col"},t&&a.createElement(M,{editUrl:t})),a.createElement("div",{className:(0,d.Z)("col",R)},(n||l)&&a.createElement(H,{lastUpdatedAt:n,formattedLastUpdatedAt:r,lastUpdatedBy:l})))}function q(){const{metadata:e}=s(),{editUrl:t,lastUpdatedAt:n,formattedLastUpdatedAt:l,lastUpdatedBy:r,tags:o}=e,c=o.length>0,i=!!(t||n||r);return c||i?a.createElement("footer",{className:(0,d.Z)(L.k.docs.docFooter,"docusaurus-mt-lg")},c&&a.createElement(F,{tags:o}),i&&a.createElement(z,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:r,formattedLastUpdatedAt:l})):null}var G=n(6043),$=n(6668);function J(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...l}=e;n>=0?t[n].children.push(l):a.push(l)})),a}function X(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=X({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function Q(e){const t=e.getBoundingClientRect();return t.top===t.bottom?Q(e.parentNode):t}function W(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>Q(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function K(e){const t=(0,a.useRef)(void 0),n=Y();(0,a.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:l,minHeadingLevel:r,maxHeadingLevel:o}=e;function c(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),c=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let l=t;l<=n;l+=1)a.push(`h${l}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:r,maxHeadingLevel:o}),s=W(c,{anchorTopOffset:n.current}),i=e.find((e=>s&&s.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(l),e.classList.add(l),t.current=e):e.classList.remove(l)}(e,e===i)}))}return document.addEventListener("scroll",c),document.addEventListener("resize",c),c(),()=>{document.removeEventListener("scroll",c),document.removeEventListener("resize",c)}}),[e,n])}function ee(e){let{toc:t,className:n,linkClassName:l,isChild:r}=e;return t.length?a.createElement("ul",{className:r?void 0:n},t.map((e=>a.createElement("li",{key:e.id},a.createElement("a",{href:`#${e.id}`,className:l??void 0,dangerouslySetInnerHTML:{__html:e.value}}),a.createElement(ee,{isChild:!0,toc:e.children,className:n,linkClassName:l}))))):null}const te=a.memo(ee);function ne(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:l="table-of-contents__link",linkActiveClassName:r,minHeadingLevel:o,maxHeadingLevel:c,...s}=e;const i=(0,$.L)(),d=o??i.tableOfContents.minHeadingLevel,m=c??i.tableOfContents.maxHeadingLevel,p=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:l}=e;return(0,a.useMemo)((()=>X({toc:J(t),minHeadingLevel:n,maxHeadingLevel:l})),[t,n,l])}({toc:t,minHeadingLevel:d,maxHeadingLevel:m});return K((0,a.useMemo)((()=>{if(l&&r)return{linkClassName:l,linkActiveClassName:r,minHeadingLevel:d,maxHeadingLevel:m}}),[l,r,d,m])),a.createElement(te,(0,u.Z)({toc:p,className:n,linkClassName:l},s))}const ae="tocCollapsibleButton_TO0P",le="tocCollapsibleButtonExpanded_MG3E";function re(e){let{collapsed:t,...n}=e;return a.createElement("button",(0,u.Z)({type:"button"},n,{className:(0,d.Z)("clean-btn",ae,!t&&le,n.className)}),a.createElement(p.Z,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component"},"On this page"))}const oe="tocCollapsible_ETCw",ce="tocCollapsibleContent_vkbj",se="tocCollapsibleExpanded_sAul";function ie(e){let{toc:t,className:n,minHeadingLevel:l,maxHeadingLevel:r}=e;const{collapsed:o,toggleCollapsed:c}=(0,G.u)({initialState:!0});return a.createElement("div",{className:(0,d.Z)(oe,!o&&se,n)},a.createElement(re,{collapsed:o,onClick:c}),a.createElement(G.z,{lazy:!0,className:ce,collapsed:o},a.createElement(ne,{toc:t,minHeadingLevel:l,maxHeadingLevel:r})))}const de="tocMobile_ITEo";function me(){const{toc:e,frontMatter:t}=s();return a.createElement(ie,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,d.Z)(L.k.docs.docTocMobile,de)})}const ue="tableOfContents_bqdL";function pe(e){let{className:t,...n}=e;return a.createElement("div",{className:(0,d.Z)(ue,"thin-scrollbar",t)},a.createElement(ne,(0,u.Z)({},n,{linkClassName:"table-of-contents__link toc-highlight",linkActiveClassName:"table-of-contents__link--active"})))}function ve(){const{toc:e,frontMatter:t}=s();return a.createElement(pe,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:L.k.docs.docTocDesktop})}var fe=n(2503),be=n(3905),he=n(9523);function ge(e){let{children:t}=e;return a.createElement(be.Zo,{components:he.Z},t)}function Ee(e){let{children:t}=e;const n=function(){const{metadata:e,frontMatter:t,contentTitle:n}=s();return t.hide_title||void 0!==n?null:e.title}();return a.createElement("div",{className:(0,d.Z)(L.k.docs.docMarkdown,"markdown")},n&&a.createElement("header",null,a.createElement(fe.Z,{as:"h1"},n)),a.createElement(ge,null,t))}var Le=n(2802),Ne=n(8596),ke=n(4996);function ye(e){return a.createElement("svg",(0,u.Z)({viewBox:"0 0 24 24"},e),a.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const _e="breadcrumbHomeIcon_YNFT";function xe(){const e=(0,ke.Z)("/");return a.createElement("li",{className:"breadcrumbs__item"},a.createElement(v.Z,{"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},a.createElement(ye,{className:_e})))}const Te="breadcrumbsContainer_Z_bl";function Ze(e){let{children:t,href:n,isLast:l}=e;const r="breadcrumbs__link";return l?a.createElement("span",{className:r,itemProp:"name"},t):n?a.createElement(v.Z,{className:r,href:n,itemProp:"item"},a.createElement("span",{itemProp:"name"},t)):a.createElement("span",{className:r},t)}function Ce(e){let{children:t,active:n,index:l,addMicrodata:r}=e;return a.createElement("li",(0,u.Z)({},r&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,d.Z)("breadcrumbs__item",{"breadcrumbs__item--active":n})}),t,a.createElement("meta",{itemProp:"position",content:String(l+1)}))}function we(){const e=(0,Le.s1)(),t=(0,Ne.Ns)();return e?a.createElement("nav",{className:(0,d.Z)(L.k.docs.docBreadcrumbs,Te),"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},a.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&a.createElement(xe,null),e.map(((t,n)=>{const l=n===e.length-1;return a.createElement(Ce,{key:n,active:l,index:n,addMicrodata:!!t.href},a.createElement(Ze,{href:t.href,isLast:l},t.label))})))):null}const Oe="docItemContainer_Djhp",He="docItemCol_VOVn";function Ue(e){let{children:t}=e;const n=function(){const{frontMatter:e,toc:t}=s(),n=(0,m.i)(),l=e.hide_table_of_contents,r=!l&&t.length>0;return{hidden:l,mobile:r?a.createElement(me,null):void 0,desktop:!r||"desktop"!==n&&"ssr"!==n?void 0:a.createElement(ve,null)}}();return a.createElement("div",{className:"row"},a.createElement("div",{className:(0,d.Z)("col",!n.hidden&&He)},a.createElement(Z,null),a.createElement("div",{className:Oe},a.createElement("article",null,a.createElement(we,null),a.createElement(C,null),n.mobile,a.createElement(Ee,null,t),a.createElement(q,null)),a.createElement(h,null))),n.desktop&&a.createElement("div",{className:"col col--3"},n.desktop))}function Ae(e){const t=`docs-doc-id-${e.content.metadata.unversionedId}`,n=e.content;return a.createElement(c,{content:e.content},a.createElement(l.FG,{className:t},a.createElement(i,null),a.createElement(Ue,null,a.createElement(n,null))))}},4477:(e,t,n)=>{n.d(t,{E:()=>c,q:()=>o});var a=n(7294),l=n(902);const r=a.createContext(null);function o(e){let{children:t,version:n}=e;return a.createElement(r.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(r);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/19a46420.b6485179.js b/handbook/build/assets/js/19a46420.b6485179.js new file mode 100644 index 000000000..34be55842 --- /dev/null +++ b/handbook/build/assets/js/19a46420.b6485179.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[5725],{3905:(e,t,r)=>{r.d(t,{Zo:()=>i,kt:()=>m});var n=r(7294);function l(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(l[r]=e[r]);return l}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(l[r]=e[r])}return l}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},i=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,l=e.mdxType,a=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),d=s(r),m=l,g=d["".concat(p,".").concat(m)]||d[m]||u[m]||a;return r?n.createElement(g,o(o({ref:t},i),{},{components:r})):n.createElement(g,o({ref:t},i))}));function m(e,t){var r=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var a=r.length,o=new Array(a);o[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c.mdxType="string"==typeof e?e:l,o[1]=c;for(var s=2;s{r.d(t,{Z:()=>_});var n=r(7294),l=r(7462);const a=(e,t,r)=>e?"string"==typeof e?e:e[t]||r:r,o={display:"block"},c=e=>{let{size:t,color:r,style:c,...p}=e;const s=c?{...o,...c}:o;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},p),n.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:a(r,0,"#333333")}))};c.defaultProps={size:18};const p=c,s={display:"block"},i=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...s,...o}:s;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:a(r,0,"#333333")}),n.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:a(r,1,"#333333")}))};i.defaultProps={size:18};const u=i,d={display:"block"},m=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...d,...o}:d;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:a(r,0,"#333333")}),n.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:a(r,1,"#333333")}),n.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:a(r,2,"#333333")}))};m.defaultProps={size:18};const g=m,h={display:"block"},k=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...h,...o}:h;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:a(r,0,"#333333")}))};k.defaultProps={size:18};const y=k,v={display:"block"},f=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...v,...o}:v;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:a(r,0,"#333333")}))};f.defaultProps={size:18};const b=f,N={display:"block"},x=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...N,...o}:N;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:a(r,0,"#333333")}),n.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:a(r,1,"#333333")}),n.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:a(r,2,"#333333")}))};x.defaultProps={size:18};const C=x,E={display:"block"},w=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...E,...o}:E;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:a(r,0,"#333333")}),n.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:a(r,1,"#333333")}))};w.defaultProps={size:18};const z=w,R={display:"block"},M=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...R,...o}:R;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:a(r,0,"#333333")}),n.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:a(r,1,"#333333")}))};M.defaultProps={size:18};const P=M,S={display:"block"},A=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...S,...o}:S;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:a(r,0,"#333333")}),n.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:a(r,1,"#333333")}))};A.defaultProps={size:18};const T=A,L={display:"block"},O=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...L,...o}:L;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:a(r,0,"#333333")}))};O.defaultProps={size:18};const B=O,j={display:"block"},G=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...j,...o}:j;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:a(r,0,"#333333")}))};G.defaultProps={size:18};const Z=G,H={display:"block"},I=e=>{let{size:t,color:r,style:o,...c}=e;const p=o?{...H,...o}:H;return n.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},c),n.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:a(r,0,"#333333")}))};I.defaultProps={size:18};const V=I,D=e=>{let{name:t,...r}=e;switch(t){case"youhua":return n.createElement(p,r);case"dayi":return n.createElement(u,r);case"shengji":return n.createElement(g,r);case"tiaozheng":return n.createElement(y,r);case"gengxin":return n.createElement(b,r);case"wendang":return n.createElement(C,r);case"shanchu":return n.createElement(z,r);case"bug":return n.createElement(P,r);case"xinzeng":return n.createElement(T,r);case"fuwu":return n.createElement(B,r);case"down":return n.createElement(Z,r);case"up":return n.createElement(V,r)}return null},Q="label_p8vM",F="icon_knQK";function _(e){const{children:t}=e,r={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return n.createElement("label",{className:Q,title:t,style:{backgroundColor:r[t].bgColor}},n.createElement(D,{name:r[t].icon,color:"white",size:14,className:F})," ",t)}},598:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>p,toc:()=>i});var n=r(7462),l=(r(7294),r(3905)),a=r(510);const o={id:"generateproxy",title:"\u751f\u6210\u3001\u83b7\u53d6\u4ee3\u7406"},c=void 0,p={unversionedId:"generateproxy",id:"generateproxy",title:"\u751f\u6210\u3001\u83b7\u53d6\u4ee3\u7406",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/generateproxy.mdx",sourceDirName:".",slug:"/generateproxy",permalink:"/touchsocket/docs/generateproxy",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/generateproxy.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675660193,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"generateproxy",title:"\u751f\u6210\u3001\u83b7\u53d6\u4ee3\u7406"},sidebar:"docs",previous:{title:"Rpc\u670d\u52a1AOP",permalink:"/touchsocket/docs/rpcactionfilter"},next:{title:"\u4f20\u8f93\u6587\u4ef6",permalink:"/touchsocket/docs/transferfile"}},s={},i=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"1.1 \u4e3a\u4ec0\u4e48\u8981\u751f\u6210\u4ee3\u7406\uff1f",id:"11-\u4e3a\u4ec0\u4e48\u8981\u751f\u6210\u4ee3\u7406",level:3},{value:"1.2 \u4e3a\u4ec0\u4e48\u4e0d\u76f4\u63a5\u652f\u6301\u63a5\u53e3\u4ee3\u7406\u8c03\u7528\uff1f",id:"12-\u4e3a\u4ec0\u4e48\u4e0d\u76f4\u63a5\u652f\u6301\u63a5\u53e3\u4ee3\u7406\u8c03\u7528",level:3},{value:"1.3 TouchRpc\u6e90\u6587\u4ef6\u4ee3\u7406\u76f8\u6bd4\u63a5\u53e3\u4ee3\u7406\uff0c\u6709\u4ec0\u4e48\u4f18\u7f3a\u70b9\uff1f",id:"13-touchrpc\u6e90\u6587\u4ef6\u4ee3\u7406\u76f8\u6bd4\u63a5\u53e3\u4ee3\u7406\u6709\u4ec0\u4e48\u4f18\u7f3a\u70b9",level:3},{value:"\u4e8c\u3001\u4ece\u670d\u52a1\u7aef\u83b7\u53d6\u4ee3\u7406",id:"\u4e8c\u4ece\u670d\u52a1\u7aef\u83b7\u53d6\u4ee3\u7406",level:2},{value:"2.1 \u751f\u6210\u4ee3\u7406",id:"21-\u751f\u6210\u4ee3\u7406",level:3},{value:"2.2 \u4ee3\u7406\u7c7b\u578b\u6dfb\u52a0",id:"22-\u4ee3\u7406\u7c7b\u578b\u6dfb\u52a0",level:3},{value:"2.2.1 \u6dfb\u52a0\u4ee3\u7406\u7c7b\u578b",id:"221-\u6dfb\u52a0\u4ee3\u7406\u7c7b\u578b",level:3},{value:"2.2.2 \u6807\u8bb0\u81ea\u5b9a\u4e49\u7c7b",id:"222-\u6807\u8bb0\u81ea\u5b9a\u4e49\u7c7b",level:3},{value:"\u4e09\u3001\u5ba2\u6237\u7aef\u6e90\u4ee3\u7801\u751f\u6210\u4ee3\u7406 \u4f01\u4e1a\u7248",id:"\u4e09\u5ba2\u6237\u7aef\u6e90\u4ee3\u7801\u751f\u6210\u4ee3\u7406-\u4f01\u4e1a\u7248",level:2}],u={toc:i};function d(e){let{components:t,...o}=e;return(0,l.kt)("wrapper",(0,n.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,l.kt)("h3",{id:"11-\u4e3a\u4ec0\u4e48\u8981\u751f\u6210\u4ee3\u7406"},"1.1 \u4e3a\u4ec0\u4e48\u8981\u751f\u6210\u4ee3\u7406\uff1f"),(0,l.kt)("p",null,"\u4f7f\u7528rpc\u7684\u539f\u5219\u5c31\u662f\u50cf\u4f7f\u7528\u672c\u5730\u65b9\u6cd5\u4e00\u6837\uff0c\u8ba9\u5f00\u53d1\u8005\u611f\u89c9\u4e0d\u5230\u4efb\u4f55\u7684\u4e0d\u540c\u3002\u6240\u4ee5\u5c31\u5fc5\u987b\u628a\u670d\u52a1\u4ee3\u7406\u5230\u672c\u5730\uff0c\u5e38\u89c1\u7684\u65b9\u5f0f\u6709\u4e09\u79cd\uff0c",(0,l.kt)("strong",{parentName:"p"},"\u52a8\u6001\u4ee3\u7406\u63a5\u53e3"),"\uff0c",(0,l.kt)("strong",{parentName:"p"},"\u9759\u6001\u7ec7\u5165"),"\uff0c",(0,l.kt)("strong",{parentName:"p"},"\u9759\u6001\u7f16\u8bd1"),"\u3002\u4e09\u79cd\u65b9\u5f0f\u6b8a\u9014\u540c\u5f52\uff0c\u6700\u7ec8\u90fd\u662f\u6784\u5efa\u672c\u5730\u6570\u636e\u7ed3\u6784\uff0c\u7136\u540e\u548c\u8fdc\u7a0b\u901a\u4fe1\u3002\u4e09\u79cd\u65b9\u5f0f\u5404\u6709\u4f18\u7f3a\uff0c\u5177\u4f53\u5982\u4e0b\uff1a"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("strong",{parentName:"th"},"\u4f18\u7f3a\u70b9")),(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("strong",{parentName:"th"},"\u52a8\u6001\u4ee3\u7406\u63a5\u53e3")),(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("strong",{parentName:"th"},"\u9759\u6001\u7ec7\u5165")),(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("strong",{parentName:"th"},"\u9759\u6001\u7f16\u8bd1")))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("strong",{parentName:"td"},"\u4f18\u70b9")),(0,l.kt)("td",{parentName:"tr",align:null},"\u52a8\u6001\u6784\u5efa\u7c7b\uff0c\u7075\u6d3b\u3001\u9002\u5e94\u6027\u5f3a\u3002"),(0,l.kt)("td",{parentName:"tr",align:null},"\u9759\u6001\u4ee3\u7801\u751f\u6210\uff0c\u81ea\u5b9a\u4e49\u7c7b\u53c2\u6570\u81ea\u52a8\u751f\u6210\uff0c\u4fee\u6539\u8f83\u7075\u6d3b\uff0c\u8c03\u7528\u6548\u7387\u9ad8"),(0,l.kt)("td",{parentName:"tr",align:null},"\u81ea\u5b9a\u4e49\u7c7b\u53c2\u6570\u81ea\u52a8\u751f\u6210\uff0c\u5bc6\u5c01\u6027\u5f3a\uff0c\u5b89\u5168\u6027\u9ad8\uff0c\u8c03\u7528\u6548\u7387\u9ad8\u3002")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("strong",{parentName:"td"},"\u7f3a\u70b9")),(0,l.kt)("td",{parentName:"tr",align:null},"\u8c03\u7528\u6548\u7387\u8f83\u4f4e\uff0c\u81ea\u5b9a\u4e49\u7c7b\u53c2\u6570\u987b\u81ea\u884c\u6784\u5efa\uff0c\u5b9e\u73b0\u987bIL\u652f\u6301\uff0c\u5bf9\u8c03\u7528\u5e73\u53f0\u6709\u8981\u6c42\uff0c\u4f8b\u5982\uff1aIOS\u4e0d\u5141\u8bb8\u52a8\u6001\u7c7b\u751f\u6210\uff0c\u5219\u4e0d\u53ef\u4f7f\u7528\u3002"),(0,l.kt)("td",{parentName:"tr",align:null},"\u9879\u76ee\u4ee3\u7801\u7ba1\u7406\u96be\u7edf\u4e00\uff0c\u5f3a\u8feb\u75c7\u731d\u6b7b"),(0,l.kt)("td",{parentName:"tr",align:null},"\u670d\u52a1\u4e00\u65e6\u6709\u7834\u574f\u6027\u5347\u7ea7\uff0c\u5219\u5fc5\u987b\u91cd\u65b0\u66ff\u6362dll\uff0c\u7075\u6d3b\u6027\u51e0\u4e4e\u4e3a0\u3002")))),(0,l.kt)("h3",{id:"12-\u4e3a\u4ec0\u4e48\u4e0d\u76f4\u63a5\u652f\u6301\u63a5\u53e3\u4ee3\u7406\u8c03\u7528"},"1.2 \u4e3a\u4ec0\u4e48\u4e0d\u76f4\u63a5\u652f\u6301\u63a5\u53e3\u4ee3\u7406\u8c03\u7528\uff1f"),(0,l.kt)("p",null,"\u3010\u539f\u56e0\u4e00\u3011\n\u652f\u6301out\u548cref\u53c2\u6570\uff0c\u5728\u4f7f\u7528\u4ee3\u7406\u65f6\uff0c\u6548\u7387\u4e0d\u9ad8\u3002"),(0,l.kt)("p",null,"\u3010\u539f\u56e0\u4e8c\u3011\n\u9700\u8981\u5728\u53c2\u6570\u652f\u6301\u8c03\u7528\u4e0a\u4e0b\u6587\uff0c\u6240\u4ee5\u65e0\u6cd5\u76f4\u63a5\u7528\u63a5\u53e3\u8c03\u7528\u3002"),(0,l.kt)("p",null,"\u3010\u539f\u56e0\u4e09\u3011\n\u652f\u6301\u5355\u6b21\u8c03\u7528\u7684\u8c03\u7528\u914d\u7f6e\uff08\u4f8b\u5982\u8d85\u65f6\u65f6\u95f4\uff0c\u53d6\u6d88\u8c03\u7528\uff0c\u5e8f\u5217\u5316\u65b9\u5f0f\u7b49\uff09"),(0,l.kt)("p",null,"\u3010\u539f\u56e0\u56db\u3011\n\u5f15\u7528\u95ee\u9898\uff0c\u5f53\u5728\u670d\u52a1\u63a5\u53e3\u4e2d\uff0c\u4f7f\u7528\u4e86\u5176\u4ed6\u7684\u9879\u76ee\u7684\u6570\u636e\u7ed3\u6784\u7684\u8bdd\uff0c\u5728\u63a5\u53e3\u8c03\u7528\u9879\u76ee\u4e0a\u4e5f\u9700\u8981\u5f15\u7528\u8be5\u9879\u76ee\u3002\u592a\u9ebb\u70e6\u3002"),(0,l.kt)("h3",{id:"13-touchrpc\u6e90\u6587\u4ef6\u4ee3\u7406\u76f8\u6bd4\u63a5\u53e3\u4ee3\u7406\u6709\u4ec0\u4e48\u4f18\u7f3a\u70b9"},"1.3 TouchRpc\u6e90\u6587\u4ef6\u4ee3\u7406\u76f8\u6bd4\u63a5\u53e3\u4ee3\u7406\uff0c\u6709\u4ec0\u4e48\u4f18\u7f3a\u70b9\uff1f"),(0,l.kt)("p",null,"\u6e90\u6587\u4ef6\u4ee3\u7406\u76f8\u6bd4\u63a5\u53e3\u4ee3\u7406\uff0c\u51e0\u4e4e\u6ca1\u4ec0\u4e48\u7f3a\u70b9\u3002\u6709\u4eba\u4f1a\u89c9\u5f97\u63a5\u53e3\u4ee3\u7406\u66f4\u6574\u6d01\u3001\u65b9\u4fbf\uff1f\u5b9e\u9645\u4e0a\u6e90\u6587\u4ef6\u4ee3\u7406\u53ea\u4f1a\u66f4\u6574\u6d01\u3001\u65b9\u4fbf\u3002"),(0,l.kt)("p",null,"\u5047\u8bbe\u4e00\u4e2a\u573a\u666f\uff0c\u4f60\u9700\u8981\u5f00\u53d1\u670d\u52a1\u5668\u548c\u5ba2\u6237\u7aef\uff0c\u8fd9\u65f6\uff0c\u4f60\u9700\u8981\u505a\uff1a"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"\u5148\u5355\u72ec\u5b9a\u4e49\u4e00\u4e2a\u63a5\u53e3\u9879\u76ee"),(0,l.kt)("li",{parentName:"ol"},"\u518d\u5b9a\u4e49\u4e00\u4e2a\u5b9e\u73b0\u9879\u76ee"),(0,l.kt)("li",{parentName:"ol"},"\u7f16\u8bd1\u63a5\u53e3\u9879\u76ee"),(0,l.kt)("li",{parentName:"ol"},"\u5f15\u7528\u5230\u5ba2\u6237\u7aef")),(0,l.kt)("p",null,"\u4e0a\u8ff0\u6b65\u9aa4\u4e2d\uff0c\u8fd8\u4e0d\u5305\u62ec\uff0c\u63a5\u53e3\u9879\u76ee\u548c\u5b9e\u73b0\u9879\u76ee\u9700\u8981\u5f15\u5165\u5176\u4ed6\u5f15\u7528\u7684\u60c5\u51b5\uff0c\u4e5f\u4e0d\u5305\u62ec\uff0c\u63a5\u53e3\u4e2d\u5305\u542b\u4e86\u5176\u4ed6\u9879\u76ee\u7684\u81ea\u5b9a\u4e49\u6570\u636e\u7ed3\u6784\u3002\u5982\u679c\u5305\u542b\u4e86\u7684\u8bdd\uff0c\u5ba2\u6237\u7aef\u8fd8\u9700\u8981\u5f15\u5165\u5176\u4ed6\u9879\u76ee\u3002"),(0,l.kt)("p",null,"\u800c\u4e14\uff0c\u8fd8\u9700\u8981\u8003\u8651\u63a5\u53e3\u9879\u76ee\u7684\u7f16\u8bd1\u76ee\u6807\u5e73\u53f0\u548c\u5176\u4ed6\u7f16\u8bd1\u53c2\u6570\u3002\u6700\u96be\u53d7\u7684\u662f\uff0c\u5982\u679c\u8fd9\u4e9b\u5de5\u4f5c\uff0c\u662f\u4f60\u548c\u540c\u4e8b\u5408\u4f5c\u7684\u8bdd\uff0c\u90a3\u53ef\u80fd\u5c31\u662f\u51fa\u4e2abug\uff0c\u540c\u4e8b\u4f20\u4f60\u4e00\u4e2adll v1.0\u7248\u672c\uff0c\u518d\u6709\u95ee\u9898\uff0cv1.1\u4fee\u590d\u7248\uff0c\u7b49\u7b49\u3002"),(0,l.kt)("p",null,"\u800c\u6700\u8981\u547d\u7684\uff0c\u5f53\u5c5e\u7a0b\u5e8f\u96c6\u6570\u636e\u6cc4\u9732\u3002\u8bbe\u60f3\u4e00\u4e0b\uff0c\u5982\u679c\u67d0\u4e2a\u540c\u4e8b\u5728\u5199\u6570\u636e\u5e93\u64cd\u4f5c\u7684\u9879\u76ee\u65f6\uff0c\u628a\u8fde\u63a5\u4fe1\u606f\u76f4\u63a5\u653e\u5728\u4e86\u4ee3\u7801\u91cc\uff08\u6216\u67d0\u4e2a\u903b\u8f91\uff09\uff0c\u672c\u8eab\u5982\u679c\u8fd9\u4e2a\u9879\u76ee\u53ea\u5728\u670d\u52a1\u5668\u5e94\u7528\uff0c\u4e5f\u6ca1\u6709\u5173\u7cfb\uff0c\u4f46\u662f\u56e0\u4e3a\u4f60\u61d2\uff0c\u4f60\u5728\u63a5\u53e3\u4e2d\u4f7f\u7528\u4e86\u8be5\u9879\u76ee\u7684\u4e00\u4e2a\u6570\u636e\u7ed3\u6784\uff0c\u8fd9\u5c31\u4f7f\u5f97\u4f60\u4e0d\u5f97\u4e0d\u628a\u8fd9\u4e2a\u9879\u76ee\u4e00\u540c\u4ea4\u7ed9\u8c03\u7528\u65b9\u7684\u540c\u4e8b\uff0c\u4f46\u4f60\u5bf9\u8fd9\u4e9b\u6beb\u65e0\u5bdf\u89c9\u3002\u55f7\u568e\uff0c\u9ed1\u7528\u6237\u4e00\u53cd\u7f16\u8bd1\uff0c\u76f4\u63a5\u5e2e\u4f60\u628a\u6570\u636e\u6574\u7406\u4e86\u3002"),(0,l.kt)("p",null,"\u4f46\u662f\u5982\u679c\u7528\u751f\u6210\u7684\u6e90\u4ee3\u7801\uff0c\u90a3\u4e0a\u8ff0\u7684\u53ef\u6015\u95ee\u9898\u6839\u672c\u4e0d\u7528\u8003\u8651\u3002\u5176\u6b21\uff0c\u4f1a\u66f4\u6574\u6d01\uff0c\u66f4\u65b9\u4fbf\u3002"),(0,l.kt)("p",null,"\u5047\u8bbe\u76f8\u540c\u573a\u666f\uff0c\u4f60\u9700\u8981\u5f00\u53d1\u670d\u52a1\u5668\u548c\u5ba2\u6237\u7aef\uff0c\u8fd9\u65f6\uff0c\u4f60\u9700\u8981\u505a\uff1a"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"\u5148\u5b9a\u4e49\u4e00\u4e2a\u670d\u52a1\u9879\u76ee\uff08\u53ef\u4ee5\u5199\u63a5\u53e3\uff0c\u4e5f\u80fd\u5199\u903b\u8f91\uff0c\u5f53\u7136\u4e5f\u53ef\u4ee5\u5206\u6210\u4e24\u4e2a\u9879\u76ee\uff09"),(0,l.kt)("li",{parentName:"ol"},"\u7f16\u8bd1\u9879\u76ee\uff0c\u7136\u540e\u5bfc\u51fa\u4ee3\u7406\u6e90\u4ee3\u7801\u3002"),(0,l.kt)("li",{parentName:"ol"},"\u5f15\u7528\u5230\u5ba2\u6237\u7aef")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"\u4e0d\u9700\u8981\u8003\u8651\u6570\u636e\u7ed3\u6784\u5f15\u7528\u95ee\u9898\uff0c\u56e0\u4e3a\u4ee3\u7406\u4f1a\u8f6c\u5199\u3002"),(0,l.kt)("li",{parentName:"ul"},"\u4e0d\u9700\u8981\u8003\u8651\u7f16\u8bd1\u53c2\u6570\u95ee\u9898\uff0c\u56e0\u4e3a\u5ba2\u6237\u7aef\u62ff\u5230\u7684\u4e5f\u662f\u6e90\u7801\u3002"),(0,l.kt)("li",{parentName:"ul"},"\u4e0d\u9700\u8981\u518d\u8ba9\u540c\u4e8b\u4e00\u6b21\u6b21\u53d1\u4f60dll\uff0c\u53ea\u9700\u8981\uff0c\u4ed6\u542f\u52a8\u670d\u52a1\uff0c\u4f60\u66f4\u65b0\u5f15\u7528\u5c31ok\u3002"),(0,l.kt)("li",{parentName:"ul"},"\u4e0d\u9700\u8981\u6015\u7a0b\u5e8f\u96c6\u6570\u636e\u6cc4\u9732\uff0c\u56e0\u4e3a\u4e00\u5207\u90fd\u662f\u8f6c\u5199\u7684\uff0c\u800c\u4e14\u53ea\u8f6c\u5199\u5e94\u7528\u7684\u3001\u516c\u5171\u7684\u90e8\u5206\u3002")),(0,l.kt)("h2",{id:"\u4e8c\u4ece\u670d\u52a1\u7aef\u83b7\u53d6\u4ee3\u7406"},"\u4e8c\u3001\u4ece\u670d\u52a1\u7aef\u83b7\u53d6\u4ee3\u7406"),(0,l.kt)("h3",{id:"21-\u751f\u6210\u4ee3\u7406"},"2.1 \u751f\u6210\u4ee3\u7406"),(0,l.kt)("p",null,"\u5728\u5f00\u53d1\u8fc7\u7a0b\u4e2d\uff0c\u5982\u679c\u670d\u52a1\u5668\u548c\u5ba2\u6237\u7aef\uff0c\u90fd\u662f\u6211\u4eec\u81ea\u5df1\u5f00\u53d1\u7684\u8bdd\uff08\u5728\u540c\u4e00\u4e2a\u7535\u8111\uff09\uff0c\u5c31\u53ef\u4ee5\u4f7f\u7528\u672c\u5730\u4ee3\u7406\u751f\u6210\u3002"),(0,l.kt)("p",null,"\u8c03\u7528\u4e0b\u5217\u4ee3\u7801\uff0c\u4f1a\u5c06\u5df2\u6ce8\u518c\u7684\u6240\u6709\u670d\u52a1\uff0c\u5bfc\u51fa\u4ee3\u7406\u4e3a\u5b57\u7b26\u4e32\u3002"),(0,l.kt)("p",null,"RpcStore\u662f",(0,l.kt)("strong",{parentName:"p"},"\u5b9e\u4f8b"),"\uff0c\u6216\u8005\u662fIRpcParser\u7684",(0,l.kt)("strong",{parentName:"p"},"\u5c5e\u6027"),"\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'string code=RpcStore.GetProxyCodes("MyNameSpace"));\n')),(0,l.kt)("p",null,"\u3010\u793a\u4f8b1\u3011\n\u5c06\u4ee3\u7406\u5b57\u7b26\u4e32\uff0c\u5199\u6210.cs\u6587\u4ef6\uff0c\u7136\u540e\u901a\u8fc7\u94fe\u63a5\u7684\u5f62\u5f0f\uff0c\u5c06\u4ee3\u7801\u6dfb\u52a0\u5230\u5ba2\u6237\u7aef\u9879\u76ee\u3002"),(0,l.kt)("p",null,"\u670d\u52a1\u5668\u4ee3\u7801\uff0c\u5728\u670d\u52a1\u5668\u6267\u884c\u540e\uff0c\u4f1a\u5728\u8fd0\u884c\u8def\u5f84\u4e0b\uff0c\u751f\u6210\u4e00\u4e2a",(0,l.kt)("strong",{parentName:"p"},"WhisperServers.cs"),"\u7684\u6587\u4ef6\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new TcpTouchRpcService();\nvar config = new TouchSocketConfig()//\u914d\u7f6e\n .SetListenIPHosts(new IPHost[] { new IPHost(port) })\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n a.AddFileLogger();\n })\n .ConfigureRpcStore(a =>\n {\n a.RegisterServer();//\u6ce8\u518c\u670d\u52a1\n\n#if DEBUG\n File.WriteAllText("../../../WhisperServers.cs", a.GetProxyCodes("WhisperServers",new Type[] { typeof(TouchRpcAttribute) }));\n#endif\n })\n .SetVerifyToken("TouchRpc");\n\n service.Setup(config)\n .Start();\n')),(0,l.kt)("p",null,"\u7136\u540e\u6253\u5f00\u9700\u8981\u5f15\u5165\u7684\u5ba2\u6237\u7aef\u89e3\u51b3\u65b9\u6848\u3002\u9009\u62e9\u9700\u8981\u6dfb\u52a0\u4ee3\u7406\u7684\u9879\u76ee\uff0c\u4f9d\u6b21\u6267\u884c\uff1a"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"\u53f3\u51fb\u9879\u76ee=\u300b\u6dfb\u52a0=\u300b\u73b0\u6709\u9879")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"\u7136\u540e\u9009\u62e9\u670d\u52a1\u5668\u751f\u6210\u7684.cs\u6587\u4ef6\uff0c\u9009\u62e9\u201c\u6dfb\u52a0\u201d\u7684\u4e0b\u62c9\u6846\uff0c\u9009\u62e9\u201c\u6dfb\u52a0\u4e3a\u8fde\u63a5\u201d\u3002")),(0,l.kt)("p",null,"\u6700\u540e\u786e\u8ba4\u6587\u4ef6\u88ab\u6b63\u786e\u6dfb\u52a0\u4e3a\u94fe\u63a5\u3002"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"\u8fd9\u6837\uff0c\u6bcf\u6b21\u5f53\u670d\u52a1\u6709\u66f4\u65b0\u7684\u65f6\u5019\uff0c\u53ea\u9700\u8981\u542f\u52a8\u4e00\u4e0b\u670d\u52a1\u5668\uff0c\u4ee3\u7406\u5c31\u4f1a\u81ea\u52a8\u5237\u65b0\u3002")),(0,l.kt)("p",null,"\u5b9e\u9645\u4e0a\u5728RpcStore\u5b8c\u6210",(0,l.kt)("strong",{parentName:"p"},"\u670d\u52a1\u6ce8\u518c"),"\u3001",(0,l.kt)("strong",{parentName:"p"},"\u89e3\u6790\u5668\u6dfb\u52a0"),"\u4ee5\u540e\uff0c\u8c03\u7528",(0,l.kt)("inlineCode",{parentName:"p"},"GetProxyInfo"),"\uff0c\u8f93\u5165\u4ee3\u7406\u7c7b\u578b\u3001\u5373\u53ef\u83b7\u5f97\u4ee3\u7406\u4fe1\u606f\uff0c\u7136\u540e\u518d\u901a\u8fc7CodeGenerator.ConvertToCode\u65b9\u6cd5\uff0c\u8f6c\u6362\u4e3a\u53ef\u4ee5",(0,l.kt)("strong",{parentName:"p"},"\u76f4\u63a5\u7f16\u8bd1"),"\u7684\u4ee3\u7801\u3002\n\u6b64\u65f6\uff0c\u4f60\u53ef\u4ee5\u590d\u5236\u3001\u6216\u8005\u76f4\u63a5\u628a\u4ee3\u7406\u4ee3\u7801\u5199\u6210",(0,l.kt)("inlineCode",{parentName:"p"},"\u6e90\u4ee3\u7801"),"\uff08cs\u6587\u4ef6\uff09\u3002\n\u7136\u540e\u4f60\u53ef\u4ee5\u628a\u8fd9\u4e2a\u4ee3\u7801\u5f15\u5165\u5230",(0,l.kt)("strong",{parentName:"p"},"\u5ba2\u6237\u7aef"),"\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'//\u6216\u8005\u76f4\u63a5\u672c\u5730\u5bfc\u51fa\u4ee3\u7406\u6587\u4ef6\u3002\nServerCellCode[] codes = rpcStore.GetProxyInfo(RpcStore.ProxyAttributeMap.Values.ToArray());\nstring codeString = CodeGenerator.ConvertToCode("RRQMProxy", codes);\n')),(0,l.kt)("p",null,"\u4ea6\u6216\u8005\uff0c\u4e3a\u9632\u6b62\u7be1\u6539\u751f\u6210\u7684\u4ee3\u7801\uff0c\u4e0d\u60f3\u628a\u4ee3\u7406\u4ee3\u7801\u76f4\u63a5\u6295\u5165\u4f7f\u7528\uff0c\u90a3\u53ef\u4ee5\u8003\u8651\u5c06\u4ee3\u7801\u5355\u72ec\u7f16\u8bd1\u6210dll\uff0c\u7136\u540e\u5c06\u7f16\u8bd1\u7684\u7a0b\u5e8f\u96c6\u52a0\u8f7d\u5230\u5ba2\u6237\u7aef\u3002"),(0,l.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u884c\u4e3a\uff0c\u5747\u662f\u5bfc\u51fa\u6240\u6709\u5df2\u6ce8\u518c\u7684\u670d\u52a1\uff0c\u5f53\u9700\u8981\u5728\u540c\u4e00\u4e2a\u670d\u52a1\u7aef\uff0c\u751f\u6210\u591a\u4e2a\u4e0d\u540c\u4ee3\u7406\u7684\u6e90\u7801\u65f6\uff0c\u53ef\u901a\u8fc7CodeGenerator\u9759\u6001\u7c7b\u7684\u76f8\u5173\u65b9\u6cd5\u76f4\u63a5\u751f\u6210\u3002\u4f8b\u5982\uff1a"),(0,l.kt)("pre",{parentName:"admonition"},(0,l.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{1}","{1}":!0},'string codes=CodeGenerator.GetProxyCodes("Namespace",new Type[]{typeof(RpcServer) },new Type[] { typeof(TouchRpcAttribute)});\n'))),(0,l.kt)("h3",{id:"22-\u4ee3\u7406\u7c7b\u578b\u6dfb\u52a0"},"2.2 \u4ee3\u7406\u7c7b\u578b\u6dfb\u52a0"),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"\u901a\u8fc7\u4e4b\u524d\u7684\u5b66\u4e60\uff0c\u5927\u5bb6\u53ef\u80fd\u5927\u6982\u660e\u767d\u4e86\uff0c\u5728RRQMRPC\u4e2d\uff0c\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5728\u8fdb\u884c\u4ea4\u4e92\u65f6\uff0c\u6240\u9700\u7684\u6570\u636e\u7ed3\u6784\u4e0d\u8981\u6c42\u662f\u540c\u4e00\u7c7b\u578b\uff0c\u4ec5\u662f",(0,l.kt)("a",{parentName:"p",href:"https://gitee.com/RRQM_OS/RRQM/wikis/RRQM%E4%B8%93%E4%B8%9A%E5%90%8D%E7%A7%B0%E8%A7%A3%E9%87%8A?sort_id=4872799"},"\u6570\u636e\u7c7b\u578b\u7ed3\u6784\u76f8\u540c"),"\u5373\u53ef\u3002\u6240\u4ee5\u5728\u58f0\u660e\u4e86\u670d\u52a1\u4ee5\u540e\uff0c\u670d\u52a1\u4e2d\u6240\u5305\u542b\u7684\u81ea\u5b9a\u4e49\u7c7b\u578b\uff0c\u4f1a\u88ab\u590d\u523b\u6210\u7ed3\u6784\u76f8\u540c\u7684\u7c7b\u578b\uff0c\u4f46\u662f\u8fd9\u4e5f\u4ec5\u4ec5\u5c40\u9650\u4e8e\u53c2\u6570\u4e0e\u670d\u52a1",(0,l.kt)("inlineCode",{parentName:"p"},"\u76f8\u540c\u7a0b\u5e8f\u96c6"),"\u7684\u65f6\u5019\u3002\u5982\u679c\u670d\u52a1\u4e2d\u5f15\u5165\u4e86\u5176\u4ed6\u7a0b\u5e8f\u96c6\u7684\u6570\u636e\u7ed3\u6784\uff0c\u5219\u4e0d\u4f1a\u590d\u523b\u3002\u6240\u4ee5\u5728\u5ba2\u6237\u7aef\u8c03\u7528\u65f6\uff0c\u9700\u8981\u5f15\u5165\u540c\u4e00\u7a0b\u5e8f\u96c6\u3002")),(0,l.kt)("p",null,"\u4f46\u662f\uff0c\u5f80\u5f80\u5728\u670d\u52a1\u4e2d\uff0c\u4f1a\u5f15\u5165\u5176\u4ed6\u7a0b\u5e8f\u96c6\uff0c\u4f8b\u5982\uff0c\u6211\u4eec\u4e60\u60ef\u5728\u9879\u76ee\u4e2d\u5efa\u7acb\u4e00\u4e2aModels\u7a0b\u5e8f\u96c6\uff0c\u7528\u4e8e\u5b58\u653e\u6240\u6709\u7684\u5b9e\u4f53\u6a21\u578b\uff0c\u90a3\u662f\u4e0d\u662f\u610f\u5473\u7740\u5ba2\u6237\u7aef\u4e5f\u5fc5\u987b\u5f15\u5165\u8fd9\u4e2a\u7a0b\u5e8f\u96c6\u624d\u80fd\u8c03\u7528\u5462\uff1f\u6ca1\u522b\u7684\u65b9\u6cd5\u4e86\uff1f\uff1f\n",(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"\u6709\uff0c\u4e14\u4e0d\u53ea\u6709\u4e00\u79cd"))," ",(0,l.kt)("a",{name:"r9HVa"})),(0,l.kt)("h3",{id:"221-\u6dfb\u52a0\u4ee3\u7406\u7c7b\u578b"},"2.2.1 \u6dfb\u52a0\u4ee3\u7406\u7c7b\u578b"),(0,l.kt)("p",null,"\u5728\u670d\u52a1\u6ce8\u518c\u4e4b\u524d\uff0c\u4efb\u610f\u65f6\u523b\uff0c\u53ef\u8c03\u7528CodeGenerator.AddProxyType\u9759\u6001\u65b9\u6cd5\uff0c\u6dfb\u52a0\u4ee3\u7406\u7c7b\u578b\uff0c\u540c\u65f6\u53ef\u4f20\u5165\u4e00\u4e2abool\u503c\uff0c\u8868\u660e\u662f\u5426\u6df1\u5ea6\u641c\u7d22\uff0c\u6bd4\u5982\uff0c\u5047\u5982RpcArgsClassLib.ProxyClass1\u4e2d\u8fd8\u6709\u5176\u4ed6\u7c7b\u578b\uff0c\u5219\u53c2\u6570\u4e3aTrue\u65f6\uff0c\u4f9d\u7136\u4f1a\u4ee3\u7406\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},"RPCService rpcService = new RPCService();\nCodeGenerator.AddProxyType();\nCodeGenerator.AddProxyType(deepSearch:true);\n")),(0,l.kt)("a",{name:"L9jEG"}),(0,l.kt)("h3",{id:"222-\u6807\u8bb0\u81ea\u5b9a\u4e49\u7c7b"},"2.2.2 \u6807\u8bb0\u81ea\u5b9a\u4e49\u7c7b"),(0,l.kt)("p",null,"\u5728\u9700\u8981\u4ee3\u7406\u7684\u7c7b\u4e0a\u9762\u58f0\u660eRpcProxy\u6807\u7b7e\uff0c\u7136\u540e\u4e5f\u53ef\u4ee5\u91cd\u65b0\u6307\u5b9a\u4ee3\u7406\u7c7b\u540d\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'[RpcProxy("MyArgs")]\npublic class Args\n{\n}\n')),(0,l.kt)("h2",{id:"\u4e09\u5ba2\u6237\u7aef\u6e90\u4ee3\u7801\u751f\u6210\u4ee3\u7406-\u4f01\u4e1a\u7248"},"\u4e09\u3001\u5ba2\u6237\u7aef\u6e90\u4ee3\u7801\u751f\u6210\u4ee3\u7406 ",(0,l.kt)(a.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,l.kt)("p",null,"\u524d\u4e00\u79cd\u65b9\u5f0f\u5df2\u7ecf\u7b97\u662f\u51e0\u8fd1\u5b8c\u7f8e\u7684\u4ee3\u7406\u751f\u6210\u65b9\u6848\uff0c\u4f46\u662f\u6709\u65f6\u5019\uff0c\u5f53\u5927\u5bb6\u534f\u4f5c\u65f6\uff0c\u559c\u6b22\u5168\u90e8\u81ea\u5df1\u6572\u5199\u3002"),(0,l.kt)("p",null,"\u4f8b\u5982\uff1a"),(0,l.kt)("p",null,"\u5bf9\u4e8e\u4e0b\u5217\u670d\u52a1\uff0c\u6709\u65f6\u5019\u5c31\u662f\u559c\u6b22\u81ea\u5df1\u5199\u4e2a\u63a5\u53e3\uff0c\u7136\u540e\u76f4\u63a5\u8c03\u7528\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyRpcServer : RpcServer\n{\n [TouchRpc]\n public bool Login(string account, string password)\n {\n if (account == "123" && password == "abc")\n {\n return true;\n }\n\n return false;\n }\n}\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},"public interface IMyRpcServer\n{\n public bool Login(string account, string password);\n}\n")),(0,l.kt)("p",null,"\u4ee5\u5f80\u6765\u8bf4\uff0c\u5b9e\u73b0\u8fd9\u79cd\u65b9\u5f0f\u7684\u7edd\u5927\u591a\u6570\uff0c\u5927\u6982\u662f\u4f7f\u7528IL\u52a8\u6001\u6784\u5efa\u4e00\u4e2a\u7c7b\uff0c\u7136\u540e\u52a8\u6001\u5b9e\u73b0\u63a5\u53e3\u4ee3\u7406\uff0c\u4f2a\u4ee3\u7801\u5982\u4e0b\uff1a"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},"IMyRpcServer myRpcServer=ProxyGenerator.CreateProxy();\n")),(0,l.kt)("p",null,"\u4f46\u662f\u73b0\u5728\uff0c\u65f6\u4ee3\u53d8\u4e86\uff0c\u6211\u4eec\u6709\u4e86\u6e90\u4ee3\u7801\u751f\u6210\uff0c\u90a3\u4e48\u4e8b\u60c5\u5c06\u53d8\u5f97\u65e0\u6bd4\u7b80\u5355\u3002"),(0,l.kt)("p",null,"\u540c\u6837\uff0c\u6211\u4eec\u9700\u8981\u8bbe\u7f6e\u63a5\u53e3\uff0c\u5982\u4e0b\uff1a"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'/// \n/// GeneratorRpcProxy\u7684\u6807\u8bc6\uff0c\u8868\u660e\u8fd9\u4e2a\u63a5\u53e3\u5e94\u8be5\u88ab\u751f\u6210\u5176\u4ed6\u6e90\u4ee3\u7801\u3002\n/// ConsoleApp2.MyRpcServer\u53c2\u6570\u662f\u6574\u4e2arpc\u8c03\u7528\u7684\u524d\u7f00\uff0c\u5373\uff1a\u9664\u65b9\u6cd5\u540d\u7684\u6240\u6709\uff0c\u5305\u62ec\u670d\u52a1\u7684\u7c7b\u540d\u3002\n/// \n[GeneratorRpcProxy("ConsoleApp2.MyRpcServer")]\ninterface IMyRpcServer\n{\n [Description("\u8fd9\u662f\u767b\u5f55\u65b9\u6cd5")]//\u8be5\u4f5c\u7528\u662f\u751f\u6210\u6ce8\u91ca\n [GeneratorRpcMethod]//\u8868\u9762\u8be5\u65b9\u6cd5\u5e94\u8be5\u88ab\u4ee3\u7406\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u53c2\u6570\uff0c\u76f4\u63a5\u8bbe\u7f6e\u8c03\u7528\u952e\n public bool Login(string account, string password);\n}\n')),(0,l.kt)("p",null,"\u8fd9\u65f6\u5019\uff0c\u795e\u5947\u7684\u4e00\u5e55\u53d1\u751f\u4e86\uff0c\u51e1\u662f\u5b9e\u73b0IRpcClient\u7684\u63a5\u53e3\u7684\u5b9e\u4f8b\uff0c\u90fd\u589e\u52a0\u4e86\u6269\u5c55\u65b9\u6cd5\u3002\u800c\u8fd9\u529f\u80fd\uff0c\u548c\u670d\u52a1\u5668\u751f\u6210\u7684\u6269\u5c55Rpc\u65b9\u6cd5\u7684\u529f\u80fd\u662f\u4e00\u81f4\u7684\u3002"),(0,l.kt)("p",null,(0,l.kt)("img",{src:r(627).Z,width:"927",height:"144"})),(0,l.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"\u5927\u5bb6\u53ef\u80fd\u4f1a\u7591\u95ee\uff0c\u6e90\u4ee3\u7801\u751f\u6210\u4ee3\u7406\uff0c\u548c\u670d\u52a1\u7aef\u751f\u6210\u4ee3\u7406\uff0c\u6709\u4ec0\u4e48\u533a\u522b\uff1f\u6216\u8005\u8bf4\u6709\u4ec0\u4e48\u4f18\u70b9\uff1f\n\u5b9e\u9645\u4e0a\u6ca1\u6709\u533a\u522b\uff0c\u4e5f\u6ca1\u6709\u4f18\u70b9\u3002\u4e4b\u6240\u4ee5\u8bbe\u8ba1\u8fd9\u4e2a\uff0c\u662f\u56e0\u4e3a\u4e4b\u524d\u6709\u4eba\u63d0\u8fc7\u9700\u6c42\uff0c\u60f3\u8981\u5b8c\u5168\u5206\u79bb\u524d\u3001\u540e\u7aef\u3002\u5373\uff1a\u540e\u7aef\u5199\u597d\u670d\u52a1\u540e\uff0c\u524d\u7aef\u81ea\u7531\u5b9a\u4e49\u670d\u52a1\u63a5\u53e3\uff0c\u548c\u8c03\u7528\u53c2\u6570\uff0c\u4ec5\u6b64\u800c\u5df2\u3002"),(0,l.kt)("p",{parentName:"admonition"},"\u6240\u4ee5\uff0c\u751f\u6210\u4ee3\u7406\u7684\u65b9\u5f0f\uff0c\u6309\u7167\u5927\u5bb6\u7684\u4e60\u60ef\u9700\u6c42\u9009\u62e9\u5c31\u53ef\u4ee5\u3002")),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://gitee.com/RRQM_Home/TouchSocket/tree/master/examples/TouchRpc%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B/%E6%BA%90%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E4%BB%A3%E7%90%86/GeneratorRpcProxyConsoleApp"},"\u6e90\u4ee3\u7801\u751f\u6210\u4ee3\u7406\u793a\u4f8b\u4ee3\u7801")))}d.isMDXComponent=!0},627:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/generateproxy-1-163d930232955088abd9e846f68067d1.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/1a4e3797.42a57863.js b/handbook/build/assets/js/1a4e3797.42a57863.js new file mode 100644 index 000000000..67f1f378d --- /dev/null +++ b/handbook/build/assets/js/1a4e3797.42a57863.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7920],{2027:(e,t,n)=>{n.r(t),n.d(t,{default:()=>_});var r=n(7294),a=n(2263),l=n(3929),s=n(5742),c=n(9960),o=n(5999);const u=["zero","one","two","few","many","other"];function m(e){return u.filter((t=>e.includes(t)))}const h={locale:"en",pluralForms:m(["one","other"]),select:e=>1===e?"one":"other"};function i(){const{i18n:{currentLocale:e}}=(0,a.Z)();return(0,r.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:m(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),h}}),[e])}function p(){const e=i();return{selectMessage:(t,n)=>function(e,t,n){const r=e.split("|");if(1===r.length)return r[0];r.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${r.length}: ${e}`);const a=n.select(t),l=n.pluralForms.indexOf(a);return r[Math.min(l,r.length-1)]}(n,t,e)}}var g=n(6775),d=n(412);const f=function(){const e=(0,g.k6)(),t=(0,g.TH)(),{siteConfig:{baseUrl:n}}=(0,a.Z)(),r=d.Z.canUseDOM?new URLSearchParams(t.search):null,l=(null==r?void 0:r.get("q"))||"",s=(null==r?void 0:r.get("ctx"))||"",c=(null==r?void 0:r.get("version"))||"",o=e=>{const n=new URLSearchParams(t.search);return e?n.set("q",e):n.delete("q"),n};return{searchValue:l,searchContext:s,searchVersion:c,updateSearchPath:t=>{const n=o(t);e.replace({search:n.toString()})},generateSearchPageLink:e=>{const t=o(e);return`${n}search?${t.toString()}`}}};var E=n(22),y=n(8202),S=n(2539),w=n(726),v=n(1073),b=n(311),I=n(3926),P=n(1029);const k="searchQueryInput_CFBF",F="searchResultItem_U687",R="searchResultItemPath_uIbk",C="searchResultItemSummary_oZHr";function $(){const{siteConfig:{baseUrl:e}}=(0,a.Z)(),{selectMessage:t}=p(),{searchValue:n,searchContext:l,searchVersion:c,updateSearchPath:u}=f(),[m,h]=(0,r.useState)(n),[i,g]=(0,r.useState)(),[d,S]=(0,r.useState)(),w=`${e}${c}`,v=(0,r.useMemo)((()=>m?(0,o.I)({id:"theme.SearchPage.existingResultsTitle",message:'Search results for "{query}"',description:"The search page title for non-empty query"},{query:m}):(0,o.I)({id:"theme.SearchPage.emptyResultsTitle",message:"Search the documentation",description:"The search page title for empty query"})),[m]);(0,r.useEffect)((()=>{u(m),i&&(m?i(m,(e=>{S(e)})):S(void 0))}),[m,i]);const I=(0,r.useCallback)((e=>{h(e.target.value)}),[]);return(0,r.useEffect)((()=>{n&&n!==m&&h(n)}),[n]),(0,r.useEffect)((()=>{!async function(){const{wrappedIndexes:e,zhDictionary:t}=await(0,E.w)(w,l);g((()=>(0,y.v)(e,t,100)))}()}),[l,w]),r.createElement(r.Fragment,null,r.createElement(s.Z,null,r.createElement("meta",{property:"robots",content:"noindex, follow"}),r.createElement("title",null,v)),r.createElement("div",{className:"container margin-vert--lg"},r.createElement("h1",null,v),r.createElement("input",{type:"search",name:"q",className:k,"aria-label":"Search",onChange:I,value:m,autoComplete:"off",autoFocus:!0}),!i&&m&&r.createElement("div",null,r.createElement(b.Z,null)),d&&(d.length>0?r.createElement("p",null,t(d.length,(0,o.I)({id:"theme.SearchPage.documentsFound.plurals",message:"1 document found|{count} documents found",description:'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)'},{count:d.length}))):r.createElement("p",null,(0,o.I)({id:"theme.SearchPage.noResultsText",message:"No documents were found",description:"The paragraph for empty search result"}))),r.createElement("section",null,d&&d.map((e=>r.createElement(x,{key:e.document.i,searchResult:e}))))))}function x(e){let{searchResult:{document:t,type:n,page:a,tokens:l,metadata:s}}=e;const o=0===n,u=2===n,m=(o?t.b:a.b).slice(),h=u?t.s:t.t;o||m.push(a.t);let i="";if(P.vc&&l.length>0){const e=new URLSearchParams;for(const t of l)e.append("_highlight",t);i=`?${e.toString()}`}return r.createElement("article",{className:F},r.createElement("h2",null,r.createElement(c.Z,{to:t.u+i+(t.h||""),dangerouslySetInnerHTML:{__html:u?(0,S.C)(h,l):(0,w.o)(h,(0,v.m)(s,"t"),l,100)}})),m.length>0&&r.createElement("p",{className:R},(0,I.e)(m)),u&&r.createElement("p",{className:C,dangerouslySetInnerHTML:{__html:(0,w.o)(t.t,(0,v.m)(s,"t"),l,100)}}))}const _=function(){return r.createElement(l.Z,null,r.createElement($,null))}}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/1be78505.9cd1e63b.js b/handbook/build/assets/js/1be78505.9cd1e63b.js new file mode 100644 index 000000000..f8a98372a --- /dev/null +++ b/handbook/build/assets/js/1be78505.9cd1e63b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9514,4972],{9963:(e,t,n)=>{n.r(t),n.d(t,{default:()=>Ce});var a=n(7294),l=n(6010),o=n(1944),r=n(5281),c=n(3320),i=n(2802),s=n(4477),d=n(1116),m=n(3929),u=n(5999),b=n(2466),p=n(5936);const h="backToTopButton_sjWU",E="backToTopButtonShow_xfvO";function f(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,l]=(0,a.useState)(!1),o=(0,a.useRef)(!1),{startScroll:r,cancelScroll:c}=(0,b.Ct)();return(0,b.RF)(((e,n)=>{let{scrollY:a}=e;const r=null==n?void 0:n.scrollY;r&&(o.current?o.current=!1:a>=r?(c(),l(!1)):a{e.location.hash&&(o.current=!0,l(!1))})),{shown:n,scrollToTop:()=>r(0)}}({threshold:300});return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,l.Z)("clean-btn",r.k.common.backToTopButton,h,e&&E),type:"button",onClick:t})}var v=n(6775),g=n(7524),_=n(6668),k=n(1327),C=n(7462);function S(e){return a.createElement("svg",(0,C.Z)({width:"20",height:"20","aria-hidden":"true"},e),a.createElement("g",{fill:"#7a7a7a"},a.createElement("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),a.createElement("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})))}const I="collapseSidebarButton_PEFL",N="collapseSidebarButtonIcon_kv0_";function Z(e){let{onClick:t}=e;return a.createElement("button",{type:"button",title:(0,u.I)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,l.Z)("button button--secondary button--outline",I),onClick:t},a.createElement(S,{className:N}))}var x=n(9689),T=n(902);const y=Symbol("EmptyContext"),w=a.createContext(y);function L(e){let{children:t}=e;const[n,l]=(0,a.useState)(null),o=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:l})),[n]);return a.createElement(w.Provider,{value:o},t)}var A=n(6043),M=n(8596),B=n(9960),F=n(2389);function H(e){let{categoryLabel:t,onClick:n}=e;return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel",message:"Toggle the collapsible sidebar category '{label}'",description:"The ARIA label to toggle the collapsible sidebar category"},{label:t}),type:"button",className:"clean-btn menu__caret",onClick:n})}function P(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{items:m,label:u,collapsible:b,className:p,href:h}=t,{docs:{sidebar:{autoCollapseCategories:E}}}=(0,_.L)(),f=function(e){const t=(0,F.Z)();return(0,a.useMemo)((()=>e.href?e.href:!t&&e.collapsible?(0,i.Wl)(e):void 0),[e,t])}(t),v=(0,i._F)(t,o),g=(0,M.Mg)(h,o),{collapsed:k,setCollapsed:S}=(0,A.u)({initialState:()=>!!b&&(!v&&t.collapsed)}),{expandedItem:I,setExpandedItem:N}=function(){const e=(0,a.useContext)(w);if(e===y)throw new T.i6("DocSidebarItemsExpandedStateProvider");return e}(),Z=function(e){void 0===e&&(e=!k),N(e?null:s),S(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:l}=e;const o=(0,T.D9)(t);(0,a.useEffect)((()=>{t&&!o&&n&&l(!1)}),[t,o,n,l])}({isActive:v,collapsed:k,updateCollapsed:Z}),(0,a.useEffect)((()=>{b&&null!=I&&I!==s&&E&&S(!0)}),[b,I,s,S,E]),a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemCategory,r.k.docs.docSidebarItemCategoryLevel(c),"menu__list-item",{"menu__list-item--collapsed":k},p)},a.createElement("div",{className:(0,l.Z)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":g})},a.createElement(B.Z,(0,C.Z)({className:(0,l.Z)("menu__link",{"menu__link--sublist":b,"menu__link--sublist-caret":!h&&b,"menu__link--active":v}),onClick:b?e=>{null==n||n(t),h?Z(!1):(e.preventDefault(),Z())}:()=>{null==n||n(t)},"aria-current":g?"page":void 0,"aria-expanded":b?!k:void 0,href:b?f??"#":f},d),u),h&&b&&a.createElement(H,{categoryLabel:u,onClick:e=>{e.preventDefault(),Z()}})),a.createElement(A.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:k},a.createElement(q,{items:m,tabIndex:k?-1:0,onItemClick:n,activePath:o,level:c+1})))}var D=n(3919),W=n(9471);const R="menuExternalLink_NmtK";function V(e){let{item:t,onItemClick:n,activePath:o,level:c,index:s,...d}=e;const{href:m,label:u,className:b,autoAddBaseUrl:p}=t,h=(0,i._F)(t,o),E=(0,D.Z)(m);return a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(c),"menu__list-item",b),key:u},a.createElement(B.Z,(0,C.Z)({className:(0,l.Z)("menu__link",!E&&R,{"menu__link--active":h}),autoAddBaseUrl:p,"aria-current":h?"page":void 0,to:m},E&&{onClick:n?()=>n(t):void 0},d),u,!E&&a.createElement(W.Z,null)))}const z="menuHtmlItem_M9Kj";function U(e){let{item:t,level:n,index:o}=e;const{value:c,defaultStyle:i,className:s}=t;return a.createElement("li",{className:(0,l.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(n),i&&[z,"menu__list-item"],s),key:o,dangerouslySetInnerHTML:{__html:c}})}function K(e){let{item:t,...n}=e;switch(t.type){case"category":return a.createElement(P,(0,C.Z)({item:t},n));case"html":return a.createElement(U,(0,C.Z)({item:t},n));default:return a.createElement(V,(0,C.Z)({item:t},n))}}function j(e){let{items:t,...n}=e;return a.createElement(L,null,t.map(((e,t)=>a.createElement(K,(0,C.Z)({key:t,item:e,index:t},n)))))}const q=(0,a.memo)(j),G="menu_SIkG",Y="menuWithAnnouncementBar_GW3s";function O(e){let{path:t,sidebar:n,className:o}=e;const c=function(){const{isActive:e}=(0,x.nT)(),[t,n]=(0,a.useState)(e);return(0,b.RF)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return a.createElement("nav",{"aria-label":(0,u.I)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,l.Z)("menu thin-scrollbar",G,c&&Y,o)},a.createElement("ul",{className:(0,l.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(q,{items:n,activePath:t,level:1})))}const X="sidebar_njMd",J="sidebarWithHideableNavbar_wUlq",Q="sidebarHidden_VK0M",$="sidebarLogo_isFc";function ee(e){let{path:t,sidebar:n,onCollapse:o,isHidden:r}=e;const{navbar:{hideOnScroll:c},docs:{sidebar:{hideable:i}}}=(0,_.L)();return a.createElement("div",{className:(0,l.Z)(X,c&&J,r&&Q)},c&&a.createElement(k.Z,{tabIndex:-1,className:$}),a.createElement(O,{path:t,sidebar:n}),i&&a.createElement(Z,{onClick:o}))}const te=a.memo(ee);var ne=n(3102),ae=n(2961);const le=e=>{let{sidebar:t,path:n}=e;const o=(0,ae.e)();return a.createElement("ul",{className:(0,l.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(q,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&o.toggle(),"link"===e.type&&o.toggle()},level:1}))};function oe(e){return a.createElement(ne.Zo,{component:le,props:e})}const re=a.memo(oe);function ce(e){const t=(0,g.i)(),n="desktop"===t||"ssr"===t,l="mobile"===t;return a.createElement(a.Fragment,null,n&&a.createElement(te,e),l&&a.createElement(re,e))}const ie="expandButton_m80_",se="expandButtonIcon_BlDH";function de(e){let{toggleSidebar:t}=e;return a.createElement("div",{className:ie,title:(0,u.I)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t},a.createElement(S,{className:se}))}const me={docSidebarContainer:"docSidebarContainer_b6E3",docSidebarContainerHidden:"docSidebarContainerHidden_b3ry",sidebarViewport:"sidebarViewport_Xe31"};function ue(e){let{children:t}=e;const n=(0,d.V)();return a.createElement(a.Fragment,{key:(null==n?void 0:n.name)??"noSidebar"},t)}function be(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:o}=e;const{pathname:c}=(0,v.TH)(),[i,s]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{i&&s(!1),o((e=>!e))}),[o,i]);return a.createElement("aside",{className:(0,l.Z)(r.k.docs.docSidebarContainer,me.docSidebarContainer,n&&me.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(me.docSidebarContainer)&&n&&s(!0)}},a.createElement(ue,null,a.createElement("div",{className:(0,l.Z)(me.sidebarViewport,i&&me.sidebarViewportHidden)},a.createElement(ce,{sidebar:t,path:c,onCollapse:d,isHidden:i}),i&&a.createElement(de,{toggleSidebar:d}))))}const pe={docMainContainer:"docMainContainer_gTbr",docMainContainerEnhanced:"docMainContainerEnhanced_Uz_u",docItemWrapperEnhanced:"docItemWrapperEnhanced_czyv"};function he(e){let{hiddenSidebarContainer:t,children:n}=e;const o=(0,d.V)();return a.createElement("main",{className:(0,l.Z)(pe.docMainContainer,(t||!o)&&pe.docMainContainerEnhanced)},a.createElement("div",{className:(0,l.Z)("container padding-top--md padding-bottom--lg",pe.docItemWrapper,t&&pe.docItemWrapperEnhanced)},n))}const Ee="docPage__5DB",fe="docsWrapper_BCFX";function ve(e){let{children:t}=e;const n=(0,d.V)(),[l,o]=(0,a.useState)(!1);return a.createElement(m.Z,{wrapperClassName:fe},a.createElement(f,null),a.createElement("div",{className:Ee},n&&a.createElement(be,{sidebar:n.items,hiddenSidebarContainer:l,setHiddenSidebarContainer:o}),a.createElement(he,{hiddenSidebarContainer:l},t)))}var ge=n(4972),_e=n(197);function ke(e){const{versionMetadata:t}=e;return a.createElement(a.Fragment,null,a.createElement(_e.Z,{version:t.version,tag:(0,c.os)(t.pluginId,t.version)}),a.createElement(o.d,null,t.noIndex&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"})))}function Ce(e){const{versionMetadata:t}=e,n=(0,i.hI)(e);if(!n)return a.createElement(ge.default,null);const{docElement:c,sidebarName:m,sidebarItems:u}=n;return a.createElement(a.Fragment,null,a.createElement(ke,e),a.createElement(o.FG,{className:(0,l.Z)(r.k.wrapper.docsPages,r.k.page.docsDocPage,e.versionMetadata.className)},a.createElement(s.q,{version:t},a.createElement(d.b,{name:m,items:u},a.createElement(ve,null,c)))))}},4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(7294),l=n(5999),o=n(1944),r=n(3929);function c(){return a.createElement(a.Fragment,null,a.createElement(o.d,{title:(0,l.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},4477:(e,t,n)=>{n.d(t,{E:()=>c,q:()=>r});var a=n(7294),l=n(902);const o=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(o.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(o);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/1c9cad99.039ee719.js b/handbook/build/assets/js/1c9cad99.039ee719.js new file mode 100644 index 000000000..62e4a3e44 --- /dev/null +++ b/handbook/build/assets/js/1c9cad99.039ee719.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1285],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(r),f=a,b=u["".concat(l,".").concat(f)]||u[f]||d[f]||o;return r?n.createElement(b,c(c({ref:t},p),{},{components:r})):n.createElement(b,c({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=u;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const o={id:"dataadaptertester",sidebar_position:5,title:"\u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5",sidebar_label:"8.5 \u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5"},c=void 0,i={unversionedId:"dataadaptertester",id:"dataadaptertester",title:"\u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/dataadaptertester.mdx",sourceDirName:".",slug:"/dataadaptertester",permalink:"/touchsocket/docs/dataadaptertester",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/dataadaptertester.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",sidebarPosition:5,frontMatter:{id:"dataadaptertester",sidebar_position:5,title:"\u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5",sidebar_label:"8.5 \u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5"},sidebar:"docs",previous:{title:"\u72ec\u7acb\u4f7f\u7528\u9002\u914d\u5668",permalink:"/touchsocket/docs/independentusedatahandlingadapter"},next:{title:"\u521b\u5efaHttpService",permalink:"/touchsocket/docs/createhttpservice"}},l={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"1.1 \u6d4b\u8bd5\u539f\u7406",id:"11-\u6d4b\u8bd5\u539f\u7406",level:3},{value:"1.2 \u6d4b\u8bd5\u4e8b\u9879",id:"12-\u6d4b\u8bd5\u4e8b\u9879",level:3},{value:"\u4e8c\u3001Tcp\u9002\u914d\u5668",id:"\u4e8ctcp\u9002\u914d\u5668",level:2}],p={toc:s};function d(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u9002\u914d\u5668\u6d4b\u8bd5\u662f\u6d4b\u8bd5\u9002\u914d\u5668\u5728\u6b63\u5e38\u60c5\u51b5\u4e0b\uff0c\u6781\u7aef\u5de5\u4f5c\u7684\u4e00\u79cd\u6d4b\u8bd5\u65b9\u5f0f\u3002\u80fd\u591f\u5728\u524d\u671f\uff0c\u89e3\u51b3100%\u7684\u7b97\u6cd5\u95ee\u9898\u3002\u4e5f\u80fd\u5728\u6781\u7aef\u914d\u7f6e\u4e0b\uff0c\u6a21\u62df\u6781\u7aef\u5de5\u4f5c\u73af\u5883\uff0c\u80fd\u591f\u7b80\u5355\uff0c\u76f4\u89c2\u7684\u5c55\u793a\u51fa\u9002\u914d\u5668\u7684\u7a33\u5b9a\u6027\u548c\u5de5\u4f5c\u6027\u80fd\u3002"),(0,a.kt)("h3",{id:"11-\u6d4b\u8bd5\u539f\u7406"},"1.1 \u6d4b\u8bd5\u539f\u7406"),(0,a.kt)("p",null,"\u5047\u8bbe\u53d1\u9001\u6570\u636e\u4e3a{0,1,2,3,4}\uff0c\u8fde\u7eed\u53d1\u900110\u6b21\u3002\n\u5f53bufferLength=1\u65f6\uff0c\u4f1a\u5148\u63a5\u6536\u4e00\u4e2a\u5b57\u8282\uff0c\u7136\u540e\u9002\u914d\u5668\u5224\u65ad\u65e0\u6cd5\u89e3\u6790\uff0c\u7136\u540e\u7f13\u5b58\uff0c\u7136\u540e\u518d\u63a5\u6536\u4e0b\u4e00\u4e2a\u5b57\u8282\uff0c\u76f4\u5230\u6210\u529f\u89e3\u6790\u4e00\u4e2a\u5b8c\u6574\u6570\u636e\u5305\u3002\u8be5\u6a21\u5f0f\u89e3\u51b3\u7684\u5c31\u662f\u5927\u5bb6\u6240\u8bf4\u7684\u5206\u5305\uff0c\u4e5f\u5c31\u662f\u80fd\u5f88\u597d\u7684\u6a21\u62df",(0,a.kt)("strong",{parentName:"p"},"\u7f51\u7edc\u5f88\u5dee"),"\u7684\u73af\u5883\u3002\n\u5f53bufferLength>5\u65f6,\u5047\u5982\u4e3a8\uff0c\u5219\u4f1a\u5148\u63a5\u6536{0,1,2,3,4,0,1,2}\uff0c\u7136\u540e\u9002\u914d\u5668\u6210\u529f\u5224\u65ad\u89e3\u6790\u524d\u4e94\u5b57\u8282\uff0c\u7136\u540e\u7f13\u5b58\u540e\u4e09\u5b57\u8282\uff0c\u7136\u540e\u518d\u63a5\u6536\u4e0b\u4e00\u4e2a\u7eed\u5305\uff0c\u76f4\u5230\u89e3\u6790\u7ed3\u675f\u3002"),(0,a.kt)("h3",{id:"12-\u6d4b\u8bd5\u4e8b\u9879"},"1.2 \u6d4b\u8bd5\u4e8b\u9879"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"bufferLength\u5e94\u8be5\u591a\u6b21\u8bbe\u7f6e\uff0c\u4e14\u6700\u597d\u4e0d\u8981\u6574\u9664\u4e8e\u53d1\u9001\u6570\u636e\u7684\u957f\u5ea6\uff0c\u8fd9\u6837\u907f\u514d\u5de7\u5408\u53d1\u751f\uff0c\u6d4b\u4e0d\u51fa\u6781\u7aef\u95ee\u9898\u3002"),(0,a.kt)("li",{parentName:"ol"},"Run\u7684\u6b21\u6570\u5e94\u8be5\u591a\u8bbe\uff0c\u6a21\u62df\u9ad8\u9891\u60c5\u51b5\u3002")),(0,a.kt)("h2",{id:"\u4e8ctcp\u9002\u914d\u5668"},"\u4e8c\u3001Tcp\u9002\u914d\u5668"),(0,a.kt)("p",null,"Tcp\u9002\u914d\u5668\u7684\u5de5\u4f5c\u73af\u5883\uff0c\u53ea\u9700\u8003\u8651\u5355\u7ebf\u7a0b\u5373\u53ef\u3002\u56e0\u4e3a\u662f\u5ba2\u6237\u7aef\u4e0e\u9002\u914d\u5668\u662f\u4e00\u4e00\u5bf9\u5e94\u7684\u3002"),(0,a.kt)("p",null,"\u4e0b\u5217\u4ee5 ",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/fixedheaderpackageadapter"},"\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668")," \u4e3a\u4f8b"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'//Tcp\u9002\u914d\u5668\u6d4b\u8bd5\n//bufferLength\u7684\u4f5c\u7528\u662f\u6a21\u62dftcp\u63a5\u6536\u7f13\u5b58\u533a\uff0c\u4f8b\u5982\uff1a\n\n//\u53d1\u9001\u6570\u636e\u4e3a{0,1,2,3,4}\u65f6\n//\u5f53bufferLength=1\u65f6\uff0c\u4f1a\u5148\u63a5\u6536\u4e00\u4e2a\u5b57\u8282\uff0c\u7136\u540e\u9002\u914d\u5668\u5224\u65ad\u65e0\u6cd5\u89e3\u6790\uff0c\u7136\u540e\u7f13\u5b58\uff0c\u7136\u540e\u518d\u63a5\u6536\u4e0b\u4e00\u4e2a\u5b57\u8282\uff0c\u76f4\u5230\u6210\u529f\u89e3\u6790\u3002\n//\u8be5\u6a21\u5f0f\u80fd\u5f88\u597d\u7684\u6a21\u62df\u7f51\u7edc\u5f88\u5dee\u7684\u73af\u5883\u3002\n//\u5f53bufferLength=8\u65f6\uff0c\u4f1a\u5148\u63a5\u6536{0,1,2,3,4,0,1,2}\uff0c\u7136\u540e\u9002\u914d\u5668\u5224\u65ad\u89e3\u6790\u524d\u4e94\u5b57\u8282\uff0c\u7136\u540e\u7f13\u5b58\u540e\u4e09\u5b57\u8282\uff0c\u7136\u540e\u518d\u63a5\u6536\u4e0b\u4e00\u4e2a\u7eed\u5305\uff0c\u76f4\u5230\u89e3\u6790\u7ed3\u675f\n\nfor (int bufferLength = 1; bufferLength < 1024 * 10; bufferLength += 1024)\n{\n bool isSuccess = true;\n var data = new byte[] { 0, 1, 2, 3, 4 };\n DataAdapterTester tester = DataAdapterTester.CreateTester(new FixedHeaderPackageAdapter()\n , bufferLength, (byteBlock, requestInfo) =>\n {\n //\u6b64\u5904\u5c31\u662f\u63a5\u6536\uff0c\u5982\u679c\u662f\u81ea\u5b9a\u4e49\u9002\u914d\u5668\uff0c\u53ef\u4ee5\u5c06requestInfo\u5f3a\u5236\u8f6c\u6362\u4e3a\u5b9e\u9645\u5bf9\u8c61\uff0c\u7136\u540e\u5224\u65ad\u6570\u636e\u7684\u786e\u5b9a\u6027\n if (byteBlock.Len!=5||(!byteBlock.ToArray().SequenceEqual(data)))\n {\n isSuccess = false;\n }\n });\n \n //data\u662f\u53d1\u9001\u7684\u6570\u636e\uff0c\u56e0\u4e3a\u6b64\u5904\u4f7f\u7528\u7684\u662f\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668\uff0c\n //\u53d1\u9001\u524d\u9002\u914d\u5668\u4f1a\u81ea\u52a8\u6dfb\u52a0\u5305\u5934\uff0c\u6240\u4ee5\uff0c\u6b64\u5904\u53ea\u53d1\u9001\u6570\u636e\u5373\u53ef\u3002\n //\u5982\u679c\u6d4b\u8bd5\u7684\u662f\u81ea\u5b9a\u4e49\u9002\u914d\u5668\uff0c\u53d1\u9001\u524d\u6ca1\u6709\u5c01\u88c5\u7684\u8bdd\uff0c\u5c31\u9700\u8981\u81ea\u884c\u6784\u5efa\u53d1\u9001\u6570\u636e\u3002\n //\u968f\u540e\u7684\u4e24\u4e2a\u53c2\u6570\uff0c10,10\u662f\u6d4b\u8bd5\u6b21\u6570\uff0c\u548c\u671f\u671b\u6b21\u6570\uff0c\u4e00\u822c\u8fd9\u4e24\u4e2a\u503c\u662f\u76f8\u7b49\u7684\u3002\n //\u610f\u4e3a\uff1a\u672c\u6b21\u6570\u636e\u5c06\u5faa\u73af\u53d1\u900110\u6b21\uff0c\u4e14\u4f1a\u63a5\u653610\u6b21\u3002\u4e0d\u7136\u6b64\u5904\u4f1a\u4e00\u76f4\u963b\u585e\u3002\n //\u6700\u540e\u4e00\u4e2a\u53c2\u6570\u662f\u6d4b\u8bd5\u7684\u6700\u5927\u8d85\u65f6\u65f6\u95f4\u3002\n\n var time = tester.Run(data, 10, 10, 1000 * 10);\n Thread.Sleep(1000);\n Console.WriteLine($"\u6d4b\u8bd5\u7ed3\u675f\uff0c\u72b6\u6001:{isSuccess}\uff0c\u7528\u65f6\uff1a{time}");\n}\nConsole.WriteLine("\u6d4b\u8bd5\u7ed3\u675f");\n\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/1ec5dc39.5959844a.js b/handbook/build/assets/js/1ec5dc39.5959844a.js new file mode 100644 index 000000000..f05f98987 --- /dev/null +++ b/handbook/build/assets/js/1ec5dc39.5959844a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7462],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>k});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),i=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},s=function(e){var t=i(e.components);return r.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=i(n),k=a,g=d["".concat(p,".").concat(k)]||d[k]||u[k]||o;return n?r.createElement(g,c(c({ref:t},s),{},{components:n})):r.createElement(g,c({ref:t},s))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,c=new Array(o);c[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l.mdxType="string"==typeof e?e:a,c[1]=l;for(var i=2;i{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>i});var r=n(7462),a=(n(7294),n(3905));const o={id:"createtouchrpcservice",title:"\u521b\u5efaTouchRpc\u670d\u52a1\u5668"},c=void 0,l={unversionedId:"createtouchrpcservice",id:"createtouchrpcservice",title:"\u521b\u5efaTouchRpc\u670d\u52a1\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/createtouchrpcservice.mdx",sourceDirName:".",slug:"/createtouchrpcservice",permalink:"/touchsocket/docs/createtouchrpcservice",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createtouchrpcservice.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675660193,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"createtouchrpcservice",title:"\u521b\u5efaTouchRpc\u670d\u52a1\u5668"},sidebar:"docs",previous:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/touchrpcdescription"},next:{title:"\u521b\u5efaTouchRpc\u5ba2\u6237\u7aef",permalink:"/touchsocket/docs/createtouchrpcclient"}},p={},i=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u670d\u52a1\u5668\u67b6\u6784",id:"\u4e8c\u670d\u52a1\u5668\u67b6\u6784",level:2},{value:"\u4e09\u3001\u53ef\u914d\u7f6e\u9879",id:"\u4e09\u53ef\u914d\u7f6e\u9879",level:2},{value:"SetVerifyTimeout",id:"setverifytimeout",level:4},{value:"SetVerifyToken",id:"setverifytoken",level:4},{value:"SetHeartbeatFrequency",id:"setheartbeatfrequency",level:4},{value:"SetSerializationSelector",id:"setserializationselector",level:4},{value:"SetResponseType",id:"setresponsetype",level:4},{value:"SetRootPath",id:"setrootpath",level:4},{value:"\u56db\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",id:"\u56db\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",level:2},{value:"\u4e94\u3001\u521b\u5efa\u670d\u52a1\u5668",id:"\u4e94\u521b\u5efa\u670d\u52a1\u5668",level:2},{value:"5.1 \u57fa\u4e8eTcp\u534f\u8bae",id:"51-\u57fa\u4e8etcp\u534f\u8bae",level:3},{value:"5.2 \u57fa\u4e8eHttp\u534f\u8bae",id:"52-\u57fa\u4e8ehttp\u534f\u8bae",level:3},{value:"5.3 \u57fa\u4e8eUdp\u534f\u8bae",id:"53-\u57fa\u4e8eudp\u534f\u8bae",level:3},{value:"5.4 \u57fa\u4e8eAspNetCore\u7684Websocket\u534f\u8bae",id:"54-\u57fa\u4e8easpnetcore\u7684websocket\u534f\u8bae",level:3}],s={toc:i};function u(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"TouchRpc\u7684\u670d\u52a1\u5668\u6709\u591a\u79cd\u5f62\u5f0f\u7684host\uff0c\u6bcf\u79cd\u670d\u52a1\u5668\u7684\u521b\u5efa\u90fd\u5927\u540c\u5c0f\u5f02\uff0c\u4e14\u529f\u80fd\u57fa\u672c\u4e00\u81f4\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u670d\u52a1\u5668\u67b6\u6784"},"\u4e8c\u3001\u670d\u52a1\u5668\u67b6\u6784"),(0,a.kt)("p",null,"TouchRpc\u670d\u52a1\u5668\u7684\u67b6\u6784\u4e0e\u5176\u6240\u5c5e\u7684\u57fa\u7840\u534f\u8bae\u67b6\u6784\u4e00\u81f4\uff0c\u4f8b\u5982\uff0c\u5728\u57fa\u4e8etcp\u534f\u8bae\u65f6\uff0c\u5176\u67b6\u6784\u5c31\u548ctcp\u670d\u52a1\u5668\u4e00\u81f4\u3002\u5728\u6536\u5230",(0,a.kt)("strong",{parentName:"p"},"\u65b0\u5ba2\u6237\u7aef\u8fde\u63a5"),"\u65f6\uff0c\u4f1a\u521b\u5efa\u4e00\u4e2a",(0,a.kt)("strong",{parentName:"p"},"TcpTouchRpcSocketClient"),"\u7684\u7c7b\u5b9e\u4f8b\uff0c\u4e0e",(0,a.kt)("strong",{parentName:"p"},"\u5ba2\u6237\u7aefTcpTouchRpcClient"),"\u4e00\u4e00\u5bf9\u5e94\uff0c\u540e\u7eed\u7684\u6570\u636e\u901a\u4fe1\u5747\u7531\u6b64\u5b9e\u4f8b\u8d1f\u8d23\u3002"),(0,a.kt)("h2",{id:"\u4e09\u53ef\u914d\u7f6e\u9879"},"\u4e09\u3001\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("details",null,(0,a.kt)("summary",null,"\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("div",null,(0,a.kt)("h4",{id:"setverifytimeout"},"SetVerifyTimeout"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u9a8c\u8bc1\u8d85\u65f6\u65f6\u95f4\uff0c\u9ed8\u8ba43000ms\u3002\uff08\u4ec5TcpTouchRpc\u53ef\u7528\uff09 \u3002"),(0,a.kt)("h4",{id:"setverifytoken"},"SetVerifyToken"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u9a8c\u8bc1\u53e3\u4ee4\u3002 "),(0,a.kt)("h4",{id:"setheartbeatfrequency"},"SetHeartbeatFrequency"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u5fc3\u8df3\u3002\u9ed8\u8ba4\u4e3a\u95f4\u96942000ms\uff0c\u8fde\u7eed3\u6b21\u65e0\u54cd\u5e94\u5373\u89c6\u4e3a\u65ad\u5f00\u3002"),(0,a.kt)("h4",{id:"setserializationselector"},"SetSerializationSelector"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u5e8f\u5217\u5316\u9009\u62e9\u5668\u3002"),(0,a.kt)("h4",{id:"setresponsetype"},"SetResponseType"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u5141\u8bb8\u7684\u54cd\u5e94\u7c7b\u578b"),(0,a.kt)("h4",{id:"setrootpath"},"SetRootPath"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u6839\u8def\u5f84"))),(0,a.kt)("h2",{id:"\u56db\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"},"\u56db\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"),(0,a.kt)("p",null,"\u58f0\u660e\u81ea\u5b9a\u4e49\u5b9e\u4f8b\u7c7b\uff0c\u7136\u540e\u5b9e\u73b0",(0,a.kt)("strong",{parentName:"p"},"ITouchRpcPlugin"),"\u63a5\u53e3\uff0c\u5373\u53ef\u5b9e\u73b0\u4e0b\u5217\u4e8b\u52a1\u7684\u89e6\u53d1\u3002\n\u6216\u8005\u7ee7\u627f\u81ea",(0,a.kt)("strong",{parentName:"p"},"TouchRpcPluginBase"),"\u7c7b\uff0c\u91cd\u5199\u76f8\u5e94\u65b9\u6cd5\u5373\u53ef\u3002"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"\u63d2\u4ef6\u65b9\u6cd5"),(0,a.kt)("th",{parentName:"tr",align:null},"\u529f\u80fd"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnHandshaking"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5ba2\u6237\u7aef\u5728\u9a8c\u8bc1\u8fde\u63a5\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6846\u67b6\u4f1a\u9996\u5148\u9a8c\u8bc1\u8fde\u63a5Token\u662f\u5426\u6b63\u786e\uff0c\u5982\u679c\u4e0d\u6b63\u786e\u5219\u76f4\u63a5\u62d2\u7edd\u3002\u4e0d\u4f1a\u6709\u4efb\u4f55\u6295\u9012\u3002\u7528\u6237\u4e5f\u53ef\u4ee5\u4f7f\u7528Metadata\u8fdb\u884c\u52a8\u6001\u9a8c\u8bc1\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnHandshaked"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5ba2\u6237\u7aef\u5b8c\u6210\u8fde\u63a5\u9a8c\u8bc1")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnFileTransfering"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u6587\u4ef6\u4f20\u8f93\u5373\u5c06\u8fdb\u884c\u65f6\u89e6\u53d1\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnFileTransfered"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u6587\u4ef6\u4f20\u8f93\u7ed3\u675f\u4e4b\u540e\u3002\u5e76\u4e0d\u610f\u5473\u7740\u5b8c\u6210\u4f20\u8f93\uff0c\u8bf7\u901a\u8fc7e.Result\u5c5e\u6027\u503c\u8fdb\u884c\u5224\u65ad\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnLoadingStream"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u8fdc\u7a0b\u8bf7\u6c42\u52a0\u8f7d\u6d41\u65f6\u89e6\u53d1\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnReceivedProtocolData"),(0,a.kt)("td",{parentName:"tr",align:null},"\u6536\u5230\u534f\u8bae\u6570\u636e")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnRemoteAccessing"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u8fdc\u7a0b\u64cd\u4f5c\u8bbf\u95ee\u4e4b\u524d\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnRemoteAccessed"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u8fdc\u7a0b\u64cd\u4f5c\u8bbf\u95ee\u4e4b\u540e\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnRouting"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u9700\u8981\u8f6c\u53d1\u8def\u7531\u5305\u65f6\u3002\u4e00\u822c\u6240\u6709\u7684",(0,a.kt)("strong",{parentName:"td"},"\u5ba2\u6237\u7aef\u4e4b\u95f4"),"\u7684\u6570\u636e\u4f20\u8f93\uff0c\u90fd\u9700\u8981\u7ecf\u8fc7\u8be5\u51fd\u6570\u7684\u8fd0\u884c\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnStreamTransfering"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5373\u5c06\u63a5\u6536\u6d41\u6570\u636e\uff0c\u7528\u6237\u9700\u8981\u5728\u6b64\u4e8b\u4ef6\u4e2d\u5bf9e.Bucket\u521d\u59cb\u5316\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnStreamTransfered"),(0,a.kt)("td",{parentName:"tr",align:null},"\u6d41\u6570\u636e\u5904\u7406\uff0c\u7528\u6237\u9700\u8981\u5728\u6b64\u4e8b\u4ef6\u4e2d\u5bf9e.Bucket\u624b\u52a8\u91ca\u653e\u3002 \u5f53\u6d41\u6570\u636e\u4f20\u8f93\u7ed3\u675f\u4e4b\u540e\u3002\u5e76\u4e0d\u610f\u5473\u7740\u5b8c\u6210\u4f20\u8f93\uff0c\u8bf7\u901a\u8fc7e.Result\u5c5e\u6027\u503c\u8fdb\u884c\u5224\u65ad\u3002")))),(0,a.kt)("h2",{id:"\u4e94\u521b\u5efa\u670d\u52a1\u5668"},"\u4e94\u3001\u521b\u5efa\u670d\u52a1\u5668"),(0,a.kt)("h3",{id:"51-\u57fa\u4e8etcp\u534f\u8bae"},"5.1 \u57fa\u4e8eTcp\u534f\u8bae"),(0,a.kt)("p",null,"\u8fd9\u662f\u57fa\u4e8eTcp\u534f\u8baeTouchRpc\u3002\u5728\u53ef\u914d\u7f6eTouchRpc\u7684\u57fa\u7840\u4e4b\u4e0a\uff0c\u8fd8\u53ef\u4ee5\u914d\u7f6e\u4e0e",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/createtcpservice#%E5%8F%AF%E9%85%8D%E7%BD%AE%E9%A1%B9"},"TcpService\u53ef\u914d\u7f6e\u9879"),"\u76f8\u5173\u7684\u914d\u7f6e\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new TcpTouchRpcService();\nvar config = new TouchSocketConfig()//\u914d\u7f6e\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n a.AddFileLogger();\n })\n .SetVerifyToken("TouchRpc");//\u8bbe\u5b9a\u8fde\u63a5\u53e3\u4ee4\uff0c\u4f5c\u7528\u7c7b\u4f3c\u8d26\u53f7\u5bc6\u7801\n\nservice.Setup(config)\n .Start();\n\nservice.Logger.Info($"{service.GetType().Name}\u5df2\u542f\u52a8");\n')),(0,a.kt)("h3",{id:"52-\u57fa\u4e8ehttp\u534f\u8bae"},"5.2 \u57fa\u4e8eHttp\u534f\u8bae"),(0,a.kt)("p",null,"\u8fd9\u662f\u57fa\u4e8eHttp\u5347\u7ea7\u534f\u8bae\u3002\u5728\u8be5\u89e3\u6790\u5668\u4e2d\uff0c\u914d\u7f6e\u8bbe\u7f6e",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/createhttpservice"},"HttpService"),"\u4e00\u81f4\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new HttpTouchRpcService();\nTouchSocketConfig config = new TouchSocketConfig()//\u914d\u7f6e\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n a.AddFileLogger();\n })\n .SetVerifyToken("TouchRpc");\n\nservice.Setup(config)\n .Start();\n\nservice.Logger.Info($"{service.GetType().Name}\u5df2\u542f\u52a8");\n')),(0,a.kt)("h3",{id:"53-\u57fa\u4e8eudp\u534f\u8bae"},"5.3 \u57fa\u4e8eUdp\u534f\u8bae"),(0,a.kt)("p",null,"\u8fd9\u662f\u57fa\u4e8eUDP\u534f\u8bae\u89e3\u6790\u5668\u3002\u5728\u8be5\u89e3\u6790\u5668\u4e2d\uff0c\u914d\u7f6e\u8bbe\u7f6e\u4e0e",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/createudpsession"},"UdpSession"),"\u4e00\u81f4\u3002\u56e0\u4e3audp\u662f\u65e0\u8fde\u63a5\u7684\uff0c\u6240\u4ee5\u4e0d\u9700\u8981SetVerifyToken\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new UdpTouchRpc();\nTouchSocketConfig config = new TouchSocketConfig()//\u914d\u7f6e\n .SetBindIPHost(new IPHost(7789))\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n a.AddFileLogger();\n });\n\nservice.Setup(config)\n .Start();\n\nservice.Logger.Info($"{service.GetType().Name}\u5df2\u542f\u52a8");\n')),(0,a.kt)("h3",{id:"54-\u57fa\u4e8easpnetcore\u7684websocket\u534f\u8bae"},"5.4 \u57fa\u4e8eAspNetCore\u7684Websocket\u534f\u8bae"),(0,a.kt)("p",null,"\u5177\u4f53\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"nuget \u5b89\u88c5",(0,a.kt)("inlineCode",{parentName:"li"},"TouchSocket.AspNetCore"),"\u6216\u8005",(0,a.kt)("inlineCode",{parentName:"li"},"TouchSocketPro.AspNetCore"),"\u3002"),(0,a.kt)("li",{parentName:"ol"},"IServiceCollection\u6dfb\u52a0AddWSTouchRpc\uff0c\u5e76\u8fdb\u884c\u76f8\u5173\u914d\u7f6e\uff08\u4e0d\u7528\u914d\u7f6e\u7aef\u53e3\uff0c\u4f1a\u548casp\u4f7f\u7528\u540c\u4e00\u7aef\u53e3\uff09\u3002"),(0,a.kt)("li",{parentName:"ol"},"IApplicationBuilder\u5fc5\u987b\u5148\u4f7f\u7528UseWebSockets\u3002"),(0,a.kt)("li",{parentName:"ol"},"IApplicationBuilder\u8c03\u7528UseWSTouchRpc\uff0c\u5e76\u4f20\u5165url\u8bbe\u7f6e\u3002")),(0,a.kt)("p",null,"\u5728ConfigureServices\u65f6\uff0c\u6dfb\u52a0AddWSTouchRpc\uff0c\u5e76\u4e14\u914d\u7f6e\u76f8\u5173\u9879\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'public void ConfigureServices(IServiceCollection services)\n{\n //\u5411Asp\u670d\u52a1\u4e2d\u6dfb\u52a0IWSTouchRpcService\n services.AddWSTouchRpc(new TouchSocketConfig()\n .UseAspNetCoreContainer(services));//\u8bbe\u7f6eIOC\u5bb9\u5668\n\n services.AddControllers();\n\n services.AddSwaggerGen(c =>\n {\n c.SwaggerDoc("v1", new OpenApiInfo { Title = "API Demo", Version = "v1" });\n });\n}\n')),(0,a.kt)("p",null,"\u542f\u7528\u4e2d\u95f4\u4ef6"),(0,a.kt)("p",null,"\u9996\u5148\u5fc5\u987b\u542f\u7528WebSocket\u3002\u5176\u6b21\u4f7f\u7528UseWSTouchRpc\u5373\u53ef\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},' public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n {\n\n if (env.IsDevelopment())\n {\n app.UseDeveloperExceptionPage();\n }\n\n // Swagger\n app.UseSwagger();\n app.UseSwaggerUI(c =>\n {\n c.SwaggerEndpoint("/swagger/v1/swagger.json", "API Demo v1");\n });\n\n\n app.UseWebSockets();//\u5fc5\u987b\u5148\u4f7f\u7528WebSocket\n app.UseWSTouchRpc("/wstouchrpc");//\u8be5\u64cd\u4f5c\u4e0d\u4f1a\u5f71\u54cd\u539f\u6709\u7684WebSocket\uff0c\u53ea\u8981url\u4e0d\u540c\u5373\u53ef\u3002\n\n app.UseRouting();\n\n app.UseAuthorization();\n\n app.UseEndpoints(endpoints =>\n {\n endpoints.MapControllers();\n });\n }\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/223951e7.8d06409f.js b/handbook/build/assets/js/223951e7.8d06409f.js new file mode 100644 index 000000000..b1ebe60f7 --- /dev/null +++ b/handbook/build/assets/js/223951e7.8d06409f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[631],{3905:(e,t,n)=>{n.d(t,{Zo:()=>i,kt:()=>d});var r=n(7294);function c(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(c[n]=e[n]);return c}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(c[n]=e[n])}return c}var l=r.createContext({}),s=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},i=function(e){var t=s(e.components);return r.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},v=r.forwardRef((function(e,t){var n=e.components,c=e.mdxType,a=e.originalType,l=e.parentName,i=p(e,["components","mdxType","originalType","parentName"]),v=s(n),d=c,m=v["".concat(l,".").concat(d)]||v[d]||u[d]||a;return n?r.createElement(m,o(o({ref:t},i),{},{components:n})):r.createElement(m,o({ref:t},i))}));function d(e,t){var n=arguments,c=t&&t.mdxType;if("string"==typeof e||c){var a=n.length,o=new Array(a);o[0]=v;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p.mdxType="string"==typeof e?e:c,o[1]=p;for(var s=2;s{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>p,toc:()=>s});var r=n(7462),c=(n(7294),n(3905));const a={id:"eventbus",title:"EventBus"},o=void 0,p={unversionedId:"eventbus",id:"eventbus",title:"EventBus",description:"\u8bf4\u660e",source:"@site/docs/eventbus.mdx",sourceDirName:".",slug:"/eventbus",permalink:"/touchsocket/docs/eventbus",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/eventbus.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"eventbus",title:"EventBus"},sidebar:"docs",previous:{title:"b.\u8fdc\u7a0b\u6d41\u8bbf\u95ee",permalink:"/touchsocket/docs/remotestreamaccess"},next:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/webapidescription"}},l={},s=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u521b\u5efa\u670d\u52a1\u5668",id:"\u521b\u5efa\u670d\u52a1\u5668",level:2},{value:"\u521b\u5efa\u5ba2\u6237\u7aef",id:"\u521b\u5efa\u5ba2\u6237\u7aef",level:2},{value:"\u670d\u52a1\u5668\u89e6\u53d1",id:"\u670d\u52a1\u5668\u89e6\u53d1",level:2},{value:"\u5176\u4ed6",id:"\u5176\u4ed6",level:2}],i={toc:s};function u(e){let{components:t,...n}=e;return(0,c.kt)("wrapper",(0,r.Z)({},i,n,{components:t,mdxType:"MDXLayout"}),(0,c.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,c.kt)("p",null,"EventBus\u529f\u80fd\u662f\u4f01\u4e1a\u7248\u4e13\u5c5e\u529f\u80fd\uff0c\u5176\u804c\u80fd\u7c7b\u4f3cMQTT\u7684\u53d1\u5e03\u8ba2\u9605\u6a21\u5f0f\uff0c\u4e5f\u7c7b\u4f3cRabbitMQ\u7684Sub\u6a21\u5f0f\u3002\u5982\u679c\u6ca1\u6709\u4f7f\u7528\u5bc6\u94a5\uff0c\u53ef\u4ee5",(0,c.kt)("a",{parentName:"p",href:"https://www.yuque.com/eo2w71/rrqm/80696720a95e415d94c87fa03642513d#Dfy2T"},"\u8bd5\u7528"),"\u53c2\u8003\u3002 ",(0,c.kt)("a",{name:"cmsde"})),(0,c.kt)("h2",{id:"\u521b\u5efa\u670d\u52a1\u5668"},"\u521b\u5efa\u670d\u52a1\u5668"),(0,c.kt)("p",null,"\u670d\u52a1\u5668\u7684\u521b\u5efa\u5c31\u662fTouchRpc\u670d\u52a1\u5668\u3002\u9664udp\u534f\u8bae\u5916\uff0ctcp\u3001http\u3001websocket\u534f\u8bae\u7684\u7248\u672c\u5747\u652f\u6301\u8be5\u529f\u80fd\u3002"),(0,c.kt)("p",null,"\u4e0b\u5217\u4ee5TcpTouchRpcService\u4e3a\u4f8b\u3002"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-csharp"},"TcpTouchRpcService tcpRpcService = new TcpTouchRpcService();\n\nvar config = new RRQMConfig();\nconfig.SetListenIPHosts(new IPHost[] { new RRQMSocket.IPHost(7789) });\ntcpRpcService\n .Setup(config)\n .Start();\n\n")),(0,c.kt)("p",null,"\u7531",(0,c.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u53d1\u5e03\u4e00\u4e2a\u4e8b\u4ef6\u3002\n\u7b2c\u4e00\u4e2a\u53c2\u6570\u4e3a\u4e8b\u4ef6\u540d\uff0c\u7b2c\u4e8c\u4e2a\u4e3a\u8bbf\u95ee\u6743\u9650\u3002"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-csharp"},'tcpRpcService.PublishEvent("Hello", AccessType.Owner | AccessType.Service | AccessType.Everyone);\n')),(0,c.kt)("a",{name:"fesMG"}),(0,c.kt)("h2",{id:"\u521b\u5efa\u5ba2\u6237\u7aef"},"\u521b\u5efa\u5ba2\u6237\u7aef"),(0,c.kt)("p",null,"\u5ba2\u6237\u7aef\u8ba2\u9605\u8be5\u4e8b\u4ef6\u3002"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClient tcpRpcClient = new TcpTouchRpcClient();\ntcpRpcClient\n .Setup("127.0.0.1:7789")\n .Connect();\n\ntcpRpcClient.SubscribeEvent("Hello", SubscribeEvent);\n\n')),(0,c.kt)("p",null,"\u5176\u4e2dSubscribeEvent\u662f\u63a5\u6536\u59d4\u6258\u3002\u6b64\u5904\u7528\u65b9\u6cd5\u8f6c\u6362\u63a5\u6536\u3002\u5176\u76ee\u7684\u4e3a\uff0c\u5f53\u670d\u52a1\u5668\u89e6\u53d1\u8be5\u65b9\u6cd5\u65f6\uff0c\u5c31\u4f1a\u5206\u53d1\u5230\u6b64\u5904\u3002"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-csharp"},' private void SubscribeEvent(EventSender eventSender, string arg)\n {\n this.ShowMsg($"\u4ece{eventSender.RaiseSourceType}\u6536\u5230\u901a\u77e5\u4e8b\u4ef6{eventSender.EventName}\uff0c\u4fe1\u606f\uff1a{arg}");\n }\n')),(0,c.kt)("a",{name:"lwUT0"}),(0,c.kt)("h2",{id:"\u670d\u52a1\u5668\u89e6\u53d1"},"\u670d\u52a1\u5668\u89e6\u53d1"),(0,c.kt)("p",null,"\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4e8b\u4ef6\u540d\uff0c\u7b2c\u4e8c\u4e2a\u662f\u4e8b\u4ef6\u53c2\u6570\u3002\u53ef\u4ee5\u662f\u4efb\u610f\u7c7b\u578b\uff0c\u4f46\u662f\u76ee\u524d\u4ec5\u652f\u6301\u4e00\u4e2a\u53c2\u6570\u3002"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-csharp"},'tcpRpcService.RaiseEvent("Hello", "Hi");\n')),(0,c.kt)("a",{name:"cLPrt"}),(0,c.kt)("h2",{id:"\u5176\u4ed6"},"\u5176\u4ed6"),(0,c.kt)("p",null,"\u5b9e\u9645\u4e0a\u5728TouchRpc\u67b6\u6784\u4e2d\u3002",(0,c.kt)("strong",{parentName:"p"},"TouchService"),"\u3001",(0,c.kt)("strong",{parentName:"p"},"TouchSocketClient"),"\u3001",(0,c.kt)("strong",{parentName:"p"},"TouchClient"),"\u4e09\u8005\u5747\u5df2\u5b9e\u73b0",(0,c.kt)("strong",{parentName:"p"},"IEventObject"),"\u63a5\u53e3\uff0c\u8fd9\u610f\u5473\u5747\u53ef\u4ee5",(0,c.kt)("strong",{parentName:"p"},"\u53d1\u5e03\u3001\u53d6\u6d88\u53d1\u5e03\u3001\u8ba2\u9605\u3001\u53d6\u6d88\u8ba2\u9605\u3001\u89e6\u53d1"),"\u7b49\u64cd\u4f5c\uff08\u4f1a\u9a8c\u8bc1\u64cd\u4f5c\u6743\u9650\uff09\u3002"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/28d8f037.a45d1145.js b/handbook/build/assets/js/28d8f037.a45d1145.js new file mode 100644 index 000000000..d2b941085 --- /dev/null +++ b/handbook/build/assets/js/28d8f037.a45d1145.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[505],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},d=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),u=l(r),m=o,f=u["".concat(p,".").concat(m)]||u[m]||s[m]||a;return r?n.createElement(f,c(c({ref:t},d),{},{components:r})):n.createElement(f,c({ref:t},d))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=u;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>s,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"adapterdemodescription",title:"\u8bf4\u660e"},c=void 0,i={unversionedId:"adapterdemodescription",id:"adapterdemodescription",title:"\u8bf4\u660e",description:"\u8bf4\u660e",source:"@site/docs/adapterdemodescription.mdx",sourceDirName:".",slug:"/adapterdemodescription",permalink:"/touchsocket/docs/adapterdemodescription",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/adapterdemodescription.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675317340,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"adapterdemodescription",title:"\u8bf4\u660e"},sidebar:"docs",previous:{title:"a.\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668",permalink:"/touchsocket/docs/udpdatahandlingadapter"},next:{title:"\u56fd\u7f51\u8f93\u7535i1\u6807\u51c6\u7248",permalink:"/touchsocket/docs/stategridtransmission"}},p={},l=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u63d0\u4ea4\u8981\u6c42",id:"\u63d0\u4ea4\u8981\u6c42",level:2}],d={toc:l};function s(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,o.kt)("p",null,"\u6b64\u9875\u9762\u5c55\u793a\u7528\u6237\u901a\u8fc7TouchSocket\u81ea\u884c\u5b9e\u73b0\u7684\u9002\u914d\u5668\u6848\u4f8b\u3002\u66f4\u597d\u7684\u5171\u4eab\u8d44\u6e90\u3002"),(0,o.kt)("p",null,"\u6b22\u8fce\u5927\u5bb6\u63d0\u4ea4\u66f4\u591a\u3002\u90ae\u7bb1\uff1a",(0,o.kt)("a",{parentName:"p",href:"mailto:505554090@qq.com"},"505554090@qq.com")),(0,o.kt)("h2",{id:"\u63d0\u4ea4\u8981\u6c42"},"\u63d0\u4ea4\u8981\u6c42"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"\u901a\u8fc7\u5355\u5143\u6d4b\u8bd5\u3002"),(0,o.kt)("li",{parentName:"ol"},"\u7f16\u7801\u5c3d\u53ef\u80fd\u89c4\u8303\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/2c06b999.5646f61e.js b/handbook/build/assets/js/2c06b999.5646f61e.js new file mode 100644 index 000000000..60c726f3e --- /dev/null +++ b/handbook/build/assets/js/2c06b999.5646f61e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[5983],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=o,k=d["".concat(s,".").concat(m)]||d[m]||u[m]||a;return n?r.createElement(k,i(i({ref:t},c),{},{components:n})):r.createElement(k,i({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:o,i[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=n(7462),o=(n(7294),n(3905));const a={id:"createudpsession",title:"\u521b\u5efaUdpSession"},i=void 0,l={unversionedId:"createudpsession",id:"createudpsession",title:"\u521b\u5efaUdpSession",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/createudpsession.mdx",sourceDirName:".",slug:"/createudpsession",permalink:"/touchsocket/docs/createudpsession",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createudpsession.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675572697,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"createudpsession",title:"\u521b\u5efaUdpSession"},sidebar:"docs",previous:{title:"\u5176\u4ed6\u573a\u666f\u5e94\u7528",permalink:"/touchsocket/docs/tcpother"},next:{title:"\u4f20\u8f93\u5927\u4e8e64K\u7684\u6570\u636e",permalink:"/touchsocket/docs/udptransmitbigdata"}},s={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4ea7\u54c1\u7279\u70b9",id:"\u4e8c\u4ea7\u54c1\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4ea7\u54c1\u5e94\u7528\u573a\u666f",id:"\u4e09\u4ea7\u54c1\u5e94\u7528\u573a\u666f",level:2},{value:"\u56db\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",id:"\u56db\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",level:2},{value:"\u56db\u3001\u4f7f\u7528UdpSession",id:"\u56db\u4f7f\u7528udpsession",level:2}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("p",null,"UDP\u7ec4\u4ef6\u662f\u57fa\u4e8eUDP\u534f\u8bae\u7684\u6700\u57fa\u7840\u7ec4\u4ef6\uff0c\u5176\u529f\u80fd\u7b80\u5355\uff0c\u6613\u7528\u3002\u5b83\u65e2\u80fd\u5145\u5f53\u670d\u52a1\u5668\uff0c\u53c8\u80fd\u591f\u4f5c\u4e3a\u5ba2\u6237\u7aef\u3002"),(0,o.kt)("h2",{id:"\u4e8c\u4ea7\u54c1\u7279\u70b9"},"\u4e8c\u3001\u4ea7\u54c1\u7279\u70b9"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"\u7b80\u5355\u6613\u7528\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u591a\u7ebf\u7a0b\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u5185\u5b58\u6c60"),(0,o.kt)("li",{parentName:"ul"},"\u9ad8\u6027\u80fd")),(0,o.kt)("h2",{id:"\u4e09\u4ea7\u54c1\u5e94\u7528\u573a\u666f"},"\u4e09\u3001\u4ea7\u54c1\u5e94\u7528\u573a\u666f"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"UDP\u57fa\u7840\u4f7f\u7528\u573a\u666f\uff1a\u53ef\u8de8\u5e73\u53f0\u3001\u8de8\u8bed\u8a00\u4f7f\u7528\u3002")),(0,o.kt)("h2",{id:"\u56db\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"},"\u56db\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"),(0,o.kt)("p",null,"\u58f0\u660e\u81ea\u5b9a\u4e49\u5b9e\u4f8b\u7c7b\uff0c\u7136\u540e\u5b9e\u73b0",(0,o.kt)("strong",{parentName:"p"},"IUdpSessionPlugin"),"\u63a5\u53e3\uff0c\u5373\u53ef\u5b9e\u73b0\u4e0b\u5217\u4e8b\u52a1\u7684\u89e6\u53d1\u3002\u6216\u8005\u7ee7\u627f\u81ea",(0,o.kt)("strong",{parentName:"p"},"UdpSessionPluginBase"),"\u7c7b\uff0c\u91cd\u5199\u76f8\u5e94\u65b9\u6cd5\u5373\u53ef\u3002"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"\u63d2\u4ef6\u65b9\u6cd5"),(0,o.kt)("th",{parentName:"tr",align:null},"\u529f\u80fd"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"OnReceivedData"),(0,o.kt)("td",{parentName:"tr",align:null},"\u5728\u6536\u5230\u6570\u636e\u65f6\u89e6\u53d1")))),(0,o.kt)("h2",{id:"\u56db\u4f7f\u7528udpsession"},"\u56db\u3001\u4f7f\u7528UdpSession"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'UdpSession udpSession = new UdpSession();\nudpSession.Received += (remote, byteBlock,requestInfo) =>\n{\n udpSession.Send(remote, byteBlock);\n Console.WriteLine($"\u6536\u5230\uff1a{Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len)}");\n};\nudpSession.Setup(new TouchSocketConfig()\n .SetBindIPHost(new IPHost(7789)))\n .Start();\nConsole.WriteLine("\u7b49\u5f85\u63a5\u6536");\n\n')),(0,o.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,o.kt)("ol",{parentName:"admonition"},(0,o.kt)("li",{parentName:"ol"},"\u5373\u4f7f\u4e0d\u76d1\u542c\u5730\u5740\uff0cSetup\u548cStart\u90fd\u662f\u5fc5\u987b\u8981\u7684\u3002"),(0,o.kt)("li",{parentName:"ol"},"\u5f53udp\u4f5c\u4e3a\u5ba2\u6237\u7aef\u65f6\uff0cConfig\u5982\u679c\u4e0d\u8bbe\u7f6eSetBindIPHost\uff0c\u5c06\u4e0d\u4f1a\u63a5\u6536\uff0c\u5982\u679c\u4e0d\u77e5\u9053\u7ed1\u5b9a\u90a3\u4e2a\u7aef\u53e3\uff0c\u53ef\u4ee5\u76f4\u63a5\u7ed1\u5b9a0\u7aef\u53e3\uff0c\u8fd9\u6837\uff0c\u5c31\u4f1a\u4f7f\u7528\u7cfb\u7edf\u7a7a\u95f2\u7684\u4e00\u4e2a\u7aef\u53e3\u4e86\u3002"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/3030335d.3367d96e.js b/handbook/build/assets/js/3030335d.3367d96e.js new file mode 100644 index 000000000..c3e934ed1 --- /dev/null +++ b/handbook/build/assets/js/3030335d.3367d96e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2289],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>k});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},d=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},s=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),s=p(r),k=a,m=s["".concat(l,".").concat(k)]||s[k]||u[k]||o;return r?n.createElement(m,c(c({ref:t},d),{},{components:r})):n.createElement(m,c({ref:t},d))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=s;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var n=r(7462),a=(r(7294),r(3905));const o={id:"fixedheaderpackageadapter",title:"\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668"},c=void 0,i={unversionedId:"fixedheaderpackageadapter",id:"fixedheaderpackageadapter",title:"\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/fixedheaderpackageadapter.mdx",sourceDirName:".",slug:"/fixedheaderpackageadapter",permalink:"/touchsocket/docs/fixedheaderpackageadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/fixedheaderpackageadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675577572,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"fixedheaderpackageadapter",title:"\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"a.\u6b63\u5e38\u6570\u636e\u5904\u7406\u9002\u914d\u5668",permalink:"/touchsocket/docs/normaldatahandlingadapter"},next:{title:"\u56fa\u5b9a\u957f\u5ea6\u6570\u636e\u5904\u7406\u9002\u914d\u5668",permalink:"/touchsocket/docs/fixedsizepackageadapter"}},l={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u534f\u8bae\u7b97\u6cd5",id:"\u4e09\u534f\u8bae\u7b97\u6cd5",level:2},{value:"\u56db\u3001\u4f7f\u7528",id:"\u56db\u4f7f\u7528",level:2}],d={toc:p};function u(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u662f\u5904\u7406\u7c98\u5305\u3001\u5206\u5305\u95ee\u9898\u7684\u6700\u6709\u529b\u3001\u6700\u53ef\u9760\u3001\u6700\u9ad8\u6548\u3001\u6700\u7a33\u5b9a\u7684\u4e00\u79cd\u65b9\u6848\uff0c\u5b83\u57fa\u672c\u4e0a\u9002\u7528\u4e8e",(0,a.kt)("strong",{parentName:"p"},"\u6240\u6709\u573a\u666f"),"\u3002\u5373\u4f7f",(0,a.kt)("strong",{parentName:"p"},"\u8de8\u8bed\u8a00"),"\u4f7f\u7528\uff0c\u4e5f\u53ea\u9700\u8981\u5728\u5176\u4ed6\u8bed\u8a00\u4e2d\u8bbe\u8ba1",(0,a.kt)("strong",{parentName:"p"},"\u76f8\u540c\u7b97\u6cd5"),"\u5c31\u53ef\u4ee5\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u6700\u6709\u529b\u7684\u89e3\u51b3\u7c98\u5305\u3002\u5206\u5305\u95ee\u9898\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u662f\u81ea\u5b9a\u4e49\u534f\u8bae\u7684\u4e0d\u4e8c\u9009\u62e9\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u652f\u6301\u6307\u5b9a\u5305\u5934\u957f\u5ea6\uff0cByte\u3001Ushort\u3001Int\u4e09\u79cd\u7c7b\u578b\u4f5c\u4e3a\u5305\u5934\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u6700\u597d\u5728\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u4f7f\u7528TouchSocket\u7ec4\u4ef6\u65f6\u4f7f\u7528\u3002\u4e0d\u7136\u5c31\u9700\u8981\u975eTouchSocket\u7684\u4e00\u65b9\u9002\u914d\u5305\u5934\u7b97\u6cd5\u3002")),(0,a.kt)("h2",{id:"\u4e09\u534f\u8bae\u7b97\u6cd5"},"\u4e09\u3001\u534f\u8bae\u7b97\u6cd5"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Byte\u5305\u5934\u7b97\u6cd5\uff1a\u4ee5\u7b2c\u4e00\u4e2a\u5b57\u8282\u4f5c\u4e3a\u540e\u7eed\u6574\u4e2a\u6570\u636e\u7684\u957f\u5ea6\uff0c\u6574\u4e2a\u6570\u636e\u957f\u5ea6\u533a\u95f4\u4e3a","[0,255]","\u3002"),(0,a.kt)("li",{parentName:"ul"},"Ushort\u5305\u5934\u7b97\u6cd5\uff1a\u524d2\u4e2a\u5b57\u8282\uff0c\u4e14\u4e3a",(0,a.kt)("a",{parentName:"li",href:"/touchsocket/docs/touchsocketbitconverter#%E5%9B%9B%E9%BB%98%E8%AE%A4%E7%AB%AF"},"\u9ed8\u8ba4\u7aef\u5e8f\uff08\u5c0f\u7aef\uff09"),"\u7684\u6392\u5217\uff0c\u4f5c\u4e3a\u540e\u7eed\u6574\u4e2a\u6570\u636e\u7684\u957f\u5ea6\uff0c\u6574\u4e2a\u6570\u636e\u957f\u5ea6\u533a\u95f4\u4e3a","[0,65535]","\u3002"),(0,a.kt)("li",{parentName:"ul"},"Int\u5305\u5934\u7b97\u6cd5\uff08\u9ed8\u8ba4\u914d\u7f6e\uff09\uff1a\u524d4\u4e2a\u5b57\u8282\uff0c\u4e14\u4e3a",(0,a.kt)("a",{parentName:"li",href:"/touchsocket/docs/touchsocketbitconverter#%E5%9B%9B%E9%BB%98%E8%AE%A4%E7%AB%AF"},"\u9ed8\u8ba4\u7aef\u5e8f\uff08\u5c0f\u7aef\uff09"),"\u6392\u5217\uff0c\u4f5c\u4e3a\u540e\u7eed\u6574\u4e2a\u6570\u636e\u7684\u957f\u5ea6\uff0c\u6574\u4e2a\u6570\u636e\u957f\u5ea6\u533a\u95f4\u4e3a","[0,2^31]","\u3002")),(0,a.kt)("h2",{id:"\u56db\u4f7f\u7528"},"\u56db\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002\u4e0b\u5217\u4ee5\u670d\u52a1\u5668\u4e3a\u4f8b\u3002"),(0,a.kt)("p",null,"\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e\uff08\u53ef\u4ee5\u540c\u65f6\u6307\u5b9aHeaderType\u7b49\u5c5e\u6027\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684ByteBlock\u8bfb\u53d6\u6570\u636e\u3002")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{10}","{10}":!0},"TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u5ba2\u6237\u7aef\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(() => { return new FixedHeaderPackageAdapter() { FixedHeaderType= FixedHeaderType.Int }; }))//\u914d\u7f6e\u9002\u914d\u5668\n .Start();//\u542f\u52a8\n")),(0,a.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"\u63a5\u6536\u7684\u6570\u636e\u957f\u5ea6\u662fbyteBlock.Len\uff0c\u800c\u4e0d\u662fbyteBlock.Buffer.Length\u3002")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u8be5\u9002\u914d\u5668\uff0c\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/320af078.69561817.js b/handbook/build/assets/js/320af078.69561817.js new file mode 100644 index 000000000..26b90bf55 --- /dev/null +++ b/handbook/build/assets/js/320af078.69561817.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6373],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,l=d(e,["components","mdxType","originalType","parentName"]),u=c(n),f=a,m=u["".concat(p,".").concat(f)]||u[f]||s[f]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=u;var d={};for(var p in t)hasOwnProperty.call(t,p)&&(d[p]=t[p]);d.originalType=e,d.mdxType="string"==typeof e?e:a,i[1]=d;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>s,frontMatter:()=>o,metadata:()=>d,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={id:"udpdatahandlingadapter",sidebar_position:1,title:"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668",sidebar_label:"a.\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668"},i=void 0,d={unversionedId:"udpdatahandlingadapter",id:"udpdatahandlingadapter",title:"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668",description:"\u8bf4\u660e",source:"@site/docs/udpdatahandlingadapter.mdx",sourceDirName:".",slug:"/udpdatahandlingadapter",permalink:"/touchsocket/docs/udpdatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/udpdatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675229490,formattedLastUpdatedAt:"Feb 1, 2023",sidebarPosition:1,frontMatter:{id:"udpdatahandlingadapter",sidebar_position:1,title:"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668",sidebar_label:"a.\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u4e09\u5143\u7ec4\u7f16\u7801\uff08TLV\uff09\u9002\u914d\u5668",permalink:"/touchsocket/docs/tlvdatahandlingadapter"},next:{title:"\u8bf4\u660e",permalink:"/touchsocket/docs/adapterdemodescription"}},p={},c=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u5355\u5143\u6d4b\u8bd5",id:"\u5355\u5143\u6d4b\u8bd5",level:2}],l={toc:c};function s(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,a.kt)("p",null,"Udp\u7684\u9002\u914d\u5668\uff0c\u4e3b\u8981\u627f\u62c5\u7ec4\u5305\u548c\u89e3\u6790\u6570\u636e\u3002\u5176\u57fa\u672c\u903b\u8f91\u548cTcp\u76f8\u4f3c\u3002\u4f46\u662f\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0cUdp\u9002\u914d\u5668\u662f",(0,a.kt)("strong",{parentName:"p"},"\u591a\u7ebf\u7a0b"),"\u64cd\u4f5c\u3002\u5728\u89e3\u6790\u6570\u636e\u65f6\uff0c\u5e94\u5f53\u5145\u5206\u8003\u8651\u5e76\u53d1\u95ee\u9898\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyUdpAdatper : UdpDataHandlingAdapter\n{\n public override bool CanSplicingSend => false;\n\n protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock)\n {\n \n }\n\n protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length, bool isAsync)\n {\n \n }\n\n protected override void PreviewSend(EndPoint endPoint, IList transferBytes, bool isAsync)\n {\n \n }\n\n protected override void Reset()\n {\n \n }\n}\n")),(0,a.kt)("h2",{id:"\u5355\u5143\u6d4b\u8bd5"},"\u5355\u5143\u6d4b\u8bd5"),(0,a.kt)("p",null,"\u4f7f\u7528",(0,a.kt)("strong",{parentName:"p"},"UdpDataAdapterTester"),"\u5373\u53ef\u6d4b\u8bd5\u3002"))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/329302c4.249a948b.js b/handbook/build/assets/js/329302c4.249a948b.js new file mode 100644 index 000000000..92de7a8c8 --- /dev/null +++ b/handbook/build/assets/js/329302c4.249a948b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[230],{2776:s=>{s.exports=JSON.parse('{"name":"@easyops-cn/docusaurus-search-local","id":"default"}')}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/355b4941.b6bf168d.js b/handbook/build/assets/js/355b4941.b6bf168d.js new file mode 100644 index 000000000..8f0c225d0 --- /dev/null +++ b/handbook/build/assets/js/355b4941.b6bf168d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[5683],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var o=r.createContext({}),s=function(e){var t=r.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(o.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,o=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=s(n),m=i,k=d["".concat(o,".").concat(m)]||d[m]||u[m]||a;return n?r.createElement(k,l(l({ref:t},c),{},{components:n})):r.createElement(k,l({ref:t},c))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,l=new Array(a);l[0]=d;var p={};for(var o in t)hasOwnProperty.call(t,o)&&(p[o]=t[o]);p.originalType=e,p.mdxType="string"==typeof e?e:i,l[1]=p;for(var s=2;s{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>l,default:()=>u,frontMatter:()=>a,metadata:()=>p,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));const a={id:"createhttpservice",title:"\u521b\u5efaHttpService"},l=void 0,p={unversionedId:"createhttpservice",id:"createhttpservice",title:"\u521b\u5efaHttpService",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/createhttpservice.mdx",sourceDirName:".",slug:"/createhttpservice",permalink:"/touchsocket/docs/createhttpservice",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createhttpservice.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675609832,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"createhttpservice",title:"\u521b\u5efaHttpService"},sidebar:"docs",previous:{title:"8.5 \u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5",permalink:"/touchsocket/docs/dataadaptertester"},next:{title:"\u521b\u5efaHttpClient",permalink:"/touchsocket/docs/createhttpclient"}},o={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4ea7\u54c1\u7279\u70b9",id:"\u4e8c\u4ea7\u54c1\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4ea7\u54c1\u5e94\u7528\u573a\u666f",id:"\u4e09\u4ea7\u54c1\u5e94\u7528\u573a\u666f",level:2},{value:"\u56db\u3001\u670d\u52a1\u5668\u67b6\u6784",id:"\u56db\u670d\u52a1\u5668\u67b6\u6784",level:2},{value:"\u4e94\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",id:"\u4e94\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",level:2},{value:"\u516d\u3001\u521b\u5efaHttpService",id:"\u516d\u521b\u5efahttpservice",level:2},{value:"\u4e03\u3001\u521b\u5efa\u52a0\u5bc6Ssl\u7684HttpsService",id:"\u4e03\u521b\u5efa\u52a0\u5bc6ssl\u7684httpsservice",level:2}],c={toc:s};function u(e){let{components:t,...a}=e;return(0,i.kt)("wrapper",(0,r.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"HttpService"),"\u662f\u80fd\u591f\u63d0\u4f9bHttp\u76f8\u5173\u670d\u52a1\u7684\u57fa\u7840\u7c7b\u578b\u3002"),(0,i.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("strong",{parentName:"p"},"HttpService"),"\u4ec5\u4ec5\u652f\u6301\u7b80\u5355\u7684web\u670d\u52a1\uff0c\u5982\u679c\u662f\u548cTouchSocket\u7684\u5176\u4ed6\u7ec4\u4ef6\u914d\u5408\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528\uff0c\u5982\u679c\u60f3\u5355\u72ec\u4f5c\u4e3aweb\u670d\u52a1\u5668\uff0c\u5219",(0,i.kt)("strong",{parentName:"p"},"\u6700\u597d\u4e0d\u8981"),"\u4f7f\u7528\u3002\u56e0\u4e3a\u5176\u517c\u5bb9\u6027\u6bd4\u8f83\u8584\u5f31\u3002")),(0,i.kt)("h2",{id:"\u4e8c\u4ea7\u54c1\u7279\u70b9"},"\u4e8c\u3001\u4ea7\u54c1\u7279\u70b9"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"\u652f\u6301HTTPS\u3002"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"\u591a\u79cd\u6570\u636e\u63a5\u6536\u6a21\u5f0f")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"\u591a\u5730\u5740\u76d1\u542c"),"\uff08\u53ef\u4ee5\u4e00\u6b21\u6027\u76d1\u542c\u591a\u4e2aIP\u53ca\u7aef\u53e3\uff09")),(0,i.kt)("h2",{id:"\u4e09\u4ea7\u54c1\u5e94\u7528\u573a\u666f"},"\u4e09\u3001\u4ea7\u54c1\u5e94\u7528\u573a\u666f"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"HTTP\u57fa\u7840\u4f7f\u7528\u573a\u666f\uff1a\u53ef\u8de8\u5e73\u53f0\u3001\u8de8\u8bed\u8a00\u4f7f\u7528\u3002")),(0,i.kt)("h2",{id:"\u56db\u670d\u52a1\u5668\u67b6\u6784"},"\u56db\u3001\u670d\u52a1\u5668\u67b6\u6784"),(0,i.kt)("p",null,"\u670d\u52a1\u5668\u5728\u6536\u5230\u65b0\u5ba2\u6237\u7aef\u8fde\u63a5\u65f6\uff0c\u4f1a\u521b\u5efa\u4e00\u4e2aHttpSocketClient\u7684\u6d3e\u751f\u7c7b\u5b9e\u4f8b\uff0c\u4e0e\u8fdc\u7a0bHttpClient\u5bf9\u5e94\uff0c\u540e\u7eed\u7684\u6570\u636e\u901a\u4fe1\u5747\u7531\u6b64\u5b9e\u4f8b\u8d1f\u8d23\u3002"),(0,i.kt)("img",{src:n(3948).Z,width:"500"}),(0,i.kt)("h2",{id:"\u4e94\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"},"\u4e94\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"),(0,i.kt)("p",null,"\u58f0\u660e\u81ea\u5b9a\u4e49\u5b9e\u4f8b\u7c7b\uff0c\u7136\u540e\u5b9e\u73b0",(0,i.kt)("strong",{parentName:"p"},"IHttpPlugin"),"\u63a5\u53e3\uff0c\u5373\u53ef\u5b9e\u73b0\u4e0b\u5217\u4e8b\u52a1\u7684\u89e6\u53d1\u3002\u6216\u8005\u7ee7\u627f\u81ea",(0,i.kt)("strong",{parentName:"p"},"HttpPluginBase"),"\u7c7b\uff0c\u91cd\u5199\u76f8\u5e94\u65b9\u6cd5\u5373\u53ef\u3002"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"\u63d2\u4ef6\u65b9\u6cd5"),(0,i.kt)("th",{parentName:"tr",align:null},"\u529f\u80fd"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},"OnDelete"),(0,i.kt)("td",{parentName:"tr",align:null},"\u5f53\u6536\u5230Delete\u8bf7\u6c42\u65f6")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},"OnGet"),(0,i.kt)("td",{parentName:"tr",align:null},"\u5f53\u6536\u5230OnGet\u8bf7\u6c42\u65f6")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},"OnPost"),(0,i.kt)("td",{parentName:"tr",align:null},"\u5f53\u6536\u5230OnPost\u8bf7\u6c42\u65f6")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},"OnPut"),(0,i.kt)("td",{parentName:"tr",align:null},"\u5f53\u6536\u5230OnPut\u8bf7\u6c42\u65f6")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},"OnReceivedOtherHttpRequest"),(0,i.kt)("td",{parentName:"tr",align:null},"\u5f53\u6536\u5230OnReceivedOtherHttpRequest\u8bf7\u6c42\u65f6")))),(0,i.kt)("h2",{id:"\u516d\u521b\u5efahttpservice"},"\u516d\u3001\u521b\u5efaHttpService"),(0,i.kt)("p",null,"HttpService\u7684\u521b\u5efa\uff0c\u57fa\u672c\u548cTcpService\u4e00\u81f4\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f\u5b9e\u73b0\uff0c\u4e0b\u5217\u4ec5\u6f14\u793a\u6700\u7b80\u5355\u5b9e\u73b0\u3002"),(0,i.kt)("p",null,"HttpService\u7684\u76f8\u5173\u4e8b\u52a1\uff0c\u4f1a\u901a\u8fc7",(0,i.kt)("strong",{parentName:"p"},"\u63d2\u4ef6"),"\u89e6\u53d1\u3002"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-csharp"},"var service = new HttpService();\nservice.Setup(new TouchSocketConfig()//\u52a0\u8f7d\u914d\u7f6e\n .UsePlugin()\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n })\n .ConfigurePlugins(a =>\n {\n a.Add();\n\n //default\u63d2\u4ef6\u5e94\u8be5\u6700\u540e\u6dfb\u52a0\uff0c\u5176\u4f5c\u7528\u662f\n //1\u3001\u4e3a\u627e\u4e0d\u5230\u7684\u8def\u7531\u8fd4\u56de404\n //2\u3001\u5904\u7406header\u4e3aOption\u7684\u63a2\u89c6\u8de8\u57df\u8bf7\u6c42\u3002\n a.UseDefaultHttpServicePlugin();\n\n }))\n .Start();\n")),(0,i.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"DefaultHttpServicePlugin\u63d2\u4ef6\u6700\u597d\u6dfb\u52a0\u5728\u63d2\u4ef6\u4e2d\uff0c\u5982\u679c\u6ca1\u6709\u6dfb\u52a0\u7684\u8bdd\uff0c\u6700\u597d\u81ea\u5df1\u505a\u597d\u7f3a\u7701\u8def\u7531\u548c\u8de8\u57df\u914d\u7f6e\u3002")),(0,i.kt)("p",null,"\u5728\u63d2\u4ef6\u4e2d\uff0c\u901a\u8fc7",(0,i.kt)("strong",{parentName:"p"},"\u91cd\u5199"),"\uff08\u6216\u5b9e\u73b0\uff09\u7684\u65b9\u5f0f\uff0c\u8fdb\u5165",(0,i.kt)("strong",{parentName:"p"},"OnGet"),"\u3001",(0,i.kt)("strong",{parentName:"p"},"OnPost"),"\u3001",(0,i.kt)("strong",{parentName:"p"},"OnDelete"),"\u3001",(0,i.kt)("strong",{parentName:"p"},"OnPut"),"\u7b49\u51fd\u6570\uff0c\u5373\u53ef\u5904\u7406\u5bf9\u5e94\u8bf7\u6c42\u3002"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-csharp"},'/// \n/// \u652f\u6301GET\u3001Post\u3001Put\uff0cDelete\uff0c\u6216\u8005\u5176\u4ed6\n/// \ninternal class MyHttpPlug : HttpPluginBase\n{\n protected override void OnGet(HttpSocketClient client, HttpContextEventArgs e)\n {\n if (e.Context.Request.UrlEquals("/success"))\n {\n //\u76f4\u63a5\u54cd\u5e94\u6587\u5b57\n e.Context.Response.FromText("Success").Answer();//\u76f4\u63a5\u56de\u5e94\n Console.WriteLine("\u5904\u7406\u5b8c\u6bd5");\n e.Handled = true;\n }\n else if (e.Context.Request.UrlEquals("/file"))\n {\n //\u76f4\u63a5\u56de\u5e94\u6587\u4ef6\u3002\n e.Context.Response\n .SetStatus()//\u5fc5\u987b\u8981\u6709\u72b6\u6001\n .FromFile(@"D:\\System\\Windows.iso", e.Context.Request);\n }\n else if (e.Context.Request.UrlEquals("/html"))\n {\n //\u56de\u5e94html\n StringBuilder stringBuilder = new StringBuilder();\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("TouchSocket");\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("
");\n stringBuilder.AppendLine("\u738b\u4e8c\u9ebb\u5b50");\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("
");\n stringBuilder.AppendLine("");\n stringBuilder.AppendLine("");\n\n e.Context.Response\n .SetStatus()//\u5fc5\u987b\u8981\u6709\u72b6\u6001\n .SetContentTypeByExtension(".html")\n .SetContent(stringBuilder.ToString());\n e.Context.Response.Answer();\n }\n }\n\n protected override void OnPost(HttpSocketClient client, HttpContextEventArgs e)\n {\n \n }\n}\n')),(0,i.kt)("h2",{id:"\u4e03\u521b\u5efa\u52a0\u5bc6ssl\u7684httpsservice"},"\u4e03\u3001\u521b\u5efa\u52a0\u5bc6Ssl\u7684HttpsService"),(0,i.kt)("p",null,"Https\u670d\u52a1\u5668\uff0c\u548chttp\u670d\u52a1\u5668\u51e0\u4e4e\u4e00\u6837\uff0c\u53ea\u4e0d\u8fc7\u589e\u52a0\u4e86\u4e00\u4e2aSsl\u7684\u914d\u7f6e\u3002"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-csharp"},'.SetServiceSslOption(new ServiceSslOption() \n{ \n Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"), \n SslProtocols = SslProtocols.Tls12 \n}))\n')))}u.isMDXComponent=!0},3948:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/createhttpservice-1-4b8f923700c533fb1182b7775268246c.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/389c2360.baae9616.js b/handbook/build/assets/js/389c2360.baae9616.js new file mode 100644 index 000000000..c07730ce8 --- /dev/null +++ b/handbook/build/assets/js/389c2360.baae9616.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1687],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),u=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},l=function(e){var t=u(e.components);return r.createElement(c.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),y=u(n),d=a,p=y["".concat(c,".").concat(d)]||y[d]||m[d]||o;return n?r.createElement(p,s(s({ref:t},l),{},{components:n})):r.createElement(p,s({ref:t},l))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=y;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:a,s[1]=i;for(var u=2;u{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var r=n(7462),a=(n(7294),n(3905));const o={id:"stategridtransmission",title:"\u56fd\u7f51\u8f93\u7535i1\u6807\u51c6\u7248"},s=void 0,i={unversionedId:"stategridtransmission",id:"stategridtransmission",title:"\u56fd\u7f51\u8f93\u7535i1\u6807\u51c6\u7248",description:"\u8bf4\u660e",source:"@site/docs/stategridtransmission.mdx",sourceDirName:".",slug:"/stategridtransmission",permalink:"/touchsocket/docs/stategridtransmission",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/stategridtransmission.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675586056,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"stategridtransmission",title:"\u56fd\u7f51\u8f93\u7535i1\u6807\u51c6\u7248"},sidebar:"docs",previous:{title:"\u8bf4\u660e",permalink:"/touchsocket/docs/adapterdemodescription"},next:{title:"\u72ec\u7acb\u4f7f\u7528\u9002\u914d\u5668",permalink:"/touchsocket/docs/independentusedatahandlingadapter"}},c={},u=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u7248\u6743",id:"\u7248\u6743",level:2},{value:"\u534f\u8bae\u7c7b\u578b",id:"\u534f\u8bae\u7c7b\u578b",level:2},{value:"\u4ee3\u7801",id:"\u4ee3\u7801",level:2}],l={toc:u};function m(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,a.kt)("p",null,"\u672c\u4ee3\u7801\u4ec5\u9002\u7528\u4ee5\u4e0b\u534f\u8bae\u3002\n\u534f\u8bae\u4e2d\uff0c\u7531Packet","_","Length\u8868\u793a\u5e8f\u53f77-11\u7684\u957f\u5ea6\u3002\u4e5f\u5c31\u662fPacket","_","Length=N+2+2+1+1\u3002\n\u4f46\u662f\u5728\u8bbe\u8ba1\u65f6\uff0c\u4f1a\u5c06\u5e8f\u53f71-10\uff0c\u89c6\u4e3a\u56fa\u5b9a\u5305\u5934\u3002\u5e8f\u53f711-13\u4e3aBody\u3002"),(0,a.kt)("h2",{id:"\u7248\u6743"},"\u7248\u6743"),(0,a.kt)("p",null,"\u8be5\u4ee3\u7801\u6240\u6709\u7248\u6743\u5f52\u82e5\u6c5d\u68cb\u8317\u6240\u6709\uff0c\u4f7f\u7528\u65f6\u8bf7\u52a1\u5fc5\u6ce8\u660e\u3002"),(0,a.kt)("h2",{id:"\u534f\u8bae\u7c7b\u578b"},"\u534f\u8bae\u7c7b\u578b"),(0,a.kt)("h2",{id:"\u4ee3\u7801"},"\u4ee3\u7801"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"using TouchSocket.Core;\nusing TouchSocket.Sockets;\n\nnamespace AdapterConsoleApp\n{\n /// \n /// \u56fd\u7f51\u8f93\u7535i1\u6807\u51c6\u7248\n /// \n internal class SGCCCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter\n {\n public override int HeaderLength => 30;\n\n public override bool CanSendRequestInfo => false;\n\n protected override SGCCRequestInfo GetInstance()\n {\n return new SGCCRequestInfo();\n }\n\n protected override void PreviewSend(IRequestInfo requestInfo)\n {\n throw new System.NotImplementedException();\n }\n }\n\n public class SGCCRequestInfo : IFixedHeaderRequestInfo\n {\n private byte[] m_sync;\n private int m_bodyLength;\n private byte[] m_cMDID;\n private byte[] m_sample;\n private byte[] m_cRC16;\n\n public int BodyLength { get => m_bodyLength; }\n\n /// \n /// \u62a5\u6587\u5934:5AA5\n /// \n public byte[] Sync { get => m_sync; set => m_sync = value; }\n\n /// \n /// \u62a5\u6587\u957f\u5ea6\n /// \n public ushort PacketLength { get => (ushort)(this.m_bodyLength - 3); }\n\n /// \n /// \u72b6\u6001\u76d1\u6d4b\u88c5\u7f6eID(17\u4f4d\u7f16\u7801)\n /// \n public byte[] CMDID { get => m_cMDID; set => m_cMDID = value; }\n\n /// \n /// \u5e27\u7c7b\u578b\u2014\u53c2\u8003\u9644\u8868C8-1\u76f8\u5173\u542b\u4e49\n /// \n public byte FrameType { get; set; }\n\n /// \n /// \u62a5\u6587\u7c7b\u578b\u2014\u53c2\u8003\u9644\u8868C8-2\u76f8\u5173\u542b\u4e49\n /// \n public byte PacketType { get; set; }\n\n /// \n /// \u5e27\u5e8f\u5217\u53f7\uff08\u65e0\u7b26\u53f7\u6574\u6570)\n /// \n public byte FrameNo { get; set; }\n\n /// \n /// \u901a\u9053\u53f7\u2014\u8868\u793a\u91c7\u96c6\u88c5\u7f6e\u4e0a\u7684\u6444\u50cf\u673a\u7f16\u53f7\u3002\u5982:\u4e00\u4e2a\u88c5\u8fde\u63a5\u2489\u90e8\u6444\u50cf\u673a\uff0c\u5219\u5206\u522b\u6807\u53f7\u4e3a1\u30012\n /// \n public byte ChannelNo { get; set; }\n\n /// \n /// \u9884\u7f6e\u4f4d\u53f7\u2014\u5373\u4e91\u53f0\u6444\u50cf\u6240\u8bbe\u7f6e\u7684\u9884\u7f6e\u4f4d\u53f7,\u4e0d\u5e26\u4e91\u53f0\u6444\u50cf\u673a\uff0c\u9884\u7f6e\u4f4d\u53f7\u4e3a255\n /// \n public byte PresettingNo { get; set; }\n\n /// \n /// \u603b\u5305\u6570\uff08\u65e0\u7b26\u53f7\u6574\u6570\uff0c\u53d6\u503c\u8303\u56f4:\u5927\u4e8e\u7b49\u4e8e0)\n /// \n public ushort PacketNo { get; set; }\n\n /// \n /// \u5b50\u5305\u5305\u53f7\uff08\u65e0\u7b26\u53f7\u6574\u6570\uff0c\u53d6\u503c\u8303\u56f4:\u5927\u4e8e\u7b49\u4e8e0>\n /// \n public ushort SubpacketNo { get; set; }\n\n /// \n /// \u6570\u636e\u533a\n /// \n public byte[] Sample { get => m_sample; set => m_sample = value; }\n\n /// \n /// \u6821\u9a8c\u4f4d\n /// \n public byte[] CRC16 { get => m_cRC16; }\n\n /// \n /// \u62a5\u6587\u5c3e:0x96\n /// \n public byte End { get; set; }\n\n public bool OnParsingHeader(byte[] header)\n {\n if (header.Length == 30)\n {\n using (ByteBlock byteBlock = new ByteBlock(header))\n {\n byteBlock.Pos = 0;\n byteBlock.Read(out m_sync, 2);\n\n byte[] lenBuffer;\n byteBlock.Read(out lenBuffer, 2);\n\n this.m_bodyLength = TouchSocketBitConverter.LittleEndian.ToUInt16(lenBuffer, 0) + 3 - 6;//\u5148\u628acrc\u6821\u9a8c\u548cend\u90fd\u83b7\u53d6\u3002\n byteBlock.Read(out m_cMDID, 17);\n this.FrameType = (byte)byteBlock.ReadByte();\n this.PacketType = (byte)byteBlock.ReadByte();\n this.FrameNo = (byte)byteBlock.ReadByte();\n this.ChannelNo = (byte)byteBlock.ReadByte();\n this.PresettingNo = (byte)byteBlock.ReadByte();\n this.PacketNo = byteBlock.ReadUInt16();\n this.SubpacketNo = byteBlock.ReadUInt16();\n\n return true;\n }\n }\n return false;\n }\n\n public bool OnParsingBody(byte[] body)\n {\n if (body.Length == this.BodyLength && body[^1] == 150)\n {\n using (ByteBlock byteBlock = new ByteBlock(body))\n {\n byteBlock.Read(out this.m_sample, this.m_bodyLength - 3);\n byteBlock.Read(out this.m_cRC16, 2);\n this.End = (byte)byteBlock.ReadByte();\n }\n return true;\n }\n return false;\n }\n }\n}\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/3ab343cc.9358ed6d.js b/handbook/build/assets/js/3ab343cc.9358ed6d.js new file mode 100644 index 000000000..dadc96ee7 --- /dev/null +++ b/handbook/build/assets/js/3ab343cc.9358ed6d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[5873],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>g});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),s=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(c.Provider,{value:t},e.children)},k={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(n),g=r,d=u["".concat(c,".").concat(g)]||u[g]||k[g]||l;return n?a.createElement(d,o(o({ref:t},p),{},{components:n})):a.createElement(d,o({ref:t},p))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=u;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:r,o[1]=i;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>k,frontMatter:()=>l,metadata:()=>i,toc:()=>s});var a=n(7462),r=(n(7294),n(3905));const l={id:"createwebsocketservice",title:"\u521b\u5efaWebSocket\u670d\u52a1\u5668"},o=void 0,i={unversionedId:"createwebsocketservice",id:"createwebsocketservice",title:"\u521b\u5efaWebSocket\u670d\u52a1\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/createwebsocketservice.mdx",sourceDirName:".",slug:"/createwebsocketservice",permalink:"/touchsocket/docs/createwebsocketservice",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createwebsocketservice.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"createwebsocketservice",title:"\u521b\u5efaWebSocket\u670d\u52a1\u5668"},sidebar:"docs",previous:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/websocketdescription"},next:{title:"\u521b\u5efaWebSocket\u5ba2\u6237\u7aef",permalink:"/touchsocket/docs/createwebsocketclient"}},c={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u53ef\u914d\u7f6e\u9879",id:"\u4e8c\u53ef\u914d\u7f6e\u9879",level:2},{value:"\u4e09\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",id:"\u4e09\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",level:2},{value:"IWebSocketPlugin",id:"iwebsocketplugin",level:3},{value:"\u56db\u3001\u521b\u5efaWebSocket\u670d\u52a1",id:"\u56db\u521b\u5efawebsocket\u670d\u52a1",level:2},{value:"4.1 \u7b80\u5355\u901a\u8fc7\u63d2\u4ef6\u521b\u5efa",id:"41-\u7b80\u5355\u901a\u8fc7\u63d2\u4ef6\u521b\u5efa",level:3},{value:"4.2 \u901a\u8fc7WebApi\u521b\u5efa",id:"42-\u901a\u8fc7webapi\u521b\u5efa",level:3},{value:"\u521b\u5efa\u57fa\u4e8eSsl\u7684WebSocket\u670d\u52a1",id:"\u521b\u5efa\u57fa\u4e8essl\u7684websocket\u670d\u52a1",level:2},{value:"\u63a5\u6536\u6d88\u606f",id:"\u63a5\u6536\u6d88\u606f",level:2},{value:"\u56de\u590d\u3001\u54cd\u5e94\u6570\u636e",id:"\u56de\u590d\u54cd\u5e94\u6570\u636e",level:2}],p={toc:s};function k(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"WebSocket\u662f\u57fa\u4e8eHttp\u534f\u8bae\u7684\u5347\u7ea7\u534f\u8bae\uff0c\u6240\u4ee5\u5e94\u5f53\u6302\u8f7d\u5728http\u670d\u52a1\u5668\u6267\u884c\u3002"),(0,r.kt)("h2",{id:"\u4e8c\u53ef\u914d\u7f6e\u9879"},"\u4e8c\u3001\u53ef\u914d\u7f6e\u9879"),(0,r.kt)("p",null,"\u7ee7\u627fHttpService"),(0,r.kt)("h2",{id:"\u4e09\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"},"\u4e09\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"),(0,r.kt)("p",null,"\u652f\u6301",(0,r.kt)("strong",{parentName:"p"},"ITcpPlugin\u3001IHttpPlugin\u3001IWebSocketPlugin")),(0,r.kt)("h3",{id:"iwebsocketplugin"},"IWebSocketPlugin"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null}),(0,r.kt)("th",{parentName:"tr",align:null}))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"OnHandshaking"),(0,r.kt)("td",{parentName:"tr",align:null},"\u8868\u793a\u5728\u5373\u5c06\u63e1\u624b\u8fde\u63a5\u65f6\u3002")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"OnHandshaked"),(0,r.kt)("td",{parentName:"tr",align:null},"\u8868\u793a\u5b8c\u6210\u63e1\u624b\u540e\u3002")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"OnHandleWSDataFrame"),(0,r.kt)("td",{parentName:"tr",align:null},"\u5f53\u6536\u5230WS\u6570\u636e\u65f6\u3002")))),(0,r.kt)("h2",{id:"\u56db\u521b\u5efawebsocket\u670d\u52a1"},"\u56db\u3001\u521b\u5efaWebSocket\u670d\u52a1"),(0,r.kt)("h3",{id:"41-\u7b80\u5355\u901a\u8fc7\u63d2\u4ef6\u521b\u5efa"},"4.1 \u7b80\u5355\u901a\u8fc7\u63d2\u4ef6\u521b\u5efa"),(0,r.kt)("p",null,"\u901a\u8fc7\u63d2\u4ef6\u521b\u5efa\u7684\u8bdd\uff0c\u53ea\u80fd\u6307\u5b9a\u4e00\u4e2a\u7279\u6b8aurl\u8def\u7531\u3002\u5982\u679c\u60f3\u83b7\u5f97\u8fde\u63a5\u524d\u7684Http\u8bf7\u6c42\uff0c\u4e5f\u5fc5\u987b\u518d\u6dfb\u52a0\u4e00\u4e2a\u5b9e\u73b0IWebSocketPlugin\u63a5\u53e3\u7684\u63d2\u4ef6\uff0c\u7136\u540e\u4eceOnHandshaking\u65b9\u6cd5\u4e2d\u6355\u83b7\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new HttpService();\nservice.Setup(new TouchSocketConfig()//\u52a0\u8f7d\u914d\u7f6e\n .UsePlugin()\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigureContainer(a =>\n {\n a.SetSingletonLogger();\n })\n .ConfigurePlugins(a =>\n {\n a.Add()//\u6dfb\u52a0WebSocket\u529f\u80fd\n .SetWSUrl("/ws")\n .SetCallback(WSCallback);//WSCallback\u56de\u8c03\u51fd\u6570\u662f\u5728WS\u6536\u5230\u6570\u636e\u65f6\u89e6\u53d1\u56de\u8c03\u7684\u3002\n a.Add();//MyWebSocketPlugin\u662f\u7ee7\u627f\u81eaWebSocketPluginBase\u7684\u63d2\u4ef6\u3002\n }))\n .Start();\n\nConsole.WriteLine("Http\u670d\u52a1\u5668\u5df2\u542f\u52a8");\nConsole.WriteLine("ws://127.0.0.1:7789/ws");\n\n')),(0,r.kt)("h3",{id:"42-\u901a\u8fc7webapi\u521b\u5efa"},"4.2 \u901a\u8fc7WebApi\u521b\u5efa"),(0,r.kt)("p",null,"\u901a\u8fc7WebApi\u7684\u65b9\u5f0f\u4f1a\u66f4\u52a0\u7075\u6d3b\uff0c\u4e5f\u80fd\u5f88\u65b9\u4fbf\u7684\u83b7\u5f97Http\u76f8\u5173\u53c2\u6570\u3002\u8fd8\u80fd\u5b9e\u73b0\u591a\u4e2aUrl\u7684\u8fde\u63a5\u8def\u7531\u3002\n\u5b9e\u73b0\u6b65\u9aa4\uff1a"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"\u5fc5\u987b\u542f\u7528\u63d2\u4ef6"),(0,r.kt)("li",{parentName:"ol"},"\u5fc5\u987b\u914d\u7f6eConfigureRpcStore\uff0c\u548c\u6ce8\u518cMyServer"),(0,r.kt)("li",{parentName:"ol"},"\u5fc5\u987b\u6dfb\u52a0WebApiParserPlugin")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new HttpService();\nservice.Setup(new TouchSocketConfig()//\u52a0\u8f7d\u914d\u7f6e\n .UsePlugin()\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigureContainer(a =>\n {\n a.SetSingletonLogger();\n })\n .ConfigureRpcStore(a=> \n {\n a.RegisterServer();\n })\n .ConfigurePlugins(a =>\n {\n a.Add();\n }))\n .Start();\n\nConsole.WriteLine("\u670d\u52a1\u5668\u5df2\u542f\u52a8\uff0c\u53ef\u4f7f\u7528\u4e0b\u5217\u5730\u5740\u8fde\u63a5");\nConsole.WriteLine("ws://127.0.0.1:7789/MyServer/ConnectWS");\n')),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyServer : RpcServer\n{\n private readonly ILog m_logger;\n\n public MyServer(ILog logger)\n {\n this.m_logger = logger;\n }\n\n [Router("/[api]/[action]")]\n [WebApi(HttpMethodType.GET, MethodFlags = MethodFlags.IncludeCallContext)]\n public void ConnectWS(IWebApiCallContext callContext)\n {\n if (callContext.Caller is HttpSocketClient socketClient)\n {\n if (socketClient.SwitchProtocolToWebSocket(callContext.Context))\n {\n m_logger.Message("WS\u901a\u8fc7WebApi\u8fde\u63a5");\n }\n }\n }\n}\n')),(0,r.kt)("a",{name:"d6n7d"}),(0,r.kt)("h2",{id:"\u521b\u5efa\u57fa\u4e8essl\u7684websocket\u670d\u52a1"},"\u521b\u5efa\u57fa\u4e8eSsl\u7684WebSocket\u670d\u52a1"),(0,r.kt)("p",null,"\u521b\u5efaWSs\u670d\u52a1\u5668\u65f6\uff0c\u5176\u4ed6\u914d\u7f6e\u4e0d\u53d8\uff0c\u53ea\u9700\u8981\u5728config\u4e2d\u914d\u7f6eSslOption\u4ee3\u7801\u5373\u53ef\u3002\n\u5728",(0,r.kt)("a",{parentName:"p",href:"https://gitee.com/RRQM_Home/RRQMBox/tree/master/Ssl%E8%AF%81%E4%B9%A6%E7%9B%B8%E5%85%B3"},"RRQMBox"),"\u4e2d\uff0c\u653e\u7f6e\u4e86\u4e00\u4e2a\u81ea\u5236Ssl\u8bc1\u4e66\uff0c\u5bc6\u7801\u4e3a\u201cRRQMSocket\u201d\u4ee5\u4f9b\u6d4b\u8bd5\u3002\u4f7f\u7528\u914d\u7f6e\u975e\u5e38\u65b9\u4fbf\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'var config = new TouchSocketConfig();\nconfig.UsePlugin()\n .SetReceiveType(ReceiveType.Auto)\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .SetServiceSslOption(new ServiceSslOption() //Ssl\u914d\u7f6e\uff0c\u5f53\u4e3anull\u7684\u65f6\u5019\uff0c\u76f8\u5f53\u4e8e\u521b\u5efa\u4e86ws\u670d\u52a1\u5668\uff0c\u5f53\u8d4b\u503c\u7684\u65f6\u5019\uff0c\u76f8\u5f53\u4e8ewss\u670d\u52a1\u5668\u3002\n { \n Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"), \n SslProtocols = SslProtocols.Tls12 \n });\n')),(0,r.kt)("a",{name:"FQrdu"}),(0,r.kt)("h2",{id:"\u63a5\u6536\u6d88\u606f"},"\u63a5\u6536\u6d88\u606f"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"\u3010\u56de\u8c03\u63a5\u6536\u3011"),"\n\u5728\u6dfb\u52a0",(0,r.kt)("strong",{parentName:"p"},"WebSocketServerPlugin"),"\u63d2\u4ef6\u540e\uff0c\u53ef\u4ee5\u8c03\u7528",(0,r.kt)("strong",{parentName:"p"},"SetCallback"),"\u51fd\u6570\uff0c\u7136\u540e\u8bbe\u7f6e\u4e00\u4e2a\u56de\u8c03\u51fd\u6570\uff08\u5982\u4e0b\u6240\u793a\uff09\uff0c\u7136\u540e\u8be5\u51fd\u6570\u5728\u670d\u52a1\u5668\u6536\u5230\u4fe1\u606f\u65f6\uff0c\u4f1a\u89e6\u53d1\uff08\u5e76\u53d1\u89e6\u53d1\uff09\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'static void WSCallback(ITcpClientBase client, WSDataFrameEventArgs e)\n{\n switch (e.DataFrame.Opcode)\n {\n case WSDataType.Cont:\n Console.WriteLine($"\u6536\u5230\u4e2d\u95f4\u6570\u636e\uff0c\u957f\u5ea6\u4e3a\uff1a{e.DataFrame.PayloadLength}");\n break;\n case WSDataType.Text:\n Console.WriteLine(e.DataFrame.ToText());\n break;\n case WSDataType.Binary:\n if (e.DataFrame.FIN)\n {\n Console.WriteLine($"\u6536\u5230\u4e8c\u8fdb\u5236\u6570\u636e\uff0c\u957f\u5ea6\u4e3a\uff1a{e.DataFrame.PayloadLength}");\n }\n else\n {\n Console.WriteLine($"\u6536\u5230\u672a\u7ed3\u675f\u7684\u4e8c\u8fdb\u5236\u6570\u636e\uff0c\u957f\u5ea6\u4e3a\uff1a{e.DataFrame.PayloadLength}");\n }\n break;\n case WSDataType.Close:\n {\n Console.WriteLine("\u8fdc\u7a0b\u8bf7\u6c42\u65ad\u5f00");\n client.Close("\u65ad\u5f00");\n }\n\n break;\n case WSDataType.Ping:\n break;\n case WSDataType.Pong:\n break;\n default:\n break;\n }\n}\n')),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"\u3010\u7ee7\u627f\u6e90\u63d2\u4ef6\u63a5\u6536\u3011"),"\n\u5b9e\u9645\u4e0a",(0,r.kt)("strong",{parentName:"p"},"WebSocketServerPlugin"),"\u662f\u53ef\u4ee5\u88ab\u7ee7\u627f\u7684\uff0c\u7136\u540e\u91cd\u5199",(0,r.kt)("strong",{parentName:"p"},"OnHandleWSDataFrame"),"\u51fd\u6570\uff0c\u4f46\u5c3d\u91cf",(0,r.kt)("strong",{parentName:"p"},"\u4e0d\u8981\u8986\u76d6"),"\u57fa\u7c7b\u65b9\u6cd5\uff0c\u4e0d\u7136\u63d2\u4ef6\u5176\u4ed6\u5c06\u4e0d\u4f1a\u89e6\u53d1\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyWebSocketServerPlugin: WebSocketServerPlugin\n{\n protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e)\n {\n base.OnHandleWSDataFrame(client, e);\n }\n}\n")),(0,r.kt)("p",null,"\u3010\u63d2\u4ef6\u63a5\u53e3\u63a5\u6536\u3011\nWS\u670d\u52a1\u5668\uff0c\u867d\u7136\u662fHttp\u7684\u63d2\u4ef6\uff0c\u4f46\u662f\u4e5f\u80fd\u89e6\u53d1\u63d2\u4ef6\u63a5\u53e3\u3002\u9002\u7528\u4e8eWS\u7684\u63d2\u4ef6\u63a5\u53e3\u662f",(0,r.kt)("strong",{parentName:"p"},"IWebSocketPlugin"),"\uff08\u6216\u8005\u4ece",(0,r.kt)("strong",{parentName:"p"},"WebSocketPluginBase"),"\u7ee7\u627f\uff09\uff0c\u58f0\u660e\u4efb\u610f\u7c7b\uff0c\u5b9e\u73b0\u8be5\u63a5\u53e3\u5373\u53ef\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyWebSocketServerPlugin: WebSocketPluginBase\n{\n protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e)\n {\n //\u6b64\u5904\u7684\u7236\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u76f4\u63a5\u8986\u76d6\u3002\n base.OnHandleWSDataFrame(client, e);\n }\n}\n")),(0,r.kt)("a",{name:"JKBcN"}),(0,r.kt)("h2",{id:"\u56de\u590d\u54cd\u5e94\u6570\u636e"},"\u56de\u590d\u3001\u54cd\u5e94\u6570\u636e"),(0,r.kt)("p",null,"\u5728\u4ee5\u4e0a\u63a5\u6536\u3001\u6216\u76f4\u63a5\u4eceHttpService\u83b7\u53d6Clients\uff0c\u5c06client\u5bf9\u8c61\u8f6c\u4e3a",(0,r.kt)("strong",{parentName:"p"},"HttpSocketClient"),"\uff0c\u5373\u53ef\u4f7f\u7528",(0,r.kt)("strong",{parentName:"p"},"\u6269\u5c55\u65b9\u6cd5"),"\uff0c\u8fdb\u884c\u53d1\u9001\u3002"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"\u4e0d\u8981\u76f4\u63a5Send\uff0c7.x\u7248\u672c\u76f4\u63a5Send\u53ef\u4ee5\uff0c\u4f468.0\u4ee5\u540e\uff0cSend\u53ea\u4f1a\u4ee5TCP\u6570\u636e\u56de\u5e94\u3002")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"\u4f5c\u4e3a\u4e00\u6761\u6d88\u606f\u53d1\u9001")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668\u5e7f\u64ad\u53d1\u9001")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"//\u5e7f\u64ad\u7ed9\u6240\u6709\u4eba\nif (client is HttpSocketClient socketClient && socketClient.Service is HttpService service)\n{\n var clients = service.GetClients();\n foreach (var item in clients)\n {\n item.SendWithWS(e.DataFrame.ToText());\n }\n}\n")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"\u5c06\u4e00\u4e2a\u6570\u636e\u5206\u5305\u53d1\u9001"),"\n\u4f8b\u5982\uff1a\u53d1\u9001\u7684\u6570\u636e\u4e3a{0,1,2,3,4,5,6,7,8,9}\uff0c\u5f53\u8bbe\u7f6epackageSize\u4e3a5\u65f6\uff0c\u4f1a\u5148\u53d1\u9001{0,1,2,3,4}\u4f5c\u4e3a\u5934\u5305\uff0c\u7136\u540e\u53d1\u9001{5,6,7,8,9}\u7684\u540e\u7ee7\u5305\u3002"))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/3b5f8c2c.9abe936a.js b/handbook/build/assets/js/3b5f8c2c.9abe936a.js new file mode 100644 index 000000000..78aedc1de --- /dev/null +++ b/handbook/build/assets/js/3b5f8c2c.9abe936a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9171],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,l=e.originalType,i=e.parentName,s=a(e,["components","mdxType","originalType","parentName"]),d=p(n),f=o,m=d["".concat(i,".").concat(f)]||d[f]||u[f]||l;return n?r.createElement(m,c(c({ref:t},s),{},{components:n})):r.createElement(m,c({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var l=n.length,c=new Array(l);c[0]=d;var a={};for(var i in t)hasOwnProperty.call(t,i)&&(a[i]=t[i]);a.originalType=e,a.mdxType="string"==typeof e?e:o,c[1]=a;for(var p=2;p{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>c,default:()=>u,frontMatter:()=>l,metadata:()=>a,toc:()=>p});var r=n(7462),o=(n(7294),n(3905));const l={id:"rpcallcontext",title:"\u8c03\u7528\u4e0a\u4e0b\u6587"},c=void 0,a={unversionedId:"rpcallcontext",id:"rpcallcontext",title:"\u8c03\u7528\u4e0a\u4e0b\u6587",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/rpcallcontext.mdx",sourceDirName:".",slug:"/rpcallcontext",permalink:"/touchsocket/docs/rpcallcontext",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/rpcallcontext.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675696587,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"rpcallcontext",title:"\u8c03\u7528\u4e0a\u4e0b\u6587"},sidebar:"docs",previous:{title:"\u5e8f\u5217\u5316\u9009\u62e9\u5668",permalink:"/touchsocket/docs/serializationselector"},next:{title:"Rpc\u670d\u52a1AOP",permalink:"/touchsocket/docs/rpcactionfilter"}},i={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u901a\u8fc7\u6807\u7b7e\u53c2\u6570\u83b7\u53d6",id:"\u4e8c\u901a\u8fc7\u6807\u7b7e\u53c2\u6570\u83b7\u53d6",level:2},{value:"\u4e09\u3001\u901a\u8fc7\u77ac\u65f6\u751f\u547d\u5468\u671f\u83b7\u53d6",id:"\u4e09\u901a\u8fc7\u77ac\u65f6\u751f\u547d\u5468\u671f\u83b7\u53d6",level:2}],s={toc:p};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"RPC\u670d\u52a1\u662f\u65e0\u72b6\u6001\u7684\uff0c\u5373\u53ea\u77e5\u9053\u5f53\u524d\u670d\u52a1\u88ab\u8c03\u7528\uff0c\u4f46\u65e0\u6cd5\u5f97\u77e5\u662f\u88ab\u8c01\u8c03\u7528\uff0c\u8fd9\u4e2a\u95ee\u9898\u7ed9\u65e5\u5fd7\u8bb0\u5f55\u3001RPC\u56de\u8c03\u7b49\u5e26\u6765\u4e86\u5f88\u591a\u9ebb\u70e6\u4e8b\u3002\u4f46\u662f\uff0cTouch\u7684Rpc\u652f\u6301\u8c03\u7528\u4e0a\u4e0b\u6587\u83b7\u53d6\u3002\u5728\u4e0a\u4e0b\u6587\u4e2d\u53ef\u4ee5\u83b7\u5f97\u8c03\u7528\u8005\uff08",(0,o.kt)("inlineCode",{parentName:"p"},"ICaller"),"\uff09\u4fe1\u606f\u7b49\u3002")),(0,o.kt)("h2",{id:"\u4e8c\u901a\u8fc7\u6807\u7b7e\u53c2\u6570\u83b7\u53d6"},"\u4e8c\u3001\u901a\u8fc7\u6807\u7b7e\u53c2\u6570\u83b7\u53d6"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"\u6b65\u9aa4\uff1a")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Rpc\u6807\u7b7e\u9700\u8981\u4f20\u5165",(0,o.kt)("inlineCode",{parentName:"li"},"MethodFlags.IncludeCallContext"),"\u53c2\u6570\u3002"),(0,o.kt)("li",{parentName:"ol"},"\u5b9a\u4e49\u7684\u670d\u52a1\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5fc5\u987b\u662f",(0,o.kt)("inlineCode",{parentName:"li"},"ICallContext"),"\u6216\u5176\u6d3e\u751f\u7c7b\u3002"),(0,o.kt)("li",{parentName:"ol"},"\u6700\u540e\u83b7\u5f97\u5176Caller\u5c5e\u6027\u5373\u53ef\u5f97\u5230\u8c03\u7528\u8005\u3002")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyRpcServer : RpcServer\n{\n [Description("\u767b\u5f55")]\n [TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]//\u4f7f\u7528\u8c03\u7528\u4e0a\u624d\u6587\n public bool Login(ICallContext callContext,string account,string password)\n {\n if (callContext.Caller is TcpTouchRpcSocketClient)\n {\n Console.WriteLine("TcpTouchRpc\u8bf7\u6c42");\n }\n if (account=="123"&&password=="abc")\n {\n return true;\n }\n\n return false;\n }\n}\n')),(0,o.kt)("h2",{id:"\u4e09\u901a\u8fc7\u77ac\u65f6\u751f\u547d\u5468\u671f\u83b7\u53d6"},"\u4e09\u3001\u901a\u8fc7\u77ac\u65f6\u751f\u547d\u5468\u671f\u83b7\u53d6"),(0,o.kt)("p",null,"\u6b65\u9aa4\uff1a"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"\u7ee7\u627fTransientRpcServer\u6216\u8005\u5b9e\u73b0ITransientRpcServer\u63a5\u53e3\u3002")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyRpcServer : TransientRpcServer\n{\n [Description("\u767b\u5f55")]\n [TouchRpc]\n public bool Login(string account,string password)\n {\n if ( this.CallContext.Caller is TcpTouchRpcSocketClient)\n {\n Console.WriteLine("TcpTouchRpc\u8bf7\u6c42");\n }\n if (account=="123"&&password=="abc")\n {\n return true;\n }\n\n return false;\n }\n}\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/41627674.e57effb8.js b/handbook/build/assets/js/41627674.e57effb8.js new file mode 100644 index 000000000..8ecc9ccb3 --- /dev/null +++ b/handbook/build/assets/js/41627674.e57effb8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2894],{3905:(t,e,n)=>{n.d(e,{Zo:()=>s,kt:()=>d});var r=n(7294);function a(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function l(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function o(t){for(var e=1;e=0||(a[n]=t[n]);return a}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(a[n]=t[n])}return a}var c=r.createContext({}),p=function(t){var e=r.useContext(c),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},s=function(t){var e=p(t.components);return r.createElement(c.Provider,{value:e},t.children)},u={inlineCode:"code",wrapper:function(t){var e=t.children;return r.createElement(r.Fragment,{},e)}},m=r.forwardRef((function(t,e){var n=t.components,a=t.mdxType,l=t.originalType,c=t.parentName,s=i(t,["components","mdxType","originalType","parentName"]),m=p(n),d=a,k=m["".concat(c,".").concat(d)]||m[d]||u[d]||l;return n?r.createElement(k,o(o({ref:e},s),{},{components:n})):r.createElement(k,o({ref:e},s))}));function d(t,e){var n=arguments,a=e&&e.mdxType;if("string"==typeof t||a){var l=n.length,o=new Array(l);o[0]=m;var i={};for(var c in e)hasOwnProperty.call(e,c)&&(i[c]=e[c]);i.originalType=t,i.mdxType="string"==typeof t?t:a,o[1]=i;for(var p=2;p{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const l={id:"createhttpclient",title:"\u521b\u5efaHttpClient"},o=void 0,i={unversionedId:"createhttpclient",id:"createhttpclient",title:"\u521b\u5efaHttpClient",description:"\u8bf4\u660e",source:"@site/docs/createhttpclient.mdx",sourceDirName:".",slug:"/createhttpclient",permalink:"/touchsocket/docs/createhttpclient",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createhttpclient.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"createhttpclient",title:"\u521b\u5efaHttpClient"},sidebar:"docs",previous:{title:"\u521b\u5efaHttpService",permalink:"/touchsocket/docs/createhttpservice"},next:{title:"\u9759\u6001\u9875\u9762\u63d2\u4ef6",permalink:"/touchsocket/docs/httpstaticpageplugin"}},c={},p=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u53ef\u914d\u7f6e\u9879",id:"\u53ef\u914d\u7f6e\u9879",level:2},{value:"\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",id:"\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",level:2},{value:"\u521b\u5efaHttpClient",id:"\u521b\u5efahttpclient",level:2},{value:"\u521b\u5efaHttpsClient",id:"\u521b\u5efahttpsclient",level:2},{value:"\u4e3b\u8981\u65b9\u6cd5\u7b80\u4ecb",id:"\u4e3b\u8981\u65b9\u6cd5\u7b80\u4ecb",level:2}],s={toc:p};function u(t){let{components:e,...n}=t;return(0,a.kt)("wrapper",(0,r.Z)({},s,n,{components:e,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,a.kt)("p",null,"HttpClient\u662fHttp\u5ba2\u6237\u7aef\u7c7b\u3002\u4e3b\u8981\u7528\u4e8e\u8bf7\u6c42Http\u62a5\u6587\u3002"),(0,a.kt)("h2",{id:"\u53ef\u914d\u7f6e\u9879"},"\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("p",null,"\u7ee7\u627fTcpClient"),(0,a.kt)("a",{name:"mMhq1"}),(0,a.kt)("h2",{id:"\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"},"\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"),(0,a.kt)("p",null,"\u652f\u6301",(0,a.kt)("strong",{parentName:"p"},"ITcpPlugin"),"\u63a5\u53e3\u3002"),(0,a.kt)("a",{name:"LAsiE"}),(0,a.kt)("h2",{id:"\u521b\u5efahttpclient"},"\u521b\u5efaHttpClient"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'HttpClient client = new HttpClient();\n\nclient.Setup(new TouchSocketConfig()\n .UsePlugin()\n .SetRemoteIPHost(new IPHost("http://localhost:7219")))\n .Connect();//\u5148\u505a\u8fde\u63a5\n\nHttpRequest request = new HttpRequest();\nrequest\n .InitHeaders()\n .SetUrl("/WeatherForecast")\n .SetHost(client.RemoteIPHost.Host)\n .AsGet();\n\nvar respose = client.Request(request, timeout: 1000*10);\nConsole.WriteLine(respose.GetBody());\n')),(0,a.kt)("a",{name:"TixmX"}),(0,a.kt)("h2",{id:"\u521b\u5efahttpsclient"},"\u521b\u5efaHttpsClient"),(0,a.kt)("p",null,"\u5982\u679c\u9700\u8981\u8fde\u63a5\u5230Https\u670d\u52a1\u5668\u3002\u5219\u5fc5\u987b\u624b\u52a8\u914d\u7f6eSsl\u3002\u793a\u4f8b\u5982\u4e0b\uff1a"),(0,a.kt)("p",null,"\u5982\u679c\u670d\u52a1\u5668\u8bc1\u4e66\u662f\u7531",(0,a.kt)("strong",{parentName:"p"},"\u8bc1\u4e66\u673a\u6784\u9881\u53d1"),"\uff0c\u5219\u53ea\u9700\u586b\u5145",(0,a.kt)("strong",{parentName:"p"},"TargetHost"),"\u548c",(0,a.kt)("strong",{parentName:"p"},"SslProtocols"),"\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'SetClientSslOption(new ClientSslOption() { TargetHost = "localhost", SslProtocols = SslProtocols.Tls12 })\n')),(0,a.kt)("p",null,"\u5982\u679c\u670d\u52a1\u5668\u8bc1\u4e66\u662f\u7531",(0,a.kt)("strong",{parentName:"p"},"\u81ea\u5df1\u5236\u4f5c\u7684"),"\uff0c\u5219\u9700\u8981\u52a0\u8f7d\u8bc1\u4e66\u6587\u4ef6\uff0c\u548c\u5fc5\u8981\u7684",(0,a.kt)("strong",{parentName:"p"},"\u9a8c\u8bc1"),"\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'.SetClientSslOption(new ClientSslOption()\n{\n ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") },\n SslProtocols = SslProtocols.Tls12,\n TargetHost = "127.0.0.1",\n CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; }\n}));\n')),(0,a.kt)("a",{name:"mhUPx"}),(0,a.kt)("h2",{id:"\u4e3b\u8981\u65b9\u6cd5\u7b80\u4ecb"},"\u4e3b\u8981\u65b9\u6cd5\u7b80\u4ecb"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},(0,a.kt)("strong",{parentName:"th"},"\u65b9\u6cd5\u540d")),(0,a.kt)("th",{parentName:"tr",align:null},(0,a.kt)("strong",{parentName:"th"},"\u529f\u80fd\u7b80\u4ecb")))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Request"),(0,a.kt)("td",{parentName:"tr",align:null},"\u8bf7\u6c42Http\u6570\u636e\uff0c\u5e76\u7b49\u5f85\u8fd4\u56de")))),(0,a.kt)("a",{name:"loqXr"}),(0,a.kt)("h2",{id:""}))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/41b30073.88c66a11.js b/handbook/build/assets/js/41b30073.88c66a11.js new file mode 100644 index 000000000..f5b5e1415 --- /dev/null +++ b/handbook/build/assets/js/41b30073.88c66a11.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1868],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var i=n.createContext({}),p=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,c=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=p(r),f=o,m=d["".concat(i,".").concat(f)]||d[f]||u[f]||c;return r?n.createElement(m,a(a({ref:t},l),{},{components:r})):n.createElement(m,a({ref:t},l))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=r.length,a=new Array(c);a[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s.mdxType="string"==typeof e?e:o,a[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>a,default:()=>u,frontMatter:()=>c,metadata:()=>s,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const c={id:"wsjsonrpc",title:"\u57fa\u4e8eWS\u7684JsonRpc"},a=void 0,s={unversionedId:"wsjsonrpc",id:"wsjsonrpc",title:"\u57fa\u4e8eWS\u7684JsonRpc",description:"",source:"@site/docs/wsjsonrpc.mdx",sourceDirName:".",slug:"/wsjsonrpc",permalink:"/touchsocket/docs/wsjsonrpc",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/wsjsonrpc.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"wsjsonrpc",title:"\u57fa\u4e8eWS\u7684JsonRpc"},sidebar:"docs",previous:{title:"WSCommandLinePlugin",permalink:"/touchsocket/docs/wscommandlineplugin"},next:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/touchrpcdescription"}},i={},p=[],l={toc:p};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/430053de.80700119.js b/handbook/build/assets/js/430053de.80700119.js new file mode 100644 index 000000000..4cb0509a4 --- /dev/null +++ b/handbook/build/assets/js/430053de.80700119.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[803],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=r.createContext({}),c=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,s=p(e,["components","mdxType","originalType","parentName"]),m=c(n),d=a,k=m["".concat(i,".").concat(d)]||m[d]||u[d]||o;return n?r.createElement(k,l(l({ref:t},s),{},{components:n})):r.createElement(k,l({ref:t},s))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=m;var p={};for(var i in t)hasOwnProperty.call(t,i)&&(p[i]=t[i]);p.originalType=e,p.mdxType="string"==typeof e?e:a,l[1]=p;for(var c=2;c{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>p,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={id:"callwebapi",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1"},l=void 0,p={unversionedId:"callwebapi",id:"callwebapi",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1",description:"\u76f4\u63a5\u8c03\u7528",source:"@site/docs/callwebapi.mdx",sourceDirName:".",slug:"/callwebapi",permalink:"/touchsocket/docs/callwebapi",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/callwebapi.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"callwebapi",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1"},sidebar:"docs",previous:{title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",permalink:"/touchsocket/docs/webapiservice"},next:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/jsonrpcdescription"}},i={},c=[{value:"\u76f4\u63a5\u8c03\u7528",id:"\u76f4\u63a5\u8c03\u7528",level:2},{value:"\u4ee3\u7406\u8c03\u7528RPC",id:"\u4ee3\u7406\u8c03\u7528rpc",level:2},{value:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\uff1f",id:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6",level:3},{value:"\u8c03\u7528",id:"\u8c03\u7528",level:3}],s={toc:c};function u(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u76f4\u63a5\u8c03\u7528"},"\u76f4\u63a5\u8c03\u7528"),(0,a.kt)("p",null,"\u76f4\u63a5\u8c03\u7528\uff0c\u5219\u662f\u4e0d\u4f7f\u7528",(0,a.kt)("strong",{parentName:"p"},"\u4efb\u4f55\u4ee3\u7406"),"\uff0c\u76f4\u63a5Call RPC\uff0c\u4f7f\u7528\u6bd4\u8f83\u7b80\u5355\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u6d4f\u89c8\u5668"),"\u4e5f\u80fd\u76f4\u63a5\u8c03\u7528\u5b9e\u73b0\u3002"),(0,a.kt)("p",null,"\u3010Url\u8bf7\u6c42\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-scheme"},"http://127.0.0.1:7789/ApiServer/Sum?a=10&b=20\n")),(0,a.kt)("p",null,"\u3010HttpClient\u8c03\u7528\u3011\nWebApi\u7684\u5ba2\u6237\u7aef\u548c\u5927\u5bb6\u6240",(0,a.kt)("strong",{parentName:"p"},"\u719f\u8bc6"),"\u7684\u6709\u4e00\u4e9b\u5dee\u8ddd\uff0cTouchSocket\u7684WebApi\u4f7f\u7528\u7684\u662f",(0,a.kt)("strong",{parentName:"p"},"\u5148\u8fde\u63a5"),"\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u540e\u8bf7\u6c42"),"\u7684\u903b\u8f91\u3002\u8bf7\u6c42\u65f6\uff0c\u5148\u6807\u8bb0",(0,a.kt)("strong",{parentName:"p"},"GET/POST"),"\u7684\u51fd\u6570\u3002\u5982\u679c\u662f",(0,a.kt)("strong",{parentName:"p"},"GET"),"\uff0c\u5219\u5fc5\u987b",(0,a.kt)("strong",{parentName:"p"},"\u7559\u7a7aURL"),"\uff0c\u5982\u679c\u662f",(0,a.kt)("strong",{parentName:"p"},"POST"),"\uff0c\u5219\u53ea\u5199URL\u5373\u53ef\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'private static WebApiClient CreateWebApiClient()\n{\n WebApiClient client = new WebApiClient();\n client.Setup("127.0.0.1:7789");\n client.Connect();\n Console.WriteLine("\u8fde\u63a5\u6210\u529f");\n return client;\n}\n')),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-scheme"},'var client = CreateWebApiClient();\n\nint sum1 = client.Invoke("GET:/ApiServer/Sum?a={0}&b={1}", null, 10, 20);\nConsole.WriteLine($"Get\u8c03\u7528\u6210\u529f\uff0c\u7ed3\u679c\uff1a{sum1}");\n\nint sum2 = client.Invoke("POST:/ApiServer/TestPost", null, new MyClass() { A = 10, B = 20 });\nConsole.WriteLine($"Post\u8c03\u7528\u6210\u529f\uff0c\u7ed3\u679c\uff1a{sum2}");\n')),(0,a.kt)("a",{name:"rrWhi"}),(0,a.kt)("h2",{id:"\u4ee3\u7406\u8c03\u7528rpc"},"\u4ee3\u7406\u8c03\u7528RPC"),(0,a.kt)("p",null,"\u4ee3\u7406\u8c03\u7528\u7684\u4fbf\u6377\u5728\u4e8e\uff0c\u4e0d\u7528\u518d\u7ea0\u7ed3\u8c03\u7528\u7684\u53c2\u6570\u7c7b\u578b\u6b63\u4e0d\u6b63\u786e\uff0c\u56e0\u4e3a\u8fd9\u4e9b\uff0c\u4ee3\u7406\u5de5\u5177\u90fd\u4f1a\u66ff\u4f60\u505a\u597d\u3002 ",(0,a.kt)("a",{name:"AbsXl"})),(0,a.kt)("h3",{id:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6"},"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\uff1f"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://www.yuque.com/eo2w71/rrqm/a13509bfc3581f4576861b690b4a809a"},"\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\u8be6\u60c5")," ",(0,a.kt)("a",{name:"jsQUz"})),(0,a.kt)("h3",{id:"\u8c03\u7528"},"\u8c03\u7528"),(0,a.kt)("p",null,"\u5f53\u4ee3\u7406\u88ab\u5ba2\u6237\u7aef\u83b7\u53d6\u4ee5\u540e\uff0c\u5ba2\u6237\u7aef\u9879\u76ee\u4e2d\u4f1a\u591a\u51fa\u4e00\u4e2a",(0,a.kt)("strong",{parentName:"p"},"RRQMProxy"),"\u7684\u6587\u4ef6\uff08\u6216\u8005\u5982\u679c\u662f\u670d\u52a1\u5668\u751f\u6210\u7684\u672c\u5730\u4ee3\u7406\uff0c\u5219\u9700\u8981\u590d\u5236\u5230\u5ba2\u6237\u7aef\u9879\u76ee\u4e2d\uff09\uff0c\u5728\u8be5\u6587\u4ef6\u4e2d\uff0c\u5219\u5305\u542b\u4e86\u6240\u6709\u7684",(0,a.kt)("strong",{parentName:"p"},"\u4ee3\u7406\u65b9\u6cd5"),"\u548c",(0,a.kt)("strong",{parentName:"p"},"\u4ee3\u7406\u7c7b"),"\uff0c\u53ef\u76f4\u63a5\u7531\u4ee3\u7406\u7c7b\u53d1\u8d77\u8c03\u7528\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'int sum3 = client.TestPost(new MyClass() { A = 10, B = 20 });\nConsole.WriteLine($"\u4ee3\u7406\u8c03\u7528\u6210\u529f\uff0c\u7ed3\u679c\uff1a{sum3}");\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/47f1b9ba.cdd48a18.js b/handbook/build/assets/js/47f1b9ba.cdd48a18.js new file mode 100644 index 000000000..18b5cd320 --- /dev/null +++ b/handbook/build/assets/js/47f1b9ba.cdd48a18.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[4929],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),l=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},s=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),d=l(n),f=o,g=d["".concat(p,".").concat(f)]||d[f]||u[f]||a;return n?r.createElement(g,c(c({ref:t},s),{},{components:n})):r.createElement(g,c({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=d;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var l=2;l{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const a={id:"httpstaticpageplugin",title:"\u9759\u6001\u9875\u9762\u63d2\u4ef6"},c=void 0,i={unversionedId:"httpstaticpageplugin",id:"httpstaticpageplugin",title:"\u9759\u6001\u9875\u9762\u63d2\u4ef6",description:"\u9759\u6001\u7f51\u9875\u6258\u7ba1\u63d2\u4ef6\u4ec5\u670d\u52a1\u5668\u652f\u6301",source:"@site/docs/httpstaticpageplugin.mdx",sourceDirName:".",slug:"/httpstaticpageplugin",permalink:"/touchsocket/docs/httpstaticpageplugin",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/httpstaticpageplugin.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"httpstaticpageplugin",title:"\u9759\u6001\u9875\u9762\u63d2\u4ef6"},sidebar:"docs",previous:{title:"\u521b\u5efaHttpClient",permalink:"/touchsocket/docs/createhttpclient"},next:{title:"\u6587\u4ef6\u4f20\u8f93",permalink:"/touchsocket/docs/httpfiletransfer"}},p={},l=[{value:"\u9759\u6001\u7f51\u9875\u6258\u7ba1\u63d2\u4ef6\u4ec5\u670d\u52a1\u5668\u652f\u6301",id:"\u9759\u6001\u7f51\u9875\u6258\u7ba1\u63d2\u4ef6\u4ec5\u670d\u52a1\u5668\u652f\u6301",level:2}],s={toc:l};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u9759\u6001\u7f51\u9875\u6258\u7ba1\u63d2\u4ef6\u4ec5\u670d\u52a1\u5668\u652f\u6301"},"\u9759\u6001\u7f51\u9875\u6258\u7ba1\u63d2\u4ef6\u4ec5\u670d\u52a1\u5668\u652f\u6301"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"HttpStaticPagePlugin"),"\u9759\u6001\u7f51\u9875\u6258\u7ba1\u63d2\u4ef6\uff0c\u662f\u7528\u4e8eHttp\u7684\u5185\u5bb9\u54cd\u5e94\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new HttpService();\n\nvar config = new TouchSocketConfig();\nconfig.UsePlugin()\n .SetReceiveType(ReceiveType.Auto)\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigurePlugins(a =>\n {\n a.Add().AddFolder("../../../../../api");//\u6dfb\u52a0\u9759\u6001\u9875\u9762\u6587\u4ef6\u5939\n });\n\nservice.Setup(config).Start();\nConsole.WriteLine("Http\u670d\u52a1\u5668\u5df2\u542f\u52a8");\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/4972.c5f9020b.js b/handbook/build/assets/js/4972.c5f9020b.js new file mode 100644 index 000000000..961909e60 --- /dev/null +++ b/handbook/build/assets/js/4972.c5f9020b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[4972],{4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(7294),o=n(5999),l=n(1944),r=n(3929);function c(){return a.createElement(a.Fragment,null,a.createElement(l.d,{title:(0,o.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(o.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(o.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(o.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/4c79e569.2b31247d.js b/handbook/build/assets/js/4c79e569.2b31247d.js new file mode 100644 index 000000000..569ed6f33 --- /dev/null +++ b/handbook/build/assets/js/4c79e569.2b31247d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8707],{3905:(e,t,l)=>{l.d(t,{Zo:()=>u,kt:()=>s});var a=l(7294);function n(e,t,l){return t in e?Object.defineProperty(e,t,{value:l,enumerable:!0,configurable:!0,writable:!0}):e[t]=l,e}function r(e,t){var l=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),l.push.apply(l,a)}return l}function o(e){for(var t=1;t=0||(n[l]=e[l]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,l)&&(n[l]=e[l])}return n}var i=a.createContext({}),c=function(e){var t=a.useContext(i),l=t;return e&&(l="function"==typeof e?e(t):o(o({},t),e)),l},u=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},k={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var l=e.components,n=e.mdxType,r=e.originalType,i=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),m=c(l),s=n,d=m["".concat(i,".").concat(s)]||m[s]||k[s]||r;return l?a.createElement(d,o(o({ref:t},u),{},{components:l})):a.createElement(d,o({ref:t},u))}));function s(e,t){var l=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=l.length,o=new Array(r);o[0]=m;var p={};for(var i in t)hasOwnProperty.call(t,i)&&(p[i]=t[i]);p.originalType=e,p.mdxType="string"==typeof e?e:n,o[1]=p;for(var c=2;c{l.d(t,{Z:()=>J});var a=l(7294),n=l(7462);const r=(e,t,l)=>e?"string"==typeof e?e:e[t]||l:l,o={display:"block"},p=e=>{let{size:t,color:l,style:p,...i}=e;const c=p?{...o,...p}:o;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:c},i),a.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:r(l,0,"#333333")}))};p.defaultProps={size:18};const i=p,c={display:"block"},u=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...c,...o}:c;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:r(l,1,"#333333")}))};u.defaultProps={size:18};const k=u,m={display:"block"},s=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...m,...o}:m;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:r(l,1,"#333333")}),a.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:r(l,2,"#333333")}))};s.defaultProps={size:18};const d=s,g={display:"block"},h=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...g,...o}:g;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:r(l,0,"#333333")}))};h.defaultProps={size:18};const N=h,y={display:"block"},T=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...y,...o}:y;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:r(l,0,"#333333")}))};T.defaultProps={size:18};const v=T,f={display:"block"},b=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...f,...o}:f;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:r(l,1,"#333333")}),a.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:r(l,2,"#333333")}))};b.defaultProps={size:18};const x=b,w={display:"block"},C=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...w,...o}:w;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:r(l,1,"#333333")}))};C.defaultProps={size:18};const R=C,Z={display:"block"},E=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...Z,...o}:Z;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:r(l,1,"#333333")}))};E.defaultProps={size:18};const z=E,M={display:"block"},P=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...M,...o}:M;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:r(l,1,"#333333")}))};P.defaultProps={size:18};const S=P,O={display:"block"},I=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...O,...o}:O;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:r(l,0,"#333333")}))};I.defaultProps={size:18};const L=I,q={display:"block"},A=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...q,...o}:q;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:r(l,0,"#333333")}))};A.defaultProps={size:18};const B=A,j={display:"block"},D=e=>{let{size:t,color:l,style:o,...p}=e;const i=o?{...j,...o}:j;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},p),a.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:r(l,0,"#333333")}))};D.defaultProps={size:18};const F=D,H=e=>{let{name:t,...l}=e;switch(t){case"youhua":return a.createElement(i,l);case"dayi":return a.createElement(k,l);case"shengji":return a.createElement(d,l);case"tiaozheng":return a.createElement(N,l);case"gengxin":return a.createElement(v,l);case"wendang":return a.createElement(x,l);case"shanchu":return a.createElement(R,l);case"bug":return a.createElement(z,l);case"xinzeng":return a.createElement(S,l);case"fuwu":return a.createElement(L,l);case"down":return a.createElement(B,l);case"up":return a.createElement(F,l)}return null},V="label_p8vM",W="icon_knQK";function J(e){const{children:t}=e,l={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return a.createElement("label",{className:V,title:t,style:{backgroundColor:l[t].bgColor}},a.createElement(H,{name:l[t].icon,color:"white",size:14,className:W})," ",t)}},7271:(e,t,l)=>{l.r(t),l.d(t,{assets:()=>c,contentTitle:()=>p,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var a=l(7462),n=(l(7294),l(3905)),r=(l(4996),l(510));const o={id:"upgrade",title:"\u5386\u53f2\u66f4\u65b0"},p=void 0,i={unversionedId:"upgrade",id:"upgrade",title:"\u5386\u53f2\u66f4\u65b0",description:"\u5347\u7ea7\u524d\u91cd\u70b9\u5173\u6ce8\u53ef\u80fd\u9020\u6210\u3010\u7834\u574f\u6027\u3011\u7684\u6807\u7b7e\u7c7b\u578b\uff1a\u4fee\u590d\u3001\u8c03\u6574\u3001\u79fb\u9664\u3001\u5347\u7ea7",source:"@site/docs/upgrade.mdx",sourceDirName:".",slug:"/upgrade",permalink:"/touchsocket/docs/upgrade",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/upgrade.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675652422,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"upgrade",title:"\u5386\u53f2\u66f4\u65b0"},sidebar:"docs",previous:{title:"\u8bf4\u660e",permalink:"/touchsocket/docs/"},next:{title:"\u652f\u6301\u4f5c\u8005",permalink:"/touchsocket/docs/donate"}},c={},u=[{value:"v1.2.1",id:"v121",level:2},{value:"v1.1.0",id:"v110",level:2},{value:"v1.0.0",id:"v100",level:2},{value:"\u7248\u672c\u53f7: 0.7.0",id:"\u7248\u672c\u53f7-070",level:2},{value:"\u7248\u672c\u53f7: 0.6.0",id:"\u7248\u672c\u53f7-060",level:2},{value:"\u7248\u672c\u53f7: 0.5.0",id:"\u7248\u672c\u53f7-050",level:2},{value:"\u7248\u672c\u53f7: 0.4.5",id:"\u7248\u672c\u53f7-045",level:2},{value:"\u7248\u672c\u53f7: 0.3.5",id:"\u7248\u672c\u53f7-035",level:2},{value:"\u7248\u672c\u53f7: 0.2.4",id:"\u7248\u672c\u53f7-024",level:2},{value:"\u7248\u672c\u53f7: 0.1.0",id:"\u7248\u672c\u53f7-010",level:2},{value:"1.\u6240\u6709\u7c7b\u7684\u547d\u540d\u7a7a\u95f4\u4fee\u6539\uff0c\u6b64\u5904\u5982\u679c\u7c7b\u578b\u540d\u672a\u4fee\u6539\u7684\u8bdd\uff0c\u53ef\u7531vs\u667a\u80fd\u63d0\u793a\u89e3\u51b3\u3002",id:"1\u6240\u6709\u7c7b\u7684\u547d\u540d\u7a7a\u95f4\u4fee\u6539\u6b64\u5904\u5982\u679c\u7c7b\u578b\u540d\u672a\u4fee\u6539\u7684\u8bdd\u53ef\u7531vs\u667a\u80fd\u63d0\u793a\u89e3\u51b3",level:3},{value:"2.\u7c7b\u578b\u540d\u79f0\u4fee\u6539",id:"2\u7c7b\u578b\u540d\u79f0\u4fee\u6539",level:3},{value:"3.\u4f7f\u7528\u903b\u8f91\u4fee\u6539",id:"3\u4f7f\u7528\u903b\u8f91\u4fee\u6539",level:3}],k={toc:u};function m(e){let{components:t,...o}=e;return(0,n.kt)("wrapper",(0,a.Z)({},k,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("admonition",{type:"tip"},(0,n.kt)("mdxAdmonitionTitle",{parentName:"admonition"},(0,n.kt)("inlineCode",{parentName:"mdxAdmonitionTitle"},"TouchSocket")," \u6846\u67b6\u5347\u7ea7/\u53d1\u7248\u89c4\u5219"),(0,n.kt)("p",{parentName:"admonition"},(0,n.kt)("strong",{parentName:"p"},"\u5347\u7ea7\u524d\u91cd\u70b9\u5173\u6ce8\u53ef\u80fd\u9020\u6210\u3010\u7834\u574f\u6027\u3011\u7684\u6807\u7b7e\u7c7b\u578b"),"\uff1a",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4fee\u590d"),"\u3001",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574"),"\u3001",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u79fb\u9664"),"\u3001",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u5347\u7ea7")),(0,n.kt)("p",{parentName:"admonition"},"\u7248\u672c\u53f7\u89c4\u5219\uff1a",(0,n.kt)("inlineCode",{parentName:"p"},"\u4e3b\u7248\u672c\u53f7.\u6b21\u7248\u672c\u53f7.\u4fee\u8ba2\u7248\u672c\u53f7")),(0,n.kt)("ul",{parentName:"admonition"},(0,n.kt)("li",{parentName:"ul"},"\u53ea\u8981\u3010\u786e\u8ba4\u3011\u4e3a\u6846\u67b6 ",(0,n.kt)("inlineCode",{parentName:"li"},"bug"),"\uff0c\u5219\u5f53\u5929\u4fee\u590d\uff0c\u5f53\u5929\u53d1\u7248\uff0c\u4fee\u8ba2\u7248\u672c\u53f7 ",(0,n.kt)("inlineCode",{parentName:"li"},"\u52a0 1"),"\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u5982\u679c ",(0,n.kt)("inlineCode",{parentName:"li"},".csproj")," \u6587\u4ef6\u6709\u53d8\u66f4\uff0c\u5219\u5f53\u5929\u53d1\u7248\uff0c\u4fee\u8ba2\u7248\u672c\u53f7 ",(0,n.kt)("inlineCode",{parentName:"li"},"\u52a0 1"),"\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u5176\u4f59\u60c5\u51b5\uff0c\u6bcf\u5e74\u53d1\u5e03\u4e00\u4e2a ",(0,n.kt)("inlineCode",{parentName:"li"},"\u4e3b\u7248\u672c"),"\u3002"))),(0,n.kt)("h2",{id:"v121"},"v1.2.1"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2023.2.2"),(0,n.kt)("p",null,"\u66f4\u65b0\u63cf\u8ff0\uff1a\u517c\u5bb9\u6027\u66f4\u65b0\u3002"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f18\u5316")," TouchRpc\u652f\u6301\u547d\u540d\u5143\u7ec4\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4fee\u590d")," TouchRpc\u5728\u8c03\u7528WaitSend\u4e0b\u5931\u8d25\u7684bug\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4fee\u590d")," TouchRpc\u5728Handshaked\u65f6\uff0c\u8c03\u7528Rpc\u8d85\u65f6bug\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4fee\u590d")," \u5e8f\u5217\u5316\u3001\u53cd\u5c04\u5728unity\u4e2d\u4f7f\u7528il2cpp\u7f16\u8bd1\u7684bug\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," ByteBlock\u5bf9\u4e8eint\uff0clong\u7b49\u6570\u636e\uff0c\u5199\u5165\u548c\u8bfb\u53d6\u7684\u65f6\u5019\u652f\u6301\u5927\u5c0f\u7aef\u6307\u5b9a\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," IServicePlugin\u63d2\u4ef6\uff0c\u7528\u4e8e\u663e\u793a\u901a\u77e5\u670d\u52a1\u5668\u7684\u542f\u52a8\u72b6\u6001\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," \u5c06BytePool\u7531\u9759\u6001\u8c03\u6574\u4e3a\u5b9e\u4f8b\uff0c\u4e14\u7531\u5176Default\u5b9e\u4f8b\u4f5c\u4e3a\u9ed8\u8ba4\u3002")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"v110"},"v1.1.0"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2023.1.13"),(0,n.kt)("p",null,"\u66f4\u65b0\u63cf\u8ff0\uff1a\u5c0f\u7248\u672c\u5347\u7ea7\uff0c\u53ef\u80fd\u4f1a\u6709\u4e0d\u517c\u5bb9\u3002\u8bf7\u6309\u4e0b\u5217\u63d0\u793a\u4fee\u6539\u3002 "),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f18\u5316")," TouchRpc\u7cfb\u6587\u4ef6\u4f20\u8f93\u65f6\uff0c\u6587\u4ef6\u5939\u4e0d\u5b58\u5728\u7684\u63d0\u793a\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f18\u5316")," WaitingClient\uff0c\u5f53\u5ba2\u6237\u7aef\u65ad\u5f00\u8fde\u63a5\u65f6\uff0c\u53ef\u9009\u662f\u5426\u629b\u51fa\u5f02\u5e38\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f18\u5316")," Fast\u5e8f\u5217\u5316\u65f6\u3002\u53ef\u9009\u5e8f\u5217\u5316\u53ea\u8bfb\u5c5e\u6027\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4fee\u590d")," \u591a\u4e2a\u4e0d\u7a33\u5b9aBug\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," Tcp\u5ba2\u6237\u7aef\u65b0\u589eDisconnecting\u4e8b\u4ef6\u3002\u5728\u4e3b\u52a8Close\u65f6\u751f\u6548\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," \u591a\u4e2a\u4e8b\u4ef6\u7c7b\u540d\u79f0\u4fee\u6539\uff0c\u8bf7\u6309\u7167\u63d0\u793a\u4fee\u6539\u5373\u53ef\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u79fb\u9664")," \u591a\u4e2a\u65e0\u7528\u65b9\u6cd5\u53c2\u6570\u3002")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"v100"},"v1.0.0"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2023.1.1"),(0,n.kt)("p",null,"\u66f4\u65b0\u63cf\u8ff0\uff1a\u5927\u7248\u672c\u5347\u7ea7\uff0c\u8bf7\u8be6\u7ec6\u9605\u8bfb\u4e0b\u5217\u66f4\u65b0\u65e5\u5fd7\u3002"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u5347\u7ea7")," \u5c06\u6700\u9ad8\u7248\u672c\u5347\u7ea7\u4e3aNET7\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f18\u5316")," Tcp\u7cfb\u5f02\u6b65\u53d1\u9001\u6548\u7387\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f18\u5316")," TouchRpc\u7cfbChannel\u7684\u7a33\u5065\u6027\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4fee\u590d")," \u591a\u4e2a\u4e0d\u7a33\u5b9aBug\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," ValueByteBlock\uff0c\u5728\u7b80\u5355\u4ee3\u7801\u5757\u91cc\u9762\u80fd\u6709\u6548\u51cf\u5c11\u521b\u5efa\u7684\u7c7b\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," MemoryCache\u7c7b\uff0c\u5176\u529f\u80fd\u7c7b\u4f3c\u5fae\u8f6f\u5b98\u65b9\u3002\u4f46\u662f\u652f\u6301\u5168\u90e8\u6cdb\u578b\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," ",(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/ag9tyar9mmhsme0m"},"IPackage\u7cfb"),"\u3002\u8be5\u7cfb\u5217\u80fd\u4ee5\u8d85\u9ad8\u6548\u7387\u7684\u8fdb\u884c\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," SingleTimer\u7c7b\uff0c\u4e0d\u53ef\u91cd\u5165\u7684Timer\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," Jsonrpc\u652f\u6301\u81ea\u5b9a\u4e49\u9002\u914d\u5668\u89e3\u6790\uff08EE\uff09"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," \u4e25\u91cdTouchRpc\u7cfbOnRouting\u901a\u77e5\uff0c\u6240\u6709\u7684\u5ba2\u6237\u7aef\u4e4b\u95f4\u7684\u901a\u4fe1\uff0c\u90fd\u5fc5\u987b\u7ecf\u8fc7OnRouting\u7684\u7b5b\u67e5\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," TouchRpc\u7cfb\u5c0f\u6587\u4ef6\u4f20\u8f93\uff0c\u5728\u6587\u4ef6\u5c0f\u4e8e1Mb\u65f6\uff0c\u5176\u4f20\u8f93\u6548\u7387\u662f\u5e38\u89c4\u4f20\u8f93\u768410\u500d\u4ee5\u4e0a\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," TouchRpc\u7cfb\u8d85\u5927\u6587\u4ef6\u591a\u94fe\u8def\u4f20\u8f93\uff0c\u652f\u6301\u591a\u4e2a\u5ba2\u6237\u7aef\u534f\u540c\u4f20\u8f93\u540c\u4e00\u4e2a\u6587\u4ef6\uff0c\u8fd9\u5728\u4e92\u8054\u7f51\u73af\u5883\u4e2d\uff0c\u6548\u7387\u6bd4\u5e38\u89c4\u4f20\u8f93\u63d0\u9ad8\u7c7b3-5\u500d\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u65b0\u589e")," TouchRpc\u7cfbRedis\u7ec4\u4ef6\uff0c\u80fd\u5b9e\u73b0\u53cc\u7aef\u5171\u540c\u5b58\u50a8\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," \u4e25\u91cd\u7cbe\u7b80\u6240\u6709\u547d\u540d\u7a7a\u95f4\uff0c\u5220\u9664\u6240\u6709\u4e09\u7ea7\u547d\u540d\u7a7a\u95f4\u3002\u4f8b\u5982\uff1aTouchSocket.Core.ByteManager\u7cbe\u7b80\u4e3aTouchSocket.Core\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," \u4e25\u91cd\u5220\u9664Newtonsoft.Json\u7684\u6e90\u4ee3\u7801\u5d4c\u5165\u3002\u5168\u5c40\u7684Json\u4f1a\u6839\u636e\u73af\u5883\u52a8\u6001\u8c03\u6574\uff0c\u8be6\u60c5\u89c1",(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/emqy43#PfVh1"},"Json\u5de5\u5177")),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," \u4e25\u91cd\u6846\u67b6\u9ed8\u8ba4\u65e5\u5fd7\u7531ConsoleLogger\uff0c\u66ff\u6362\u4e3aEmptyLogger\uff08\u4e0d\u8f93\u51fa\u4efb\u4f55\u4e1c\u897f\uff09\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," \u4e25\u91cdTcp\u5168\u7cfb\uff0c\u5728\u8fde\u63a5\u65f6\uff0cID\u7684\u521d\u59cb\u503c\u4f7f\u7528long\u7c7b\u578b\u4ece0\u9012\u589e\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," \u4e25\u91cdTcp\u670d\u52a1\u5668\uff0c\u5c06\u5b9a\u65f6\u6e05\u7406\u65e0\u6570\u636e\u4ea4\u4e92\u7684\u9009\u9879\u66ff\u6362\u4e3aUseCheckClear\u63d2\u4ef6\u3002\u5e76\u4e14\u9ed8\u8ba4\u6ca1\u6709\u542f\u7528\uff0c\u9700\u8981\u624b\u52a8\u52a0\u5165\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," Tcp\u7cfb\u9002\u914d\u5668\uff0c\u53d6\u6d88\u90e8\u5206\u53c2\u6570\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," DataLock\u6539\u540d\u4e3aDataSecurity\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," EasyAction\u6539\u540dEasyTask\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," IMessage\u6539\u540dIMessageObject\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," TokenInstance\u6539\u540dMessageInstance\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," TouchRpc\u7cfb\uff0c\u7cbe\u7b80\u5e38\u89c4\u6587\u4ef6\u4f20\u8f93\u64cd\u4f5c\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u8c03\u6574")," \u4e25\u91cdTouchRpc\u7cfb\uff0c\u6240\u6709\u63d2\u4ef6\u901a\u77e5\u53c2\u6570\uff0c\u9ed8\u8ba4\u90fd\u8bbe\u4e3a\u4e0d\u5141\u8bb8\u64cd\u4f5c\uff0c\u9700\u8981\u624b\u52a8\u8bbe\u7f6ee.IsPermitOperation=true\u3002"),(0,n.kt)("li",{parentName:"ul"},"\xa0",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u79fb\u9664")," Newtonsoft.Json\u7684\u6e90\u4ee3\u7801\u5d4c\u5165\u3002\u5168\u5c40\u7684Json\u4f1a\u6839\u636e\u73af\u5883\u52a8\u6001\u8c03\u6574\uff0c\u8be6\u60c5\u89c1",(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/emqy43#PfVh1"},"Json\u5de5\u5177"),"\u3002")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("em",{parentName:"strong"}," \u66f4\u65b0\u793a\u4f8b\u6307\u5357 "))),(0,n.kt)("p",null,"\uff081\uff09\u9002\u914d\u5668\u53c2\u6570\u62a5\u9519\uff1a\u76f4\u63a5\u5220\u9664isAsync\u53c2\u6570\uff0c\u4ee5\u53caisAsync\u4e3a",(0,n.kt)("strong",{parentName:"p"},"True"),"\u7684\u6240\u6709\u903b\u8f91\u3002\n",(0,n.kt)("img",{alt:"image.png",src:l(3007).Z,width:"1500",height:"91"}),"\n\uff082\uff09\u4f9d\u8d56\u5c5e\u6027\u7684\u58f0\u660e\u62a5\u9519\uff1a\u589e\u52a0\u6cdb\u578b\u7ea6\u675f\u5373\u53ef\uff0c\u8be6\u60c5\u67e5\u770b",(0,n.kt)("a",{parentName:"p",href:"https://www.yuque.com/rrqm/touchsocket/ubk57o#jyzSl"},"\u4f9d\u8d56\u5c5e\u6027"),"\n",(0,n.kt)("img",{alt:"image.png",src:l(6866).Z,width:"1500",height:"200"}),"\n\uff083\uff09\u670d\u52a1\u7aef\u5b9a\u65f6\u6e05\u7406\u8b66\u544a\uff1a\u5728\u914d\u7f6e\u63d2\u4ef6\u4e2d\u4f7f\u7528UseCheckClear\uff0c\u5e76\u4e14\u8fdb\u884c\u76f8\u5173\u914d\u7f6e\u3002\n",(0,n.kt)("img",{alt:"image.png",src:l(6257).Z,width:"1500",height:"281"}),"\n",(0,n.kt)("img",{alt:"image.png",src:l(4475).Z,width:"1500",height:"388"})),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"\u7248\u672c\u53f7-070"},"\u7248\u672c\u53f7: 0.7.0"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2022.9.21\n\u66f4\u65b0\u63cf\u8ff0\uff1a\u517c\u5bb9\u6027\u66f4\u65b0\uff0c\u589e\u5f3a\u578b\u66f4\u65b0\u3002",(0,n.kt)("strong",{parentName:"p"},"RPC\u5185\u5bb9\u9700\u8981\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u540c\u6b65\u66f4\u65b0"),"\u3002\n\u66f4\u65b0\u8be6\u60c5\uff1a"),(0,n.kt)("p",null,"\u4f18\u5316"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Fast\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316\uff0c\u652f\u6301\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u3002"),(0,n.kt)("li",{parentName:"ol"},"TouchRpc\u5168\u7cfb\uff0c\u5728\u6587\u4ef6\u4f20\u8f93\u7b49\u5927\u578bIO\u65f6\uff0c\u7531\u4e8e\u5fc3\u8df3\u5931\u8d25\u800c\u65ad\u5f00\u8fde\u63a5\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u4f18\u5316AspNetCore\u7684IContainer\u3002"),(0,n.kt)("li",{parentName:"ol"},"TcpCommandLinePlugin\u4e0eWSCommandLinePlugin\u652f\u6301\u83b7\u53d6\u5ba2\u6237\u7aef\u53c2\u6570\u3002")),(0,n.kt)("p",null,"\u65b0\u589e"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u63d2\u4ef6\u5b9e\u4f8b\u4f1a\u4ee5\u5355\u4f8b\u6ce8\u5165\u5bb9\u5668\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u6240\u6709\u9002\u914d\u5668\u652f\u6301",(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/83526e6320dfc85fef317d850aa51e92#Z0S0g"},"\u7f13\u5b58\u8d85\u65f6"),"\u8bbe\u5b9a\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u4fee\u6539\u6240\u6709\u4e8b\u4ef6\u4e3a\u59d4\u6258\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u5f00\u653e",(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/55e5bbf58745fa639dba511c7bcd54d1#WqOmh"},"AspnetCore"),"\u521b\u5efaTcp\uff0cHttp\u7b49\u670d\u52a1\u5668\u7684\u914d\u7f6e\u3002"),(0,n.kt)("li",{parentName:"ol"},"IClient\u589e\u52a0\u53d1\u9001\u3001\u63a5\u6536\u7684\u6700\u540e\u65f6\u95f4\u8bb0\u5f55\u3002"),(0,n.kt)("li",{parentName:"ol"},"Http\u652f\u6301\u591a\u6587\u4ef6\u4e0a\u4f20\uff08\u76ee\u524d\u4ec5\u652f\u6301\u5c0f\u6587\u4ef6\uff0c\u5177\u4f53\u5927\u5c0f\u4ee5\u5b9e\u9645\u8fd0\u884c\u5185\u5b58\u4e3a\u51c6\uff0c\u5b9e\u6d4b100Mb\u6ca1\u95ee\u9898\uff09\u3002"),(0,n.kt)("li",{parentName:"ol"},"Websocket\u63d2\u4ef6\u9ed8\u8ba4\u4f1a\u5904\u7406Close\u62a5\u6587\u3002\u4e14\u63d2\u4ef6\u652f\u6301Close\u3002"),(0,n.kt)("li",{parentName:"ol"},"Rpc\u652f\u6301\u6a21\u677f\u4ee3\u7801\u91cd\u5199\u3002"),(0,n.kt)("li",{parentName:"ol"},"TouchRpc\u652f\u6301\u5143\u7ec4\u3002"),(0,n.kt)("li",{parentName:"ol"},"JsonRpc\u652f\u6301Websocket\u534f\u8bae\u3002")),(0,n.kt)("p",null,"\u4fee\u6539 "),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"IScopedContainer\u4fee\u6539\u4e3aIContainerProvider")),(0,n.kt)("p",null,"\u4fee\u590d"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"BytePool\u56de\u6536\u5185\u5b58\u65f6\u4e0d\u5224\u65ad\u5927\u5c0f\u7684bug\u3002")),(0,n.kt)("p",null,"\u5220\u9664"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u65e0\u3002")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"\u7248\u672c\u53f7-060"},"\u7248\u672c\u53f7: 0.6.0"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2022.9.10\n\u66f4\u65b0\u63cf\u8ff0\uff1a\u517c\u5bb9\u6027\u66f4\u65b0\uff0c\u589e\u5f3a\u578b\u66f4\u65b0\u3002",(0,n.kt)("strong",{parentName:"p"},"\u4e13\u4e3aUnity 3D\u9002\u914d"),"\u3002\n\u66f4\u65b0\u8be6\u60c5\uff1a"),(0,n.kt)("p",null,"\u4f18\u5316"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Gzip\u7684\u538b\u7f29\u6548\u7387\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u53d1\u9001\u6548\u7387\u3002")),(0,n.kt)("p",null,"\u65b0\u589e"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"IDataCompressor\u6570\u636e\u4f20\u8f93\u538b\u7f29\u63a5\u53e3\u3002"),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/ukq0mu"},"RemoteStream"),"\u652f\u6301\u6570\u636e\u8bfb\u5199\u538b\u7f29\u3002"),(0,n.kt)("li",{parentName:"ol"},"WaitResultPackageBase\u7c7b\uff0c\u4e13\u5c5e\u975e\u5e8f\u5217\u5316\u7684\u6570\u636e\u683c\u5f0f\u5316\u3002"),(0,n.kt)("li",{parentName:"ol"},"DelaySender",(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/1f21a56ee75f896a5b5b38b37b071881#RL0kx"},"\u5ef6\u8fdf\u7f13\u5b58\u53d1\u9001"),"\u3002")),(0,n.kt)("p",null,"\u4fee\u6539"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u65e0")),(0,n.kt)("p",null,"\u4fee\u590d"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Rpc\u6ce8\u518c\u670d\u52a1\u4e3a\u5355\u4f8b\u65f6\uff0c\u5b9e\u9645\u4e0a\u662f\u77ac\u65f6\u670d\u52a1\u7684bug\u3002")),(0,n.kt)("p",null,"\u5220\u9664"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u72ec\u7acb\u7ebf\u7a0b\u53d1\u9001\u3002")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"\u7248\u672c\u53f7-050"},"\u7248\u672c\u53f7: 0.5.0"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2022.9.1\n\u66f4\u65b0\u63cf\u8ff0\uff1a\u517c\u5bb9\u6027\u66f4\u65b0\uff0c\u589e\u5f3a\u578b\u66f4\u65b0\u3002\n\u66f4\u65b0\u8be6\u60c5\uff1a"),(0,n.kt)("p",null,"\u4f18\u5316"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u5168\u5c40\u8d44\u6e90\u7684\u83b7\u53d6\u903b\u8f91\u3002")),(0,n.kt)("p",null,"\u65b0\u589e"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Container\u589e\u52a0\u5378\u8f7d\u6ce8\u518c\u529f\u80fd\u3002"),(0,n.kt)("li",{parentName:"ol"},"FilePool\u65b0\u589eFileStorageStream\u7684\u83b7\u53d6\u3002"),(0,n.kt)("li",{parentName:"ol"},"http\u5ba2\u6237\u7aef\uff08\u53cawebsocket\uff09\u652f\u6301\u4ee3\u7406\u548c\u9a8c\u8bc1\u4ee3\u7406\u3002"),(0,n.kt)("li",{parentName:"ol"},"TouchRpc\u5168\u7cfb\u65b0\u589e",(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/pearz0"},"\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c")),(0,n.kt)("li",{parentName:"ol"},"TouchRpc\uff08\u9664udp\uff09\u65b0\u589e",(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/ukq0mu"},"\u8fdc\u7a0b\u6d41\u8bbf\u95ee"))),(0,n.kt)("p",null,"\u4fee\u6539"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u65e0")),(0,n.kt)("p",null,"\u4fee\u590d"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u4fee\u590dHttp\u5ba2\u6237\u7aef\u8bf7\u6c42\u91cd\u590dHeader\u65f6\u7684bug\u3002")),(0,n.kt)("p",null,"\u5220\u9664"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"TouchRpc\u5168\u7cfb\u7684\u4e8b\u4ef6\u64cd\u4f5c\uff0c\u63a8\u8350\u76f4\u63a5\u63d2\u4ef6\u7684\u65b9\u5f0f\uff0c\u6216\u8005\u4f7f\u7528TouchRpcActionPlugin\u7136\u540e\u6dfb\u52a0\u59d4\u6258\u3002")),(0,n.kt)("p",null,"\u66f4\u65b0\u793a\u4f8b\nTouchRpc\u7684\u76f8\u5173\u4e8b\u4ef6\u5747\u5df2\u4f7f\u7528\u63d2\u4ef6\u4ee3\u66ff\u3002\u6240\u4ee5\u8bf7\u4f7f\u7528\u63d2\u4ef6\u5b9e\u73b0\u64cd\u4f5c\u3002\u5982\u679c\u9700\u8981\u4e8b\u4ef6\u7b49\u529f\u80fd\u7684\u8bdd\uff0c\u53ef\u4ee5\u7528TouchRpcActionPlugin\u7684\u63d2\u4ef6\u5b9e\u73b0\u3002\u4f8b\u5982\uff1a"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},'.UsePlugin()\n.ConfigurePlugins(a=> \n{\n a.Add>()//\u6b64\u5904\u7684\u903b\u8f91\u53ef\u7528\u63d2\u4ef6\u66ff\u4ee3\u5b8c\u6210\u3002\n .SetFileTransfering((client, e) =>\n {\n //\u6709\u53ef\u80fd\u662f\u4e0a\u4f20\uff0c\u4e5f\u6709\u53ef\u80fd\u662f\u4e0b\u8f7d\n client.Logger.Info($"\u670d\u52a1\u5668\u8bf7\u6c42\u4f20\u8f93\u6587\u4ef6\uff0cID={client.ID}\uff0c\u8bf7\u6c42\u7c7b\u578b={e.TransferType}\uff0c\u6587\u4ef6\u540d={e.FileInfo.FileName}");\n })\n .SetFileTransfered((client, e) =>\n {\n //\u4f20\u8f93\u7ed3\u675f\uff0c\u4f46\u662f\u4e0d\u4e00\u5b9a\u6210\u529f\uff0c\u9700\u8981\u4ecee.Result\u5224\u65ad\u72b6\u6001\u3002\n client.Logger.Info($"\u670d\u52a1\u5668\u4f20\u8f93\u6587\u4ef6\u7ed3\u675f\uff0cID={client.ID}\uff0c\u8bf7\u6c42\u7c7b\u578b={e.TransferType}\uff0c\u6587\u4ef6\u540d={e.FileInfo.FileName}\uff0c\u8bf7\u6c42\u72b6\u6001={e.Result}");\n });\n})\n')),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"\u7248\u672c\u53f7-045"},"\u7248\u672c\u53f7: 0.4.5"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2022.8.25\n\u66f4\u65b0\u63cf\u8ff0\uff1a\u517c\u5bb9\u6027\u66f4\u65b0\uff0c\u589e\u5f3a\u578b\u66f4\u65b0\u3002\n\u66f4\u65b0\u8be6\u60c5\uff1a"),(0,n.kt)("p",null,"\u4f18\u5316"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"FileLogger\u7684\u5199\u5165\u903b\u8f91\uff0c\u5927\u5927\u5730\u63d0\u5347\u4e86\u5199\u5165\u6548\u7387\u3002")),(0,n.kt)("p",null,"\u65b0\u589e"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/ofnliu"},"Pipeline\u9002\u914d\u5668")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/wug4bv"},"TLV\u9002\u914d\u5668")),(0,n.kt)("li",{parentName:"ol"},"WaitingClient\u652f\u6301\u6309\u6761\u4ef6\u7b49\u5f85\u8fd4\u56de\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u65e5\u5fd7\u7cfb\u7edf\u53ef\u4ee5\u7b5b\u9009\u65e5\u5fd7\u7684\u8f93\u51fa\u7c7b\u578b"),(0,n.kt)("li",{parentName:"ol"},"Rpc\u7cfb\u7edf\uff0c\u53ef\u4ee5\u4f7f\u7528\u5355\u4f8b\u3001\u77ac\u65f6\u751f\u547d\u5468\u671f\u7684\u670d\u52a1\u3002"),(0,n.kt)("li",{parentName:"ol"},"Rpc\u7cfb\u7edf\uff0c\u53ef\u5b9a\u4e49\u6301\u4e45\u5316\u6a21\u578b\u3002"),(0,n.kt)("li",{parentName:"ol"},"Rpc\u5728\u4f7f\u7528\u77ac\u65f6\u751f\u547d\u5468\u671f\u7684\u670d\u52a1\u65f6\uff0c\u53ef\u4ee5\u76f4\u63a5\u83b7\u53d6\u8c03\u7528\u4e0a\u4e0b\u6587\u3002"),(0,n.kt)("li",{parentName:"ol"},"XmlRpc\u589e\u52a0\u8c03\u7528\u4e0a\u4e0b\u6587\u3002")),(0,n.kt)("p",null,"\u4fee\u6539"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u65e5\u5fd7\u7cfb\u7edf\u3002"),(0,n.kt)("li",{parentName:"ol"},"Rpc\u7684\u8c03\u7528\u4e0a\u4e0b\u6587\u5747\u91c7\u7528\u63a5\u53e3\uff0c\u4f8b\u5982\uff1aJsonRpc\u6539\u4e3aIJsonRpcCallContext\uff0cWebApi\u4e3aIWebApiCallContext\u3002"),(0,n.kt)("li",{parentName:"ol"},"IRpcActionFilter\u7684\u53c2\u6570\u5217\u8868\u3002")),(0,n.kt)("p",null,"\u4fee\u590d"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"UdpSession\u8d44\u6e90\u4e0d\u91ca\u653e\u7684Bug\u3002")),(0,n.kt)("p",null,"\u5220\u9664"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u5197\u4f59\u5143\u7d20\u3002")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"\u7248\u672c\u53f7-035"},"\u7248\u672c\u53f7: 0.3.5"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2022.8.12\n\u66f4\u65b0\u63cf\u8ff0\uff1a\u517c\u5bb9\u6027\u66f4\u65b0\uff0c\u589e\u5f3a\u578b\u66f4\u65b0\u3002\n\u66f4\u65b0\u8be6\u60c5\uff1a"),(0,n.kt)("p",null,"\u4f18\u5316"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u5404\u7c7b\u5ba2\u6237\u7aef\u53d1\u9001\u903b\u8f91\u3002"),(0,n.kt)("li",{parentName:"ol"},"Method\u7c7b\u7684\u8c03\u7528\u903b\u8f91\u3002")),(0,n.kt)("p",null,"\u65b0\u589e"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u9002\u914d\u5668\u53ef\u4ee5\u8bbe\u5b9a\u53d1\u9001IRequestInfo\u5bf9\u8c61\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u63d2\u4ef6\u65b0\u589eUseWebSocket\u7684\u5feb\u6377\u65b9\u5f0f\u3002"),(0,n.kt)("li",{parentName:"ol"},"ReconnectionPlugin\u63d2\u4ef6\u53ef\u4ee5\u83b7\u5f97\u91cd\u8fde\u6b21\u6570\u7684\u91cd\u8f7d\u8bbe\u7f6e\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u3010\u4f01\u4e1a\u7248\u3011TcpService\u7684\u670d\u52a1\u6ce8\u5165\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u3010\u4f01\u4e1a\u7248\u3011HttpService\u7684\u670d\u52a1\u6ce8\u5165\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u3010\u4f01\u4e1a\u7248\u3011IOC\u5bb9\u5668\u7684\u5171\u4eab\u4f7f\u7528\u3002")),(0,n.kt)("p",null,"\u4fee\u6539 "),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u5404\u7c7b\u53d1\u9001\u903b\u8f91\uff0c\u4ee5\u6700\u5c0f\u5316\u53d1\u9001\u65b9\u6cd5\u4e3a\u57fa\u7840\uff0c\u5176\u4f59\u65b9\u6cd5\u6539\u4e3a\u6269\u5c55\u65b9\u6cd5\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u76f8\u5173\u63a5\u53e3\u7684\u5b9e\u73b0\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u7531\u7f51\u53cb",(0,n.kt)("a",{parentName:"li",href:"https://gitee.com/dotnetchina/TouchSocket/pulls/11"},"\u4fee\u6539GetInfo"))),(0,n.kt)("p",null,"\u4fee\u590d"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Container\u83b7\u53d6\u6cdb\u578b\u5931\u8d25bug\u3002"),(0,n.kt)("li",{parentName:"ol"},"BetweenAnd\u9002\u914d\u5668\u9002\u914d\u5668\u90e8\u5206bug\u3002"),(0,n.kt)("li",{parentName:"ol"},"Router\u6807\u7b7e\u65e0\u6cd5\u8def\u7531\u7684bug\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u4fee\u590dTouchRpc\u63a8\u9001\u6587\u4ef6\u72b6\u6001\u4e0d\u6b63\u786ebug"),(0,n.kt)("li",{parentName:"ol"},"\u4fee\u590d\u72ec\u7acb\u7ebf\u7a0b\u5728\u65ad\u7ebf\u91cd\u8fde\u540e\u53d1\u9001bug\u3002")),(0,n.kt)("p",null,"\u5220\u9664"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u5197\u4f59\u7684\u53d1\u9001\u65b9\u6cd5\uff0c\u4e0d\u5f71\u54cd\u4e0a\u7248\u672c\u4efb\u4f55\u4f7f\u7528\u3002")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"\u7248\u672c\u53f7-024"},"\u7248\u672c\u53f7: 0.2.4"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2022.7.28\n\u66f4\u65b0\u63cf\u8ff0\uff1a\u517c\u5bb9\u6027\u66f4\u65b0\u3002\n\u66f4\u65b0\u8be6\u60c5\uff1a"),(0,n.kt)("p",null,"\u4f18\u5316 "),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u4f18\u5316IOC\u5bb9\u5668\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u4f18\u5316Metadata\u7684\u5199\u5165\u65b9\u5f0f\u3002"),(0,n.kt)("li",{parentName:"ol"},"FileLogger\uff0c\u5f53\u65e5\u5fd7\u6587\u4ef6\u8fbe\u52301Mb\u65f6\uff0c\u4f1a\u518d\u65b0\u589e\u6587\u4ef6\u5e8f\u53f7\u3002")),(0,n.kt)("p",null,"\u65b0\u589e"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Mapper\u7c7b\uff0c\u652f\u6301\u7b80\u5355\u7c7b\u578b\u6620\u5c04"),(0,n.kt)("li",{parentName:"ol"},"Tcp\u670d\u52a1\u5668\u3001\u5ba2\u6237\u7aef\u3001udp\u7b49\u589e\u52a0\u7aef\u53e3\u590d\u7528\u914d\u7f6e\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u3010\u4f01\u4e1a\u7248\u3011\u8f6e\u8be2\u5f0f\u65ad\u7ebf\u91cd\u8fde\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u3010\u4f01\u4e1a\u7248\u3011NATService\u8f6c\u53d1\u5ba2\u6237\u7aef\u91cd\u8fde\u3002")),(0,n.kt)("p",null,"\u4fee\u6539"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"RRQM\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316\uff0c\u6539\u540d\u4e3aFast\u3002"),(0,n.kt)("li",{parentName:"ol"},"TouchRpcClient\u8fde\u63a5\u65f6\u7684Metadata\uff0c\u6539\u4e3a\u7531Config\u914d\u7f6e\u6ce8\u5165\u3002"),(0,n.kt)("li",{parentName:"ol"},"FilePool\uff0c\u53d6\u6d88\u5ef6\u8fdf\u91ca\u653e\u673a\u5236\u3002")),(0,n.kt)("p",null,"\u4fee\u590d"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u4fee\u590dWebSocket\u8fde\u63a5\u95ee\u9898")),(0,n.kt)("p",null,"\u5220\u9664"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u5ba2\u6237\u7aef\u76f4\u63a5\u8c03\u7528\u7684\u77ed\u7ebf\u91cd\u8fde\u65b9\u5f0f\u3002\u4ec5\u4fdd\u7559\u5728Config\u6ce8\u5165\u7684\u529f\u80fd\u3002")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"\u7248\u672c\u53f7-010"},"\u7248\u672c\u53f7: 0.1.0"),(0,n.kt)("p",null,"\u66f4\u65b0\u65e5\u671f\uff1a2022.7.16\n\u66f4\u65b0\u63cf\u8ff0\uff1a\u521d\u59cb\u5316\u7248\u672c\u53d1\u5e03\u3002\u7531RRQMSocket\u8fc1\u79fb\u800c\u6765\u3002"),(0,n.kt)("p",null,"\u8fc1\u79fb\u6307\u5357\uff1a"),(0,n.kt)("h3",{id:"1\u6240\u6709\u7c7b\u7684\u547d\u540d\u7a7a\u95f4\u4fee\u6539\u6b64\u5904\u5982\u679c\u7c7b\u578b\u540d\u672a\u4fee\u6539\u7684\u8bdd\u53ef\u7531vs\u667a\u80fd\u63d0\u793a\u89e3\u51b3"},"1.\u6240\u6709\u7c7b\u7684\u547d\u540d\u7a7a\u95f4\u4fee\u6539\uff0c\u6b64\u5904\u5982\u679c\u7c7b\u578b\u540d\u672a\u4fee\u6539\u7684\u8bdd\uff0c\u53ef\u7531vs\u667a\u80fd\u63d0\u793a\u89e3\u51b3\u3002"),(0,n.kt)("h3",{id:"2\u7c7b\u578b\u540d\u79f0\u4fee\u6539"},"2.\u7c7b\u578b\u540d\u79f0\u4fee\u6539"),(0,n.kt)("table",null,(0,n.kt)("thead",{parentName:"table"},(0,n.kt)("tr",{parentName:"thead"},(0,n.kt)("th",{parentName:"tr",align:null},"\u539f\u7c7b\u578b\u540d\u79f0"),(0,n.kt)("th",{parentName:"tr",align:null},"\u65b0\u7c7b\u578b\u540d\u79f0"))),(0,n.kt)("tbody",{parentName:"table"},(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"RRQMBitConverter"),(0,n.kt)("td",{parentName:"tr",align:null},"TouchSocketBitConverter")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"RRQMConfig"),(0,n.kt)("td",{parentName:"tr",align:null},"TouchSocketConfig")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"RRQMConverter"),(0,n.kt)("td",{parentName:"tr",align:null},"TouchSocketConverter")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"RRQMDependencyObject"),(0,n.kt)("td",{parentName:"tr",align:null},"DependencyObject")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"MsgEventArgs"),(0,n.kt)("td",{parentName:"tr",align:null},"MsgEventArgs")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"RRQMEventAgrs"),(0,n.kt)("td",{parentName:"tr",align:null},"TouchSocketEventArgs")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"IServerProvider"),(0,n.kt)("td",{parentName:"tr",align:null},"IRpcServer")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"ServerProvider"),(0,n.kt)("td",{parentName:"tr",align:null},"RpcServer")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"RRQMOverlengthException"),(0,n.kt)("td",{parentName:"tr",align:null},"OverlengthException")))),(0,n.kt)("h3",{id:"3\u4f7f\u7528\u903b\u8f91\u4fee\u6539"},"3.\u4f7f\u7528\u903b\u8f91\u4fee\u6539"),(0,n.kt)("p",null,"1\uff09\u539fRRQMConfig\u8bbe\u7f6eLogger\u7684\u65b9\u6cd5\uff0c\u6539\u4e3a\u5bb9\u5668\u6ce8\u5165\uff1a\n",(0,n.kt)("img",{alt:"image.png",src:l(3710).Z,width:"1500",height:"277"}),"\n\u65ad\u7ebf\u91cd\u8fde\u903b\u8f91\n",(0,n.kt)("img",{alt:"image.png",src:l(9772).Z,width:"1409",height:"815"}),"\nRpcStore\u4f7f\u7528\u53d8\u66f4\n\u5982\u679c\u662f\u4ec5\u6709\u4e00\u4e2aRpc\u89e3\u6790\u5668\uff0c\u90a3\u4e48\u53ef\u4ee5\u76f4\u63a5\u5220\u9664RpcStore\u7684\u58f0\u660e\uff0c\u4ece\u800c\u4f7f\u7528\u5bf9\u5e94\u7684",(0,n.kt)("strong",{parentName:"p"},"\u89e3\u6790\u5668\u5b9e\u4f8b"),"\uff0c\u76f4\u63a5\u6ce8\u518c\u670d\u52a1\u3002\u7136\u540e\u53ef\u4ee5\u901a\u8fc7\u5176\u5c5e\u6027RpcStore\uff0c\u83b7\u53d6\u5230\u5177\u4f53\u7684RpcStore\u5b9e\u4f8b\u3002"),(0,n.kt)("p",null,"\u5982\u679c\u662f\u6709\u591a\u4e2a\u89e3\u6790\u5668\uff0c\u90a3\u4e48\uff0c\u9996\u5148\u53ef\u4ee5\u4f7f\u7528\u4efb\u610f\u4e00\u4e2a\u89e3\u6790\u5668\u7684RpcStore\u5c5e\u6027\u5b9e\u4f8b\uff0c\u4f5c\u4e3a\u4e3bRpcStore\uff0c\u7136\u540e\u6dfb\u52a0\u5176\u4ed6\u89e3\u6790\u5668\u3002\u5f53\u7136\u4e5f\u53ef\u4ee5\u76f4\u63a5new RpcStore\uff0c\u7136\u540e\u7edf\u4e00\u7ba1\u7406\u89e3\u6790\u5668\u3002\u5176\u4e2d\u6784\u9020\u51fd\u6570\u4e2d\u7684Container\u5bb9\u5668\uff0c\u53ef\u4ee5\u76f4\u63a5new Container()\uff0c\u4f46\u662f\u66f4\u5efa\u8bae\u4f7f\u7528\u548c\u89e3\u6790\u5668\u76f8\u540c\u7684\u5bb9\u5668\uff0c\u8fd9\u6837\u6ce8\u5165\u7684\u670d\u52a1\u4f1a\u53d8\u5f97\u5168\u5c40\u53ef\u7528\u3002"))}m.isMDXComponent=!0},3007:(e,t,l)=>{l.d(t,{Z:()=>a});const a=l.p+"assets/images/upgrade-1-6b82b0abeb6cf5bcaf6aca07f67ad2aa.png"},6866:(e,t,l)=>{l.d(t,{Z:()=>a});const a=l.p+"assets/images/upgrade-2-e69c2951e8df8d2c064b1990fb4ca3ba.png"},6257:(e,t,l)=>{l.d(t,{Z:()=>a});const a=l.p+"assets/images/upgrade-3-69fbf6d003e3a06604cf5aaf4689fe9e.png"},4475:(e,t,l)=>{l.d(t,{Z:()=>a});const a=l.p+"assets/images/upgrade-4-2d7db90014741755af54830e9ffc187d.png"},3710:(e,t,l)=>{l.d(t,{Z:()=>a});const a=l.p+"assets/images/upgrade-5-fe66cc273eb92e8ceed0135da45a3a1c.png"},9772:(e,t,l)=>{l.d(t,{Z:()=>a});const a=l.p+"assets/images/upgrade-6-4e52667e8ec250b8e2c5a9acf63eaaf2.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/4d13c877.321d1ac4.js b/handbook/build/assets/js/4d13c877.321d1ac4.js new file mode 100644 index 000000000..0fe049b38 --- /dev/null +++ b/handbook/build/assets/js/4d13c877.321d1ac4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9030],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>p});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function d(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function s(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var u=r.createContext({}),i=function(e){var n=r.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},c=function(e){var n=i(e.components);return r.createElement(u.Provider,{value:n},e.children)},A={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},l=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,d=e.originalType,u=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),l=i(t),p=a,m=l["".concat(u,".").concat(p)]||l[p]||A[p]||d;return t?r.createElement(m,s(s({ref:n},c),{},{components:t})):r.createElement(m,s({ref:n},c))}));function p(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var d=t.length,s=new Array(d);s[0]=l;var o={};for(var u in n)hasOwnProperty.call(n,u)&&(o[u]=n[u]);o.originalType=e,o.mdxType="string"==typeof e?e:a,s[1]=o;for(var i=2;i{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>s,default:()=>A,frontMatter:()=>d,metadata:()=>o,toc:()=>i});var r=t(7462),a=(t(7294),t(3905));const d={id:"customfixedheaderdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668"},s=void 0,o={unversionedId:"customfixedheaderdatahandlingadapter",id:"customfixedheaderdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/customfixedheaderdatahandlingadapter.mdx",sourceDirName:".",slug:"/customfixedheaderdatahandlingadapter",permalink:"/touchsocket/docs/customfixedheaderdatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/customfixedheaderdatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675660193,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"customfixedheaderdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668",permalink:"/touchsocket/docs/customdatahandlingadapter"},next:{title:"\u6a21\u677f\u89e3\u6790\u201c\u975e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/customunfixedheaderdatahandlingadapter"}},u={},i=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2}],c={toc:i};function A(e){let{components:n,...d}=e;return(0,a.kt)("wrapper",(0,r.Z)({},c,d,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u548c\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668\u76f8\u6bd4\uff0c\u4f7f\u7528\u6a21\u677f\u89e3\u6790\u5c06\u4f1a\u66f4\u52a0\u7b80\u5355\u6d41\u7a0b\u3002\u4f8b\u5982\u5728\u4e0a\u8282\u6240\u8bf4\u7684\u6570\u636e\u683c\u5f0f\uff0c\u524d\u4e09\u4e2a\u5b57\u8282\u662f",(0,a.kt)("strong",{parentName:"p"},"\u56fa\u5b9a\u957f\u5ea6"),"\u7684\uff0c\u4e3a3\uff0c\u800c\u540e\u7eed\u957f\u5ea6\u5219\u7531\u7b2c\u4e00\u4e2a\u5b57\u8282\u8ba1\u7b97\u53ef\u5f97\uff0c\u6240\u4ee5\u6211\u4eec\u628a\u7c7b\u4f3c\u8fd9\u6837\u7684\u6570\u636e\u683c\u5f0f\uff0c\u53eb\u505a\u201c",(0,a.kt)("strong",{parentName:"p"},"\u56fa\u5b9a\u5305\u5934"),"\u201d\u6570\u636e\uff0c\u90a3\u4e48\uff0c\u4ed6\u5c31\u53ef\u4ee5\u4f7f\u7528\u56fa\u5b9a\u5305\u5934\u6570\u636e\u89e3\u6790\u6a21\u677f\u3002"),(0,a.kt)("img",{src:t(3718).Z}),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u81ea\u7531\u9002\u914d",(0,a.kt)("strong",{parentName:"li"},"99%"),"\u7684\u6570\u636e\u534f\u8bae\uff08\u4f8b\u5982\uff1amodbus\uff0c\u7535\u529b\u63a7\u5236\u534f\u8bae\u7b49\uff09\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u968f\u610f\u5b9a\u5236\u6570\u636e\u534f\u8bae\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u4e0e",(0,a.kt)("strong",{parentName:"li"},"\u4efb\u610f\u8bed\u8a00\u3001\u6846\u67b6"),"\u5bf9\u63a5\u6570\u636e\u3002")),(0,a.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002\u4e0b\u5217\u4ee5\u670d\u52a1\u5668\u4e3a\u4f8b\u3002"),(0,a.kt)("p",null,"\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u5b9e\u73b0IFixedHeaderRequestInfo\u63a5\u53e3\uff0c\u6b64\u5bf9\u8c61\u5373\u4e3a\u5b58\u50a8\u6570\u636e\u7684\u5b9e\u4f53\u7c7b\uff0c\u53ef\u5728\u6b64\u7c7b\u4e2d\u58f0\u660e\u4e00\u4e9b\u5c5e\u6027\uff0c\u4ee5\u5907\u4f7f\u7528\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u7ee7\u627fCustomFixedHeaderDataHandlingAdapter\uff0c\u5e76\u4e14\u4ee5\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u4f5c\u4e3a\u6cdb\u578b\u3002\u5e76\u5b9e\u73b0\u5bf9\u5e94\u62bd\u8c61\u65b9\u6cd5\u3002"),(0,a.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684RequestInfo\u5bf9\u8c61\uff0c\u5f3a\u8f6c\u4e3a\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u578b\uff0c\u7136\u540e\u8bfb\u53d6\u5176\u5c5e\u6027\u503c\uff0c\u4ee5\u5907\u4f7f\u7528\u3002")),(0,a.kt)("p",null,"\u3010MyFixedHeaderRequestInfo\u3011"),(0,a.kt)("p",null,"\u9996\u5148\uff0c\u65b0\u5efaMyFixedHeaderRequestInfo\u7c7b\uff0c\u7136\u540e\u5b9e\u73b0",(0,a.kt)("strong",{parentName:"p"},"IFixedHeaderRequestInfo"),"\u7528\u6237\u81ea\u5b9a\u4e49\u56fa\u5b9a\u5305\u5934\u63a5\u53e3\u3002"),(0,a.kt)("p",null,"\u7136\u540e\u5728",(0,a.kt)("strong",{parentName:"p"},"OnParsingHeader"),"\u51fd\u6570\u6267\u884c\u7ed3\u675f\u65f6\uff0c\u5bf9\u5b9e\u73b0\u7684",(0,a.kt)("inlineCode",{parentName:"p"},"BodyLength"),"\u5c5e\u6027\u4f5c\u51fa\u8d4b\u503c\uff0c\u4ee5\u6b64\u6765\u51b3\u5b9a\uff0c\u540e\u7eed\u8fd8\u5e94\u8be5\u63a5\u6536\u591a\u5c11\u6570\u636e\u4f5c\u4e3aBody \u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo\n{\n private int bodyLength;\n /// \n /// \u63a5\u53e3\u5b9e\u73b0\uff0c\u6807\u8bc6\u6570\u636e\u957f\u5ea6\n /// \n public int BodyLength\n {\n get { return bodyLength; }\n }\n\n private byte dataType;\n /// \n /// \u81ea\u5b9a\u4e49\u5c5e\u6027\uff0c\u6807\u8bc6\u6570\u636e\u7c7b\u578b\n /// \n public byte DataType\n {\n get { return dataType; }\n }\n\n private byte orderType;\n /// \n /// \u81ea\u5b9a\u4e49\u5c5e\u6027\uff0c\u6807\u8bc6\u6307\u4ee4\u7c7b\u578b\n /// \n public byte OrderType\n {\n get { return orderType; }\n }\n\n private byte[] body;\n /// \n /// \u81ea\u5b9a\u4e49\u5c5e\u6027\uff0c\u6807\u8bc6\u5b9e\u9645\u6570\u636e\n /// \n public byte[] Body\n {\n get { return body; }\n }\n\n \n public bool OnParsingBody(byte[] body)\n {\n if (body.Length == this.bodyLength)\n {\n this.body = body;\n return true;\n }\n return false;\n }\n\n \n public bool OnParsingHeader(byte[] header)\n {\n //\u5728\u8be5\u793a\u4f8b\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u5b57\u8282\u8868\u793a\u540e\u7eed\u7684\u6240\u6709\u6570\u636e\u957f\u5ea6\uff0c\u4f46\u662fheader\u8bbe\u7f6e\u7684\u662f3\uff0c\u6240\u4ee5\u540e\u7eed\u8fd8\u5e94\u5f53\u63a5\u6536length-2\u4e2a\u957f\u5ea6\u3002\n this.bodyLength = header[0]-2;\n this.dataType = header[1];\n this.orderType = header[2];\n return true;\n }\n}\n\n")),(0,a.kt)("p",null,"\u65b0\u5efaMyFixedHeaderCustomDataHandlingAdapter\u7ee7\u627f",(0,a.kt)("strong",{parentName:"p"},"CustomFixedHeaderDataHandlingAdapter"),"\uff0c\u7136\u540e\u5bf9HeaderLength\u4f5c\u51fa\u8d4b\u503c\uff0c\u4ee5\u6b64\u8868\u660e\u56fa\u5b9a\u5305\u5934\u7684\u957f\u5ea6\u662f\u591a\u5c11\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter\n{\n /// \n /// \u63a5\u53e3\u5b9e\u73b0\uff0c\u6307\u793a\u56fa\u5b9a\u5305\u5934\u957f\u5ea6\n /// \n public override int HeaderLength => 3;\n\n /// \n /// \u83b7\u53d6\u65b0\u5b9e\u4f8b\n /// \n /// \n protected override MyFixedHeaderRequestInfo GetInstance()\n {\n return new MyFixedHeaderRequestInfo();\n }\n}\n")),(0,a.kt)("p",null,"\u3010\u63a5\u6536\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{15}","{15}":!0},"TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u63a5\u6536\u4fe1\u606f\uff0c\u5728CustomDataHandlingAdapter\u6d3e\u751f\u7684\u9002\u914d\u5668\u4e2d\uff0cbyteBlock\u5c06\u4e3anull\uff0crequestInfo\u5c06\u4e3a\u9002\u914d\u5668\u5b9a\u4e49\u7684\u6cdb\u578b\n if (requestInfo is MyFixedHeaderRequestInfo myRequestInfo)\n {\n //\u6b64\u5904\u53ef\u4ee5\u5904\u7406MyFixedHeaderRequestInfo\u7684\u76f8\u5173\u4fe1\u606f\u4e86\u3002\n string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);\n }\n \n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(() => { return new MyFixedHeaderCustomDataHandlingAdapter(); }))//\u914d\u7f6e\u9002\u914d\u5668\n .Start();//\u542f\u52a8\n")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u793a\u4f8b\u7684\u6570\u636e\u662f\u7ecf\u5178\u7684\u56fa\u5b9a\u5305\u5934\u683c\u5f0f\uff0c\u5177\u6709Header+Body\u7684\u660e\u663e\u5206\u5272\u70b9\u3002\u4f46\u6709\u65f6\u5019\uff0c\u4e5f\u6709\u4e00\u4e9b\u6570\u636e\u6709\u597d\u51e0\u6bb5\uff0c\u4f8b\u5982\uff1a\u5177\u6709Crc\u6821\u9a8c\u7684\u6570\u636e\uff0c\u4e5f\u5c31\u662fHeader+Body+Crc\u7684\u683c\u5f0f\uff0c\u8fd9\u65f6\u5019\uff0c\u6211\u4eec\u53ef\u4ee5\u628aBody+Crc\u770b\u505a\u4e00\u6bb5\u6570\u636e\uff0c\u7136\u540e\u4eceHeader\u89e3\u6790BodyLength\u4ee5\u540e\uff0c\u52a0\u4e0aCrc\u7684\u957f\u5ea6\u3002\u6700\u540e\u4f1a\u5728OnParsingBody\u65f6\uff0c\u5c06Body\u548cCrc\u4e00\u8d77\u6295\u9012\uff0c\u5c4a\u65f6\u505a\u597d\u6570\u636e\u5206\u5272\u5373\u53ef\u3002")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u521b\u5efa\u7684\u9002\u914d\u5668\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}A.isMDXComponent=!0},3718:(e,n,t)=>{t.d(n,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA7MAAAEECAMAAADNkJO5AAAAzFBMVEX////v7+7n5+fc3NyZ2ev/fib29PS15xwAAADtHCT9/fynp6fFxcXV1dW4/f+enp76+PgHC2aRkZHOzs67u7ug5vja4ufbkTqysrJ/f3/u8jmIiIj//9/k///8qcb5cjH73//+/7zvX6y377H7p1X/8ZzP+f//znfd6e3zu//x//+86HLW6iT/3Zj/iniEhIS72+8EUqPC8+H0Nm3/lZ3993Lb/v9mFwC3ZgD7v9//jzH/2LT/qyb3SiQnCiCRZjrtHFBYkcNmt//JkWZqAa6EAAAQQ0lEQVR42uydC1viOB9HS7koUbEO4u66yE1uIrIdUXeNl3Xe/f7f6U3SizrqSDOgzXDO6FCQOM/TX07+SVodzwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgJWyCQCfBs4C4CwA4CwA4CzAWjlbtcQ0LmXGNCsvjnn/BsAvBc4C4CzOAuAszgLgLADO4iwAzuIsAM4C4CzOAuAszgLgLADO4iwAzuIsAM4C4CzOAuAszgLgLADO4iwAzuIsAM7iLOAszgLgLM4C4CzOAs7iLADO4iwAzuIs4CzOAuAszgLgbLm/V5M4Czhr4+xor/YTzqrWFs7e/Lu5V6POAs5aOGvssXbWtM7srGq1ibOAszbOxvZYOhu3zuasvPnbfA1nAWczO5vaY+Vs2jpjnT2739wr/YazgLPZnU3tsXI2bZ3V2b1SuYyzgLM2zu6VqlVrZ0d76q/3nZVPPh/BWcBZ233j335mDypjnZUvnE1txlnA2Rw6S50FnMVZyMp/f3y7av53v3n/NeRk4Oz7zkqc/Wz+2dzrRnv+9//jbODsK87K8osdKJz9XGe//n3/rbjzr75Qx+nA2R/UWfnS2UefcfYDnY1dVQcUWpxlPeuEs5GqZ/eb3zgdOLuAsxJnP3s9G02J1ar2K6cDZ793Vr4+PcbZT13PDnEWZ39YZyVz45zV2Sucxdn358Zv3bsY3wmFsx9ZZ3EWZ9mDYm4Mv6yz8omzEmc/d258j7M4+/rP9VBnmRvjrGN1Vr65GYWzOIuzrv2uVImznzY3xlmcXWjfWFJnqbM462ydlTgLOJs3ZyX/jwDgrKt1Vj47eDZbxlnA2Rw5K8s/XsxSZwFn+T+2AHDWxtn3K6zEWcDZvNdZSZ0FnHVvbvzd7ynHWcDZXF3rkaxnAWcdvdYjXy+5OAs4y74xAM4uy9mXNx/jLOBs7uuspM4CzuZ1D0q+uw2Fs4Czuayz8q2Ki7OAs9xTAYCzP3Pv4mveSpwFnOV3ywDg7FJ+Fo89KMBZJ+usxFnAWXeclW/Ki7OAs3n+fVCSOgs4+56zAPAp4CwAzgIAzgIAzgKsi7NLQOg/C+LpD5uBxQMAAAAAAAAAgF+TapVzQOrgVHjW8ZH7OqYOeQjPMj67hvQVt1MHh9Oza0lfwVlwylk6C87CUtKr4iypg1PhVT8qd/qK46mDw+lVf8JZOgvOgiPO0llwFpYTnkV8OLuOqYPD6dm1pK/gLDjlLJ0FZ2FZ4VletMHZ9Uod8pFe+rD63OkrbqcOzjubtSUDPM7CMiZJVjc62DtLZ3E3dcjLgGthkV3uOOt26uC8s1lbMsDjLCw1veqHOEtncTd1yE942S2yyh1nHU8dHE7PriUDPM6CU87SWXAWlhBe9eUxzpI65H7AzWiRXe4463bq4LyzWVsywOMsLG+SlNEie2fpLO6mDvkacLPv/2bOHWfdTh2cdzZrSwZ4nIVlTpIyWWTvLJ3F3dQhbwNuBovscsdZt1MH553N2pIBHmfBQWfpLDgLS1vYeJYXbXB2TVKH/A24C6dnlzvOup06OO9s1pYM8DgLS58kLbotZO8sncXd1CGPA+6CFtnljrNupw7OO5u1JQM8zsLyJ0kLWmTvLJ3F3dQhnwPu4vu/mXPHWbdTB+edzdqSAR5nYSmzpFduJrTZAF7QWTqLu6lDfsL7/ofjFr3QmjF3nHU8dXA4PbuWDPA4C045S2fBWVhefDbLWZxds9QhVxFmXVva5I6zrqcOzqeXtSUDPM6CW87SWXAWcBZwlvRwltQBZ+ksOAs4CzhLejhL6oCzdBacBZwFnCU9nCV1zgnO0llwFnAWcBZwltSJAWfpLDgLOAs4CzhL6sSAs3QWnAWcBZwFnAViwFmcxVnAWcBZwFkgBpzFWZwFnAWcBZwFYiA9nMVZwFnAWcBZIAbSw1mcBZwFnAWcBWIgPZzFWcBZwFnAWSAG0sNZUoccpfcMnCV1+IWdzdoSZ3EWHHSWzoKzgLOAs2sbn4ezpA7kjrMADPAAAAAAAAAAAAAAAABribhpNedB/2TU08/OeqIdXXY58UT7RL8UfUF/7aHD6QLIgbT963m/5fVPIme9tjFT+1o+Eepg7uun6SXUHmcM4JOVNSq2jI/t6sP8aZ0Vo2pL6DcphZXLIhI7Jqh5B1eFWqVhnjS8cclQ8yqloTceeiIcqkNNo9BQb03aDVre6NrzmrIc1e3bi+j1kex4/Y7XVQ+jsuZi1GrOSGilNKdD/TA9j54eHnNKXJBWzO56Qb8XdOcVkdZZI+r1XVJVyw9JnW09tvRr4bjhFWra6iDUmioOap5XaEzGQxE2JuqbhFeVhlAf4dFTZ7WS19HT21Y//p6jC68vuuXrwPO6M2+k3oazK6U7vVLOmo8rkTh7uRFzesQZyutIe3c9H/Vm80D56g16YtbRq9q4uCb6ll+pswVTQ8NQF9IDfRTVWW2u8A6GUSdQrqpCrD7GSZ29VbqOjK+DC11tlbD9i2jw8HSdjXoTzn4Eg9Pm9FxV2kHsp7hUzsbHA5zNLe1Oc97sTWadUUvZqufH1XienGKEbUdHTxmrUqpqahBembnxMDLvoJTSiI/D53VWFVODngR3tLkDdXhbTmnFxzj7AXNjXWEPTWE9Ng+nqbMTTk9uY5vr4jbqtU+ad9Ve86GjKq4QgQjUejYurMGs88qk+qA2HjfG4VGgJsHCOKuPTHFVsjailuHkuzrrnT1Or2/VodDSmkWtmhbfls0X9WvU2ZVzGM+Cj/Wi1ixlmRu7UWdNVRVNtajV+8bdudmUeugIvW/cnQdG64eztOQ+VtlhEB4NjwrDSqjdLMV7UHqOfKRWuXr7SamqhRVmjpzW2fLszJTRmXg6csjyTM+N9VK35d1ea2c9gbMrHq9Ppxvnyt1zpavehkrmxspd5sb55Ww+ad4pO81VnJveWa9/olaWevWq1rPBzdwsL3uBrsbNu9azpgdDtXKtNMY1octqONRVNdmfMhNlXWD1pwhLjeQrUik50N9H+9iPZ8OJmv1IY+2r+uyW5QUBrQ5xudGcjqfH09PjeAP5MHJWr2thwZO4UzA9vf7jdxUretbp6/LlJ7VK+DuRLPWs/2hX19lR9USqQjvotVuzqM5qZ/vzjnG539N7VerFp0scs1ZtTJSvE32tR4RRoR0+Xc9Gm1U14T0pqWo9O3gUtWlq7LWusynRjrLejxL0iRUyPdeqdk+F8nQQO3t4msyNN44DTtH7BLtGPP+vVMRifFTfenxX5Yt+tfCHOqWVPwtJt97ZNw/F/YzDRFvf3jSaT7SZ7epFbyLNrRQdNVuOLs6OqtfzrpkWd5/dUxGEV2pJqx50CQ3CQNVb5Vi0E1UpxXNhP9U30V1oZ5M663VluTNoJ51j1I8Lrt6EMhJTZ1fKYMPE1Z0OL49VQJcbp1fmQC9uBQPmQs7WTZ0tJLVS1Hei6ultPXNW35pU2FXntLKrS65fPCj6O9vF5MEv1isZzY32mMSzyvZeaGrGW2pUSjW/caTqrN8oJNd6KiW9mVyK10PC1FnxRp1VE+DEy5E66qbT5PS6D6yszib1VKj58bnQVfZYTYsra3BvhSjubxf9yJLC9u/qWNeNSrFe3yn6UR2s+NvBK2XQ39/a2o7fsr+7u1Xc2lXs73xRx7tf9Mv1P+vmloUv28+cFcIv/O776q+DYtGr/7+d822RIgfCeFdKS8gfE5Lckrb1hYhynMNFFn1xcN//c11V0j3TepyrB4os9YAz0jvdy+70L89TlZptraHPnp9C2fjROfrxP/bvT95ZS0ympd/unjz/8Ac8HzXunQRmofTDdc/2bLR/P/3r5LOD1Y+zB/VxZ/jpn8NiZ1hWo/2BeiH7OTID9Va6xHaw+uLN5fH3jSmurtbgxSLLGqvn/zMy4LJz0YUwTJGPzQQbzyf2GrAw5HIqMIIUPT+B2YxoWF2dztvxdB4fI2/W1qphQv1wROvaIutGiz+5CBzjF3b46D5GcXjq9cn+y7Q1dv0Kenl5dm9fvJfsc3n/St6TT29eXu5HB/k6W/EoXbZ1MyrPZtkB22gMtcZkOS+3JmJlh4WME74Ts7BFGveuGYwPGrewQFrCut/6xu53vHE3YIPhJaLymjBOuBoqQor8bY1RHlTf7rTDTt8+u79IGcsm+/by6vLomYXuByWBq0xw0w5rE5+dzgqhcXrcYKbiG7MpO6HSkCXCtgNZyMZ47f3iqGYBEYrHOzCIHgjBZK5ZeU1Arlz7KQQXD0BAZEDvRdU3taDYaF9f7j+x3b6+zH3Zy5tj1OIRMxvW3S2dsYzXLcHuzC4YE3sqV7T4GbOFLZLyVkPJbMMHepYvc7q2wI9c8vboPObY5IsWi7yEVl+LufnsEjYphgvGbvRuVH1TD+rd9Fqh015kdhE5Iz96n7U+nyrNEgzZo1rd3RIiMrNgJTzfmLXSVYrRMq91sfwSNlWufU2rYQor41g9CflmBfbqnUWSL0osFrO++WwJIUldWdegd6Pq/9zKR3v/sVdXycfTj4iucW4FOvssuCI+yyG5nJgVAgVF9su7Zdlw8VykenBbvWrgWCRS+zjAnXwixtBgAU9EcPhsar0WZLIVWZXqQWY/W6uwxRakDj357GR2Eee8zkbQZhcUi5YH6GlujsJ6G2OaS14Uc92kN1ymoVuHufTCrMfY7qbPWsgdrWFoXVdkVaqvB4oQv4wSENCBvfksY8TMWg619eSzDhYjrSfPRur2HlTCL7u+IwEL8dbm+SLMkGVTB9ZFelszircMHGyS75u2jVWqByQtplnYXtu1VnrGR99YmlSchEn6S56uzKbgF1MM+YDU9hZUKnWdCodJlzbScJJoPMvZWMcclB2FLu2jGlKHWL4+KrEq1UMyZR/OX9EeU06U/bWeTTkyxKPuTIi3HpTMF/qcS9m6m7RT9N7ZKVcmfcKubc4bajNV42qYWXAubs61uEUXJ8vJuJxddK4Gp++KSvXfIizidSlmMUSzWytaqmPfJ7V+J+l2YGnCrfqlgvTZgC/kjQS3ccBNn6XZd7IBS5iX5igts4sGEsD4x4+yGrSNy9wxPkWY9V1Rqb4WjgsCmdi5kkw1GCCo3Un1asCYkvvIsHt/F08dK2jFJD4nTCyxZ5hReDA7Tbrc2swt4N6In58RSLHZFIKsF/zNuws275vDRplVqb4mG2LuaxzNn1Rz3tZcZSd2FKZ5jkiU3S/NeuoyW47GW18namF1SSYgEyUiStNnbZ5h29LWLFe++watMJvcZsaklFzYS8GbjoJamVWpHqIWDO0z8HaB7xkdJCPJdlrwYLvnIYyjnjV9rATswU5Gl0sbR4kNmYO02dP2dYSqterlEwpBmVWpfpbaYcNZfNbGLqiGuDY7K95hu9iNX49P25m8d5zYi+s+QKXMqlQ/rTY+5pX3jtOwbB+Po2mgmyCVcO1dmcNnycMcPvv+Py+jUql+bBbXX4FKpVKpVCqVSqVSqVQqlUqlUqlUKpVKpVL9qvoHFd+Yldt1J+4AAAAASUVORK5CYII="}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/4e9c6747.35f5eddc.js b/handbook/build/assets/js/4e9c6747.35f5eddc.js new file mode 100644 index 000000000..6e1f5f858 --- /dev/null +++ b/handbook/build/assets/js/4e9c6747.35f5eddc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1168],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>k});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=c(n),k=a,d=u["".concat(p,".").concat(k)]||u[k]||m[k]||i;return n?r.createElement(d,o(o({ref:t},s),{},{components:n})):r.createElement(d,o({ref:t},s))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const i={id:"serializationselector",title:"\u5e8f\u5217\u5316\u9009\u62e9\u5668"},o=void 0,l={unversionedId:"serializationselector",id:"serializationselector",title:"\u5e8f\u5217\u5316\u9009\u62e9\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/serializationselector.mdx",sourceDirName:".",slug:"/serializationselector",permalink:"/touchsocket/docs/serializationselector",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/serializationselector.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675691081,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"serializationselector",title:"\u5e8f\u5217\u5316\u9009\u62e9\u5668"},sidebar:"docs",previous:{title:"\u8c03\u7528\u914d\u7f6e",permalink:"/touchsocket/docs/rpcoption"},next:{title:"\u8c03\u7528\u4e0a\u4e0b\u6587",permalink:"/touchsocket/docs/rpcallcontext"}},p={},c=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u652f\u6301\u7684\u5e8f\u5217\u5316",id:"\u4e8c\u652f\u6301\u7684\u5e8f\u5217\u5316",level:2},{value:"\u4e09\u3001\u4f7f\u7528\u9884\u8bbe\u5e8f\u5217\u5316",id:"\u4e09\u4f7f\u7528\u9884\u8bbe\u5e8f\u5217\u5316",level:2},{value:"\u56db\u3001\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316",id:"\u56db\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316",level:2},{value:"4.1 \u5b9a\u4e49\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u5668",id:"41-\u5b9a\u4e49\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u5668",level:3},{value:"4.2 \u4f7f\u7528",id:"42-\u4f7f\u7528",level:3}],s={toc:c};function m(e){let{components:t,...i}=e;return(0,a.kt)("wrapper",(0,r.Z)({},s,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u4ece\u4e0b\u56fe\uff08\u56fe\u7247\u6765\u6e90",(0,a.kt)("a",{parentName:"p",href:"https://www.jianshu.com/p/7d6853140e13"},"\u7f51\u7edc"),"\uff09\u53ef\u4ee5\u770b\u51fa\uff0c\u5e8f\u5217\u5316\u662fRPC\u4e2d\u81f3\u5173\u91cd\u8981\u7684\u4e00\u4e2a\u73af\u8282\uff0c\u53ef\u4ee5\u8bf4\uff0c\u5e8f\u5217\u5316\u7684\u4f18\u52a3\uff0c\u4f1a\u5f88\u5927\u7a0b\u5ea6\u7684\u5f71\u54cdRPC\u8c03\u7528\u6027\u80fd\u3002"),(0,a.kt)("img",{src:n(4831).Z}),(0,a.kt)("h2",{id:"\u4e8c\u652f\u6301\u7684\u5e8f\u5217\u5316"},"\u4e8c\u3001\u652f\u6301\u7684\u5e8f\u5217\u5316"),(0,a.kt)("p",null,"\u5728TouchRpc\u4e2d\uff0c\u5185\u7f6e\u4e86\u56db\u79cd\u5e8f\u5217\u5316\u65b9\u5f0f\uff0c\u5206\u522b\u4e3a",(0,a.kt)("inlineCode",{parentName:"p"},"FastBinary"),"\u3001",(0,a.kt)("inlineCode",{parentName:"p"},"Json"),"\u3001",(0,a.kt)("inlineCode",{parentName:"p"},"Xml"),"\u3001",(0,a.kt)("inlineCode",{parentName:"p"},"SystemBinary"),"\u3002\u8fd9\u56db\u79cd\u65b9\u5f0f\u7684\u7279\u70b9\uff0c\u5c31\u662f\u5176\u5e8f\u5217\u5316\u7684\u7279\u70b9\u3002"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null}),(0,a.kt)("th",{parentName:"tr",align:null},"FastBinary"),(0,a.kt)("th",{parentName:"tr",align:null},"Json"),(0,a.kt)("th",{parentName:"tr",align:null},"Xml"),(0,a.kt)("th",{parentName:"tr",align:null},"SystemBinary"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"\u7279\u70b9"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5e8f\u5217\u5316\u65b9\u5f0f\u901f\u5ea6\u5feb\uff0c\u6570\u636e\u91cf\u5c0f\uff0c\u4f46\u662f\u517c\u5bb9\u7684\u6570\u636e\u683c\u5f0f\u4e5f\u6bd4\u8f83\u6709\u9650\u3002\u4ec5\u652f\u6301\u57fa\u7840\u7c7b\u578b\u3001\u81ea\u5b9a\u4e49\u5b9e\u4f53\u7c7b\u3001\u6570\u7ec4\u3001List\u3001\u5b57\u5178"),(0,a.kt)("td",{parentName:"tr",align:null},"\u517c\u5bb9\u6027\u597d\uff0c\u53ef\u8bfb\u6027\u5f3a\uff0c\u4f46\u662f\u53d7\u5b57\u7b26\u4e32\u5f71\u54cd\uff0c\u6027\u80fd\u4e0d\u51fa\u4f17\uff0c\u4e14\u6570\u636e\u91cf\u53d7\u9650\u5236"),(0,a.kt)("td",{parentName:"tr",align:null},"\u517c\u5bb9\u6027\u4e00\u822c\uff0c\u53ef\u8bfb\u6027\u5f3a\uff0c\u540c\u6837\u53d7\u5b57\u7b26\u4e32\u5f71\u54cd\uff0c\u6027\u80fd\u4e0d\u51fa\u4f17\uff0c\u4e14\u6570\u636e\u91cf\u53d7\u9650\u5236"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5e8f\u5217\u5316\u901f\u5ea6\u5feb\u3002\u4f46\u662f\u517c\u5bb9\u6027\u4f4e\u3002\u4e14\u8981\u6c42\u7c7b\u5fc5\u987b\u4e00\u81f4\uff0c\u4e0d\u7136\u9700\u8981\u91cd\u65b0\u6307\u5b9a\u56fe\u6839\u3002")))),(0,a.kt)("h2",{id:"\u4e09\u4f7f\u7528\u9884\u8bbe\u5e8f\u5217\u5316"},"\u4e09\u3001\u4f7f\u7528\u9884\u8bbe\u5e8f\u5217\u5316"),(0,a.kt)("p",null,"\u5728TouchRpc\u4e2d\uff0c\u9009\u62e9\u5e8f\u5217\u5316\u662f\u975e\u5e38\u7b80\u5355\u7684\uff0c\u4e14\u5e8f\u5217\u5316\u65b9\u5f0f\u5b8c\u5168\u7531",(0,a.kt)("inlineCode",{parentName:"p"},"\u8c03\u7528\u7aef"),"\u51b3\u5b9a\u3002\n\u5728\u5b9e\u9645\u7684\u8c03\u7528\u4e2d\uff0c\u901a\u8fc7",(0,a.kt)("inlineCode",{parentName:"p"},"InvokeOption"),"\u7684\u53c2\u6570\u6307\u5b9a\u3002"),(0,a.kt)("p",null,"\u5b9e\u9645\u4e0a\uff0c\u53ea\u9700\u8981\u4f20\u5165\u76f8\u5173\u53c2\u6570\u5373\u53ef\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'InvokeOption invokeOption = new InvokeOption() //InvokeOption\u662f\u7ed3\u6784\u4f53\uff0c\u6240\u4ee5\u6210\u5458\u5fc5\u987b\u5168\u90e8\u521d\u59cb\u5316\u3002\n{\n FeedbackType = FeedbackType.WaitInvoke,\n Timeout = 1000 * 10\n};\n;\ninvokeOption.SerializationType = SerializationType.FastBinary;\n//invokeOption.SerializationType = Serialization.SerializationType.Json;\n//invokeOption.SerializationType = Serialization.SerializationType.Xml;\nstring returnString = client.Invoke("TestOne", invokeOption, "10");\n')),(0,a.kt)("h2",{id:"\u56db\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316"},"\u56db\u3001\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316"),(0,a.kt)("h3",{id:"41-\u5b9a\u4e49\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u5668"},"4.1 \u5b9a\u4e49\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u5668"),(0,a.kt)("p",null,"\u60f3\u8981\u5b9e\u73b0\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\uff0c\u5fc5\u987b\u901a\u8fc7\u91cd\u5199\u5e8f\u5217\u5316\u9009\u62e9\u5668\uff0c\u5b9e\u73b0",(0,a.kt)("inlineCode",{parentName:"p"},"SerializeParameter"),"\u548c",(0,a.kt)("inlineCode",{parentName:"p"},"DeserializeParameter"),"\u51fd\u6570\u3002"),(0,a.kt)("p",null,"\u4e0b\u5217\u4ee3\u7801\u5c06\u4ee5",(0,a.kt)("inlineCode",{parentName:"p"},"MemoryPack"),"\u5e8f\u5217\u5316\u4f5c\u4e3a\u793a\u4f8b\uff0c\u5e76\u4e14\u4fdd\u7559\u4e86\u9884\u8bbe\u5e8f\u5217\u5316\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MemoryPackSerializationSelector:DefaultSerializationSelector\n{\n public override byte[] SerializeParameter(SerializationType serializationType, object parameter)\n {\n if ((byte)serializationType == 4)\n {\n return MemoryPackSerializer.Serialize(parameter.GetType(),parameter);\n }\n return base.SerializeParameter(serializationType, parameter);\n }\n\n public override object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType)\n {\n if ((byte)serializationType == 4)\n {\n if (parameterBytes==null)\n {\n return default;\n }\n return MemoryPackSerializer.Deserialize(parameterType,parameterBytes);\n }\n return base.DeserializeParameter(serializationType, parameterBytes, parameterType);\n }\n}\n")),(0,a.kt)("h3",{id:"42-\u4f7f\u7528"},"4.2 \u4f7f\u7528"),(0,a.kt)("p",null,"\u5fc5\u987b\u5728",(0,a.kt)("inlineCode",{parentName:"p"},"\u670d\u52a1\u5668"),"\u548c",(0,a.kt)("inlineCode",{parentName:"p"},"\u5ba2\u6237\u7aef"),"\u7684",(0,a.kt)("strong",{parentName:"p"},"Config\u914d\u7f6e"),"\u4e2d\u8bbe\u7f6e\u89e3\u6790\u5668\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"var config = new TouchSocketConfig()//\u914d\u7f6e\n .SetSerializationSelector(new MemoryPackSerializationSelector());\n")),(0,a.kt)("p",null,"\u7136\u540e\uff0c\u56e0\u4e3a\u8d4b\u503c\u65f6\u662f",(0,a.kt)("inlineCode",{parentName:"p"},"SerializationType"),"\u7684\u679a\u4e3e\u7c7b\u578b\uff0c\u6240\u4ee5\u6267\u884c\u5f3a\u5236\u7c7b\u578b\u8f6c\u6362\u5373\u53ef\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'InvokeOption invokeOption = new InvokeOption()\n{\n FeedbackType = FeedbackType.WaitInvoke,\n SerializationType = (SerializationType)4,\n Timeout = 1000 * 10\n};\n\nvar msg = client.Login(new LoginModel() { Account = "Account", Password = "Password" }, invokeOption);\n')),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u56e0\u4e3a\u4f7f\u7528\u7684\u662f",(0,a.kt)("inlineCode",{parentName:"p"},"MemoryPack"),"\u5e8f\u5217\u5316\uff0c\u6240\u4ee5\u6700\u597d\u5c06Rpc\u7684\u6240\u6709\u53c2\u6570\u58f0\u660e\u5728\u5355\u72ec\u7684\u7a0b\u5e8f\u96c6\u4e2d\u3002\u8fd9\u6837\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u9879\u76ee\u90fd\u53ef\u4ee5\u76f4\u63a5\u5f15\u7528\u3002")),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://gitee.com/RRQM_Home/TouchSocket/tree/master/examples/TouchRpc%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B/%E5%BA%8F%E5%88%97%E5%8C%96%E9%80%89%E6%8B%A9%E5%99%A8"},"\u5e8f\u5217\u5316\u9009\u62e9\u5668\u793a\u4f8b\u4ee3\u7801")))}m.isMDXComponent=!0},4831:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/serializationselector-1-d45835b7e936897b4e5403f61565f668.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/4ecf139e.eaf47e4a.js b/handbook/build/assets/js/4ecf139e.eaf47e4a.js new file mode 100644 index 000000000..ab0cfd3b1 --- /dev/null +++ b/handbook/build/assets/js/4ecf139e.eaf47e4a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[5215],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),d=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},s=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=d(r),f=o,m=s["".concat(l,".").concat(f)]||s[f]||p[f]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=s;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var d=2;d{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>c,toc:()=>d});var n=r(7462),o=(r(7294),r(3905));const a={id:"webdataforwarding",title:"Web\u6570\u636e\u8f6c\u53d1Winform\u9879\u76ee"},i=void 0,c={unversionedId:"webdataforwarding",id:"webdataforwarding",title:"Web\u6570\u636e\u8f6c\u53d1Winform\u9879\u76ee",description:"\u5b9a\u5236\u65b9",source:"@site/docs/webdataforwarding.mdx",sourceDirName:".",slug:"/webdataforwarding",permalink:"/touchsocket/docs/webdataforwarding",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/webdataforwarding.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675265724,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"webdataforwarding",title:"Web\u6570\u636e\u8f6c\u53d1Winform\u9879\u76ee"},sidebar:"docs",previous:{title:"\u6570\u636e\u8f6c\u53d1\u9879\u76ee",permalink:"/touchsocket/docs/dataforwarding"},next:{title:"FPS\u5b9e\u65f6\u6e38\u620f",permalink:"/touchsocket/docs/fpsgame"}},l={},d=[{value:"\u5b9a\u5236\u65b9",id:"\u5b9a\u5236\u65b9",level:2},{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u6280\u672f\u70b9",id:"\u6280\u672f\u70b9",level:2},{value:"\u6548\u679c",id:"\u6548\u679c",level:2}],u={toc:d};function p(e){let{components:t,...a}=e;return(0,o.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u5b9a\u5236\u65b9"},"\u5b9a\u5236\u65b9"),(0,o.kt)("p",null,"\u7f51\u53cb\u201c\u8f6f\u4ef6\u5f00\u53d1\u201d"),(0,o.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,o.kt)("p",null,"\u5e94\u8be5\u7f51\u53cb\u8981\u6c42\uff0c\u9700\u8981\u5b9e\u73b0Web\u7aef\u6570\u636e\u5411Winform\u7aef\u8f6c\u53d1\u7684\u529f\u80fd\u3002"),(0,o.kt)("h2",{id:"\u6280\u672f\u70b9"},"\u6280\u672f\u70b9"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"\u7f51\u7edc\u7f16\u7a0b")),(0,o.kt)("h2",{id:"\u6548\u679c"},"\u6548\u679c"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"6.gif",src:r(4301).Z,width:"2776",height:"1658"})))}p.isMDXComponent=!0},4301:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/webdataforwarding-1-669ef575ba0422c1a8881c07203101e9.gif"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/5137840a.ba3ea2d3.js b/handbook/build/assets/js/5137840a.ba3ea2d3.js new file mode 100644 index 000000000..957c67f6a --- /dev/null +++ b/handbook/build/assets/js/5137840a.ba3ea2d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8494],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function l(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=o.createContext({}),p=function(e){var t=o.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},u=function(e){var t=p(e.components);return o.createElement(c.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},k=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,c=e.parentName,u=a(e,["components","mdxType","originalType","parentName"]),k=p(r),m=n,h=k["".concat(c,".").concat(m)]||k[m]||s[m]||i;return r?o.createElement(h,l(l({ref:t},u),{},{components:r})):o.createElement(h,l({ref:t},u))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,l=new Array(i);l[0]=k;var a={};for(var c in t)hasOwnProperty.call(t,c)&&(a[c]=t[c]);a.originalType=e,a.mdxType="string"==typeof e?e:n,l[1]=a;for(var p=2;p{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>s,frontMatter:()=>i,metadata:()=>a,toc:()=>p});var o=r(7462),n=(r(7294),r(3905));const i={id:"description",title:"\u8bf4\u660e",slug:"/"},l=void 0,a={unversionedId:"description",id:"description",title:"\u8bf4\u660e",description:"\u5f53\u524d\u7248\u672c",source:"@site/docs/description.mdx",sourceDirName:".",slug:"/",permalink:"/touchsocket/docs/",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/description.mdx",tags:[],version:"current",frontMatter:{id:"description",title:"\u8bf4\u660e",slug:"/"},sidebar:"docs",next:{title:"\u5386\u53f2\u66f4\u65b0",permalink:"/touchsocket/docs/upgrade"}},c={},p=[{value:"\u5f53\u524d\u7248\u672c",id:"\u5f53\u524d\u7248\u672c",level:2},{value:"\u4f7f\u7528\u524d\u5fc5\u8981\u9605\u8bfb",id:"\u4f7f\u7528\u524d\u5fc5\u8981\u9605\u8bfb",level:2},{value:"\u4e2a\u4eba\u4f7f\u7528\u987b\u77e5:",id:"\u4e2a\u4eba\u4f7f\u7528\u987b\u77e5",level:3},{value:"\u4e8c\u6b21\u5f00\u53d1\u987b\u77e5:",id:"\u4e8c\u6b21\u5f00\u53d1\u987b\u77e5",level:3},{value:"\u76c8\u5229\u6027\uff08\u5546\u4e1a\uff09\u7528\u9014\u4f7f\u7528\u987b\u77e5:",id:"\u76c8\u5229\u6027\u5546\u4e1a\u7528\u9014\u4f7f\u7528\u987b\u77e5",level:3},{value:"TouchSocketPro \u5546\u7528\u8bb8\u53ef",id:"touchsocketpro-\u5546\u7528\u8bb8\u53ef",level:2},{value:"TouchSocketPro \u529f\u80fd\u90e8\u5206\u9075\u5faa\uff1a",id:"touchsocketpro-\u529f\u80fd\u90e8\u5206\u9075\u5faa",level:3}],u={toc:p};function s(e){let{components:t,...r}=e;return(0,n.kt)("wrapper",(0,o.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"\u5f53\u524d\u7248\u672c"},"\u5f53\u524d\u7248\u672c"),(0,n.kt)("p",null,(0,n.kt)("img",{parentName:"p",src:"https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket#crop=0&crop=0&crop=1&crop=1&height=25&id=nWQ9P&originHeight=20&originWidth=126&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=160",alt:null})," ",(0,n.kt)("img",{parentName:"p",src:"https://img.shields.io/nuget/v/TouchSocket.AspNetCore.svg?label=TouchSocket.AspNetCore#crop=0&crop=0&crop=1&crop=1&height=25&id=FWXGC&originHeight=20&originWidth=194&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=245",alt:null}),"\n",(0,n.kt)("img",{parentName:"p",src:"https://img.shields.io/nuget/v/TouchSocketPro.svg?label=TouchSocketPro#crop=0&crop=0&crop=1&crop=1&height=25&id=oHu5g&originHeight=20&originWidth=144&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=179",alt:null})," ",(0,n.kt)("img",{parentName:"p",src:"https://img.shields.io/nuget/v/TouchSocketPro.AspNetCore.svg?label=TouchSocketPro.AspNetCore#crop=0&crop=0&crop=1&crop=1&height=25&id=K0VEy&originHeight=20&originWidth=212&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=261",alt:null})),(0,n.kt)("hr",null),(0,n.kt)("admonition",{title:"\u516c\u544a",type:"tip"},(0,n.kt)("ol",{parentName:"admonition"},(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"\u539f RRQM \u7cfb\u6587\u6863\uff0c\u53ef\u4ee5\u52a0 qq \u7fa4\uff08234762506\uff09\uff0c\u5728\u7fa4\u6587\u4ef6\u81ea\u884c\u83b7\u53d6\u3002")))),(0,n.kt)("h2",{id:"\u4f7f\u7528\u524d\u5fc5\u8981\u9605\u8bfb"},"\u4f7f\u7528\u524d\u5fc5\u8981\u9605\u8bfb"),(0,n.kt)("p",null,"TouchSocket \u7531\u4f5c\u8005\u82e5\u6c5d\u68cb\u8317\u53ca\u5176\u4ed6\u8d21\u732e\u8005\u5f00\u53d1\uff0c\u6240\u6709\u7248\u6743\u5f52\u4f5c\u8005\u82e5\u6c5d\u68cb\u8317\u6240\u6709\uff0c\u7a0b\u5e8f\u96c6\u6e90\u4ee3\u7801\u5728\u9075\u5faa Apache License 2.0 \u7684\u5f00\u6e90\u534f\u8bae\u4ee5\u53ca",(0,n.kt)("strong",{parentName:"p"},"\u9644\u52a0\u534f\u8bae"),"\u4e0b\uff0c\u53ef",(0,n.kt)("strong",{parentName:"p"},"\u514d\u8d39"),"\u4f9b\u5176\u4ed6\u5f00\u53d1\u8005\u4e8c\u6b21\u5f00\u53d1\u6216\uff08\u5546\u4e1a\uff09\u4f7f\u7528\u3002"),(0,n.kt)("h1",{id:"apache-license-20-\u5f00\u6e90\u534f\u8bae\u7b80\u8ff0"},"Apache License 2.0 \u5f00\u6e90\u534f\u8bae\u7b80\u8ff0"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u6c38\u4e45\u6743\u5229"),(0,n.kt)("li",{parentName:"ul"},"\u4e00\u65e6\u88ab\u6388\u6743\uff0c\u6c38\u4e45\u62e5\u6709\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u5168\u7403\u8303\u56f4\u7684\u6743\u5229"),(0,n.kt)("li",{parentName:"ul"},"\u5728\u4e00\u4e2a\u56fd\u5bb6\u83b7\u5f97\u6388\u6743\uff0c\u9002\u7528\u4e8e\u6240\u6709\u56fd\u5bb6\u3002\u5047\u5982\u4f60\u5728\u7f8e\u56fd\uff0c\u8bb8\u53ef\u662f\u4ece\u5370\u5ea6\u6388\u6743\u7684\uff0c\u4e5f\u6ca1\u6709\u95ee\u9898\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u6388\u6743\u514d\u8d39\uff0c\u4e14\u65e0\u7248\u7a0e"),(0,n.kt)("li",{parentName:"ul"},"\u524d\u671f\uff0c\u540e\u671f\u5747\u65e0\u4efb\u4f55\u8d39\u7528\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u6388\u6743\u65e0\u6392\u4ed6\u6027"),(0,n.kt)("li",{parentName:"ul"},"\u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u83b7\u5f97\u6388\u6743"),(0,n.kt)("li",{parentName:"ul"},"\u6388\u6743\u4e0d\u53ef\u64a4\u6d88"),(0,n.kt)("li",{parentName:"ul"},"\u4e00\u65e6\u83b7\u5f97\u6388\u6743\uff0c\u6ca1\u6709\u4efb\u4f55\u4eba\u53ef\u4ee5\u53d6\u6d88\u3002\u6bd4\u5982\uff0c\u4f60\u57fa\u4e8e\u8be5\u4ea7\u54c1\u4ee3\u7801\u5f00\u53d1\u4e86\u884d\u751f\u4ea7\u54c1\uff0c\u4f60\u4e0d\u7528\u62c5\u5fc3\u4f1a\u5728\u67d0\u4e00\u5929\u88ab\u7981\u6b62\u4f7f\u7528\u8be5\u4ee3\u7801\u3002")),(0,n.kt)("h1",{id:"\u9644\u52a0\u534f\u8bae"},"\u9644\u52a0\u534f\u8bae"),(0,n.kt)("a",{name:"qLp3q"}),(0,n.kt)("h3",{id:"\u4e2a\u4eba\u4f7f\u7528\u987b\u77e5"},"\u4e2a\u4eba\u4f7f\u7528\u987b\u77e5:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u4e0d\u5f97\u5c06\u7a0b\u5e8f\u96c6\u7528\u4f5c\u8fdd\u6cd5\u72af\u7f6a\u6d3b\u52a8\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u4e0d\u5f97\u5c06\u7a0b\u5e8f\u96c6\u5355\u72ec\u5305\u88c5\u552e\u5356\uff0c\u7533\u8bf7\u4e13\u5229\u7b49\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u4e0d\u5f97\u64e6\u9664\u7a0b\u5e8f\u96c6\u6240\u6709\u6709\u5173\u4f5c\u8005\u7684\u4fe1\u606f\u3002")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"\u4ee5\u4e0a\u5185\u5bb9\u5fc5\u987b\u5168\u90e8\u7b26\u5408\uff0c\u4e2a\u4eba\u4f7f\u7528\u6388\u6743\u624d\u6210\u7acb\u3002")),(0,n.kt)("h3",{id:"\u4e8c\u6b21\u5f00\u53d1\u987b\u77e5"},"\u4e8c\u6b21\u5f00\u53d1\u987b\u77e5:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u4e0d\u5f97\u5c06\u7a0b\u5e8f\u96c6\u7528\u4f5c\u8fdd\u6cd5\u72af\u7f6a\u6d3b\u52a8\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u4e0d\u5f97\u5c06\u7a0b\u5e8f\u96c6\u5355\u72ec\u5305\u88c5\u552e\u5356\uff0c\u7533\u8bf7\u4e13\u5229\u7b49\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u4e0d\u5f97\u64e6\u9664\u7a0b\u5e8f\u96c6\u6240\u6709\u6709\u5173\u4f5c\u8005\u7684\u4fe1\u606f\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u4e8c\u6b21\u5f00\u53d1\u5b8c\u6210\u540e\u7684\u4f5c\u54c1\u5fc5\u987b\u9644\u5e26\u6e90\u4f5c\u54c1\u6240\u6709\u4f5c\u8005\u4fe1\u606f\uff0c\u5305\u62ec\u4f46\u4e0d\u9650\u4e8e\u4f5c\u8005\u540d\u3001Gitee\u3001Github \u5730\u5740\u7b49\u3002"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"\u5b8c\u6210\u540e"),"\u7684\u4f5c\u54c1\uff08\u4ec5 TouchSocket \u90e8\u5206\uff09\u5fc5\u987b\u5c06\u53d1\u5e03\u65f6\u6700\u65b0\u6e90\u4ee3\u7801\u63d0\u4ea4\u4e00\u4efd\u7ed9\u672c\u4f5c\u8005\uff0cQQ \u90ae\u7bb1\uff1a",(0,n.kt)("a",{parentName:"li",href:"mailto:505554090@qq.com"},"505554090@qq.com"),"\u3002")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"\u4ee5\u4e0a\u5185\u5bb9\u5fc5\u987b\u5168\u90e8\u7b26\u5408\uff0c\u4e8c\u6b21\u5f00\u53d1\u6388\u6743\u624d\u6210\u7acb\u3002")),(0,n.kt)("h3",{id:"\u76c8\u5229\u6027\u5546\u4e1a\u7528\u9014\u4f7f\u7528\u987b\u77e5"},"\u76c8\u5229\u6027\uff08\u5546\u4e1a\uff09\u7528\u9014\u4f7f\u7528\u987b\u77e5:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u4e0d\u5f97\u5c06\u7a0b\u5e8f\u96c6\u7528\u4f5c\u8fdd\u6cd5\u72af\u7f6a\u6d3b\u52a8\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u4e0d\u5f97\u5c06\u7a0b\u5e8f\u96c6\u5355\u72ec\u5305\u88c5\u552e\u5356\uff0c\u7533\u8bf7\u4e13\u5229\u7b49\u3002"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"\u4e0d\u5f97\u64e6\u9664\u7a0b\u5e8f\u96c6\u6240\u6709\u6709\u5173\u4f5c\u8005\u7684\u4fe1\u606f\uff0c\u5e76\u5fc5\u987b\u4e8e\u7528\u6237\u53ef\u89c1\u754c\u9762\uff08\u5982\u5173\u4e8e\uff09\u4e2d\u63d0\u540d\u3002"))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"\u4ee5\u4e0a\u5185\u5bb9\u5fc5\u987b\u5168\u90e8\u7b26\u5408\uff0c\u4f7f\u7528\u6388\u6743\u624d\u6210\u7acb\u3002")),(0,n.kt)("h2",{id:"touchsocketpro-\u5546\u7528\u8bb8\u53ef"},"TouchSocketPro \u5546\u7528\u8bb8\u53ef"),(0,n.kt)("p",null,"TouchSocketPro \u662f TouchSocket \u7684\u4f01\u4e1a\u7248\uff0c\u5176 99%\u529f\u80fd\u4e0e TouchSocket \u4e00\u81f4\u3002\u6240\u6709\u7248\u6743\u5f52\u4f5c\u8005\u82e5\u6c5d\u68cb\u8317\u6240\u6709\u3002"),(0,n.kt)("h3",{id:"touchsocketpro-\u529f\u80fd\u90e8\u5206\u9075\u5faa"},"TouchSocketPro \u529f\u80fd\u90e8\u5206\u9075\u5faa\uff1a"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u9650\u65f6\uff081h\uff09\u514d\u8d39\u6d4b\u8bd5\uff0c\u6d4b\u8bd5\u671f\u95f4\u53ef\u53c2\u4e0e\u5546\u4e1a\u4f7f\u7528\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u4ed8\u8d39\u4f7f\u7528\uff0c\u8d2d\u4e70\u540e\u8fd8\u987b\u9075\u5faa\u76f8\u5173\u4f7f\u7528\u534f\u8bae\uff0c\u8be6\u60c5\u54a8\u8be2\u82e5\u6c5d\u68cb\u8317\u3002")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"TouchSocketPro \u7a0b\u5e8f\u96c6\u6e90\u4ee3\u7801\u4e0d\u516c\u5f00\u5f00\u6e90\uff0c\u9700\u8981\u4ed8\u8d39\u8d2d\u4e70\u3002")),(0,n.kt)("h1",{id:"\u514d\u8d23\u7533\u660e"},"\u514d\u8d23\u7533\u660e"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"\u5728\u4f7f\u7528 TouchSocket"),"\u6216",(0,n.kt)("strong",{parentName:"p"},"TouchSocketPro \u4e4b\u524d\u8bf7\u8fdb\u884c\u7f1c\u5bc6\u7684\u6d4b\u8bd5\u3002\u5728\u4f7f\u7528\u671f\u95f4\uff0c\u7531\u672c\u7a0b\u5e8f\u96c6\u9020\u6210\u6216\u95f4\u63a5\u9020\u6210\u7684\u6240\u6709\u635f\u5931\uff0c\u5747\u81ea\u5df1\u627f\u62c5\uff0c\u4e0e\u672c\u7a0b\u5e8f\u96c6\u65e0\u5173\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/53cff02b.6893293e.js b/handbook/build/assets/js/53cff02b.6893293e.js new file mode 100644 index 000000000..a5b609702 --- /dev/null +++ b/handbook/build/assets/js/53cff02b.6893293e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9311],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=r.createContext({}),s=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},k=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),k=s(n),d=a,m=k["".concat(i,".").concat(d)]||k[d]||u[d]||o;return n?r.createElement(m,l(l({ref:t},p),{},{components:n})):r.createElement(m,l({ref:t},p))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=k;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c.mdxType="string"==typeof e?e:a,l[1]=c;for(var s=2;s{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>s});var r=n(7462),a=(n(7294),n(3905));const o={id:"createwebsocketclient",title:"\u521b\u5efaWebSocket\u5ba2\u6237\u7aef"},l=void 0,c={unversionedId:"createwebsocketclient",id:"createwebsocketclient",title:"\u521b\u5efaWebSocket\u5ba2\u6237\u7aef",description:"\u8bf4\u660e",source:"@site/docs/createwebsocketclient.mdx",sourceDirName:".",slug:"/createwebsocketclient",permalink:"/touchsocket/docs/createwebsocketclient",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createwebsocketclient.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"createwebsocketclient",title:"\u521b\u5efaWebSocket\u5ba2\u6237\u7aef"},sidebar:"docs",previous:{title:"\u521b\u5efaWebSocket\u670d\u52a1\u5668",permalink:"/touchsocket/docs/createwebsocketservice"},next:{title:"WSCommandLinePlugin",permalink:"/touchsocket/docs/wscommandlineplugin"}},i={},s=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u53ef\u914d\u7f6e\u9879",id:"\u53ef\u914d\u7f6e\u9879",level:2},{value:"\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",id:"\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",level:2},{value:"\u521b\u5efaWS\u5ba2\u6237\u7aef",id:"\u521b\u5efaws\u5ba2\u6237\u7aef",level:2},{value:"\u521b\u5efaWSs\u5ba2\u6237\u7aef",id:"\u521b\u5efawss\u5ba2\u6237\u7aef",level:2},{value:"\u53d1\u9001\u6570\u636e",id:"\u53d1\u9001\u6570\u636e",level:2},{value:"\u63a5\u6536\u6570\u636e",id:"\u63a5\u6536\u6570\u636e",level:2}],p={toc:s};function u(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,a.kt)("p",null,"\u652f\u6301Ssl\u7684WebSocket\u5ba2\u6237\u7aef\u3002"),(0,a.kt)("h2",{id:"\u53ef\u914d\u7f6e\u9879"},"\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("p",null,"\u7ee7\u627fHttpClient\u3002"),(0,a.kt)("h2",{id:"\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"},"\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"),(0,a.kt)("p",null,"\u652f\u6301",(0,a.kt)("strong",{parentName:"p"},"ITcpPlugin\u3001IWebSocketPlugin")),(0,a.kt)("h2",{id:"\u521b\u5efaws\u5ba2\u6237\u7aef"},"\u521b\u5efaWS\u5ba2\u6237\u7aef"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'WebSocketClient myWSClient = new WebSocketClient();\n//myWSClient.Received += this.MyWSClient_Received;\n//myWSClient.Handshaked += this.MyWSClient_Handshaked;\n\nmyWSClient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost(this.textBox3.Text)\n .ConfigureContainer(a =>\n {\n a.SetSingletonLogger(new LoggerGroup(new EasyLogger(this.ShowMsg), new FileLogger()));\n }));\nmyWSClient.Connect();\n\nmyWSClient.Logger.Message("\u8fde\u63a5\u6210\u529f");\n')),(0,a.kt)("a",{name:"xWVU6"}),(0,a.kt)("h2",{id:"\u521b\u5efawss\u5ba2\u6237\u7aef"},"\u521b\u5efaWSs\u5ba2\u6237\u7aef"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"*\u5f53\u9700\u8981\u8fde\u63a5\u5230\u7531\u8bc1\u4e66\u673a\u6784\u9881\u53d1\u7684\u7f51\u5740\uff08\u4f8b\u5982\uff1a"),"\u5c0f\u7a0b\u5e8f",(0,a.kt)("strong",{parentName:"p"},"\u3001","_","_","\u7269\u8054\u7f51","_","_","\u7b49\uff09\u65f6\uff0c\u4ec5\u9700\u8981\u8bbe\u7f6eurl\u5373\u53ef\u3002*")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"wss://127.0.0.1:7789/ws\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u5f53\u8fde\u63a5\u81ea\u5b9a\u4e49\u8bc1\u4e66\u7684Ssl\uff1awss://127.0.0.1:7789/ws")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'WebSocketClient myWSClient = new WebSocketClient();\n\nmyWSClient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost(new IPHost("wss://127.0.0.1:7789/ws"))\n .SetClientSslOption(\n new ClientSslOption()\n {\n ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") },\n SslProtocols = SslProtocols.Tls12,\n TargetHost = "127.0.0.1",\n CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; }\n }))\n .Connect();\n\nConsole.WriteLine("\u8fde\u63a5\u6210\u529f");\nwhile (true)\n{\n myWSClient.SendWithWS(Console.ReadLine());\n}\n')),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},(0,a.kt)("em",{parentName:"strong"},'\u6ce8\u610f\uff1a\u5f53\u4f7f\u7528\u57df\u540d\u8fde\u63a5\u65f6\uff0cTargetHost\u4e3a\u57df\u540d\uff0c\u4f8b\u5982\u8fde\u63a5\u5230IPHost("ws://baidu.com")\u65f6\uff0cTargetHost\u5e94\u5f53\u586b\u5199\uff1abaidu.com'))," ",(0,a.kt)("a",{name:"JKBcN"})),(0,a.kt)("h2",{id:"\u53d1\u9001\u6570\u636e"},"\u53d1\u9001\u6570\u636e"),(0,a.kt)("p",null,"\u5c06client\u5bf9\u8c61\u8f6c\u4e3a",(0,a.kt)("strong",{parentName:"p"},"HttpClient"),"\uff0c\u5373\u53ef\u4f7f\u7528",(0,a.kt)("strong",{parentName:"p"},"\u6269\u5c55\u65b9\u6cd5"),"\uff0c\u8fdb\u884c\u53d1\u9001\u3002"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u4f5c\u4e3a\u4e00\u6761\u6d88\u606f\u53d1\u9001")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u5c06\u4e00\u4e2a\u6570\u636e\u5206\u5305\u53d1\u9001"),"\n\u4f8b\u5982\uff1a\u53d1\u9001\u7684\u6570\u636e\u4e3a{0,1,2,3,4,5,6,7,8,9}\uff0c\u5f53\u8bbe\u7f6epackageSize\u4e3a5\u65f6\uff0c\u4f1a\u5148\u53d1\u9001{0,1,2,3,4}\u4f5c\u4e3a\u5934\u5305\uff0c\u7136\u540e\u53d1\u9001{5,6,7,8,9}\u7684\u540e\u7ee7\u5305\u3002"),(0,a.kt)("a",{name:"RhCgs"}),(0,a.kt)("h2",{id:"\u63a5\u6536\u6570\u636e"},"\u63a5\u6536\u6570\u636e"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u8ba2\u9605Received\u4e8b\u4ef6\u5b9e\u73b0\uff0c\u6216\u4f7f\u7528\u63d2\u4ef6\u5b9e\u73b0\u3002")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"client.Received += (c, e) =>\n {\n switch (e.Opcode)\n {\n case WSDataType.Cont:\n break;\n case WSDataType.Text:\n break;\n case WSDataType.Binary:\n break;\n case WSDataType.Close:\n break;\n case WSDataType.Ping:\n break;\n case WSDataType.Pong:\n break;\n default:\n break;\n }\n };\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u9644\u52a0\u63d2\u4ef6\u5b9e\u73b0"),"\n\u8be5\u64cd\u4f5c\u548c\u670d\u52a1\u5668\u4e00\u81f4\u3002"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/5525.c53056dc.js b/handbook/build/assets/js/5525.c53056dc.js new file mode 100644 index 000000000..5b53d4f5f --- /dev/null +++ b/handbook/build/assets/js/5525.c53056dc.js @@ -0,0 +1 @@ +(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[5525],{5525:()=>{}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/578e6f54.582b3ec5.js b/handbook/build/assets/js/578e6f54.582b3ec5.js new file mode 100644 index 000000000..74a4cbe6b --- /dev/null +++ b/handbook/build/assets/js/578e6f54.582b3ec5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2375],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),i=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},p=function(e){var t=i(e.components);return n.createElement(c.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=i(r),d=a,f=u["".concat(c,".").concat(d)]||u[d]||m[d]||o;return r?n.createElement(f,s(s({ref:t},p),{},{components:r})):n.createElement(f,s({ref:t},p))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=u;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,s[1]=l;for(var i=2;i{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>m,frontMatter:()=>o,metadata:()=>l,toc:()=>i});var n=r(7462),a=(r(7294),r(3905));const o={id:"streamtransfer",title:"Stream\u4f20\u8f93"},s=void 0,l={unversionedId:"streamtransfer",id:"streamtransfer",title:"Stream\u4f20\u8f93",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/streamtransfer.mdx",sourceDirName:".",slug:"/streamtransfer",permalink:"/touchsocket/docs/streamtransfer",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/streamtransfer.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"streamtransfer",title:"Stream\u4f20\u8f93"},sidebar:"docs",previous:{title:"\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c",permalink:"/touchsocket/docs/remotefilecontrol"},next:{title:"b.\u8fdc\u7a0b\u6d41\u8bbf\u95ee",permalink:"/touchsocket/docs/remotestreamaccess"}},c={},i=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u6027",id:"\u4e8c\u7279\u6027",level:2},{value:"\u4e09\u3001\u793a\u4f8b",id:"\u4e09\u793a\u4f8b",level:2}],p={toc:i};function m(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"Stream\u7684\u76f4\u63a5\u53d1\u9001\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u5355\u4e2a"),"TCP\u8fde\u63a5\u4e0a\u53ef\u4ee5",(0,a.kt)("strong",{parentName:"p"},"\u540c\u65f6"),"\u8fdb\u884c\u591a\u4e2a\u4f20\u8f93\u3002\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u4e4b\u95f4\u53ef\u4ee5\u4efb\u610f\u76f8\u4e92\u53d1\u9001\u3002"),(0,a.kt)("a",{name:"CtYNg"}),(0,a.kt)("h2",{id:"\u4e8c\u7279\u6027"},"\u4e8c\u3001\u7279\u6027"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5b9e\u65f6\u68c0\u6d4b\u901f\u5ea6\uff0c\u8fdb\u5ea6\u7b49\u4fe1\u606f\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u4eceStream.Position\u5f00\u59cb\uff0c\u76f4\u5230Read\u7ed3\u675f\u3002")),(0,a.kt)("a",{name:"BxGNl"}),(0,a.kt)("h2",{id:"\u4e09\u793a\u4f8b"},"\u4e09\u3001\u793a\u4f8b"),(0,a.kt)("p",null,"\u4e0b\u5217\u4ee5\u670d\u52a1\u5668\u4f5c\u4e3aStream\u7684\u63a5\u6536\u65b9\u3002\u5ba2\u6237\u7aef\u4e3a\u53d1\u9001\u65b9\u3002"),(0,a.kt)("p",null,"\u3010\u670d\u52a1\u5668\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouceRpcService service = CreateTcpTouceRpcService();\n\nservice.StreamTransfering += (socketClient, e) =>\n{\n e.Bucket = new MemoryStream();//\u6b64\u5904\u7528MemoryStream\u4f5c\u4e3a\u63a5\u6536\u5bb9\u5668\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528FileStream\u3002\n e.AddOperation(Operation.Permit);//\u5141\u8bb8\u63a5\u6536\u8be5\u6d41\n Metadata metadata = e.Metadata;//\u83b7\u53d6\u5143\u6570\u636e\n StreamOperator streamOperator = e.StreamOperator;//\u83b7\u53d6\u64cd\u4f5c\u5668\uff0c\u53ef\u7528\u4e8e\u53d6\u6d88\u4efb\u52a1\uff0c\u83b7\u53d6\u8fdb\u5ea6\u7b49\u3002\n\n //Console.WriteLine("\u8bbe\u7f6e\u6700\u5927\u4f20\u8f93\u901f\u5ea6\u4e3a1024byte");\n //streamOperator.SetMaxSpeed(1024);\n\n //Console.WriteLine("5\u79d2\u540e\u8bbe\u7f6e\u4e3a5Mb");\n //RRQMCore.Run.EasyAction.DelayRun(5, () =>\n //{\n // streamOperator.SetMaxSpeed(1024 * 1024 * 5);\n //});\n\n Task.Run(async () =>\n {\n while (streamOperator.Result.ResultCode == ResultCode.Default)\n {\n Console.WriteLine($"\u901f\u5ea6={streamOperator.Speed()},\u8fdb\u5ea6={streamOperator.Progress}");\n\n await Task.Delay(1000);\n }\n\n Console.WriteLine($"\u4ece\u5faa\u73af\u4f20\u8f93\u7ed3\u675f,\u72b6\u6001={streamOperator.Result}");\n });\n Console.WriteLine("\u5f00\u59cb\u63a5\u6536\u6d41\u6570\u636e");\n};\n\nservice.StreamTransfered += (socketClient, e) =>\n{\n //\u6b64\u5904\u4e0d\u7ba1\u4f20\u8f93\u6210\u529f\u4e0e\u5426\uff0c\u90fd\u4f1a\u6267\u884c\uff0c\u5177\u4f53\u72b6\u6001\u901a\u8fc7e.Status\u5224\u65ad\u3002\n if (e.Result.ResultCode == ResultCode.Success)\n {\n \n }\n e.Bucket.Dispose();//\u5fc5\u987b\u624b\u52a8\u91ca\u653e\u6d41\u6570\u636e\u3002\n Console.WriteLine($"\u4eceReceivedStream\u4f20\u8f93\u7ed3\u675f,\u72b6\u6001={e.Result}");\n};\n\n')),(0,a.kt)("p",null,"\u3010\u5ba2\u6237\u7aef\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClient client = CreateTcpTouchRpcClient();\n\nbyte[] data = new byte[1024 * 1024 * 50];\nnew Random().NextBytes(data);\nMemoryStream stream = new MemoryStream(data);\nstream.Position = 0;\n\nConsole.WriteLine($"\u5373\u5c06\u53d1\u9001\u6d41\u6570\u636e\uff0c\u957f\u5ea6\u4e3a:{stream.Length}");\n\nStreamOperator streamOperator = new StreamOperator();\nstreamOperator.PackageSize = 1024 * 64;//\u5206\u5305\u957f\u5ea6\n//streamOperator.SetMaxSpeed(1024 * 1024 * 5);//\u6700\u5927\u4f20\u8f93\u503c\n\n//streamOperator.Cancel();//\u968f\u65f6\u53d6\u6d88\u4f20\u8f93\n\nLoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (a) =>\n{\n if (streamOperator.Result.ResultCode != ResultCode.Default)\n {\n a.Dispose();\n }\n Console.WriteLine($"\u901f\u5ea6\uff1a{streamOperator.Speed()},\u8fdb\u5ea6\uff1a{streamOperator.Progress}");\n});\nloopAction.RunAsync();\n\nMetadata metadata = new Metadata();//\u5c06\u952e\u503c\u5bf9\u7684\u5143\u6570\u636e\u4f20\u5230\u63a5\u6536\u7aef\nmetadata.Add("1", "1");\nmetadata.Add("2", "2");\n\n//\u8be5\u65b9\u6cd5\u4f1a\u963b\u585e\uff0c\u76f4\u5230\u7ed3\u675f\nResult result = client.SendStream(stream, streamOperator, metadata);\nConsole.WriteLine(result);\n\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/6bf8fe32.dcdba073.js b/handbook/build/assets/js/6bf8fe32.dcdba073.js new file mode 100644 index 000000000..e8dfda827 --- /dev/null +++ b/handbook/build/assets/js/6bf8fe32.dcdba073.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8808],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>g});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function c(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var o=l.createContext({}),p=function(e){var t=l.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):c(c({},t),e)),a},s=function(e){var t=p(e.components);return l.createElement(o.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},d=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,o=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),d=p(a),g=n,h=d["".concat(o,".").concat(g)]||d[g]||u[g]||r;return a?l.createElement(h,c(c({ref:t},s),{},{components:a})):l.createElement(h,c({ref:t},s))}));function g(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,c=new Array(r);c[0]=d;var i={};for(var o in t)hasOwnProperty.call(t,o)&&(i[o]=t[o]);i.originalType=e,i.mdxType="string"==typeof e?e:n,c[1]=i;for(var p=2;p{a.d(t,{Z:()=>X});var l=a(7294),n=a(7462);const r=(e,t,a)=>e?"string"==typeof e?e:e[t]||a:a,c={display:"block"},i=e=>{let{size:t,color:a,style:i,...o}=e;const p=i?{...c,...i}:c;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},o),l.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:r(a,0,"#333333")}))};i.defaultProps={size:18};const o=i,p={display:"block"},s=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...p,...c}:p;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:r(a,0,"#333333")}),l.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:r(a,1,"#333333")}))};s.defaultProps={size:18};const u=s,d={display:"block"},g=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...d,...c}:d;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:r(a,0,"#333333")}),l.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:r(a,1,"#333333")}),l.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:r(a,2,"#333333")}))};g.defaultProps={size:18};const h=g,m={display:"block"},v=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...m,...c}:m;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:r(a,0,"#333333")}))};v.defaultProps={size:18};const f=v,k={display:"block"},y=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...k,...c}:k;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:r(a,0,"#333333")}))};y.defaultProps={size:18};const b=y,z={display:"block"},x=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...z,...c}:z;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:r(a,0,"#333333")}),l.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:r(a,1,"#333333")}),l.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:r(a,2,"#333333")}))};x.defaultProps={size:18};const E=x,w={display:"block"},T=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...w,...c}:w;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:r(a,0,"#333333")}),l.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:r(a,1,"#333333")}))};T.defaultProps={size:18};const L=T,P={display:"block"},C=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...P,...c}:P;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:r(a,0,"#333333")}),l.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:r(a,1,"#333333")}))};C.defaultProps={size:18};const V=C,N={display:"block"},M=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...N,...c}:N;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:r(a,0,"#333333")}),l.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:r(a,1,"#333333")}))};M.defaultProps={size:18};const O=M,H={display:"block"},S=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...H,...c}:H;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:r(a,0,"#333333")}))};S.defaultProps={size:18};const D=S,j={display:"block"},F=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...j,...c}:j;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:r(a,0,"#333333")}))};F.defaultProps={size:18};const Z=F,A={display:"block"},B=e=>{let{size:t,color:a,style:c,...i}=e;const o=c?{...A,...c}:A;return l.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:o},i),l.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:r(a,0,"#333333")}))};B.defaultProps={size:18};const I=B,U=e=>{let{name:t,...a}=e;switch(t){case"youhua":return l.createElement(o,a);case"dayi":return l.createElement(u,a);case"shengji":return l.createElement(h,a);case"tiaozheng":return l.createElement(f,a);case"gengxin":return l.createElement(b,a);case"wendang":return l.createElement(E,a);case"shanchu":return l.createElement(L,a);case"bug":return l.createElement(V,a);case"xinzeng":return l.createElement(O,a);case"fuwu":return l.createElement(D,a);case"down":return l.createElement(Z,a);case"up":return l.createElement(I,a)}return null},q="label_p8vM",_="icon_knQK";function X(e){const{children:t}=e,a={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return l.createElement("label",{className:q,title:t,style:{backgroundColor:a[t].bgColor}},l.createElement(U,{name:a[t].icon,color:"white",size:14,className:_})," ",t)}},7507:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>d,frontMatter:()=>c,metadata:()=>o,toc:()=>s});var l=a(7462),n=(a(7294),a(3905)),r=a(510);const c={id:"tlvdatahandlingadapter",title:"\u4e09\u5143\u7ec4\u7f16\u7801\uff08TLV\uff09\u9002\u914d\u5668"},i=void 0,o={unversionedId:"tlvdatahandlingadapter",id:"tlvdatahandlingadapter",title:"\u4e09\u5143\u7ec4\u7f16\u7801\uff08TLV\uff09\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248",source:"@site/docs/tlvdatahandlingadapter.mdx",sourceDirName:".",slug:"/tlvdatahandlingadapter",permalink:"/touchsocket/docs/tlvdatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/tlvdatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675586056,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"tlvdatahandlingadapter",title:"\u4e09\u5143\u7ec4\u7f16\u7801\uff08TLV\uff09\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"Pipeline\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/pipelinedatahandlingadapter"},next:{title:"a.\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668",permalink:"/touchsocket/docs/udpdatahandlingadapter"}},p={},s=[{value:"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248",id:"\u4e00\u8bf4\u660e-\u4f01\u4e1a\u7248",level:2},{value:"\u4e8c\u3001\u4f7f\u7528",id:"\u4e8c\u4f7f\u7528",level:2},{value:"\u4e09\u3001\u4fdd\u6d3b\u673a\u5236",id:"\u4e09\u4fdd\u6d3b\u673a\u5236",level:2},{value:"\u81ea\u52a8ping",id:"\u81ea\u52a8ping",level:3},{value:"\u56db\u3001\u6784\u5efa\u6570\u636e",id:"\u56db\u6784\u5efa\u6570\u636e",level:2},{value:"\u4e94\u3001\u53d1\u9001\u6570\u636e",id:"\u4e94\u53d1\u9001\u6570\u636e",level:2}],u={toc:s};function d(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,l.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"\u4e00\u8bf4\u660e-\u4f01\u4e1a\u7248"},"\u4e00\u3001\u8bf4\u660e ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("p",null,"TLV\u9002\u914d\u5668\uff0c\u5b9a\u4e49\u4e86\u4e00\u79cd\u7b80\u5355\u9ad8\u6548\u7684\u4e09\u5143\u7ec4\u7f16\u7801\uff0c\u7b80\u79f0TLV\u7f16\u7801\u3002\u5b83\u662f\u7531\u6570\u636e\u7684\u7c7b\u578bTag\uff08T\uff09\uff0c\u6570\u636e\u7684\u957f\u5ea6Length\uff08L\uff09\uff0c\u6570\u636e\u7684\u503cValue\uff08V\uff09\u6784\u6210\u7684\u4e00\u7ec4\u6570\u636e\u62a5\u6587\u3002TLV\u662f\u57fa\u4e8e\u4e8c\u8fdb\u5236\u7f16\u7801\u7684\uff0c\u5c06\u6570\u636e\u4ee5\uff08T -L- V\uff09\u7684\u5f62\u5f0f\u7f16\u7801\u4e3a\u5b57\u8282\u6570\u7ec4\uff0c\u5373TLV\u662f\u5b57\u8282\u6d41\u7684\u6570\u636e\u4f20\u8f93\u534f\u8bae\u3002\u5b83\u89c4\u5b9a\u4e86\u4e00\u5e27\u6570\u636e\u7684\u9996\u4e2a\u5b57\u8282\u6216\u51e0\u4e2a\u5b57\u8282\u6765\u8868\u793a\u6570\u636e\u7c7b\u578b\uff0c\u7d27\u63a5\u7740\u4e00\u4e2a\u6216\u51e0\u4e2a\u5b57\u8282\u8868\u793a\u6570\u636e\u957f\u5ea6\uff0c\u6700\u540e\u662f\u6570\u636e\u7684\u5185\u5bb9\u3002"),(0,n.kt)("p",null,"\u6570\u636e\u534f\u8bae\u5982\u4e0b\uff1a"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tag")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u6807\u8bc6\u6570\u636e\u7684\u7c7b\u578b\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u53602\u5b57\u8282"),(0,n.kt)("li",{parentName:"ul"},"\u5927\u7aef\u5e8f\u65e0\u7b26\u53f7\u6574\u578b\u3002"),(0,n.kt)("li",{parentName:"ul"},"0-9\u4fdd\u7559\u7cfb\u7edf\u4f7f\u7528\u3002","[","10,65535]\u5ba2\u6237\u7aef\u81ea\u884c\u5b9a\u4e49\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u5df2\u7528Tag\uff1a0\u8868\u793aClose\uff0c\u8f7d\u8377Value\u4e3a\u5173\u95ed\u6d88\u606f\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u5df2\u7528Tag\uff1a1\u8868\u793aPing\uff0c\u65e0\u8f7d\u8377\uff0c\u5bf9\u65b9\u6536\u5230\u540e\u5fc5\u987b\u65e0\u6761\u4ef6\u8fd4\u56dePong\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u5df2\u7528Tag\uff1a2\u8868\u793aPong\uff0c\u65e0\u8f7d\u8377\u3002")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Length")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u6807\u8bc6\u540e\u7eedValue\u7684\u957f\u5ea6\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u6309LengtType\u7684\u6307\u5b9a\uff0c\u53ef\u4ee5\u75281\u5b57\u8282\u30012\u5b57\u8282\u30014\u5b57\u8282\u6765\u8868\u793a\u957f\u5ea6\uff0c\u5206\u522b\u5bf9\u5e94255\u300165535\u30012147483647\u5b57\u8282\u7684\u5bf9\u5e94\u503c\u3002"),(0,n.kt)("li",{parentName:"ul"},"1\u5b57\u8282\u65f6\uff0c\u4e0d\u533a\u5206\u7aef\u5e8f\u3002"),(0,n.kt)("li",{parentName:"ul"},"2\u5b57\u8282\u65f6\uff0c\u5927\u7aef\u5e8f\u65e0\u7b26\u53f7\u6574\u578b\u3002"),(0,n.kt)("li",{parentName:"ul"},"4\u5b57\u8282\u65f6\uff0c\u5927\u7aef\u5e8f\u6709\u7b26\u53f7\u6574\u578b\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u9ed8\u8ba4\u4f7f\u75282\u5b57\u8282\u7684Ushort\u7c7b\u578b\u3002")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Value")),(0,n.kt)("p",null,"\u8f7d\u8377\u6570\u636e\u3002\u53ef\u4ee5\u4e3a\u4efb\u610f\u7c7b\u578b\u3002"),(0,n.kt)("h2",{id:"\u4e8c\u4f7f\u7528"},"\u4e8c\u3001\u4f7f\u7528"),(0,n.kt)("p",null,"\u3010\u9002\u914d\u5668\u4f7f\u7528\u3011\n\u8bbe\u7f6e\u7684FixedHeaderType\u7c7b\u578b\u540e\uff0c\u5b9e\u9645\u7684\u652f\u6301\u6700\u5927\u6570\u636e\u8fd8\u53d7SetMaxPackageSize\u5f71\u54cd\u3002\u9ed8\u8ba4\u4e3a1024",(0,n.kt)("em",{parentName:"p"},"1024"),"10\u5b57\u8282\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},".SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//\u5982\u679c\u4f7f\u7528TLVPlugin\u63d2\u4ef6\uff0c\u6b64\u6b65\u9aa4\u53ef\u7701\u7565\u3002\n")),(0,n.kt)("p",null,"\u3010\u63d2\u4ef6\u3011"),(0,n.kt)("p",null,"\u53ea\u9700\u8981\u6dfb\u52a0TLVPlugin\u63d2\u4ef6\u5373\u53ef\u3002\u5ba2\u6237\u7aef\u4ea6\u7136\u3002"),(0,n.kt)("p",null,"\u4f7f\u7528\u63d2\u4ef6\uff0c\u76f8\u5f53\u4e8e\u81ea\u52a8\u8bbe\u7f6e\u9002\u914d\u5668\uff0c\u5e76\u4e14\u4e3b\u52a8\u56de\u5e94Ping\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},"var config = new TouchSocketConfig();\n\nconfig.UsePlugin()\n.SetMaxPackageSize(1024 * 1024 * 10)\n//.SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//\u5982\u679c\u4f7f\u7528TLVPlugin\u63d2\u4ef6\uff0c\u6b64\u6b65\u9aa4\u53ef\u7701\u7565\u3002\n.ConfigurePlugins(a =>\n{\n a.Add()//\u4f7f\u7528\u63d2\u4ef6\uff0c\u76f8\u5f53\u4e8e\u81ea\u52a8\u8bbe\u7f6e\u9002\u914d\u5668\uff0c\u5e76\u4e14\u4e3b\u52a8\u56de\u5e94Ping\u3002\n .SetLengthType(FixedHeaderType.Int);//\u8bbe\u7f6e\u652f\u6301\u7684\u6700\u5927\u6570\u636e\u7c7b\u578b\uff0c\u8be5\u503c\u8fd8\u53d7SetMaxPackageSize\u5f71\u54cd\u3002\n});\n")),(0,n.kt)("h2",{id:"\u4e09\u4fdd\u6d3b\u673a\u5236"},"\u4e09\u3001\u4fdd\u6d3b\u673a\u5236"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"TLV\u6570\u636e\u534f\u8bae\u4e2d\uff0c\u5b9a\u4e49\u4e86Tag=1\u65f6\u4e3aping\uff0cTag=2\u65f6\u4e3aPong\u3002\u6240\u4ee5\u53ef\u4ee5\u4f9d\u9760\u8fd9\u5957\u673a\u5236\uff0c\u8fdb\u884c\u4fdd\u6d3b\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u5b9e\u9645\u4e0a\uff0c\u5728\u63d2\u4ef6\u4e2d\uff0c\u5df2\u7ecf\u505a\u4e86Ping\uff0cPong\u7684\u5904\u7406\u3002\u5ba2\u6237\u7aef\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u8be5\u64cd\u4f5c\uff0c\u670d\u52a1\u5668\u4e5f\u53ef\u4ee5\u76f4\u63a5ping\u5ba2\u6237\u7aef\u3002")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},"bool result=this.m_client.Ping();//\u8fd4\u56de\u503c\u4e3atrue\u65f6\uff0c\u5bf9\u7aef\u4e00\u5b9a\u5728\u7ebf\u3002\u6b64\u65b9\u6cd5\u670d\u52a1\u5668\u4e5f\u53ef\u4ee5\u4e3b\u52a8ping\u5ba2\u6237\u7aef\u3002\n")),(0,n.kt)("h3",{id:"\u81ea\u52a8ping"},"\u81ea\u52a8ping"),(0,n.kt)("p",null,"\u5229\u7528PollingKeepAlivePlugin\u63d2\u4ef6\u81ea\u52a8Ping\u3002"),(0,n.kt)("h2",{id:"\u56db\u6784\u5efa\u6570\u636e"},"\u56db\u3001\u6784\u5efa\u6570\u636e"),(0,n.kt)("p",null,"\u5982\u679c\u5bf9\u65b9\u662f\u5176\u4ed6\u8bed\u8a00\uff0c\u8bf7\u4f7f\u7528\u7ea6\u5b9a\u7684\u65b9\u5f0f\u53d1\u9001\u6570\u636e\u3002\n\u5982\u679c\u662fCSharp\u7684\u8bdd\uff0c\u6784\u5efa\u6570\u636e\u975e\u5e38\u7b80\u5355\u3002\n\u6784\u5efa\u6570\u636e\u65f6\uff0c\u53ef\u7528TLVDataFrame\u6784\u5efa\u3002\u6216\u8005\u5176\u503c\u7c7b\u578b\u6784\u5efa\uff0c\u6b64\u5904\u63a8\u8350",(0,n.kt)("strong",{parentName:"p"},"ValueTLVDataFrame"),"\n\u3010\u76f4\u63a5\u6784\u9020\u3011"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},"ValueTLVDataFrame requestInfo = new ValueTLVDataFrame(10, new byte[] { 0, 1, 2, 3 });\n")),(0,n.kt)("p",null,"\u3010\u8ffd\u52a0\u578b\u6784\u5efa\u3011"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"}," ValueTLVDataFrame requestInfo = new ValueTLVDataFrame();\n requestInfo.AppendValue(new byte[] { 0, 1, 2, 3 });\n requestInfo.AppendValue(new byte[] { 4, 5, 6, 7 });\n")),(0,n.kt)("h2",{id:"\u4e94\u53d1\u9001\u6570\u636e"},"\u4e94\u3001\u53d1\u9001\u6570\u636e"),(0,n.kt)("p",null,"\u6784\u5efa\u5b8c\u6570\u636e\u540e\uff0c\u76f4\u63a5\u53d1\u9001\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},'client.Send(new ValueTLVDataFrame(10,Encoding.UTF8.GetBytes("rrqm")));//\u63a8\u8350\u5199\u6cd5\uff0c\u5982\u679c\u4f7f\u7528\u81ea\u5df1Build\uff0c\u5219\u9700\u8981\u660e\u786e\u6307\u51faFixedHeaderType\u7684\u503c\u3002\n')),(0,n.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u521b\u5efa\u7684\u9002\u914d\u5668\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/763782ab.f77e52b3.js b/handbook/build/assets/js/763782ab.f77e52b3.js new file mode 100644 index 000000000..dab833ef2 --- /dev/null +++ b/handbook/build/assets/js/763782ab.f77e52b3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1969],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function a(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var i=o.createContext({}),c=function(e){var t=o.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=c(e.components);return o.createElement(i.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,l=e.originalType,i=e.parentName,p=g(e,["components","mdxType","originalType","parentName"]),u=c(r),d=n,m=u["".concat(i,".").concat(d)]||u[d]||s[d]||l;return r?o.createElement(m,a(a({ref:t},p),{},{components:r})):o.createElement(m,a({ref:t},p))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=r.length,a=new Array(l);a[0]=u;var g={};for(var i in t)hasOwnProperty.call(t,i)&&(g[i]=t[i]);g.originalType=e,g.mdxType="string"==typeof e?e:n,a[1]=g;for(var c=2;c{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>a,default:()=>s,frontMatter:()=>l,metadata:()=>g,toc:()=>c});var o=r(7462),n=(r(7294),r(3905));const l={id:"ilog",title:"\u65e5\u5fd7\u8bb0\u5f55\u5668"},a=void 0,g={unversionedId:"ilog",id:"ilog",title:"\u65e5\u5fd7\u8bb0\u5f55\u5668",description:"\u4e00\u3001\u65e5\u5fd7\u8bb0\u5f55\u63a5\u53e3\uff08ILog\uff09",source:"@site/docs/ilog.mdx",sourceDirName:".",slug:"/ilog",permalink:"/touchsocket/docs/ilog",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/ilog.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"ilog",title:"\u65e5\u5fd7\u8bb0\u5f55\u5668"},sidebar:"docs",previous:{title:"\u6570\u636e\u52a0\u5bc6",permalink:"/touchsocket/docs/datasecurity"},next:{title:"\u5e94\u7528\u4fe1\u4f7f",permalink:"/touchsocket/docs/appmessenger"}},i={},c=[{value:"\u4e00\u3001\u65e5\u5fd7\u8bb0\u5f55\u63a5\u53e3\uff08ILog\uff09",id:"\u4e00\u65e5\u5fd7\u8bb0\u5f55\u63a5\u53e3ilog",level:2},{value:"\u4e8c\u3001\u63a7\u5236\u53f0\u65e5\u5fd7\u8bb0\u5f55\u5668\uff08ConsoleLogger\uff09",id:"\u4e8c\u63a7\u5236\u53f0\u65e5\u5fd7\u8bb0\u5f55\u5668consolelogger",level:2},{value:"\u4e09\u3001\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u5668\uff08FileLogger\uff09",id:"\u4e09\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u5668filelogger",level:2},{value:"\u56db\u3001\u65e5\u5fd7\u7ec4\u8bb0\u5f55\u5668\uff08LoggerGroup\uff09",id:"\u56db\u65e5\u5fd7\u7ec4\u8bb0\u5f55\u5668loggergroup",level:2},{value:"\u4e94\u3001\u65e5\u5fd7\u6269\u5c55",id:"\u4e94\u65e5\u5fd7\u6269\u5c55",level:2}],p={toc:c};function s(e){let{components:t,...l}=e;return(0,n.kt)("wrapper",(0,o.Z)({},p,l,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"\u4e00\u65e5\u5fd7\u8bb0\u5f55\u63a5\u53e3ilog"},"\u4e00\u3001\u65e5\u5fd7\u8bb0\u5f55\u63a5\u53e3\uff08ILog\uff09"),(0,n.kt)("p",null,"\u7ee7\u627fILog\u63a5\u53e3\uff0c\u7136\u540e\u5b9e\u73b0\u4ee5\u4e0b\u65b9\u6cd5\u3002\u5373\u53ef\u5b9e\u73b0\u5185\u90e8\u7684\u65e5\u5fd7\u8bb0\u5f55\u3002\n\u5f53\u7528\u6237\u81ea\u884c\u8f93\u51fa\u65e5\u5fd7\u65f6\uff0c\u53ef\u81ea\u884c\u5b9e\u73b0\u8fc7\u7a0b\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyLogger : ILog\n{\n public LogType LogType { get; set; } = LogType.Debug | LogType.Error;\n\n public void Log(LogType logType, object source, string message, Exception exception)\n {\n //\u6b64\u5904\u5c31\u662f\u65e5\u5fd7\u5b9e\u9645\u8f93\u51fa\u7684\u4f4d\u7f6e\u3002\n }\n}\n")),(0,n.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,n.kt)("p",{parentName:"admonition"},(0,n.kt)("strong",{parentName:"p"},"LogType")," \u8868\u793a\u5f53\u524d\u65e5\u5fd7\u7684\u53ef\u8f93\u51fa\u7c7b\u578b\uff0c\u5e76\u975e\u8f93\u51fa\u7ea7\u522b\uff0c\u6240\u4ee5\u5f53\u9700\u8981\u8f93\u51fa\u591a\u79cd\u7c7b\u578b\u65f6\uff0c\u8bf7\u8fdb\u884c\u4f4d\u57df\u64cd\u4f5c\u3002")),(0,n.kt)("h2",{id:"\u4e8c\u63a7\u5236\u53f0\u65e5\u5fd7\u8bb0\u5f55\u5668consolelogger"},"\u4e8c\u3001\u63a7\u5236\u53f0\u65e5\u5fd7\u8bb0\u5f55\u5668\uff08ConsoleLogger\uff09"),(0,n.kt)("p",null,"\u5728\u4f7f\u7528\u63a7\u5236\u53f0\u65e5\u5fd7\u8bb0\u5f55\u5668\u65f6\uff0c\u4f1a\u6309\u7167\u4ee5\u4e0b\u683c\u5f0f\u8f93\u51fa\u3002\n",(0,n.kt)("img",{alt:"image.png",src:r(7426).Z,width:"920",height:"198"})),(0,n.kt)("h2",{id:"\u4e09\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u5668filelogger"},"\u4e09\u3001\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u5668\uff08FileLogger\uff09"),(0,n.kt)("p",null,"\u5728\u4f7f\u7528\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u5668\u65f6\uff0c\u5148\u4f1a\u5728\u6307\u5b9a\u76ee\u5f55\u4e0b\u521b\u5efa\u201clogs\u201d\u76ee\u5f55\uff0c\u7136\u540e\u6309\u65e5\u671f\u751f\u6210\u201c.log\u201d\u6587\u4ef6\u3002\n",(0,n.kt)("img",{alt:"image.png",src:r(7405).Z,width:"940",height:"202"})),(0,n.kt)("h2",{id:"\u56db\u65e5\u5fd7\u7ec4\u8bb0\u5f55\u5668loggergroup"},"\u56db\u3001\u65e5\u5fd7\u7ec4\u8bb0\u5f55\u5668\uff08LoggerGroup\uff09"),(0,n.kt)("p",null,"\u4f7f\u7528\u65e5\u5fd7\u7ec4\u8bb0\u5f55\u5668\u65f6\uff0c\u53ef\u4ee5\u540c\u65f6\u8bb0\u5f55\u591a\u4e2a\u65e5\u5fd7\uff0c\u4f8b\u5982\uff1a\u4e0b\u5217\u793a\u4f8b\u5c31\u540c\u65f6\u5728\u63a7\u5236\u53f0\u548c\u6587\u4ef6\u8bb0\u5f55\u65e5\u5fd7\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},"LoggerGroup logger = new LoggerGroup(new ConsoleLogger(),new FileLogger());\n")),(0,n.kt)("h2",{id:"\u4e94\u65e5\u5fd7\u6269\u5c55"},"\u4e94\u3001\u65e5\u5fd7\u6269\u5c55"),(0,n.kt)("p",null,"\u5f15\u5165\u547d\u540d\u7a7a\u95f4\u3002\u53ef\u5feb\u6377\u8bb0\u5f55\u65e5\u5fd7\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},'LoggerGroup logger = new LoggerGroup(new ConsoleLogger(),new FileLogger());\nlogger.Info("Message");\nlogger.Warning("Warning");\nlogger.Error("Error");\n')))}s.isMDXComponent=!0},7426:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/ilog-1-cfa95e95bee4088509c9c35784bca442.png"},7405:(e,t,r)=>{r.d(t,{Z:()=>o});const o=r.p+"assets/images/ilog-2-715cd211ac8ac352a6e44fd2ac11f6ee.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/7a6724ae.5b8f96aa.js b/handbook/build/assets/js/7a6724ae.5b8f96aa.js new file mode 100644 index 000000000..8cdb1b26d --- /dev/null +++ b/handbook/build/assets/js/7a6724ae.5b8f96aa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[4456],{3905:(e,n,t)=>{t.d(n,{Zo:()=>i,kt:()=>k});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function c(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function s(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=o.createContext({}),a=function(e){var n=o.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},i=function(e){var n=a(e.components);return o.createElement(p.Provider,{value:n},e.children)},u={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},j=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,c=e.originalType,p=e.parentName,i=l(e,["components","mdxType","originalType","parentName"]),j=a(t),k=r,d=j["".concat(p,".").concat(k)]||j[k]||u[k]||c;return t?o.createElement(d,s(s({ref:n},i),{},{components:t})):o.createElement(d,s({ref:n},i))}));function k(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var c=t.length,s=new Array(c);s[0]=j;var l={};for(var p in n)hasOwnProperty.call(n,p)&&(l[p]=n[p]);l.originalType=e,l.mdxType="string"==typeof e?e:r,s[1]=l;for(var a=2;a{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>s,default:()=>u,frontMatter:()=>c,metadata:()=>l,toc:()=>a});var o=t(7462),r=(t(7294),t(3905));const c={id:"calljsonrpc",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1"},s=void 0,l={unversionedId:"calljsonrpc",id:"calljsonrpc",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1",description:"\u4e00\u3001\u76f4\u63a5\u8c03\u7528",source:"@site/docs/calljsonrpc.mdx",sourceDirName:".",slug:"/calljsonrpc",permalink:"/touchsocket/docs/calljsonrpc",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/calljsonrpc.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"calljsonrpc",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1"},sidebar:"docs",previous:{title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",permalink:"/touchsocket/docs/jsonrpcservice"},next:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/xmlrpcdescription"}},p={},a=[{value:"\u4e00\u3001\u76f4\u63a5\u8c03\u7528",id:"\u4e00\u76f4\u63a5\u8c03\u7528",level:2},{value:"\u4e8c\u3001\u5ba2\u6237\u7aef\u76f4\u63a5\u8c03\u7528",id:"\u4e8c\u5ba2\u6237\u7aef\u76f4\u63a5\u8c03\u7528",level:2},{value:"\u4ee3\u7406\u8c03\u7528RPC",id:"\u4ee3\u7406\u8c03\u7528rpc",level:2},{value:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\uff1f",id:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6",level:3},{value:"\u8c03\u7528",id:"\u8c03\u7528",level:3}],i={toc:a};function u(e){let{components:n,...t}=e;return(0,r.kt)("wrapper",(0,o.Z)({},i,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u76f4\u63a5\u8c03\u7528"},"\u4e00\u3001\u76f4\u63a5\u8c03\u7528"),(0,r.kt)("p",null,"\u56e0\u4e3aJsonRpc\u662f\u901a\u7528\u8c03\u7528\u534f\u8bae\uff0c\u6240\u4ee5\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528Json\u5b57\u7b26\u4e32\u8c03\u7528\u3002"),(0,r.kt)("p",null,"\u4ee5\u4e0b\u5b57\u7b26\u4e32\u53ea\u662f\u793a\u4f8b\uff0c\u5177\u4f53\u7684method\u53c2\u6570\uff0c\u5e94\u5f53\u9075\u5faa\u5f53\u524d\u8def\u7531\u3002"),(0,r.kt)("p",null,"\u3010Tcp\u534f\u8bae\u76f4\u63a5\u8c03\u7528\u3011\n\u5728TCP\u534f\u8bae\u65f6\uff0c\u6309\u7167\u9002\u914d\u5668\uff0c\u9009\u62e9\u6027\u7684\u662f\u5426\u4ee5\\r\\n\u7ed3\u5c3e\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1}\n')),(0,r.kt)("p",null,"\u3010Http\u534f\u8bae\u76f4\u63a5\u8c03\u7528\u3011\n\u5728Http\u534f\u8bae\u65f6\uff0c\u4ee5Url+Post\u65b9\u5f0f\u5373\u53ef"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1}\n')),(0,r.kt)("p",null,"\u3010Websocket\u534f\u8bae\u76f4\u63a5\u8c03\u7528\u3011\n\u5728Websocket\u534f\u8bae\u65f6\uff0c\u4ee5\u6587\u672c\u7c7b\u578b\uff0c\u76f4\u63a5\u53d1\u9001\u5230\u670d\u52a1\u5668\u5373\u53ef\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1}\n')),(0,r.kt)("a",{name:"aDbqe"}),(0,r.kt)("h2",{id:"\u4e8c\u5ba2\u6237\u7aef\u76f4\u63a5\u8c03\u7528"},"\u4e8c\u3001\u5ba2\u6237\u7aef\u76f4\u63a5\u8c03\u7528"),(0,r.kt)("p",null,"TouchSocket\u63d0\u4f9b\u4e86JsonRpc\u7684\u4e13\u5c5e\u5ba2\u6237\u7aef\uff0c\u76f4\u63a5\u8c03\u7528\uff0c\u5219\u4f1a\u5219\u662f\u4e0d\u4f7f\u7528",(0,r.kt)("strong",{parentName:"p"},"\u4efb\u4f55\u4ee3\u7406"),"\uff0c\u76f4\u63a5Call RPC\uff0c\u4f7f\u7528\u6bd4\u8f83\u7b80\u5355\u3002"),(0,r.kt)("p",null,"\u3010TCP\u534f\u8bae\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'JsonRpcClient jsonRpcClient = new JsonRpcClient();\njsonRpcClient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("127.0.0.1:7705")\n .SetJRPT(JRPT.Tcp));\njsonRpcClient.Connect();\n\nConsole.WriteLine("\u8fde\u63a5\u6210\u529f");\nstring result = jsonRpcClient.Invoke("jsonrpcconsoleapp.server.testjsonrpc", InvokeOption.WaitInvoke, "TouchSocket");\nConsole.WriteLine($"Tcp\u8fd4\u56de\u7ed3\u679c:{result}");\n\nresult = jsonRpcClient.Invoke("TestJsonRpc1", InvokeOption.WaitInvoke, "TouchSocket");\nConsole.WriteLine($"Tcp\u8fd4\u56de\u7ed3\u679c:{result}");\n\nresult = jsonRpcClient.Invoke("jsonrpcconsoleapp.server.testgetcontext", InvokeOption.WaitInvoke, "TouchSocket");\nConsole.WriteLine($"Tcp\u8fd4\u56de\u7ed3\u679c:{result}");\n\nJObject obj = new JObject();\nobj.Add("A", "A");\nobj.Add("B", 10);\nobj.Add("C", 100.1);\nJObject newObj = jsonRpcClient.Invoke("jsonrpcconsoleapp.server.testjobject", InvokeOption.WaitInvoke, obj);\nConsole.WriteLine($"Tcp\u8fd4\u56de\u7ed3\u679c:{newObj}");\n')),(0,r.kt)("p",null,"\u3010Http\u534f\u8bae\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'static void JsonRpcClientInvokeByHttp()\n{\n JsonRpcClient jsonRpcClient = new JsonRpcClient();\n jsonRpcClient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("http://127.0.0.1:7706/jsonrpc")\n .SetJRPT(JRPT.Http));\n jsonRpcClient.Connect();\n Console.WriteLine("\u8fde\u63a5\u6210\u529f");\n string result = jsonRpcClient.Invoke("server/testjsonrpc", InvokeOption.WaitInvoke, "TouchSocket");\n Console.WriteLine($"Http\u8fd4\u56de\u7ed3\u679c:{result}");\n\n JObject obj = new JObject();\n obj.Add("A", "A");\n obj.Add("B", 10);\n obj.Add("C", 100.1);\n JObject newObj = jsonRpcClient.Invoke("server/testjobject", InvokeOption.WaitInvoke, obj);\n Console.WriteLine($"Http\u8fd4\u56de\u7ed3\u679c:{newObj}");\n}\n')),(0,r.kt)("p",null,"\u3010Websocket\u534f\u8bae\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'JsonRpcClient jsonRpcClient = new JsonRpcClient();\njsonRpcClient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("ws://127.0.0.1:7706/ws")//\u6b64url\u5c31\u662f\u80fd\u8fde\u63a5\u5230websocket\u7684\u8def\u5f84\u3002\n .SetDataHandlingAdapter(() => new TerminatorPackageAdapter("\\r\\n"))\n .SetJRPT(JRPT.Websocket));\njsonRpcClient.Connect();\n\nConsole.WriteLine("\u8fde\u63a5\u6210\u529f");\nstring result = jsonRpcClient.TestJsonRpc("RRQM");\nConsole.WriteLine($"Websocket\u8fd4\u56de\u7ed3\u679c:{result}");\n\nresult = jsonRpcClient.TestJsonRpc1("RRQM");\nConsole.WriteLine($"Websocket\u8fd4\u56de\u7ed3\u679c:{result}");\n\nresult = jsonRpcClient.TestGetContext("RRQM");\nConsole.WriteLine($"Websocket\u8fd4\u56de\u7ed3\u679c:{result}");\n\nJObject obj = new JObject();\nobj.Add("A", "A");\nobj.Add("B", 10);\nobj.Add("C", 100.1);\nJObject newObj = jsonRpcClient.TestJObject(obj);\nConsole.WriteLine($"Websocket\u8fd4\u56de\u7ed3\u679c:{newObj}");\n')),(0,r.kt)("a",{name:"rrWhi"}),(0,r.kt)("h2",{id:"\u4ee3\u7406\u8c03\u7528rpc"},"\u4ee3\u7406\u8c03\u7528RPC"),(0,r.kt)("p",null,"\u4ee3\u7406\u8c03\u7528\u7684\u4fbf\u6377\u5728\u4e8e\uff0c\u4e0d\u7528\u518d\u7ea0\u7ed3\u8c03\u7528\u7684\u53c2\u6570\u7c7b\u578b\u6b63\u4e0d\u6b63\u786e\uff0c\u56e0\u4e3a\u8fd9\u4e9b\uff0c\u4ee3\u7406\u5de5\u5177\u90fd\u4f1a\u66ff\u4f60\u505a\u597d\u3002 ",(0,r.kt)("a",{name:"AbsXl"})),(0,r.kt)("h3",{id:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6"},"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\uff1f"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://www.yuque.com/eo2w71/rrqm/a13509bfc3581f4576861b690b4a809a"},"\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\u8be6\u60c5")," ",(0,r.kt)("a",{name:"jsQUz"})),(0,r.kt)("h3",{id:"\u8c03\u7528"},"\u8c03\u7528"),(0,r.kt)("p",null,"\u5f53\u4ee3\u7406\u88ab\u5ba2\u6237\u7aef\u83b7\u53d6\u4ee5\u540e\uff0c\u5ba2\u6237\u7aef\u9879\u76ee\u4e2d\u4f1a\u591a\u51fa\u4e00\u4e2a",(0,r.kt)("strong",{parentName:"p"},"RRQMProxy\uff08//TODO:\u8fd9\u91cc\u9700\u8981\u4fee\u6539\uff0c\u4e0a\u9762\u7684\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\u8be6\u60c5\u7684\u94fe\u63a5\u5931\u6548\u9700\u8981\u4fee\u6539\uff0c\u4e0b\u9762\u622a\u56fe\u9700\u8981\u4fee\u6539\uff09"),"\u7684\u6587\u4ef6\uff08\u6216\u8005\u5982\u679c\u662f\u670d\u52a1\u5668\u751f\u6210\u7684\u672c\u5730\u4ee3\u7406\uff0c\u5219\u9700\u8981\u590d\u5236\u5230\u5ba2\u6237\u7aef\u9879\u76ee\u4e2d\uff09\uff0c\u5728\u8be5\u6587\u4ef6\u4e2d\uff0c\u5219\u5305\u542b\u4e86\u6240\u6709\u7684",(0,r.kt)("strong",{parentName:"p"},"\u4ee3\u7406\u65b9\u6cd5"),"\u548c",(0,r.kt)("strong",{parentName:"p"},"\u4ee3\u7406\u7c7b"),"\uff0c\u53ef\u76f4\u63a5\u7531\u4ee3\u7406\u7c7b\u53d1\u8d77\u8c03\u7528\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'JsonRpcClient jsonRpcClient = new JsonRpcClient(JRPT.Http);\njsonRpcClient.Setup("http://127.0.0.1:7706/jsonrpc");\njsonRpcClient.Connect();\nServer server= new Server(jsonRpcClient);//Server\u662f\u751f\u6210\u7684\u4ee3\u7406\u7c7b\u3002\nserver.TestJsonRpc("TouchSocket");//\u4ee3\u7406\u8c03\u7528\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/7b93349f.84dc1f60.js b/handbook/build/assets/js/7b93349f.84dc1f60.js new file mode 100644 index 000000000..48c3f786c --- /dev/null +++ b/handbook/build/assets/js/7b93349f.84dc1f60.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6171],{3905:(e,t,n)=>{n.d(t,{Zo:()=>y,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function p(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var p=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),i=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},y=function(e){var t=i(e.components);return r.createElement(c.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,p=e.originalType,c=e.parentName,y=l(e,["components","mdxType","originalType","parentName"]),u=i(n),m=a,d=u["".concat(c,".").concat(m)]||u[m]||s[m]||p;return n?r.createElement(d,o(o({ref:t},y),{},{components:n})):r.createElement(d,o({ref:t},y))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var p=n.length,o=new Array(p);o[0]=u;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var i=2;i{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>s,frontMatter:()=>p,metadata:()=>l,toc:()=>i});var r=n(7462),a=(n(7294),n(3905));const p={id:"dependencyproperty",title:"\u4f9d\u8d56\u5c5e\u6027"},o=void 0,l={unversionedId:"dependencyproperty",id:"dependencyproperty",title:"\u4f9d\u8d56\u5c5e\u6027",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/dependencyproperty.mdx",sourceDirName:".",slug:"/dependencyproperty",permalink:"/touchsocket/docs/dependencyproperty",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/dependencyproperty.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"dependencyproperty",title:"\u4f9d\u8d56\u5c5e\u6027"},sidebar:"docs",previous:{title:"\u4f9d\u8d56\u6ce8\u5165\u5bb9\u5668",permalink:"/touchsocket/docs/ioc"},next:{title:"\u6587\u4ef6\u6d41\u6c60",permalink:"/touchsocket/docs/filepool"}},c={},i=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4ec0\u4e48\u662f\u4f9d\u8d56\u5c5e\u6027\uff1f",id:"\u4e8c\u4ec0\u4e48\u662f\u4f9d\u8d56\u5c5e\u6027",level:2},{value:"\u4e09\u3001\u4f18\u7f3a\u70b9",id:"\u4e09\u4f18\u7f3a\u70b9",level:2}],y={toc:i};function s(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},y,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u7528\u8fc7WPF\u7684\u5c0f\u4f19\u4f34\u4e00\u5b9a\u5bf9\u4f9d\u8d56\u5c5e\u6027\u4e0d\u964c\u751f\u3002\u6240\u4ee5TouchSocket\u6a21\u4eff\u5176\u7ed3\u6784\uff0c\u521b\u5efa\u4e86\u9002\u7528\u4e8e\u7f51\u7edc\u6846\u67b6\u7684\u4f9d\u8d56\u5c5e\u6027\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u4ec0\u4e48\u662f\u4f9d\u8d56\u5c5e\u6027"},"\u4e8c\u3001\u4ec0\u4e48\u662f\u4f9d\u8d56\u5c5e\u6027\uff1f"),(0,a.kt)("p",null,"\u6211\u4eec\u77e5\u9053\u5e38\u89c4\u5c5e\u6027\uff0c\u5c31\u662f\u62e5\u6709get\uff0cset\u8bbf\u95ee\u5668\u7684\u5b57\u6bb5\uff0c\u53eb\u505a\u5c5e\u6027\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyClass\n{\n public int MyProperty { get; set; }\n}\n")),(0,a.kt)("p",null,"\u800c\u4f9d\u8d56\u5c5e\u6027\uff0c\u5219\u662f\u5177\u6709\u6ce8\u5165\u7279\u5f81\u7684\u5c5e\u6027\u3002\u5b83\u53ef\u4ee5\u50cf\u666e\u901a\u5c5e\u6027\u4e00\u6837\uff0c\u58f0\u660e\u5728\u7c7b\u5185\u90e8\uff08\u793a\u4f8b1\uff09\u3002\u4e5f\u53ef\u4ee5\u58f0\u660e\u5728\u4efb\u4f55\u5730\u65b9\uff08\u793a\u4f8b2\uff09\u3002"),(0,a.kt)("p",null,"\u3010\u793a\u4f8b1\u3011"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u7ee7\u627f",(0,a.kt)("strong",{parentName:"li"},"DependencyObject")),(0,a.kt)("li",{parentName:"ol"},"\u6309\u5982\u4e0b\u683c\u5f0f\u751f\u6210\u5c5e\u6027\u9879\uff08propdp\u4ee3\u7801\u5757\u53ef\u5feb\u901f\u5b9e\u73b0\uff09")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'class MyClass: DependencyObject\n{\n /// \n /// \u5c5e\u6027\u9879\n /// \n public int MyProperty\n {\n get { return GetValue(MyPropertyProperty); }\n set { SetValue(MyPropertyProperty, value); }\n }\n\n /// \n /// \u4f9d\u8d56\u9879\n /// \n public static readonly DependencyProperty MyPropertyProperty =\n DependencyProperty.Register("MyProperty", typeof(MyClass), 10);\n\n}\n')),(0,a.kt)("p",null,"\u3010\u793a\u4f8b2\u3011\n\u5047\u8bbe\u4ee5\u4e0b\u60c5\u51b5\uff1a\n\u5bf9\u4e8eTouchSocket\u7684",(0,a.kt)("strong",{parentName:"p"},"IClient"),"\u63a5\u53e3\u5bf9\u8c61\uff08\u5df2\u7ecf\u5b9e\u73b0IDependencyObject\uff09\uff0c\u5e0c\u671b\u521b\u5efa\u4e00\u4e2aint\u7c7b\u578b\u7684\uff0c\u540d\u4e3aMyProperty\u7684\u4f9d\u8d56\u9879\u5c5e\u6027\u3002"),(0,a.kt)("p",null,"\u90a3\u4e48\uff0c\u53ef\u4ee5\u7528\u4e0b\u5217\u4ee3\u7801\u5b9e\u73b0"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'public static class DependencyExtensions\n{\n /// \n /// \u4f9d\u8d56\u9879\n /// \n public static readonly DependencyProperty MyPropertyProperty =\n DependencyProperty.Register("MyProperty", typeof(MyClass), 10);\n\n /// \n /// \u8bbe\u7f6eMyProperty\n /// \n /// \n /// \n /// \n /// \n public static TClient SetMyProperty(this TClient client, int value) where TClient : IClient\n {\n client.SetValue(MyPropertyProperty, value);\n return client;\n }\n\n /// \n /// \u83b7\u53d6MyProperty\n /// \n /// \n /// \n /// \n public static int GetMyProperty(this TClient client) where TClient : IClient\n {\n return client.GetValue(MyPropertyProperty);\n }\n}\n')),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"TcpClient tcpClient = new TcpClient();\ntcpClient.SetMyProperty(100);\nint MyProperty = tcpClient.GetMyProperty();\n")),(0,a.kt)("h2",{id:"\u4e09\u4f18\u7f3a\u70b9"},"\u4e09\u3001\u4f18\u7f3a\u70b9"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u4f18\u70b9\uff1a")),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u4e0d\u58f0\u660e\u5728\u7c7b\u5185\u90e8\u3002\u8fd9\u610f\u5473\u7740\u53ef\u4ee5\u4ece\u5916\u90e8\u6ce8\u5165\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u4e0d\u9700\u8981\u521d\u59cb\u8d4b\u503c\uff0c\u4e5f\u5c31\u610f\u5473\u7740\u521b\u5efa\u5927\u91cf\u5bf9\u8c61\u65f6\uff0c\u53ef\u4ee5\u4e0d\u9700\u8981\u5360\u7528\u592a\u591a\u5185\u5b58\u3002")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u7f3a\u70b9\uff1a")),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5bf9\u4e8e\u503c\u7c7b\u578b\uff0c\u6d89\u53ca\u62c6\u88c5\u7bb1\u64cd\u4f5c\uff0c\u5bf9\u6027\u80fd\u6709\u4e00\u5b9a\u6027\u80fd\u5f71\u54cd\uff08\u4e0d\u662f\u51e0\u767e\u4e07\u64cd\u4f5c\uff0c\u53ef\u4ee5\u5ffd\u7565\uff09\u3002")),(0,a.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"\u5f53\u4e00\u4e2a\u5c5e\u6027\u88ab\u9891\u7e41\uff08\u5343\u4e07\u7ea7\u522b\uff09\u4f7f\u7528\u65f6\uff0c\u4e0d\u5efa\u8bae\u4f7f\u7528\u4f9d\u8d56\u5c5e\u6027\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/7c171c7d.82420f61.js b/handbook/build/assets/js/7c171c7d.82420f61.js new file mode 100644 index 000000000..1483dad2c --- /dev/null +++ b/handbook/build/assets/js/7c171c7d.82420f61.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2373],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>d});var r=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=r.createContext({}),i=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},s=function(e){var t=i(e.components);return r.createElement(p.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,l=e.mdxType,a=e.originalType,p=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=i(n),d=l,f=u["".concat(p,".").concat(d)]||u[d]||m[d]||a;return n?r.createElement(f,o(o({ref:t},s),{},{components:n})):r.createElement(f,o({ref:t},s))}));function d(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var a=n.length,o=new Array(a);o[0]=u;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c.mdxType="string"==typeof e?e:l,o[1]=c;for(var i=2;i{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>m,frontMatter:()=>a,metadata:()=>c,toc:()=>i});var r=n(7462),l=(n(7294),n(3905));const a={id:"callxmlrpc",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1"},o=void 0,c={unversionedId:"callxmlrpc",id:"callxmlrpc",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1",description:"\u76f4\u63a5\u8c03\u7528",source:"@site/docs/callxmlrpc.mdx",sourceDirName:".",slug:"/callxmlrpc",permalink:"/touchsocket/docs/callxmlrpc",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/callxmlrpc.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"callxmlrpc",title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1"},sidebar:"docs",previous:{title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",permalink:"/touchsocket/docs/xmlrpcservice"}},p={},i=[{value:"\u76f4\u63a5\u8c03\u7528",id:"\u76f4\u63a5\u8c03\u7528",level:2},{value:"\u4ee3\u7406\u8c03\u7528RPC",id:"\u4ee3\u7406\u8c03\u7528rpc",level:2},{value:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\uff1f",id:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6",level:3},{value:"\u8c03\u7528",id:"\u8c03\u7528",level:3}],s={toc:i};function m(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"\u76f4\u63a5\u8c03\u7528"},"\u76f4\u63a5\u8c03\u7528"),(0,l.kt)("p",null,"\u76f4\u63a5\u8c03\u7528\uff0c\u5219\u662f\u4e0d\u4f7f\u7528",(0,l.kt)("strong",{parentName:"p"},"\u4efb\u4f55\u4ee3\u7406"),"\uff0c\u76f4\u63a5Call RPC\uff0c\u4f7f\u7528\u6bd4\u8f83\u7b80\u5355\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'static void Main(string[] args)\n{\n var client = GetXmlRpcClient();\n\n //\u76f4\u63a5\u8c03\u7528\n int result1 = client.Invoke("Sum", InvokeOption.WaitInvoke, 10, 20);\n Console.WriteLine($"\u76f4\u63a5\u8c03\u7528\uff0c\u8fd4\u56de\u7ed3\u679c:{result1}");\n\n Console.ReadKey();\n}\nstatic XmlRpcClient GetXmlRpcClient()\n{\n XmlRpcClient jsonRpcClient = new XmlRpcClient();\n jsonRpcClient.Setup("http://127.0.0.1:7706/xmlRpc");\n jsonRpcClient.Connect();\n Console.WriteLine("\u8fde\u63a5\u6210\u529f");\n return jsonRpcClient;\n}\n')),(0,l.kt)("p",null,"\u3010\u4ea6\u6216\u8005\u76f4\u63a5\u4f7f\u7528\u5b57\u7b26\u4e32\u8c03\u7528\u3011\n\u5728Http-Post\u65b9\u5f0f\u5373\u53ef\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-xml"},'\n\n Sum\n \n \n \n 10\n \n \n \n \n 20\n \n \n \n\n')),(0,l.kt)("a",{name:"rrWhi"}),(0,l.kt)("h2",{id:"\u4ee3\u7406\u8c03\u7528rpc"},"\u4ee3\u7406\u8c03\u7528RPC"),(0,l.kt)("p",null,"\u4ee3\u7406\u8c03\u7528\u7684\u4fbf\u6377\u5728\u4e8e\uff0c\u4e0d\u7528\u518d\u7ea0\u7ed3\u8c03\u7528\u7684\u53c2\u6570\u7c7b\u578b\u6b63\u4e0d\u6b63\u786e\uff0c\u56e0\u4e3a\u8fd9\u4e9b\uff0c\u4ee3\u7406\u5de5\u5177\u90fd\u4f1a\u66ff\u4f60\u505a\u597d\u3002 ",(0,l.kt)("a",{name:"AbsXl"})),(0,l.kt)("h3",{id:"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6"},"\u5982\u4f55\u751f\u6210\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\uff1f"),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://www.yuque.com/eo2w71/rrqm/a13509bfc3581f4576861b690b4a809a"},"\u83b7\u53d6\u4ee3\u7406\u6587\u4ef6\u8be6\u60c5")," ",(0,l.kt)("a",{name:"jsQUz"})),(0,l.kt)("h3",{id:"\u8c03\u7528"},"\u8c03\u7528"),(0,l.kt)("p",null,"\u5f53\u4ee3\u7406\u88ab\u5ba2\u6237\u7aef\u83b7\u53d6\u4ee5\u540e\uff0c\u5ba2\u6237\u7aef\u9879\u76ee\u4e2d\u4f1a\u591a\u51fa\u4e00\u4e2a",(0,l.kt)("strong",{parentName:"p"},"RRQMProxy"),"\u7684\u6587\u4ef6\uff08\u6216\u8005\u5982\u679c\u662f\u670d\u52a1\u5668\u751f\u6210\u7684\u672c\u5730\u4ee3\u7406\uff0c\u5219\u9700\u8981\u590d\u5236\u5230\u5ba2\u6237\u7aef\u9879\u76ee\u4e2d\uff09\uff0c\u5728\u8be5\u6587\u4ef6\u4e2d\uff0c\u5219\u5305\u542b\u4e86\u6240\u6709\u7684",(0,l.kt)("strong",{parentName:"p"},"\u4ee3\u7406\u65b9\u6cd5"),"\u548c",(0,l.kt)("strong",{parentName:"p"},"\u4ee3\u7406\u7c7b"),"\uff0c\u53ef\u76f4\u63a5\u7531\u4ee3\u7406\u7c7b\u53d1\u8d77\u8c03\u7528\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'static void Main(string[] args)\n{\n var client = GetXmlRpcClient();\n\n Server server = new Server(client);\n int result2 = server.Sum(10, 20);\n Console.WriteLine($"\u4ee3\u7406\u8c03\u7528\uff0c\u8fd4\u56de\u7ed3\u679c:{result2}");\n\n Console.ReadKey();\n}\n\nstatic XmlRpcClient GetXmlRpcClient()\n{\n XmlRpcClient jsonRpcClient = new XmlRpcClient();\n jsonRpcClient.Setup("http://127.0.0.1:7706/xmlRpc");\n jsonRpcClient.Connect();\n Console.WriteLine("\u8fde\u63a5\u6210\u529f");\n return jsonRpcClient;\n}\n\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/8154dd80.de0713d0.js b/handbook/build/assets/js/8154dd80.de0713d0.js new file mode 100644 index 000000000..d5a328ee0 --- /dev/null +++ b/handbook/build/assets/js/8154dd80.de0713d0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[908],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},s=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=p(r),m=o,d=s["".concat(l,".").concat(m)]||s[m]||f[m]||a;return r?n.createElement(d,i(i({ref:t},u),{},{components:r})):n.createElement(d,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=s;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const a={id:"wpfuifiletransfer",title:"WPF\u754c\u9762\u3001\u6587\u4ef6\u4f20\u8f93\u9879\u76ee"},i=void 0,c={unversionedId:"wpfuifiletransfer",id:"wpfuifiletransfer",title:"WPF\u754c\u9762\u3001\u6587\u4ef6\u4f20\u8f93\u9879\u76ee",description:"\u5b9a\u5236\u65b9",source:"@site/docs/wpfuifiletransfer.mdx",sourceDirName:".",slug:"/wpfuifiletransfer",permalink:"/touchsocket/docs/wpfuifiletransfer",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/wpfuifiletransfer.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675263272,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"wpfuifiletransfer",title:"WPF\u754c\u9762\u3001\u6587\u4ef6\u4f20\u8f93\u9879\u76ee"},sidebar:"docs",previous:{title:"\u5546\u4e1a\u5408\u4f5c",permalink:"/touchsocket/docs/cooperation"},next:{title:"\u8fdc\u7a0b\u76d1\u6d4b\u3001\u63a7\u5236\u9879\u76ee",permalink:"/touchsocket/docs/remotemonitoring"}},l={},p=[],u={toc:p};function f(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"\u5b9a\u5236\u65b9\n\u51ef",(0,o.kt)("strong",{parentName:"p"},"**"),"\u6709\u9650\u516c\u53f8\n\u8bf4\u660e\n\u5e94\u8be5\u516c\u53f8\u8981\u6c42\uff0c\u5f00\u53d1\u4ee5WPF\u4e3a\u6280\u672f\u6846\u67b6\u7684\u684c\u9762\u9879\u76ee\u7ba1\u7406\u5e94\u7528\uff0c\u5176\u754c\u9762\u7c7b\u4f3cQQ\uff08\u6b64\u5904\u56e0\u4e3a\u6d89\u53caUI\u7248\u6743\uff0c\u4e0d\u5c55\u793a\u5b9e\u9645\u6548\u679c\uff09\u3002\u5e76\u4e14\u4ee5RRQMSocket\u4e3a\u901a\u4fe1\u57fa\u7840\uff0c\u89e3\u51b3\u9879\u76ee\u6587\u4ef6\u7684\u4e0a\u4f20\u548c\u4e0b\u8f7d\u3002\u5b9e\u9645\u7684\u89e3\u51b3\u4e86\u57282G\u7f51\uff0c\u751a\u81f3\u66f4\u5dee\u7684\u7f51\u7edc\u73af\u5883\u4e0b\u7684\u5927\u6587\u4ef6\u4f20\u8f93\u3002"),(0,o.kt)("p",null,"\u6280\u672f\u70b9"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"\u6574\u4f53\u754c\u9762\uff1a\u5706\u89d2\u7a97\u4f53\u3001\u7a97\u4f53\u9634\u5f71\u3001\u6700\u5c0f\u5316\u5d4c\u5165\u3001\u62d6\u62fd\u6548\u679c\u7b49\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u9879\u76ee\u6811\u89c6\u56fe\uff1a\u6837\u5f0f\u3001\u641c\u7d22\u3001\u5b9a\u5411\u641c\u7d22\u3001\u641c\u7d22\u9879\u5b9a\u4f4d\u3001\u6811\u89c6\u56fe\u8fde\u7ebf\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u6570\u636e\u540c\u6b65\uff1a\u8bbe\u7f6e\u914d\u7f6e\u6570\u636e\u3001\u9879\u76ee\u6587\u4ef6\u6570\u636e\u7b49\u3002")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/8443.0060be2a.js b/handbook/build/assets/js/8443.0060be2a.js new file mode 100644 index 000000000..46e057bdb --- /dev/null +++ b/handbook/build/assets/js/8443.0060be2a.js @@ -0,0 +1,2 @@ +/*! For license information please see 8443.0060be2a.js.LICENSE.txt */ +(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8443],{8443:(t,e,n)=>{"use strict";t.exports=n(295)},1228:(t,e,n)=>{"use strict";var i=n(2856),s={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none",opacity:"1"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},dropdown:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},suggestions:{display:"block"},suggestion:{whiteSpace:"nowrap",cursor:"pointer"},suggestionChild:{whiteSpace:"normal"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:"0"},defaultClasses:{root:"algolia-autocomplete",prefix:"aa",noPrefix:!1,dropdownMenu:"dropdown-menu",input:"input",hint:"hint",suggestions:"suggestions",suggestion:"suggestion",cursor:"cursor",dataset:"dataset",empty:"empty"},appendTo:{wrapper:{position:"absolute",zIndex:"100",display:"none"},input:{},inputWithNoHint:{},dropdown:{display:"block"}}};i.isMsie()&&i.mixin(s.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),i.isMsie()&&i.isMsie()<=7&&i.mixin(s.input,{marginTop:"-1px"}),t.exports=s},9050:(t,e,n)=>{"use strict";var i="aaDataset",s="aaValue",r="aaDatum",o=n(2856),a=n(4910),u=n(3561),c=n(1228),l=n(3109);function h(t){var e;(t=t||{}).templates=t.templates||{},t.source||o.error("missing source"),t.name&&(e=t.name,!/^[_a-zA-Z0-9-]+$/.test(e))&&o.error("invalid dataset name: "+t.name),this.query=null,this._isEmpty=!0,this.highlight=!!t.highlight,this.name=void 0===t.name||null===t.name?o.getUniqueId():t.name,this.source=t.source,this.displayFn=function(t){return t=t||"value",o.isFunction(t)?t:e;function e(e){return e[t]}}(t.display||t.displayKey),this.debounce=t.debounce,this.cache=!1!==t.cache,this.templates=function(t,e){return{empty:t.empty&&o.templatify(t.empty),header:t.header&&o.templatify(t.header),footer:t.footer&&o.templatify(t.footer),suggestion:t.suggestion||n};function n(t){return"

"+e(t)+"

"}}(t.templates,this.displayFn),this.css=o.mixin({},c,t.appendTo?c.appendTo:{}),this.cssClasses=t.cssClasses=o.mixin({},c.defaultClasses,t.cssClasses||{}),this.cssClasses.prefix=t.cssClasses.formattedPrefix||o.formatPrefix(this.cssClasses.prefix,this.cssClasses.noPrefix);var n=o.className(this.cssClasses.prefix,this.cssClasses.dataset);this.$el=t.$menu&&t.$menu.find(n+"-"+this.name).length>0?a.element(t.$menu.find(n+"-"+this.name)[0]):a.element(u.dataset.replace("%CLASS%",this.name).replace("%PREFIX%",this.cssClasses.prefix).replace("%DATASET%",this.cssClasses.dataset)),this.$menu=t.$menu,this.clearCachedSuggestions()}h.extractDatasetName=function(t){return a.element(t).data(i)},h.extractValue=function(t){return a.element(t).data(s)},h.extractDatum=function(t){var e=a.element(t).data(r);return"string"==typeof e&&(e=JSON.parse(e)),e},o.mixin(h.prototype,l,{_render:function(t,e){if(this.$el){var n,c=this,l=[].slice.call(arguments,2);if(this.$el.empty(),n=e&&e.length,this._isEmpty=!n,!n&&this.templates.empty)this.$el.html(h.apply(this,l)).prepend(c.templates.header?f.apply(this,l):null).append(c.templates.footer?d.apply(this,l):null);else if(n)this.$el.html(p.apply(this,l)).prepend(c.templates.header?f.apply(this,l):null).append(c.templates.footer?d.apply(this,l):null);else if(e&&!Array.isArray(e))throw new TypeError("suggestions must be an array");this.$menu&&this.$menu.addClass(this.cssClasses.prefix+(n?"with":"without")+"-"+this.name).removeClass(this.cssClasses.prefix+(n?"without":"with")+"-"+this.name),this.trigger("rendered",t)}function h(){var e=[].slice.call(arguments,0);return e=[{query:t,isEmpty:!0}].concat(e),c.templates.empty.apply(this,e)}function p(){var t,n,l=[].slice.call(arguments,0),h=this,p=u.suggestions.replace("%PREFIX%",this.cssClasses.prefix).replace("%SUGGESTIONS%",this.cssClasses.suggestions);return t=a.element(p).css(this.css.suggestions),n=o.map(e,f),t.append.apply(t,n),t;function f(t){var e,n=u.suggestion.replace("%PREFIX%",h.cssClasses.prefix).replace("%SUGGESTION%",h.cssClasses.suggestion);return(e=a.element(n).attr({role:"option",id:["option",Math.floor(1e8*Math.random())].join("-")}).append(c.templates.suggestion.apply(this,[t].concat(l)))).data(i,c.name),e.data(s,c.displayFn(t)||void 0),e.data(r,JSON.stringify(t)),e.children().each((function(){a.element(this).css(h.css.suggestionChild)})),e}}function f(){var e=[].slice.call(arguments,0);return e=[{query:t,isEmpty:!n}].concat(e),c.templates.header.apply(this,e)}function d(){var e=[].slice.call(arguments,0);return e=[{query:t,isEmpty:!n}].concat(e),c.templates.footer.apply(this,e)}},getRoot:function(){return this.$el},update:function(t){function e(e){if(!this.canceled&&t===this.query){var n=[].slice.call(arguments,1);this.cacheSuggestions(t,e,n),this._render.apply(this,[t,e].concat(n))}}if(this.query=t,this.canceled=!1,this.shouldFetchFromCache(t))e.apply(this,[this.cachedSuggestions].concat(this.cachedRenderExtraArgs));else{var n=this,i=function(){n.canceled||n.source(t,e.bind(n))};if(this.debounce){clearTimeout(this.debounceTimeout),this.debounceTimeout=setTimeout((function(){n.debounceTimeout=null,i()}),this.debounce)}else i()}},cacheSuggestions:function(t,e,n){this.cachedQuery=t,this.cachedSuggestions=e,this.cachedRenderExtraArgs=n},shouldFetchFromCache:function(t){return this.cache&&this.cachedQuery===t&&this.cachedSuggestions&&this.cachedSuggestions.length},clearCachedSuggestions:function(){delete this.cachedQuery,delete this.cachedSuggestions,delete this.cachedRenderExtraArgs},cancel:function(){this.canceled=!0},clear:function(){this.$el&&(this.cancel(),this.$el.empty(),this.trigger("rendered",""))},isEmpty:function(){return this._isEmpty},destroy:function(){this.clearCachedSuggestions(),this.$el=null}}),t.exports=h},3354:(t,e,n)=>{"use strict";var i=n(2856),s=n(4910),r=n(3109),o=n(9050),a=n(1228);function u(t){var e,n,r,o=this;(t=t||{}).menu||i.error("menu is required"),i.isArray(t.datasets)||i.isObject(t.datasets)||i.error("1 or more datasets required"),t.datasets||i.error("datasets is required"),this.isOpen=!1,this.isEmpty=!0,this.minLength=t.minLength||0,this.templates={},this.appendTo=t.appendTo||!1,this.css=i.mixin({},a,t.appendTo?a.appendTo:{}),this.cssClasses=t.cssClasses=i.mixin({},a.defaultClasses,t.cssClasses||{}),this.cssClasses.prefix=t.cssClasses.formattedPrefix||i.formatPrefix(this.cssClasses.prefix,this.cssClasses.noPrefix),e=i.bind(this._onSuggestionClick,this),n=i.bind(this._onSuggestionMouseEnter,this),r=i.bind(this._onSuggestionMouseLeave,this);var c=i.className(this.cssClasses.prefix,this.cssClasses.suggestion);this.$menu=s.element(t.menu).on("mouseenter.aa",c,n).on("mouseleave.aa",c,r).on("click.aa",c,e),this.$container=t.appendTo?t.wrapper:this.$menu,t.templates&&t.templates.header&&(this.templates.header=i.templatify(t.templates.header),this.$menu.prepend(this.templates.header())),t.templates&&t.templates.empty&&(this.templates.empty=i.templatify(t.templates.empty),this.$empty=s.element('
'),this.$menu.append(this.$empty),this.$empty.hide()),this.datasets=i.map(t.datasets,(function(e){return function(t,e,n){return new u.Dataset(i.mixin({$menu:t,cssClasses:n},e))}(o.$menu,e,t.cssClasses)})),i.each(this.datasets,(function(t){var e=t.getRoot();e&&0===e.parent().length&&o.$menu.append(e),t.onSync("rendered",o._onRendered,o)})),t.templates&&t.templates.footer&&(this.templates.footer=i.templatify(t.templates.footer),this.$menu.append(this.templates.footer()));var l=this;s.element(window).resize((function(){l._redraw()}))}i.mixin(u.prototype,r,{_onSuggestionClick:function(t){this.trigger("suggestionClicked",s.element(t.currentTarget))},_onSuggestionMouseEnter:function(t){var e=s.element(t.currentTarget);if(!e.hasClass(i.className(this.cssClasses.prefix,this.cssClasses.cursor,!0))){this._removeCursor();var n=this;setTimeout((function(){n._setCursor(e,!1)}),0)}},_onSuggestionMouseLeave:function(t){if(t.relatedTarget&&s.element(t.relatedTarget).closest("."+i.className(this.cssClasses.prefix,this.cssClasses.cursor,!0)).length>0)return;this._removeCursor(),this.trigger("cursorRemoved")},_onRendered:function(t,e){if(this.isEmpty=i.every(this.datasets,(function(t){return t.isEmpty()})),this.isEmpty)if(e.length>=this.minLength&&this.trigger("empty"),this.$empty)if(e.length=this.minLength?this._show():this._hide());this.trigger("datasetRendered")},_hide:function(){this.$container.hide()},_show:function(){this.$container.css("display","block"),this._redraw(),this.trigger("shown")},_redraw:function(){this.isOpen&&this.appendTo&&this.trigger("redrawn")},_getSuggestions:function(){return this.$menu.find(i.className(this.cssClasses.prefix,this.cssClasses.suggestion))},_getCursor:function(){return this.$menu.find(i.className(this.cssClasses.prefix,this.cssClasses.cursor)).first()},_setCursor:function(t,e){t.first().addClass(i.className(this.cssClasses.prefix,this.cssClasses.cursor,!0)).attr("aria-selected","true"),this.trigger("cursorMoved",e)},_removeCursor:function(){this._getCursor().removeClass(i.className(this.cssClasses.prefix,this.cssClasses.cursor,!0)).removeAttr("aria-selected")},_moveCursor:function(t){var e,n,i,s;this.isOpen&&(n=this._getCursor(),e=this._getSuggestions(),this._removeCursor(),-1!==(i=((i=e.index(n)+t)+1)%(e.length+1)-1)?(i<-1&&(i=e.length-1),this._setCursor(s=e.eq(i),!0),this._ensureVisible(s)):this.trigger("cursorRemoved"))},_ensureVisible:function(t){var e,n,i,s;n=(e=t.position().top)+t.height()+parseInt(t.css("margin-top"),10)+parseInt(t.css("margin-bottom"),10),i=this.$menu.scrollTop(),s=this.$menu.height()+parseInt(this.$menu.css("padding-top"),10)+parseInt(this.$menu.css("padding-bottom"),10),e<0?this.$menu.scrollTop(i+e):s{"use strict";var i=n(2856),s=n(4910);function r(t){t&&t.el||i.error("EventBus initialized without el"),this.$el=s.element(t.el)}i.mixin(r.prototype,{trigger:function(t,e,n,s){var r=i.Event("autocomplete:"+t);return this.$el.trigger(r,[e,n,s]),r}}),t.exports=r},3109:(t,e,n)=>{"use strict";var i=n(624),s=/\s+/;function r(t,e,n,i){var r;if(!n)return this;for(e=e.split(s),n=i?function(t,e){return t.bind?t.bind(e):function(){t.apply(e,[].slice.call(arguments,0))}}(n,i):n,this._callbacks=this._callbacks||{};r=e.shift();)this._callbacks[r]=this._callbacks[r]||{sync:[],async:[]},this._callbacks[r][t].push(n);return this}function o(t,e,n){return function(){for(var i,s=0,r=t.length;!i&&s{"use strict";t.exports={wrapper:'',dropdown:'',dataset:'
',suggestions:'',suggestion:'
'}},2534:(t,e,n)=>{"use strict";var i;i={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"};var s=n(2856),r=n(4910),o=n(3109);function a(t){var e,n,o,a,u,c=this;(t=t||{}).input||s.error("input is missing"),e=s.bind(this._onBlur,this),n=s.bind(this._onFocus,this),o=s.bind(this._onKeydown,this),a=s.bind(this._onInput,this),this.$hint=r.element(t.hint),this.$input=r.element(t.input).on("blur.aa",e).on("focus.aa",n).on("keydown.aa",o),0===this.$hint.length&&(this.setHint=this.getHint=this.clearHint=this.clearHintIfInvalid=s.noop),s.isMsie()?this.$input.on("keydown.aa keypress.aa cut.aa paste.aa",(function(t){i[t.which||t.keyCode]||s.defer(s.bind(c._onInput,c,t))})):this.$input.on("input.aa",a),this.query=this.$input.val(),this.$overflowHelper=(u=this.$input,r.element('').css({position:"absolute",visibility:"hidden",whiteSpace:"pre",fontFamily:u.css("font-family"),fontSize:u.css("font-size"),fontStyle:u.css("font-style"),fontVariant:u.css("font-variant"),fontWeight:u.css("font-weight"),wordSpacing:u.css("word-spacing"),letterSpacing:u.css("letter-spacing"),textIndent:u.css("text-indent"),textRendering:u.css("text-rendering"),textTransform:u.css("text-transform")}).insertAfter(u))}function u(t){return t.altKey||t.ctrlKey||t.metaKey||t.shiftKey}a.normalizeQuery=function(t){return(t||"").replace(/^\s*/g,"").replace(/\s{2,}/g," ")},s.mixin(a.prototype,o,{_onBlur:function(){this.resetInputValue(),this.$input.removeAttr("aria-activedescendant"),this.trigger("blurred")},_onFocus:function(){this.trigger("focused")},_onKeydown:function(t){var e=i[t.which||t.keyCode];this._managePreventDefault(e,t),e&&this._shouldTrigger(e,t)&&this.trigger(e+"Keyed",t)},_onInput:function(){this._checkInputValue()},_managePreventDefault:function(t,e){var n,i,s;switch(t){case"tab":i=this.getHint(),s=this.getInputValue(),n=i&&i!==s&&!u(e);break;case"up":case"down":n=!u(e);break;default:n=!1}n&&e.preventDefault()},_shouldTrigger:function(t,e){var n;if("tab"===t)n=!u(e);else n=!0;return n},_checkInputValue:function(){var t,e,n,i,s;t=this.getInputValue(),i=t,s=this.query,n=!(!(e=a.normalizeQuery(i)===a.normalizeQuery(s))||!this.query)&&this.query.length!==t.length,this.query=t,e?n&&this.trigger("whitespaceChanged",this.query):this.trigger("queryChanged",this.query)},focus:function(){this.$input.focus()},blur:function(){this.$input.blur()},getQuery:function(){return this.query},setQuery:function(t){this.query=t},getInputValue:function(){return this.$input.val()},setInputValue:function(t,e){void 0===t&&(t=this.query),this.$input.val(t),e?this.clearHint():this._checkInputValue()},expand:function(){this.$input.attr("aria-expanded","true")},collapse:function(){this.$input.attr("aria-expanded","false")},setActiveDescendant:function(t){this.$input.attr("aria-activedescendant",t)},removeActiveDescendant:function(){this.$input.removeAttr("aria-activedescendant")},resetInputValue:function(){this.setInputValue(this.query,!0)},getHint:function(){return this.$hint.val()},setHint:function(t){this.$hint.val(t)},clearHint:function(){this.setHint("")},clearHintIfInvalid:function(){var t,e,n;n=(t=this.getInputValue())!==(e=this.getHint())&&0===e.indexOf(t),""!==t&&n&&!this.hasOverflow()||this.clearHint()},getLanguageDirection:function(){return(this.$input.css("direction")||"ltr").toLowerCase()},hasOverflow:function(){var t=this.$input.width()-2;return this.$overflowHelper.text(this.getInputValue()),this.$overflowHelper.width()>=t},isCursorAtEnd:function(){var t,e,n;return t=this.$input.val().length,e=this.$input[0].selectionStart,s.isNumber(e)?e===t:!document.selection||((n=document.selection.createRange()).moveStart("character",-t),t===n.text.length)},destroy:function(){this.$hint.off(".aa"),this.$input.off(".aa"),this.$hint=this.$input=this.$overflowHelper=null}}),t.exports=a},6549:(t,e,n)=>{"use strict";var i="aaAttrs",s=n(2856),r=n(4910),o=n(50),a=n(2534),u=n(3354),c=n(3561),l=n(1228);function h(t){var e,n;if((t=t||{}).input||s.error("missing input"),this.isActivated=!1,this.debug=!!t.debug,this.autoselect=!!t.autoselect,this.autoselectOnBlur=!!t.autoselectOnBlur,this.openOnFocus=!!t.openOnFocus,this.minLength=s.isNumber(t.minLength)?t.minLength:1,this.autoWidth=void 0===t.autoWidth||!!t.autoWidth,this.clearOnSelected=!!t.clearOnSelected,this.tabAutocomplete=void 0===t.tabAutocomplete||!!t.tabAutocomplete,t.hint=!!t.hint,t.hint&&t.appendTo)throw new Error("[autocomplete.js] hint and appendTo options can't be used at the same time");this.css=t.css=s.mixin({},l,t.appendTo?l.appendTo:{}),this.cssClasses=t.cssClasses=s.mixin({},l.defaultClasses,t.cssClasses||{}),this.cssClasses.prefix=t.cssClasses.formattedPrefix=s.formatPrefix(this.cssClasses.prefix,this.cssClasses.noPrefix),this.listboxId=t.listboxId=[this.cssClasses.root,"listbox",s.getUniqueId()].join("-");var a=function(t){var e,n,o,a;e=r.element(t.input),n=r.element(c.wrapper.replace("%ROOT%",t.cssClasses.root)).css(t.css.wrapper),t.appendTo||"block"!==e.css("display")||"table"!==e.parent().css("display")||n.css("display","table-cell");var u=c.dropdown.replace("%PREFIX%",t.cssClasses.prefix).replace("%DROPDOWN_MENU%",t.cssClasses.dropdownMenu);o=r.element(u).css(t.css.dropdown).attr({role:"listbox",id:t.listboxId}),t.templates&&t.templates.dropdownMenu&&o.html(s.templatify(t.templates.dropdownMenu)());(a=e.clone().css(t.css.hint).css(function(t){return{backgroundAttachment:t.css("background-attachment"),backgroundClip:t.css("background-clip"),backgroundColor:t.css("background-color"),backgroundImage:t.css("background-image"),backgroundOrigin:t.css("background-origin"),backgroundPosition:t.css("background-position"),backgroundRepeat:t.css("background-repeat"),backgroundSize:t.css("background-size")}}(e))).val("").addClass(s.className(t.cssClasses.prefix,t.cssClasses.hint,!0)).removeAttr("id name placeholder required").prop("readonly",!0).attr({"aria-hidden":"true",autocomplete:"off",spellcheck:"false",tabindex:-1}),a.removeData&&a.removeData();e.data(i,{"aria-autocomplete":e.attr("aria-autocomplete"),"aria-expanded":e.attr("aria-expanded"),"aria-owns":e.attr("aria-owns"),autocomplete:e.attr("autocomplete"),dir:e.attr("dir"),role:e.attr("role"),spellcheck:e.attr("spellcheck"),style:e.attr("style"),type:e.attr("type")}),e.addClass(s.className(t.cssClasses.prefix,t.cssClasses.input,!0)).attr({autocomplete:"off",spellcheck:!1,role:"combobox","aria-autocomplete":t.datasets&&t.datasets[0]&&t.datasets[0].displayKey?"both":"list","aria-expanded":"false","aria-label":t.ariaLabel,"aria-owns":t.listboxId}).css(t.hint?t.css.input:t.css.inputWithNoHint);try{e.attr("dir")||e.attr("dir","auto")}catch(l){}return(n=t.appendTo?n.appendTo(r.element(t.appendTo).eq(0)).eq(0):e.wrap(n).parent()).prepend(t.hint?a:null).append(o),{wrapper:n,input:e,hint:a,menu:o}}(t);this.$node=a.wrapper;var u=this.$input=a.input;e=a.menu,n=a.hint,t.dropdownMenuContainer&&r.element(t.dropdownMenuContainer).css("position","relative").append(e.css("top","0")),u.on("blur.aa",(function(t){var n=document.activeElement;s.isMsie()&&(e[0]===n||e[0].contains(n))&&(t.preventDefault(),t.stopImmediatePropagation(),s.defer((function(){u.focus()})))})),e.on("mousedown.aa",(function(t){t.preventDefault()})),this.eventBus=t.eventBus||new o({el:u}),this.dropdown=new h.Dropdown({appendTo:t.appendTo,wrapper:this.$node,menu:e,datasets:t.datasets,templates:t.templates,cssClasses:t.cssClasses,minLength:this.minLength}).onSync("suggestionClicked",this._onSuggestionClicked,this).onSync("cursorMoved",this._onCursorMoved,this).onSync("cursorRemoved",this._onCursorRemoved,this).onSync("opened",this._onOpened,this).onSync("closed",this._onClosed,this).onSync("shown",this._onShown,this).onSync("empty",this._onEmpty,this).onSync("redrawn",this._onRedrawn,this).onAsync("datasetRendered",this._onDatasetRendered,this),this.input=new h.Input({input:u,hint:n}).onSync("focused",this._onFocused,this).onSync("blurred",this._onBlurred,this).onSync("enterKeyed",this._onEnterKeyed,this).onSync("tabKeyed",this._onTabKeyed,this).onSync("escKeyed",this._onEscKeyed,this).onSync("upKeyed",this._onUpKeyed,this).onSync("downKeyed",this._onDownKeyed,this).onSync("leftKeyed",this._onLeftKeyed,this).onSync("rightKeyed",this._onRightKeyed,this).onSync("queryChanged",this._onQueryChanged,this).onSync("whitespaceChanged",this._onWhitespaceChanged,this),this._bindKeyboardShortcuts(t),this._setLanguageDirection()}s.mixin(h.prototype,{_bindKeyboardShortcuts:function(t){if(t.keyboardShortcuts){var e=this.$input,n=[];s.each(t.keyboardShortcuts,(function(t){"string"==typeof t&&(t=t.toUpperCase().charCodeAt(0)),n.push(t)})),r.element(document).keydown((function(t){var i=t.target||t.srcElement,s=i.tagName;if(!i.isContentEditable&&"INPUT"!==s&&"SELECT"!==s&&"TEXTAREA"!==s){var r=t.which||t.keyCode;-1!==n.indexOf(r)&&(e.focus(),t.stopPropagation(),t.preventDefault())}}))}},_onSuggestionClicked:function(t,e){var n;(n=this.dropdown.getDatumForSuggestion(e))&&this._select(n,{selectionMethod:"click"})},_onCursorMoved:function(t,e){var n=this.dropdown.getDatumForCursor(),i=this.dropdown.getCurrentCursor().attr("id");this.input.setActiveDescendant(i),n&&(e&&this.input.setInputValue(n.value,!0),this.eventBus.trigger("cursorchanged",n.raw,n.datasetName))},_onCursorRemoved:function(){this.input.resetInputValue(),this._updateHint(),this.eventBus.trigger("cursorremoved")},_onDatasetRendered:function(){this._updateHint(),this.eventBus.trigger("updated")},_onOpened:function(){this._updateHint(),this.input.expand(),this.eventBus.trigger("opened")},_onEmpty:function(){this.eventBus.trigger("empty")},_onRedrawn:function(){this.$node.css("top","0px"),this.$node.css("left","0px");var t=this.$input[0].getBoundingClientRect();this.autoWidth&&this.$node.css("width",t.width+"px");var e=this.$node[0].getBoundingClientRect(),n=t.bottom-e.top;this.$node.css("top",n+"px");var i=t.left-e.left;this.$node.css("left",i+"px"),this.eventBus.trigger("redrawn")},_onShown:function(){this.eventBus.trigger("shown"),this.autoselect&&this.dropdown.cursorTopSuggestion()},_onClosed:function(){this.input.clearHint(),this.input.removeActiveDescendant(),this.input.collapse(),this.eventBus.trigger("closed")},_onFocused:function(){if(this.isActivated=!0,this.openOnFocus){var t=this.input.getQuery();t.length>=this.minLength?this.dropdown.update(t):this.dropdown.empty(),this.dropdown.open()}},_onBlurred:function(){var t,e;t=this.dropdown.getDatumForCursor(),e=this.dropdown.getDatumForTopSuggestion();var n={selectionMethod:"blur"};this.debug||(this.autoselectOnBlur&&t?this._select(t,n):this.autoselectOnBlur&&e?this._select(e,n):(this.isActivated=!1,this.dropdown.empty(),this.dropdown.close()))},_onEnterKeyed:function(t,e){var n,i;n=this.dropdown.getDatumForCursor(),i=this.dropdown.getDatumForTopSuggestion();var s={selectionMethod:"enterKey"};n?(this._select(n,s),e.preventDefault()):this.autoselect&&i&&(this._select(i,s),e.preventDefault())},_onTabKeyed:function(t,e){if(this.tabAutocomplete){var n;(n=this.dropdown.getDatumForCursor())?(this._select(n,{selectionMethod:"tabKey"}),e.preventDefault()):this._autocomplete(!0)}else this.dropdown.close()},_onEscKeyed:function(){this.dropdown.close(),this.input.resetInputValue()},_onUpKeyed:function(){var t=this.input.getQuery();this.dropdown.isEmpty&&t.length>=this.minLength?this.dropdown.update(t):this.dropdown.moveCursorUp(),this.dropdown.open()},_onDownKeyed:function(){var t=this.input.getQuery();this.dropdown.isEmpty&&t.length>=this.minLength?this.dropdown.update(t):this.dropdown.moveCursorDown(),this.dropdown.open()},_onLeftKeyed:function(){"rtl"===this.dir&&this._autocomplete()},_onRightKeyed:function(){"ltr"===this.dir&&this._autocomplete()},_onQueryChanged:function(t,e){this.input.clearHintIfInvalid(),e.length>=this.minLength?this.dropdown.update(e):this.dropdown.empty(),this.dropdown.open(),this._setLanguageDirection()},_onWhitespaceChanged:function(){this._updateHint(),this.dropdown.open()},_setLanguageDirection:function(){var t=this.input.getLanguageDirection();this.dir!==t&&(this.dir=t,this.$node.css("direction",t),this.dropdown.setLanguageDirection(t))},_updateHint:function(){var t,e,n,i,r;(t=this.dropdown.getDatumForTopSuggestion())&&this.dropdown.isVisible()&&!this.input.hasOverflow()?(e=this.input.getInputValue(),n=a.normalizeQuery(e),i=s.escapeRegExChars(n),(r=new RegExp("^(?:"+i+")(.+$)","i").exec(t.value))?this.input.setHint(e+r[1]):this.input.clearHint()):this.input.clearHint()},_autocomplete:function(t){var e,n,i,s;e=this.input.getHint(),n=this.input.getQuery(),i=t||this.input.isCursorAtEnd(),e&&n!==e&&i&&((s=this.dropdown.getDatumForTopSuggestion())&&this.input.setInputValue(s.value),this.eventBus.trigger("autocompleted",s.raw,s.datasetName))},_select:function(t,e){void 0!==t.value&&this.input.setQuery(t.value),this.clearOnSelected?this.setVal(""):this.input.setInputValue(t.value,!0),this._setLanguageDirection(),!1===this.eventBus.trigger("selected",t.raw,t.datasetName,e).isDefaultPrevented()&&(this.dropdown.close(),s.defer(s.bind(this.dropdown.empty,this.dropdown)))},open:function(){if(!this.isActivated){var t=this.input.getInputValue();t.length>=this.minLength?this.dropdown.update(t):this.dropdown.empty()}this.dropdown.open()},close:function(){this.dropdown.close()},setVal:function(t){t=s.toStr(t),this.isActivated?this.input.setInputValue(t):(this.input.setQuery(t),this.input.setInputValue(t,!0)),this._setLanguageDirection()},getVal:function(){return this.input.getQuery()},destroy:function(){this.input.destroy(),this.dropdown.destroy(),function(t,e){var n=t.find(s.className(e.prefix,e.input));s.each(n.data(i),(function(t,e){void 0===t?n.removeAttr(e):n.attr(e,t)})),n.detach().removeClass(s.className(e.prefix,e.input,!0)).insertAfter(t),n.removeData&&n.removeData(i);t.remove()}(this.$node,this.cssClasses),this.$node=null},getWrapper:function(){return this.dropdown.$container[0]}}),h.Dropdown=u,h.Input=a,h.sources=n(3580),t.exports=h},4910:t=>{"use strict";t.exports={element:null}},6177:t=>{"use strict";t.exports=function(t){var e=t.match(/Algolia for JavaScript \((\d+\.)(\d+\.)(\d+)\)/)||t.match(/Algolia for vanilla JavaScript (\d+\.)(\d+\.)(\d+)/);if(e)return[e[1],e[2],e[3]]}},2856:(t,e,n)=>{"use strict";var i,s=n(8820),r=n(4910);function o(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}t.exports={isArray:null,isFunction:null,isObject:null,bind:null,each:null,map:null,mixin:null,isMsie:function(t){if(void 0===t&&(t=navigator.userAgent),/(msie|trident)/i.test(t)){var e=t.match(/(msie |rv:)(\d+(.\d+)?)/i);if(e)return e[2]}return!1},escapeRegExChars:function(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isNumber:function(t){return"number"==typeof t},toStr:function(t){return null==t?"":t+""},cloneDeep:function(t){var e=this.mixin({},t),n=this;return this.each(e,(function(t,i){t&&(n.isArray(t)?e[i]=[].concat(t):n.isObject(t)&&(e[i]=n.cloneDeep(t)))})),e},error:function(t){throw new Error(t)},every:function(t,e){var n=!0;return t?(this.each(t,(function(i,s){n&&(n=e.call(null,i,s,t)&&n)})),!!n):n},any:function(t,e){var n=!1;return t?(this.each(t,(function(i,s){if(e.call(null,i,s,t))return n=!0,!1})),n):n},getUniqueId:(i=0,function(){return i++}),templatify:function(t){if(this.isFunction(t))return t;var e=r.element(t);return"SCRIPT"===e.prop("tagName")?function(){return e.text()}:function(){return String(t)}},defer:function(t){setTimeout(t,0)},noop:function(){},formatPrefix:function(t,e){return e?"":t+"-"},className:function(t,e,n){return n?t+e:"."+s(t+e,{isIdentifier:!0})},escapeHighlightedString:function(t,e,n){e=e||"";var i=document.createElement("div");i.appendChild(document.createTextNode(e)),n=n||"";var s=document.createElement("div");s.appendChild(document.createTextNode(n));var r=document.createElement("div");return r.appendChild(document.createTextNode(t)),r.innerHTML.replace(RegExp(o(i.innerHTML),"g"),e).replace(RegExp(o(s.innerHTML),"g"),n)}}},9983:(t,e,n)=>{"use strict";var i=n(2856),s=n(533),r=n(6177);var o,a,u=(o=[],a=window.Promise.resolve(),function(t,e){return function(n,s){(function(t,e){return window.Promise.resolve().then((function(){return o.length&&(a=t.search(o),o=[]),a})).then((function(t){if(t)return t.results[e]}))})(t.as,o.push({indexName:t.indexName,query:n,params:e})-1).then((function(t){t&&s(t.hits,t)})).catch((function(t){i.error(t.message)}))}});t.exports=function(t,e){var n=r(t.as._ua);if(n&&n[0]>=3&&n[1]>20){var i="autocomplete.js "+s;-1===t.as._ua.indexOf(i)&&(t.as._ua+="; "+i)}return u(t,e)}},3580:(t,e,n)=>{"use strict";t.exports={hits:n(9983),popularIn:n(4445)}},4445:(t,e,n)=>{"use strict";var i=n(2856),s=n(533),r=n(6177);t.exports=function(t,e,n,o){var a=r(t.as._ua);if(a&&a[0]>=3&&a[1]>20&&((e=e||{}).additionalUA="autocomplete.js "+s),!n.source)return i.error("Missing 'source' key");var u=i.isFunction(n.source)?n.source:function(t){return t[n.source]};if(!n.index)return i.error("Missing 'index' key");var c=n.index;return o=o||{},function(a,l){t.search(a,e,(function(t,a){if(t)i.error(t.message);else{if(a.hits.length>0){var h=a.hits[0],p=i.mixin({hitsPerPage:0},n);delete p.source,delete p.index;var f=r(c.as._ua);return f&&f[0]>=3&&f[1]>20&&(e.additionalUA="autocomplete.js "+s),void c.search(u(h),p,(function(t,e){if(t)i.error(t.message);else{var n=[];if(o.includeAll){var s=o.allTitle||"All departments";n.push(i.mixin({facet:{value:s,count:e.nbHits}},i.cloneDeep(h)))}i.each(e.facets,(function(t,e){i.each(t,(function(t,s){n.push(i.mixin({facet:{facet:e,value:s,count:t}},i.cloneDeep(h)))}))}));for(var r=1;r{"use strict";var i=n(6990);n(4910).element=i;var s=n(2856);s.isArray=i.isArray,s.isFunction=i.isFunction,s.isObject=i.isPlainObject,s.bind=i.proxy,s.each=function(t,e){i.each(t,(function(t,n){return e(n,t)}))},s.map=i.map,s.mixin=i.extend,s.Event=i.Event;var r="aaAutocomplete",o=n(6549),a=n(50);function u(t,e,n,u){n=s.isArray(n)?n:[].slice.call(arguments,2);var c=i(t).each((function(t,s){var c=i(s),l=new a({el:c}),h=u||new o({input:c,eventBus:l,dropdownMenuContainer:e.dropdownMenuContainer,hint:void 0===e.hint||!!e.hint,minLength:e.minLength,autoselect:e.autoselect,autoselectOnBlur:e.autoselectOnBlur,tabAutocomplete:e.tabAutocomplete,openOnFocus:e.openOnFocus,templates:e.templates,debug:e.debug,clearOnSelected:e.clearOnSelected,cssClasses:e.cssClasses,datasets:n,keyboardShortcuts:e.keyboardShortcuts,appendTo:e.appendTo,autoWidth:e.autoWidth,ariaLabel:e.ariaLabel||s.getAttribute("aria-label")});c.data(r,h)}));return c.autocomplete={},s.each(["open","close","getVal","setVal","destroy","getWrapper"],(function(t){c.autocomplete[t]=function(){var e,n=arguments;return c.each((function(s,o){var a=i(o).data(r);e=a[t].apply(a,n)})),e}})),c}u.sources=o.sources,u.escapeHighlightedString=s.escapeHighlightedString;var c="autocomplete"in window,l=window.autocomplete;u.noConflict=function(){return c?window.autocomplete=l:delete window.autocomplete,u},t.exports=u},533:t=>{t.exports="0.38.1"},6990:t=>{var e;e=window,t.exports=function(t){var e,n,i=function(){var e,n,i,s,r,o,a=[],u=a.concat,c=a.filter,l=a.slice,h=t.document,p={},f={},d={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},g=/^\s*<(\w+|!)[^>]*>/,m=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,y=/^(?:body|html)$/i,w=/([A-Z])/g,b=["val","css","html","text","data","width","height","offset"],C=["after","prepend","before","append"],x=h.createElement("table"),_=h.createElement("tr"),S={tr:h.createElement("tbody"),tbody:x,thead:x,tfoot:x,td:_,th:_,"*":h.createElement("div")},E=/complete|loaded|interactive/,A=/^[\w-]*$/,$={},T=$.toString,O={},D=h.createElement("div"),N={tabindex:"tabIndex",readonly:"readOnly",for:"htmlFor",class:"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},k=Array.isArray||function(t){return t instanceof Array};function I(t){return null==t?String(t):$[T.call(t)]||"object"}function P(t){return"function"==I(t)}function L(t){return null!=t&&t==t.window}function M(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function F(t){return"object"==I(t)}function R(t){return F(t)&&!L(t)&&Object.getPrototypeOf(t)==Object.prototype}function q(t){var e=!!t&&"length"in t&&t.length,n=i.type(t);return"function"!=n&&!L(t)&&("array"==n||0===e||"number"==typeof e&&e>0&&e-1 in t)}function V(t){return c.call(t,(function(t){return null!=t}))}function H(t){return t.length>0?i.fn.concat.apply([],t):t}function B(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function K(t){return t in f?f[t]:f[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function j(t,e){return"number"!=typeof e||d[B(t)]?e:e+"px"}function z(t){var e,n;return p[t]||(e=h.createElement(t),h.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),p[t]=n),p[t]}function U(t){return"children"in t?l.call(t.children):i.map(t.childNodes,(function(t){if(1==t.nodeType)return t}))}function Q(t,e){var n,i=t?t.length:0;for(n=0;n")),n===e&&(n=g.test(t)&&RegExp.$1),n in S||(n="*"),(a=S[n]).innerHTML=""+t,r=i.each(l.call(a.childNodes),(function(){a.removeChild(this)}))),R(s)&&(o=i(r),i.each(s,(function(t,e){b.indexOf(t)>-1?o[t](e):o.attr(t,e)}))),r},O.Z=function(t,e){return new Q(t,e)},O.isZ=function(t){return t instanceof O.Z},O.init=function(t,n){var s;if(!t)return O.Z();if("string"==typeof t)if("<"==(t=t.trim())[0]&&g.test(t))s=O.fragment(t,RegExp.$1,n),t=null;else{if(n!==e)return i(n).find(t);s=O.qsa(h,t)}else{if(P(t))return i(h).ready(t);if(O.isZ(t))return t;if(k(t))s=V(t);else if(F(t))s=[t],t=null;else if(g.test(t))s=O.fragment(t.trim(),RegExp.$1,n),t=null;else{if(n!==e)return i(n).find(t);s=O.qsa(h,t)}}return O.Z(s,t)},(i=function(t,e){return O.init(t,e)}).extend=function(t){var e,n=l.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach((function(n){W(t,n,e)})),t},O.qsa=function(t,e){var n,i="#"==e[0],s=!i&&"."==e[0],r=i||s?e.slice(1):e,o=A.test(r);return t.getElementById&&o&&i?(n=t.getElementById(r))?[n]:[]:1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType?[]:l.call(o&&!i&&t.getElementsByClassName?s?t.getElementsByClassName(r):t.getElementsByTagName(e):t.querySelectorAll(e))},i.contains=h.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},i.type=I,i.isFunction=P,i.isWindow=L,i.isArray=k,i.isPlainObject=R,i.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},i.isNumeric=function(t){var e=Number(t),n=typeof t;return null!=t&&"boolean"!=n&&("string"!=n||t.length)&&!isNaN(e)&&isFinite(e)||!1},i.inArray=function(t,e,n){return a.indexOf.call(e,t,n)},i.camelCase=r,i.trim=function(t){return null==t?"":String.prototype.trim.call(t)},i.uuid=0,i.support={},i.expr={},i.noop=function(){},i.map=function(t,e){var n,i,s,r=[];if(q(t))for(i=0;i=0?t:t+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each((function(){null!=this.parentNode&&this.parentNode.removeChild(this)}))},each:function(t){return a.every.call(this,(function(e,n){return!1!==t.call(e,n,e)})),this},filter:function(t){return P(t)?this.not(this.not(t)):i(c.call(this,(function(e){return O.matches(e,t)})))},add:function(t,e){return i(o(this.concat(i(t,e))))},is:function(t){return this.length>0&&O.matches(this[0],t)},not:function(t){var n=[];if(P(t)&&t.call!==e)this.each((function(e){t.call(this,e)||n.push(this)}));else{var s="string"==typeof t?this.filter(t):q(t)&&P(t.item)?l.call(t):i(t);this.forEach((function(t){s.indexOf(t)<0&&n.push(t)}))}return i(n)},has:function(t){return this.filter((function(){return F(t)?i.contains(this,t):i(this).find(t).size()}))},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!F(t)?t:i(t)},last:function(){var t=this[this.length-1];return t&&!F(t)?t:i(t)},find:function(t){var e=this;return t?"object"==typeof t?i(t).filter((function(){var t=this;return a.some.call(e,(function(e){return i.contains(e,t)}))})):1==this.length?i(O.qsa(this[0],t)):this.map((function(){return O.qsa(this,t)})):i()},closest:function(t,e){var n=[],s="object"==typeof t&&i(t);return this.each((function(i,r){for(;r&&!(s?s.indexOf(r)>=0:O.matches(r,t));)r=r!==e&&!M(r)&&r.parentNode;r&&n.indexOf(r)<0&&n.push(r)})),i(n)},parents:function(t){for(var e=[],n=this;n.length>0;)n=i.map(n,(function(t){if((t=t.parentNode)&&!M(t)&&e.indexOf(t)<0)return e.push(t),t}));return Z(e,t)},parent:function(t){return Z(o(this.pluck("parentNode")),t)},children:function(t){return Z(this.map((function(){return U(this)})),t)},contents:function(){return this.map((function(){return this.contentDocument||l.call(this.childNodes)}))},siblings:function(t){return Z(this.map((function(t,e){return c.call(U(e.parentNode),(function(t){return t!==e}))})),t)},empty:function(){return this.each((function(){this.innerHTML=""}))},pluck:function(t){return i.map(this,(function(e){return e[t]}))},show:function(){return this.each((function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=z(this.nodeName))}))},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=P(t);if(this[0]&&!e)var n=i(t).get(0),s=n.parentNode||this.length>1;return this.each((function(r){i(this).wrapAll(e?t.call(this,r):s?n.cloneNode(!0):n)}))},wrapAll:function(t){if(this[0]){var e;for(i(this[0]).before(t=i(t));(e=t.children()).length;)t=e.first();i(t).append(this)}return this},wrapInner:function(t){var e=P(t);return this.each((function(n){var s=i(this),r=s.contents(),o=e?t.call(this,n):t;r.length?r.wrapAll(o):s.append(o)}))},unwrap:function(){return this.parent().each((function(){i(this).replaceWith(i(this).children())})),this},clone:function(){return this.map((function(){return this.cloneNode(!0)}))},hide:function(){return this.css("display","none")},toggle:function(t){return this.each((function(){var n=i(this);(t===e?"none"==n.css("display"):t)?n.show():n.hide()}))},prev:function(t){return i(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return i(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0 in arguments?this.each((function(e){var n=this.innerHTML;i(this).empty().append(X(this,t,e,n))})):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each((function(e){var n=X(this,t,e,this.textContent);this.textContent=null==n?"":""+n})):0 in this?this.pluck("textContent").join(""):null},attr:function(t,i){var s;return"string"!=typeof t||1 in arguments?this.each((function(e){if(1===this.nodeType)if(F(t))for(n in t)G(this,n,t[n]);else G(this,t,X(this,i,e,this.getAttribute(t)))})):0 in this&&1==this[0].nodeType&&null!=(s=this[0].getAttribute(t))?s:e},removeAttr:function(t){return this.each((function(){1===this.nodeType&&t.split(" ").forEach((function(t){G(this,t)}),this)}))},prop:function(t,e){return t=N[t]||t,1 in arguments?this.each((function(n){this[t]=X(this,e,n,this[t])})):this[0]&&this[0][t]},removeProp:function(t){return t=N[t]||t,this.each((function(){delete this[t]}))},data:function(t,n){var i="data-"+t.replace(w,"-$1").toLowerCase(),s=1 in arguments?this.attr(i,n):this.attr(i);return null!==s?Y(s):e},val:function(t){return 0 in arguments?(null==t&&(t=""),this.each((function(e){this.value=X(this,t,e,this.value)}))):this[0]&&(this[0].multiple?i(this[0]).find("option").filter((function(){return this.selected})).pluck("value"):this[0].value)},offset:function(e){if(e)return this.each((function(t){var n=i(this),s=X(this,e,t,n.offset()),r=n.offsetParent().offset(),o={top:s.top-r.top,left:s.left-r.left};"static"==n.css("position")&&(o.position="relative"),n.css(o)}));if(!this.length)return null;if(h.documentElement!==this[0]&&!i.contains(h.documentElement,this[0]))return{top:0,left:0};var n=this[0].getBoundingClientRect();return{left:n.left+t.pageXOffset,top:n.top+t.pageYOffset,width:Math.round(n.width),height:Math.round(n.height)}},css:function(t,e){if(arguments.length<2){var s=this[0];if("string"==typeof t){if(!s)return;return s.style[r(t)]||getComputedStyle(s,"").getPropertyValue(t)}if(k(t)){if(!s)return;var o={},a=getComputedStyle(s,"");return i.each(t,(function(t,e){o[e]=s.style[r(e)]||a.getPropertyValue(e)})),o}}var u="";if("string"==I(t))e||0===e?u=B(t)+":"+j(t,e):this.each((function(){this.style.removeProperty(B(t))}));else for(n in t)t[n]||0===t[n]?u+=B(n)+":"+j(n,t[n])+";":this.each((function(){this.style.removeProperty(B(n))}));return this.each((function(){this.style.cssText+=";"+u}))},index:function(t){return t?this.indexOf(i(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return!!t&&a.some.call(this,(function(t){return this.test(J(t))}),K(t))},addClass:function(t){return t?this.each((function(e){if("className"in this){s=[];var n=J(this);X(this,t,e,n).split(/\s+/g).forEach((function(t){i(this).hasClass(t)||s.push(t)}),this),s.length&&J(this,n+(n?" ":"")+s.join(" "))}})):this},removeClass:function(t){return this.each((function(n){if("className"in this){if(t===e)return J(this,"");s=J(this),X(this,t,n,s).split(/\s+/g).forEach((function(t){s=s.replace(K(t)," ")})),J(this,s.trim())}}))},toggleClass:function(t,n){return t?this.each((function(s){var r=i(this);X(this,t,s,J(this)).split(/\s+/g).forEach((function(t){(n===e?!r.hasClass(t):n)?r.addClass(t):r.removeClass(t)}))})):this},scrollTop:function(t){if(this.length){var n="scrollTop"in this[0];return t===e?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=t}:function(){this.scrollTo(this.scrollX,t)})}},scrollLeft:function(t){if(this.length){var n="scrollLeft"in this[0];return t===e?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=t}:function(){this.scrollTo(t,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),n=this.offset(),s=y.test(e[0].nodeName)?{top:0,left:0}:e.offset();return n.top-=parseFloat(i(t).css("margin-top"))||0,n.left-=parseFloat(i(t).css("margin-left"))||0,s.top+=parseFloat(i(e[0]).css("border-top-width"))||0,s.left+=parseFloat(i(e[0]).css("border-left-width"))||0,{top:n.top-s.top,left:n.left-s.left}}},offsetParent:function(){return this.map((function(){for(var t=this.offsetParent||h.body;t&&!y.test(t.nodeName)&&"static"==i(t).css("position");)t=t.offsetParent;return t}))}},i.fn.detach=i.fn.remove,["width","height"].forEach((function(t){var n=t.replace(/./,(function(t){return t[0].toUpperCase()}));i.fn[t]=function(s){var r,o=this[0];return s===e?L(o)?o["inner"+n]:M(o)?o.documentElement["scroll"+n]:(r=this.offset())&&r[t]:this.each((function(e){(o=i(this)).css(t,X(this,s,e,o[t]()))}))}})),C.forEach((function(n,s){var r=s%2;i.fn[n]=function(){var n,o,a=i.map(arguments,(function(t){var s=[];return"array"==(n=I(t))?(t.forEach((function(t){return t.nodeType!==e?s.push(t):i.zepto.isZ(t)?s=s.concat(t.get()):void(s=s.concat(O.fragment(t)))})),s):"object"==n||null==t?t:O.fragment(t)})),u=this.length>1;return a.length<1?this:this.each((function(e,n){o=r?n:n.parentNode,n=0==s?n.nextSibling:1==s?n.firstChild:2==s?n:null;var c=i.contains(h.documentElement,o);a.forEach((function(e){if(u)e=e.cloneNode(!0);else if(!o)return i(e).remove();o.insertBefore(e,n),c&&tt(e,(function(e){if(!(null==e.nodeName||"SCRIPT"!==e.nodeName.toUpperCase()||e.type&&"text/javascript"!==e.type||e.src)){var n=e.ownerDocument?e.ownerDocument.defaultView:t;n.eval.call(n,e.innerHTML)}}))}))}))},i.fn[r?n+"To":"insert"+(s?"Before":"After")]=function(t){return i(t)[n](this),this}})),O.Z.prototype=Q.prototype=i.fn,O.uniq=o,O.deserializeValue=Y,i.zepto=O,i}();return function(e){var n,i=1,s=Array.prototype.slice,r=e.isFunction,o=function(t){return"string"==typeof t},a={},u={},c="onfocusin"in t,l={focus:"focusin",blur:"focusout"},h={mouseenter:"mouseover",mouseleave:"mouseout"};function p(t){return t._zid||(t._zid=i++)}function f(t,e,n,i){if((e=d(e)).ns)var s=g(e.ns);return(a[p(t)]||[]).filter((function(t){return t&&(!e.e||t.e==e.e)&&(!e.ns||s.test(t.ns))&&(!n||p(t.fn)===p(n))&&(!i||t.sel==i)}))}function d(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function g(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function m(t,e){return t.del&&!c&&t.e in l||!!e}function v(t){return h[t]||c&&l[t]||t}function y(t,i,s,r,o,u,c){var l=p(t),f=a[l]||(a[l]=[]);i.split(/\s/).forEach((function(i){if("ready"==i)return e(document).ready(s);var a=d(i);a.fn=s,a.sel=o,a.e in h&&(s=function(t){var n=t.relatedTarget;if(!n||n!==this&&!e.contains(this,n))return a.fn.apply(this,arguments)}),a.del=u;var l=u||s;a.proxy=function(e){if(!(e=S(e)).isImmediatePropagationStopped()){try{var i=Object.getOwnPropertyDescriptor(e,"data");i&&!i.writable||(e.data=r)}catch(e){}var s=l.apply(t,e._args==n?[e]:[e].concat(e._args));return!1===s&&(e.preventDefault(),e.stopPropagation()),s}},a.i=f.length,f.push(a),"addEventListener"in t&&t.addEventListener(v(a.e),a.proxy,m(a,c))}))}function w(t,e,n,i,s){var r=p(t);(e||"").split(/\s/).forEach((function(e){f(t,e,n,i).forEach((function(e){delete a[r][e.i],"removeEventListener"in t&&t.removeEventListener(v(e.e),e.proxy,m(e,s))}))}))}u.click=u.mousedown=u.mouseup=u.mousemove="MouseEvents",e.event={add:y,remove:w},e.proxy=function(t,n){var i=2 in arguments&&s.call(arguments,2);if(r(t)){var a=function(){return t.apply(n,i?i.concat(s.call(arguments)):arguments)};return a._zid=p(t),a}if(o(n))return i?(i.unshift(t[n],t),e.proxy.apply(null,i)):e.proxy(t[n],t);throw new TypeError("expected function")},e.fn.bind=function(t,e,n){return this.on(t,e,n)},e.fn.unbind=function(t,e){return this.off(t,e)},e.fn.one=function(t,e,n,i){return this.on(t,e,n,i,1)};var b=function(){return!0},C=function(){return!1},x=/^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/,_={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};function S(t,i){if(i||!t.isDefaultPrevented){i||(i=t),e.each(_,(function(e,n){var s=i[e];t[e]=function(){return this[n]=b,s&&s.apply(i,arguments)},t[n]=C}));try{t.timeStamp||(t.timeStamp=Date.now())}catch(s){}(i.defaultPrevented!==n?i.defaultPrevented:"returnValue"in i?!1===i.returnValue:i.getPreventDefault&&i.getPreventDefault())&&(t.isDefaultPrevented=b)}return t}function E(t){var e,i={originalEvent:t};for(e in t)x.test(e)||t[e]===n||(i[e]=t[e]);return S(i,t)}e.fn.delegate=function(t,e,n){return this.on(e,t,n)},e.fn.undelegate=function(t,e,n){return this.off(e,t,n)},e.fn.live=function(t,n){return e(document.body).delegate(this.selector,t,n),this},e.fn.die=function(t,n){return e(document.body).undelegate(this.selector,t,n),this},e.fn.on=function(t,i,a,u,c){var l,h,p=this;return t&&!o(t)?(e.each(t,(function(t,e){p.on(t,i,a,e,c)})),p):(o(i)||r(u)||!1===u||(u=a,a=i,i=n),u!==n&&!1!==a||(u=a,a=n),!1===u&&(u=C),p.each((function(n,r){c&&(l=function(t){return w(r,t.type,u),u.apply(this,arguments)}),i&&(h=function(t){var n,o=e(t.target).closest(i,r).get(0);if(o&&o!==r)return n=e.extend(E(t),{currentTarget:o,liveFired:r}),(l||u).apply(o,[n].concat(s.call(arguments,1)))}),y(r,t,u,a,i,h||l)})))},e.fn.off=function(t,i,s){var a=this;return t&&!o(t)?(e.each(t,(function(t,e){a.off(t,i,e)})),a):(o(i)||r(s)||!1===s||(s=i,i=n),!1===s&&(s=C),a.each((function(){w(this,t,s,i)})))},e.fn.trigger=function(t,n){return(t=o(t)||e.isPlainObject(t)?e.Event(t):S(t))._args=n,this.each((function(){t.type in l&&"function"==typeof this[t.type]?this[t.type]():"dispatchEvent"in this?this.dispatchEvent(t):e(this).triggerHandler(t,n)}))},e.fn.triggerHandler=function(t,n){var i,s;return this.each((function(r,a){(i=E(o(t)?e.Event(t):t))._args=n,i.target=a,e.each(f(a,t.type||t),(function(t,e){if(s=e.proxy(i),i.isImmediatePropagationStopped())return!1}))})),s},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach((function(t){e.fn[t]=function(e){return 0 in arguments?this.bind(t,e):this.trigger(t)}})),e.Event=function(t,e){o(t)||(t=(e=t).type);var n=document.createEvent(u[t]||"Events"),i=!0;if(e)for(var s in e)"bubbles"==s?i=!!e[s]:n[s]=e[s];return n.initEvent(t,i,!0),S(n)}}(i),n=[],i.fn.remove=function(){return this.each((function(){this.parentNode&&("IMG"===this.tagName&&(n.push(this),this.src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=",e&&clearTimeout(e),e=setTimeout((function(){n=[]}),6e4)),this.parentNode.removeChild(this))}))},function(t){var e={},n=t.fn.data,i=t.camelCase,s=t.expando="Zepto"+ +new Date,r=[];function o(r,o){var u=r[s],c=u&&e[u];if(void 0===o)return c||a(r);if(c){if(o in c)return c[o];var l=i(o);if(l in c)return c[l]}return n.call(t(r),o)}function a(n,r,o){var a=n[s]||(n[s]=++t.uuid),c=e[a]||(e[a]=u(n));return void 0!==r&&(c[i(r)]=o),c}function u(e){var n={};return t.each(e.attributes||r,(function(e,s){0==s.name.indexOf("data-")&&(n[i(s.name.replace("data-",""))]=t.zepto.deserializeValue(s.value))})),n}t.fn.data=function(e,n){return void 0===n?t.isPlainObject(e)?this.each((function(n,i){t.each(e,(function(t,e){a(i,t,e)}))})):0 in this?o(this[0],e):void 0:this.each((function(){a(this,e,n)}))},t.data=function(e,n,i){return t(e).data(n,i)},t.hasData=function(n){var i=n[s],r=i&&e[i];return!!r&&!t.isEmptyObject(r)},t.fn.removeData=function(n){return"string"==typeof n&&(n=n.split(/\s+/)),this.each((function(){var r=this[s],o=r&&e[r];o&&t.each(n||o,(function(t){delete o[n?i(this):t]}))}))},["remove","empty"].forEach((function(e){var n=t.fn[e];t.fn[e]=function(){var t=this.find("*");return"remove"===e&&(t=t.add(this)),t.removeData(),n.call(this)}}))}(i),i}(e)},8820:t=>{"use strict";var e={}.hasOwnProperty,n=/[ -,\.\/:-@\[-\^`\{-~]/,i=/[ -,\.\/:-@\[\]\^`\{-~]/,s=/(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g,r=function t(r,o){"single"!=(o=function(t,n){if(!t)return n;var i={};for(var s in n)i[s]=e.call(t,s)?t[s]:n[s];return i}(o,t.options)).quotes&&"double"!=o.quotes&&(o.quotes="single");for(var a="double"==o.quotes?'"':"'",u=o.isIdentifier,c=r.charAt(0),l="",h=0,p=r.length;h126){if(d>=55296&&d<=56319&&h{"use strict";var i,s,r,o=[n(5525),n(4785),n(8291),n(2709),n(2506),n(9176)],a=-1,u=[],c=!1;function l(){i&&s&&(i=!1,s.length?u=s.concat(u):a=-1,u.length&&h())}function h(){if(!i){c=!1,i=!0;for(var t=u.length,e=setTimeout(l);t;){for(s=u,u=[];s&&++a1)for(var n=1;n{"use strict";e.test=function(){return!n.g.setImmediate&&void 0!==n.g.MessageChannel},e.install=function(t){var e=new n.g.MessageChannel;return e.port1.onmessage=t,function(){e.port2.postMessage(0)}}},8291:(t,e,n)=>{"use strict";var i=n.g.MutationObserver||n.g.WebKitMutationObserver;e.test=function(){return i},e.install=function(t){var e=0,s=new i(t),r=n.g.document.createTextNode("");return s.observe(r,{characterData:!0}),function(){r.data=e=++e%2}}},4785:(t,e,n)=>{"use strict";e.test=function(){return"function"==typeof n.g.queueMicrotask},e.install=function(t){return function(){n.g.queueMicrotask(t)}}},2506:(t,e,n)=>{"use strict";e.test=function(){return"document"in n.g&&"onreadystatechange"in n.g.document.createElement("script")},e.install=function(t){return function(){var e=n.g.document.createElement("script");return e.onreadystatechange=function(){t(),e.onreadystatechange=null,e.parentNode.removeChild(e),e=null},n.g.document.documentElement.appendChild(e),t}}},9176:(t,e)=>{"use strict";e.test=function(){return!0},e.install=function(t){return function(){setTimeout(t,0)}}}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/8443.0060be2a.js.LICENSE.txt b/handbook/build/assets/js/8443.0060be2a.js.LICENSE.txt new file mode 100644 index 000000000..4f7ccd8a7 --- /dev/null +++ b/handbook/build/assets/js/8443.0060be2a.js.LICENSE.txt @@ -0,0 +1 @@ +/*! https://mths.be/cssesc v3.0.0 by @mathias */ diff --git a/handbook/build/assets/js/88be757d.6021c737.js b/handbook/build/assets/js/88be757d.6021c737.js new file mode 100644 index 000000000..745639f17 --- /dev/null +++ b/handbook/build/assets/js/88be757d.6021c737.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1302],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),f=s(r),m=o,d=f["".concat(p,".").concat(m)]||f[m]||u[m]||a;return r?n.createElement(d,c(c({ref:t},l),{},{components:r})):n.createElement(d,c({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=f;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>i,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={id:"fpsgame",title:"FPS\u5b9e\u65f6\u6e38\u620f"},c=void 0,i={unversionedId:"fpsgame",id:"fpsgame",title:"FPS\u5b9e\u65f6\u6e38\u620f",description:"B\u7ad9\u9996\u9875",source:"@site/docs/fpsgame.mdx",sourceDirName:".",slug:"/fpsgame",permalink:"/touchsocket/docs/fpsgame",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/fpsgame.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"fpsgame",title:"FPS\u5b9e\u65f6\u6e38\u620f"},sidebar:"docs",previous:{title:"Web\u6570\u636e\u8f6c\u53d1Winform\u9879\u76ee",permalink:"/touchsocket/docs/webdataforwarding"},next:{title:"\u5de5\u7a0b\u5e08\u8f6f\u4ef6\u5de5\u5177\u7bb1",permalink:"/touchsocket/docs/engineertoolbox"}},p={},s=[],l={toc:s};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://space.bilibili.com/41336899"},"B\u7ad9\u9996\u9875")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/8973b48c.310d4fb3.js b/handbook/build/assets/js/8973b48c.310d4fb3.js new file mode 100644 index 000000000..e0182d3ee --- /dev/null +++ b/handbook/build/assets/js/8973b48c.310d4fb3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[3635],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var r=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=r.createContext({}),u=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(p.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},k=r.forwardRef((function(e,t){var n=e.components,l=e.mdxType,a=e.originalType,p=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),k=u(n),m=l,g=k["".concat(p,".").concat(m)]||k[m]||s[m]||a;return n?r.createElement(g,o(o({ref:t},c),{},{components:n})):r.createElement(g,o({ref:t},c))}));function m(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var a=n.length,o=new Array(a);o[0]=k;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:l,o[1]=i;for(var u=2;u{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>s,frontMatter:()=>a,metadata:()=>i,toc:()=>u});var r=n(7462),l=(n(7294),n(3905));const a={id:"pluginsmanager",title:"\u63d2\u4ef6\u7cfb\u7edf"},o=void 0,i={unversionedId:"pluginsmanager",id:"pluginsmanager",title:"\u63d2\u4ef6\u7cfb\u7edf",description:"\u8bf4\u660e",source:"@site/docs/pluginsmanager.mdx",sourceDirName:".",slug:"/pluginsmanager",permalink:"/touchsocket/docs/pluginsmanager",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/pluginsmanager.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"pluginsmanager",title:"\u63d2\u4ef6\u7cfb\u7edf"},sidebar:"docs",previous:{title:"\u6587\u4ef6\u6d41\u6c60",permalink:"/touchsocket/docs/filepool"},next:{title:"\u5305\u5e8f\u5217\u5316\u6a21\u5f0f",permalink:"/touchsocket/docs/ipackage"}},p={},u=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u4ea7\u54c1\u7279\u70b9",id:"\u4ea7\u54c1\u7279\u70b9",level:2},{value:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f",id:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f",level:2},{value:"\u63d2\u4ef6\u7279\u6027",id:"\u63d2\u4ef6\u7279\u6027",level:2},{value:"\u7528\u6237\u81ea\u5b9a\u4e49\u63d2\u4ef6",id:"\u7528\u6237\u81ea\u5b9a\u4e49\u63d2\u4ef6",level:2},{value:"\u7cfb\u7edf\u81ea\u5b9a\u4e49\u63d2\u4ef6",id:"\u7cfb\u7edf\u81ea\u5b9a\u4e49\u63d2\u4ef6",level:2}],c={toc:u};function s(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"\u63d2\u4ef6\u662f\u5bf9TouchSocket\u4ea7\u54c1\u7684\u6a2a\u5411\u6269\u5c55\u3002")),(0,l.kt)("h2",{id:"\u4ea7\u54c1\u7279\u70b9"},"\u4ea7\u54c1\u7279\u70b9"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"\u7b80\u5355\u6613\u7528\u3002"),(0,l.kt)("li",{parentName:"ul"},"\u6613\u6269\u5c55\u3002")),(0,l.kt)("h2",{id:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f"},"\u4ea7\u54c1\u5e94\u7528\u573a\u666f"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"TCP\u57fa\u7840\u4f7f\u7528\u573a\u666f\u3002"),(0,l.kt)("li",{parentName:"ul"},"\u81ea\u5b9a\u4e49\u534f\u8bae\u89e3\u6790\u573a\u666f\u3002")),(0,l.kt)("h2",{id:"\u63d2\u4ef6\u7279\u6027"},"\u63d2\u4ef6\u7279\u6027"),(0,l.kt)("p",null,"\u3010\u591a\u7ebf\u7a0b\u5e76\u53d1\u3011\n\u63d2\u4ef6\u7684\u6240\u6709\u89e6\u53d1\uff0c\u5747\u662f\u540c\u4e00\u5b9e\u4f8b\uff0c\u6240\u4ee5\u5728\u670d\u52a1\u5668\u8fd0\u884c\u65f6\uff0c\u51e0\u4e4e\u90fd\u662f\u5e76\u53d1\u89e6\u53d1\u7684\uff0c\u6240\u6709\u5e94\u5f53\u8003\u8651\u5e76\u53d1\u95ee\u9898\u3002"),(0,l.kt)("p",null,"\u3010\u63d2\u4ef6\u5148\u884c\u3011\n\u5f53\u542f\u7528\u63d2\u4ef6\u65f6\uff0c\u63d2\u4ef6\u7684\u89e6\u53d1",(0,l.kt)("strong",{parentName:"p"},"\u4ec5\u6b21\u4e8e"),"\u65b9\u6cd5\u91cd\u5199\uff0c\u800c",(0,l.kt)("strong",{parentName:"p"},"\u4f18\u4e8e"),"\u4e8b\u4ef6\u3002"),(0,l.kt)("p",null,"\u3010\u6267\u884c\u987a\u5e8f\u3011\n\u6bcf\u4e2a\u63d2\u4ef6\u90fd\u6709\u4e00\u4e2a",(0,l.kt)("strong",{parentName:"p"},"Order"),"\u5c5e\u6027\uff0c\u8be5\u5c5e\u6027\u8868\u793a\u8be5\u63d2\u4ef6\u7684\u6267\u884c\u987a\u5e8f\uff0c\u6570\u503c\u5c0f\uff0c\u8d8a\u63d0\u524d\u6267\u884c\uff08Order\u5728Add\u4e4b\u524d\u751f\u6548\uff0c\u540e\u7eed\u4fee\u6539\u65e0\u6548\uff09\u3002"),(0,l.kt)("p",null,"\u3010\u4e2d\u65ad\u4f20\u9012\u3011\n\u5f53\u67d0\u4e2a\u63d2\u4ef6\u5728\u54cd\u5e94\u65f6\uff0c\u5982\u679c\u8bbe\u7f6ee.Handled=true,\u5219\u8be5\u6570\u636e\u5c06",(0,l.kt)("strong",{parentName:"p"},"\u4e0d\u4f1a"),"\u518d\u89e6\u53d1\u540e\u7eed\u7684\u63d2\u4ef6\u3001\u4e8b\u4ef6\u3001\u91cd\u5199\u65b9\u6cd5\u3002"),(0,l.kt)("h2",{id:"\u7528\u6237\u81ea\u5b9a\u4e49\u63d2\u4ef6"},"\u7528\u6237\u81ea\u5b9a\u4e49\u63d2\u4ef6"),(0,l.kt)("p",null,"\u7528\u6237\u901a\u8fc7\u5b9e\u73b0\u6846\u67b6\u9884\u8bbe\u7684\u63d2\u4ef6\u63a5\u53e3\uff0c\u5373\u53ef\u63a5\u6536\u76f8\u5e94\u7684\u89e6\u53d1\u3002\u6bcf\u4e2a\u7ec4\u4ef6\u90fd\u6709\u8be6\u7ec6\u7684\u63d2\u4ef6\u652f\u6301\u8bf4\u660e\u3002"),(0,l.kt)("p",null,"\u4f8b\u5982\uff1a",(0,l.kt)("strong",{parentName:"p"},"ITcpPlugin"),"\u3001",(0,l.kt)("strong",{parentName:"p"},"ITokenPlugin"),"\u3001",(0,l.kt)("strong",{parentName:"p"},"IProtocolPlugin"),"\u7b49\u3002"),(0,l.kt)("h2",{id:"\u7cfb\u7edf\u81ea\u5b9a\u4e49\u63d2\u4ef6"},"\u7cfb\u7edf\u81ea\u5b9a\u4e49\u63d2\u4ef6"),(0,l.kt)("p",null,"\u5f53\u5404\u4f4d\u670b\u53cb\u4f7f\u7528TouchSocket\u5c01\u88c5\u81ea\u5df1\u7684dll\u65f6\uff0c\u53ef\u80fd\u9700\u8981\u4e00\u4e9b\u5b9a\u4e49\u63d2\u4ef6\u3002\u90a3\u4e48\u8fd9\u4e2a\u9700\u6c42TouchSocket\u4e5f\u80fd\u6ee1\u8db3\u5927\u5bb6\u3002"),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"\u4f8b\u5982\uff1a\u5b9e\u73b0\u57fa\u4e8eTCP\u7684\u7279\u6b8a\u4fe1\u606f\u81ea\u5b9a\u4e49\u63d2\u4ef6\uff0c\u5f53\u6536\u5230\u5b57\u6bcd\u2018A\u2019\u65f6\uff0c\u5e0c\u671b\u89e6\u53d1\u5b9e\u73b0IAPlugin\u63a5\u53e3\u63d2\u4ef6\u7684GoToA\u65b9\u6cd5\u3002")),(0,l.kt)("p",null,"\u5177\u4f53\u64cd\u4f5c\u5982\u4e0b\uff1a"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"\u58f0\u660eIAPlugin\u63a5\u53e3\uff0c\u7ee7\u627f",(0,l.kt)("strong",{parentName:"li"},"IPlugin"),"\u3002"),(0,l.kt)("li",{parentName:"ol"},"\u58f0\u660eGoToA\u63a5\u53e3\u65b9\u6cd5\uff08\u8be5\u65b9\u6cd5\u5fc5\u987b",(0,l.kt)("strong",{parentName:"li"},"\u4e24\u4e2a"),"\u53c2\u6570\uff0c\u7b2c\u4e00\u53c2\u6570\u65e0\u8981\u6c42\uff0c\u4e00\u822c\u4e3a\u89e6\u53d1\u4e3b\u4f53\uff0c\u7b2c\u4e8c\u53c2\u6570",(0,l.kt)("strong",{parentName:"li"},"\u5fc5\u987b\u7ee7\u627f"),"\u81ea",(0,l.kt)("strong",{parentName:"li"},"TouchSocketEventArgs"),"\uff09\u3002"),(0,l.kt)("li",{parentName:"ol"},"\u5728\u5408\u9002\u65f6\u5019\uff0c\u5224\u65ad\u5f53\u524d\u914d\u7f6e\u662f\u5426\u652f\u6301\u63d2\u4ef6\uff0c\u7136\u540e\u4f7f\u7528\u670d\u52a1\u5668\u6216\u5ba2\u6237\u7aef\u7684",(0,l.kt)("strong",{parentName:"li"},"PluginsManager"),"\u5c5e\u6027\u8c03\u7528",(0,l.kt)("strong",{parentName:"li"},"Raise"),"\u65b9\u6cd5\uff0c\u6b64\u5904\u7684\u6cdb\u578b\uff08",(0,l.kt)("strong",{parentName:"li"},"IAPlugin"),"\uff09\u5fc5\u987b\u4e3a\u63a5\u53e3\u7c7b\u578b\u3002")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},"public interface IAPlugin : IPlugin\n{\n void GoToA(ITcpClientBase client,TouchSocketEventArgs e);\n}\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyTClient : TcpClient\n{\n protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)\n {\n if (this.UsePlugin)\n {\n if (byteBlock.ToString()=="A")\n {\n this.PluginsManager.Raise("GoToA",this,new TouchSocketEventArgs());\n }\n }\n }\n}\n')))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/8aa4b8ad.20446be6.js b/handbook/build/assets/js/8aa4b8ad.20446be6.js new file mode 100644 index 000000000..7356ac6f4 --- /dev/null +++ b/handbook/build/assets/js/8aa4b8ad.20446be6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1877],{3905:(t,e,l)=>{l.d(e,{Zo:()=>p,kt:()=>u});var A=l(7294);function r(t,e,l){return e in t?Object.defineProperty(t,e,{value:l,enumerable:!0,configurable:!0,writable:!0}):t[e]=l,t}function a(t,e){var l=Object.keys(t);if(Object.getOwnPropertySymbols){var A=Object.getOwnPropertySymbols(t);e&&(A=A.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),l.push.apply(l,A)}return l}function n(t){for(var e=1;e=0||(r[l]=t[l]);return r}(t,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);for(A=0;A=0||Object.prototype.propertyIsEnumerable.call(t,l)&&(r[l]=t[l])}return r}var o=A.createContext({}),g=function(t){var e=A.useContext(o),l=e;return t&&(l="function"==typeof t?t(e):n(n({},e),t)),l},p=function(t){var e=g(t.components);return A.createElement(o.Provider,{value:e},t.children)},s={inlineCode:"code",wrapper:function(t){var e=t.children;return A.createElement(A.Fragment,{},e)}},c=A.forwardRef((function(t,e){var l=t.components,r=t.mdxType,a=t.originalType,o=t.parentName,p=i(t,["components","mdxType","originalType","parentName"]),c=g(l),u=r,d=c["".concat(o,".").concat(u)]||c[u]||s[u]||a;return l?A.createElement(d,n(n({ref:e},p),{},{components:l})):A.createElement(d,n({ref:e},p))}));function u(t,e){var l=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var a=l.length,n=new Array(a);n[0]=c;var i={};for(var o in e)hasOwnProperty.call(e,o)&&(i[o]=e[o]);i.originalType=t,i.mdxType="string"==typeof t?t:r,n[1]=i;for(var g=2;g{l.r(e),l.d(e,{assets:()=>o,contentTitle:()=>n,default:()=>s,frontMatter:()=>a,metadata:()=>i,toc:()=>g});var A=l(7462),r=(l(7294),l(3905));const a={id:"startguide",title:"\u5165\u95e8\u6307\u5357"},n=void 0,i={unversionedId:"startguide",id:"startguide",title:"\u5165\u95e8\u6307\u5357",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/startguide.mdx",sourceDirName:".",slug:"/startguide",permalink:"/touchsocket/docs/startguide",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/startguide.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675676224,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"startguide",title:"\u5165\u95e8\u6307\u5357"},sidebar:"docs",previous:{title:"\u5de5\u7a0b\u5e08\u8f6f\u4ef6\u5de5\u5177\u7bb1",permalink:"/touchsocket/docs/engineertoolbox"},next:{title:"\u5185\u5b58\u6c60",permalink:"/touchsocket/docs/bytepool"}},o={},g=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u521b\u5efa\u9879\u76ee",id:"\u4e8c\u521b\u5efa\u9879\u76ee",level:2},{value:"2.1 \u521b\u5efa\u65b0\u9879\u76ee",id:"21-\u521b\u5efa\u65b0\u9879\u76ee",level:3},{value:"2.2 \u9009\u62e9\u9879\u76ee\u7c7b\u578b",id:"22-\u9009\u62e9\u9879\u76ee\u7c7b\u578b",level:3},{value:"2.3 \u914d\u7f6e\u9879\u76ee\u540d\u79f0\u548c\u8def\u5f84",id:"23-\u914d\u7f6e\u9879\u76ee\u540d\u79f0\u548c\u8def\u5f84",level:3},{value:"2.4 \u9009\u62e9Net\u7248\u672c",id:"24-\u9009\u62e9net\u7248\u672c",level:3},{value:"\u4e09\u3001\u5b89\u88c5",id:"\u4e09\u5b89\u88c5",level:2},{value:"3.1 Nuget\u5b89\u88c5",id:"31-nuget\u5b89\u88c5",level:3},{value:"3.2 PackageReference",id:"32-packagereference",level:3},{value:"3.3 Dll\u76f4\u63a5\u5f15\u7528",id:"33-dll\u76f4\u63a5\u5f15\u7528",level:3},{value:"\u56db\u3001\u7ed3\u675f",id:"\u56db\u7ed3\u675f",level:2}],p={toc:g};function s(t){let{components:e,...a}=t;return(0,r.kt)("wrapper",(0,A.Z)({},p,a,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"TouchSocket\uff08Pro\uff09\u662f\u57fa\u4e8e.Net\u53d1\u5e03\u7684\u7a0b\u5e8f\u96c6\uff0c\u6240\u4ee5\u5b83\u53ef\u4ee5\u88ab\u7528\u4e8e\u5bf9\u5e94.Net\u7248\u672c\u7684C#\u3001F#\u3001VB.net\u7b49\u8bed\u8a00\u9879\u76ee\u3002\u5b83\u4e0d\u533a\u5206\u60a8\u7684\u9879\u76ee\u662f\u63a7\u5236\u53f0\u3001Winform\u3001Wpf\u3001\u6216\u8005\u662fAspnetcore\uff0c\u5b83\u7edf\u7edf\u90fd\u652f\u6301\u3002"),(0,r.kt)("p",null,"\u4e0b\u9762\u6211\u4eec\u5c06\u4ee5\u6700\u7b80\u5355\u7684",(0,r.kt)("inlineCode",{parentName:"p"},"C# \u63a7\u5236\u53f0"),"\u7a0b\u5e8f\u4f5c\u4e3a\u5165\u95e8\uff0c\u8ba9\u60a8\u6700\u76f4\u89c2\u7684\u611f\u53d7ToucSocket\u7684\u5f3a\u5927\u3002"),(0,r.kt)("h2",{id:"\u4e8c\u521b\u5efa\u9879\u76ee"},"\u4e8c\u3001\u521b\u5efa\u9879\u76ee"),(0,r.kt)("p",null,"\u7531\u4e8eTouchSocket\uff08Pro\uff09\u662f\u57fa\u4e8enet45\u3001netstandard2.0\u3001netcoreapp3.1\u4e09\u4e2a\u5e73\u53f0\u4f5c\u4e3a\u5e38\u671f\u652f\u6301\u5e73\u53f0\uff0cnet7.0\u4f5c\u4e3a\u6700\u65b0\u53d1\u5e03\u5e73\u53f0\u7684\u7a0b\u5e8f\uff0c\u6240\u4ee5\u60a8\u53ef\u4ee5\u7528vs2010\u53ca\u4ee5\u4e0a\u7684\u4efb\u610f\u7248\u672c\u521b\u5efa\u9879\u76ee\u3002"),(0,r.kt)("p",null,"\u4e0b\u9762\u6211\u4eec\u5c06\u4ee5vs2022\u4f5c\u4e3a\u793a\u4f8b\uff1a"),(0,r.kt)("admonition",{title:"\u8bf4\u660e",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"\u5982\u679c\u60a8\u9009\u62e9vs code\u7b49\u5176\u4ed6\u7684\u7f16\u8bd1\u5de5\u5177\uff0c\u90a3\u4e48\u6211\u76f8\u4fe1\u60a8\u5df2\u4e0d\u662f\u65b0\u624b\u3002\u90a3\u4e48\u60a8\u53ea\u9700\u8981\u5b89\u88c5TouchSocket\uff08Pro\uff09\u7684\u6700\u65b0nuget\u5305\u5373\u53ef\u3002")),(0,r.kt)("h3",{id:"21-\u521b\u5efa\u65b0\u9879\u76ee"},"2.1 \u521b\u5efa\u65b0\u9879\u76ee"),(0,r.kt)("img",{src:l(8964).Z}),(0,r.kt)("h3",{id:"22-\u9009\u62e9\u9879\u76ee\u7c7b\u578b"},"2.2 \u9009\u62e9\u9879\u76ee\u7c7b\u578b"),(0,r.kt)("img",{src:l(2313).Z}),(0,r.kt)("h3",{id:"23-\u914d\u7f6e\u9879\u76ee\u540d\u79f0\u548c\u8def\u5f84"},"2.3 \u914d\u7f6e\u9879\u76ee\u540d\u79f0\u548c\u8def\u5f84"),(0,r.kt)("img",{src:l(6365).Z}),(0,r.kt)("h3",{id:"24-\u9009\u62e9net\u7248\u672c"},"2.4 \u9009\u62e9Net\u7248\u672c"),(0,r.kt)("img",{src:l(164).Z}),(0,r.kt)("img",{src:l(7375).Z}),(0,r.kt)("h2",{id:"\u4e09\u5b89\u88c5"},"\u4e09\u3001\u5b89\u88c5"),(0,r.kt)("h3",{id:"31-nuget\u5b89\u88c5"},"3.1 Nuget\u5b89\u88c5"),(0,r.kt)("p",null,"\u53f3\u51fb\u9879\u76ee=\u300b\u70b9\u51fb\u201c\u7ba1\u7406Nuget\u7a0b\u5e8f\u5305\u201d\u3002"),(0,r.kt)("img",{src:l(8659).Z}),(0,r.kt)("p",null,"\u70b9\u51fb\u201c\u6d4f\u89c8\u201d\uff0c\u7136\u540e\u5728\u641c\u7d22\u6846\u8f93\u5165",(0,r.kt)("inlineCode",{parentName:"p"},"TouchSocket"),"\uff0c\u7136\u540e\u5728\u641c\u7d22\u7ed3\u679c\u4e2d\u9009\u62e9\u3002\u6700\u540e\u70b9\u51fb\u5b89\u88c5\u3002"),(0,r.kt)("img",{src:l(8614).Z}),(0,r.kt)("h3",{id:"32-packagereference"},"3.2 PackageReference"),(0,r.kt)("p",null,"\u5355\u51fb\u9879\u76ee\uff0c\u6253\u5f00\u9879\u76ee\u7f16\u8f91\uff0c\u7136\u540e\u5728\u7a7a\u767d\u6839\u5185\u90e8\u5f15\u7528\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-xml"},'\n \n\n')),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},'Version="1.2.3"\u53ef\u80fd\u4e0d\u662f\u6700\u65b0\u7684\u7248\u672c\uff0c\u8bf7\u524d\u5f80',(0,r.kt)("a",{parentName:"p",href:"https://www.nuget.org/packages?q=TouchSocket"},"Nuget\u5b98\u7f51"),"\u67e5\u770b\u3002")),(0,r.kt)("img",{src:l(5397).Z}),(0,r.kt)("h3",{id:"33-dll\u76f4\u63a5\u5f15\u7528"},"3.3 Dll\u76f4\u63a5\u5f15\u7528"),(0,r.kt)("p",null,"\u5728",(0,r.kt)("a",{parentName:"p",href:"https://www.nuget.org/packages?q=TouchSocket"},"Nuget\u5b98\u7f51"),"\u4e2d\uff0c\u9009\u62e9\u9700\u8981\u7684\uff0c\u7136\u540e\u9009\u62e9\u201cDownload package\u201d\uff0c\u5373\u53ef\u4e0b\u8f7d\u4e00\u4e2a\u540e\u7f00\u4e3a",(0,r.kt)("inlineCode",{parentName:"p"},".nupkg"),"\u6587\u4ef6\u3002"),(0,r.kt)("img",{src:l(6094).Z}),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"\u5982\u679c\u4e0b\u8f7d\u901f\u5ea6\u8f83\u6162\uff0c\u53ef\u4ee5\u8003\u8651\u4f7f\u7528\u8fc5\u96f7\u7b49\u5de5\u5177\u52a0\u901f\u3002")),(0,r.kt)("p",null,"\u5c06\u4e0b\u8f7d\u7684\u540e\u7f00\u4e3a",(0,r.kt)("inlineCode",{parentName:"p"},".nupkg"),"\u7684\u6587\u4ef6\uff0c\u901a\u8fc7\u538b\u7f29\u5de5\u5177",(0,r.kt)("inlineCode",{parentName:"p"},"\u89e3\u538b"),"\u3002\u5f97\u5230\u5982\u4e0b\u76ee\u5f55\u7ed3\u6784\u3002"),(0,r.kt)("img",{src:l(6420).Z}),(0,r.kt)("p",null,"\u7136\u540e\u8fdb\u5165\u201clib\u201d\u7684\u6587\u4ef6\u5939\u3002\u9009\u62e9\u5bf9\u5e94\u5e73\u53f0\u3002"),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"\u4e00\u822c\u6765\u8bf4\uff0c\u6240\u6709\u57fa\u4e8e.NET Framework\u7684\u9879\u76ee\uff0c\u90fd\u6700\u597d\u5f15\u7528net45\u7684\u5e93\u3002\u7136\u540e\u5176\u4ed6\u7248\u672c\u7684\uff0c\u9009\u62e9\u6700\u8fd1\u7684\uff0c\u8f83\u4f4e\u7684\u5e93\u5373\u53ef\u3002\u5728\u672c\u793a\u4f8b\u4e2d\uff0c\u9009\u62e9netcoreapp3.1\u7684\u5e93\u3002")),(0,r.kt)("p",null,"\u628a\u4e0b\u5217\u6587\u4ef6\u5f15\u7528\u5230\u9879\u76ee\u5373\u53ef\u3002"),(0,r.kt)("img",{src:l(2754).Z}),(0,r.kt)("img",{src:l(8485).Z}),(0,r.kt)("h2",{id:"\u56db\u7ed3\u675f"},"\u56db\u3001\u7ed3\u675f"),(0,r.kt)("p",null,"\u606d\u559c\u4f60\uff0c\u5230\u8fd9\u91cc\uff0c\u4f60\u5c31\u5b8c\u6210\u4e86\u5165\u95e8\u7684\u6559\u5b66\uff0c\u4f60\u53ef\u80fd\u4f1a\u597d\u5947\uff0c\u505a\u4e86\u8fd9\u4e48\u591a\uff0c\u8fd8\u662f\u4ec0\u4e48\u90fd\u6ca1\u6709\u505a\u554a\u3002\u8fd9\u662f\u56e0\u4e3aTouchSocket\u5e76\u4e0d\u662f\u4e00\u4e2a\u5355\u529f\u80fd\u7684\uff0c\u800c\u662f\u4e00\u4e2a\u591a\u529f\u80fd\u7a0b\u5e8f\u5e93\u3002\u6240\u4ee5\uff0c\u4f60\u5fc5\u987b\u5728\u5176\u4ed6\u6a21\u5757\u4e2d\u67e5\u770b\u4f60\u6240\u9700\u8981\u7684\u5185\u5bb9\u3002"),(0,r.kt)("p",null,"\u795d\u4f60\u597d\u8fd0\uff01\uff01\uff01"))}s.isMDXComponent=!0},8964:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-1-ee9268f00fb23eec237bb5bf587216f3.png"},6420:(t,e,l)=>{l.d(e,{Z:()=>A});const A="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABEoAAADPCAMAAADVqsSqAAABUFBMVEUAeNf9/f/9///7ODj5/f/z+f8AAAD////1+//3+//7/f/1+f/7//+3ZgA6kdtmt///t2b//9v//7eR3P/b//+ROgC3////25EAOpHz+f0AZrdlAAAAAGb5+frbkTr8/Pz/6poAAzpmADp+sLX/54+Ki4w6AAA6AGbTjTicnKD39veROjo2itux/Pw6ADo5ZrjpxEVmAGaxsrBis/85OpH/5YevZBZlOZGF1P/uy0kAZLam9/+0ZUD2/LcIoO9zoI/j8P73/NvU/P+lpaXu1o74s2WKOGXys2b/+//Nys5lZgrj4+p9dX/x0E+3rNlmd9bM5v6Yl2KROmZott6KkdJoZmYAeOU1bWZiAGX42I//1eU/vfZywraJNwACSGqSZQ02AADb/+oRPnw2kqvd+7dLOTn+29uKODhpj9iwlZFkOWZXOQD96+4gYKAAAGQ6OmbfUThVAAAgAElEQVR42uyd/VfayBrHkSWQEN4UVCJitMtp2d5waYtuAZEqRwptD9qzx7Klrd322Lfd7fb+/7/dZ2YSCAarIG4D+X5QXhKZSYbMh+eZ4OCTAJhRnsvzVsos1+uTJVzm6+IZAs+n0S4/pJSpvYouqteH9zYws1FJYN5KmeV6oZK5Q/MK0v402uWHlDK1V9FF9UIlYGbZn7tSZrleUsnerbL1qHd7fTdawjE603hmTEjbzwctqlKvSPu+lxFH78Hnsnl1Wbt8rxQOrU03Li1G229tlbVamfUmtcULS7eqB48LN/sqUr18L22dVm0Zoi+/E/u0XmCraelehh6VplSxNkIlMq+BMOQ8q7Z3Z1cGYAaQ9vOGZD04eLw7OJJlqZVuyNHS9UoRiqmyv7lCKVI+3aiV9zJnz1V172WhVZWYSnZvvA0Ot/8o8y1NN1p8c2tlvuawKJl7ZO7I2csCU8606nUU5MsHS6qqSr3thipRtQenoh1VANyNxCRAt60qe3RYzr/962OZPTai/TAjmJ68FDVfGmNj9iVVY1GJxB4MVFKQb74Nai8oBqBISlUViqqECqtqr8j/gG2CGZW8LGi/lqa0PdK+oyAfU6msksQlYREKTFSV5IVDFbgd6kayKQHqQOuFXjEq3p4l0c2k65ViS3wuL+WPgb7OxNtx8AWLSpQbboMPGaNW1vYyW2X+sFfMGxrvv72ixhawTZB+ZdGBSHC0abW9o3F9Gm1GKVpV2Rry1t6JnDcOKUQBwO1hCUnACkBKUtSgjIZ6TkHVeKfZKueNvYeNiUtRpXGiEn2fPETlCOlQB7KikpttAjlS+2jUnga33mS48LTeP6fpxsFn8sphf6xE1aIljUUlu3Rnahp3LPFR9ZTjCMW0gsxtFO9JCErALEQlJTbMyLsvxdWH70p53nfoLVFSa0Il0sSljJXgqKfBbwWSDx+uUKMGeYSN/t50VCLLf9ZilFblt5KfGmKk9ezxLjdoryiJqITaIsqjEjFWMq22V5xRiWVkI3Dw2/8+PGxV82enJRyms4tnhl0D+7yzN6u9Lyo7jLeeluhtkPrO6Khk3FJIJXlnfqPIIy8Ke5fWaizLULiWmlWWLqUbN/wq3k3lY7U3mZicpyiAgqFekUIBNvijibESEaZRVNI0E5wp1RseoZLgR0OillCahpwnoX14uUuvwK1yQAHA5VAXYUduVcQPitn313fp/VdVzKhEnbSUAo9rFL7qCttyOhgr4U9SRGk33wZ5o5YM9N4ZlNX0thtaVmHjJtR9e0WNdWKmEhEt/E5royV5WvU6lvg00VxyMybXCo8LpyWFFjTTOE6B601CyhA9nfqL0gyukQQMpR+VJLlKrlHKy8LVVaJR15ITW3dYUYraP4WUbtxwG1BMFdMOTtONZrCUJZU00429DKuVohK+KewMjnbw+MGdAslSWHMqbT9CJbI1Tm3IAar2bkAR7QeAy5FbVc3q6QenVRYI9MdKWFSSzZJKsnJ2wlLyVcVKcK7Ut5pB1o2/MZnIMivm32iDLIUCmiw3g2wneu/4eadSc6usK4OPqMkHn5PZyj+fy1mZMp0bc4nPMkczpjCVBJqUTwUUXHBx/UWrlZv2t/+wLZ5oBr8VqDNdLoGLS6EY5epRiXxKT5YjgQBFRG//tn2u5YbbQNbyMeqzbAsDlEw0KNMhvzAliqiE7QgTSEBrGQr7DOq0HCY5o5KAHT0AZh49EPbIr6YM73k4HGbXgXB/Sda+9oL20gKjSslmx+sMrJQIv6fo7X/tVWT12hoha+0w24PBcsXcMi6fKaE5lvhs9WUHTa/o/L6O29m7ZX1J8cCv43C2Ooq4zQYCTtM4CZwXklXKaJMo4QtKka266UWwF5g1u9X4r+IYbWDfVkUfvu07NXsVQ1ywf879VZ0qsa2PMIaeEQlHcDtzt7pHLmH5e0c7tYVutYuAnqM4f8Oyf9Sz9UggMrLcUWWwUvgzIhH9u1s09VeR2iCiU9Dh2Er7rvMNu2B3rrZ/I/bX8UTfAgAzSsBlpeh0mc02mEa9UAmASuaqS0MlAIxJeO5KmeV6fSEAZpSFuStlluuFSgAAUwAqAQBMSSWdTqfSqTA6HbQIAGBSlWz2qSygSQAA11RJbrOCFgEAXFMluc3cvdF/tXR/RdxZXI7zf6DeSoZCCfM/luz311fQpMDbUB8x7yVi7GrNWrER91BU4lTJxtqQSjaocaLx0NLDVL+NFv+THFJONIajCXiZpVtmj6gl6cdTKqlYInGqZHU7ZVfJ6pfF5RipJBoPDatk9XY/KrGrBQBvBSS26QVS1HnoPZd3k8RgeXyeVdLpm8Shkmh8KMGh5GaNwg5qMXKGPcGxJ0IDDQPgNUTowVObjarVR2KhTymx6lNq/qOSXG7TqRIrwljKCM/yKCVKtyzDsUUl0XMyxhEFPMpq0UxtqNOssb4husnq7XRqI76UeftcnXOV5ERQsnMvO5z1mdGI/Xbx899xPmZyfqwkERt+EgAezHF4vs/eTTd+LzKvDI2VtHVl3qMSIZJcp3Kojxgq6duB4rWtN/cfbL//bWX4DM4GS3jSIlLBYAnwcliynRLjrn8eFv0hUyVDYfv8qmShMghKdu59Nyph5LbfR4O2s1zCHEv3n74Ixljug6gEeJqENXrYKybs+lj668tc7zePSphGVnM7O0wlFJWs/jdJP1wh5mmtvh0SwfWnMbo+fwaHcsFY4izDh5xW70AlwMsqMc/SiGETK8GhvpSo6nOuknubPLsRKgnZVeI4g5NOURoT/fYhszaU4Cwur6/oidjicjqFMzjAy0SDa+wqdl4l0W8rup4IxudbJRWR3fSjkuHEz5bmiYGQ5VhEjkTXhs7gxFk2GNcpOFnDUAnwKovLlis22KnMgUqi1nJumjmOSkyR7DjGSqxPu9rQdd3PuFjL+LQrAN6Dq8QO/jUYADCZSgQLbb2dDcMkAIBrqQQAAK6lkg4Ds6gBAK6pEsyiBgCYokowixoA4PoquXAWNXwUHoCrglnURs+iBpUAMB6YRW3U1EdQCQBjBCSYRe2iWdSgEgDGAbOoOWZRW1x+k0mn2PRpMa6SDUwnD8CleHkWtZ9mFxy4wHU5jodnUYNKAJhiWOLdWdSgEgCmiHdnUaMuuWlNWGKbZGBxOb5A6V6c8r6Vpfsrq+X24Hy5K4BKgEtV4tVZ1KhLmpNEn1dJSHxVVpwNu7b5V+BAJQB8Fy/PomaqxJr66IJ/wmm32y7bcqgEuA2Pz6LGVbKTu2AWNfcClQDgNpUMz6ImvorP9ZEYVAKA21TC77FZ1PQZmkUNKgHAlSphNgm1Z2fLoRIA3KaSR31+piUzAm23DwDwQ7hAJT/3eQSVAACgEgCAe1TSLRzXUyfd5BFUAsDY9DtO/UmXrl5Zy18fzdFOXjEqKRx3Uyc+qASACeiunIg75RP68bRKuivHrEF2oRIAxgtIBj3rq9F9b3R3Da6Suj8U8vv5Jy2OvKQSikqG4jSoBIArIkKP+hN295WvfrdNEmnTI8NcZXgtKqm/P+4mj1b8LnYoVAJcSP2Zmdr4uoVX3eQJHyvp+uqpr8bro+7K1y+eUYkuohJSiS+pH/vq+jFUAsAYOc4J8wkLQp496z7z7LDro0cPIvwMTjd1LMZK3JvlQCXAnWGJ0S2wcdeSwQMUrpKy3G63FxYW+BiKN1RCGc4gKiGLdKESAMZzSTsrzuDUn9T9/hAbK+H66BY8FJX8IlRijZV8opgMCQ4A46kkYo4wdp91fYMEh0KVQa7joaiEEhxf8nnE716TQCXAjcQj5Is4O2fT7Q4SHEpxWFeqh448oZJfuEras7IvUAlwHUm/6YrXlNTwD7sKlcQj5vKyPCeRySVRySMzKoFKAAATqOSRDagEADChStgk0G1d1/lc0FAJAGBClQwtgUoAABOppNOpdCqMTqe/ws9hZ8UxISMAY9MO8f/e84uLf3A71xMybprkNiuY2xUAcE2V5DahEgDA5CrB148DMC0G362dYF/3meh/Hd9G/P/snflz00gahjeuLWt2sI7Yju04sVRhcEK0AwEDxU5qqqhds4U8yRwZNpWaKo6dAvaCZf//37a/ow/ZDpYVJ/GY7wVip9Vut4T61det7kdiJWIlIlFh1W8yAenbhvorViJWIhLNHZBUjTrN9sNm/XETrSSy6eHqWonnfc9DJUr3CoRtIpHoPFHogV2b+FBbSOD9o0mb4HWFreQb9hFtJesbL7bQPdu7+AIPEQ7AStq7XSdt56TTpG1yAolEpPYBd21U0+iu/7HBYyXt3U4zDutbr366seJWcgvN5NGjez2wkpfbLS/abq0fN+GlvhVQVBLtNDKTFqpsnSZ0CyVeEYlM9K7cw1NdGxWEnB2Ar+TGSrLkDyseldziqOT7b54m4BoP0DqyLK5Wt1tRp4lWcqoMxvOcNPUj4vhNJBJRWPKwSeOu/356APPR0Ep8dwxlla2EnUQFJY/u6WER9aO9G3jtPWMlO3fBb500sJJOU04ekchRVN2hOzi/HESufdT/86+V3m+OSshJwEowKlFGGlPoEVNnpv43ZS23dkPPSVvfUB0c9ep925LzRyQyVsJ3aWjYRHdwVKgSHSYrbiX30EjYSqgvA50YvLV1tteCkdbtFoQq9a2Pd2waDrvyKKxIJPKwK9OFH8G4lfgfW0kSrXJboQ4OxSQ2KjE7nI3nT2zamvRuRCJX6uLLTSeGeSXWSnydjk6z2lEJBiXuWMmMY/Zzy6M7OyKRSMRRyT1Ha8Vmo0HHRpxEJBI5VkJdmbUsy3pfrskhEYlEF7ASz/MqcjhEIlF5Kxkq7YOGR3JARCJRaStJSMOReIlIJCprJWvDpIcapqOhHBGRSFQyKtn32Er6/X5uY/tuQ46QSHTJojU7fuj+9hu1kgpZSdrzFmYl8WpjXkRL3DBpvpOZ9hRV9aIYbK1AyvBnL6srVwqyj0KbBSEc/KIbA+CQglwDwfdnu1QcZJ1/jSxXD9gfDfe37ZbZH3eLm+Tk0ludKWPwtlhjdqKStNdL+sUqXowr0N6TxTmiK9b6xvZ3gXmhlgtYDG0CuGrMV5v87iWUAogBuADrLDhTPgpwydrP3BraB4gzsQ2kvXcSAOIEU2NqsogpmMM+qXrrGwEiQPg39Y26fvktbpKTy5Si9xrrExRszGglPFaSppWFWokvQYnoGuQH7ovbZ/BDut7Cprh7CaUgrUSlcxa0k7wxwNzOapWmz3MDURbyrOF3mtCo404THKXMmhRVPWjv3Da5srqgyS1ukvN13NnSe91++Doo2JitlaSbaWqjEqSSwJcxLq1+8wRjLly+BzFY5+leq6IyAHINVghzRGYIbFw/LEfObtG1WomJJ55vBLxp5tWwVCnGSiiLbqLaUtg54Oqfb8B/rR5GuuOhMvtlFuqo6tF6n8CprK7+5BY3aWInIQGiK7V//KHZ3qasJFFWktIfYyUUzqifBpe2dbimymaImvqG2i+wPlhZycvtO56FqeGvWB38Xfo4ouu3kvauWUxHLaLAWEm5UkwHhzaYBhjZC6qKPaIgH9qr6+0DKJ/NJC41xgjVi407YGXVdd98RX6Lm+TkMlu1lfhBxQ8KdkMwKsGQRPVvNo2V1LdgtxzGkTKLijpODFZD0KuOSkIN1DbfaV2EyhGJrtFKYnMO+qGPjRs2RTOi5VKlwLAr5OMszrU85iXBxFODT5nLrMqKqZ23W10LXJtzhRtWzwQaprI+9hh2Gvkt+STMld9J3muoP/lPgZAArKSfpDBQojo4vb5zUHYaeSsBy2WIGluJZ6zEHDJrJVwbKEfObtH1WYnTW/BDxHrhpln3XEuVgh0cm8XdasZN9KirP8UsKn71Hbfi+ayEqgftEBqfrayuweQWk+SOAnVzO8/P4tB+UmisJEUjASsBzJOKbNp/yoDIuGdxaWQlDFFDK7nbqPBbj2Fq0ANiAhvXjsqRs1t0PVYCp7JzQcUbK925o5LipVgroSwUKwRALtHNNQ5pqMSxGUiAT9xXZVVul7ESrh60NdVE9Z0h9a0xX+TzW3JJNpfdqjs4BW3XjUrQSJQwKlFlZD4MMrctLo2tRIPVgOwS41tyCoKpoZWcOuFbRuWIRNdmJZEzKcLHyx71J2bdDShVimMlmAW7/l2aORJObf06Umk/fHu/xQMn83dwdPUQeGh+c+955Lc4SU4uu3XMSgoNedJYCfnIZto75tXBWebw0/K4NBesNgFZGx+fyZUjEonO8wHtH3GpDs4SiKKS3u97vS/gjvDEvJJ5cWnSnRGJPkuhlbCO+8fHtYle2Hy4NLESkeiztRJUJalUahWhH4lEogtZiUgkEl3ESpKR0aAmB0QkEpWMSkYpreZLKqNRmsghEYlEpaxkkLF/JKN0kMohEYlE5aKSnp78MRiMBtdQh/p9WfMn+kxkbnHSnNdodR4mhVFJlvWOXnz1g+cdHaGV+FXLfyos33IYzs0xfTWmWInoUi9VZl7UHBS1cqVEtFiuq1eewYzXsfkRehK6shI/ACtZyPNyL0BRc3eN3uU/F1Dx2wXQR6N0dJw8eRE+qR0fJaOEjxXzn87z1GkpMy0hEisRXX0YYJlghSlqpUuBNbYx2Me7ACZWwAIT00J4dRzq1XuY2xp3oyBexMKSC1DUPEtK0+w453O0rZDbQVTy4ThJDt68Oat5p+nAPVafCM/ESkS/GfnWBIpT1MqVotoNIoNePoFlK+v/PMlHJTFBwQIvy4istsAOTmmKmiGlOTtpPgfb9Mqi2VayqaKSH87efKWiEk9biWn10M/Bhb5AUUN8GiPT3BRrCWB16sO/apga49VoyRAVCuuG/W795v7fq2GEJYmViK7GSuagqJUsJdp5/3VFpT/wv4aG8KzzFzcPLMP1CDLg7+ydlCKTnHuhLklRM6Q0Nz8gkQxFTflJgVqClQAfulbrJdC3GbcS9F+IjJiipg4LI9OcFDe6QFpKqGFqnJdXFnKhfgAAFNWLjGj1sViJ6IqsZA6KWslSaogRUlZCsMFn+agEr+8Yj9RP73/336a3uMCkNEVNk9LsTtLnLEUtolX/Baykl6ZJklQSWOg7biURHZjQQAZCjUxzUlwrUcnqVROQdF6CqXGh+Btg2aAIyi+nu+hKOjjFKWolS4levUdUfajic3W+R2PDrspGGMT84nEzWmBUUpqiFuXIRiYqMUBJnweGZ9KPKCqB5wXDQ4OzzIyVOPQlcAzXStgQpluJFwfxoYGpmX4SDmmPWYknViK6YispTlErVwoMWFDHQJ3tr7EV5jtBEd01WT9++1hzXxdhJaUpas8NKS23k/g5TVF7+rCwlaTpjV4vQw0yshLNf6IOjoM+CjUy7Twraf/vHRzKQxwU0Xg1gqkBswmjpphgsWIloiu2kuIUtVKlqPM+ozs4kOdja5qVYKcjy+qLtJILUNRyu0agI/qcQR/V/rwRFOrgJPvpjX1Wlu3zsfI0/8kMu6Jx4N0tQqa5Ka6VYGxkYWqQV8PUyErgiR8bhxKViK7DSgpT1EqV4tOzFrpoHzGd8nht5zaCM7Z87NLUH/+6sbAOzkUoahNWwp9zgYxbBZ60qaKSPkQlKBWV9I2VXOg/bnxkm+bTujeDBWcg+sykPEWPeMJ90MfNZHEdnCXQ77ysn3648YGQjB/o6RX+RXisGENNvdXmVxcxr08kEi2llXjHOZUogx6YbJ43FHoCUxOJPkMrSSq1NaXMS6TbIRKJSluJSCQSLcJKhkOaVbI/PJIDIhKJSltJ4iWg4Ui8RCQSlbWStWHSS4DIOExHQzkiIpGoZFSy7w0Gw8EgHfb7fTkiItGFlLt7GQeT6SvHT3OsJAFQdKr+eH1nn30GKlW7NBkfVjqaVXk0/43T5fQRLY+YCTaOBsNTel6KmuWJwbOzG8VKcdflOFZySfw00lSK2jRkmvOoTUqKnQmwE5limvLuFlQkKlF/e+NWwiw1TlnfOIWdR0RACLAla8DT3olE1xATEAnMUM8uQlGzPDH4mG7555fictI6t+37N5fHT7OBzgRFbQoyzT0YlqJml/CMZ6IZ9W5BBaIS+JuORyWapWas5DmRjZqEgPLESkTLJ15RMrlyvhRFLTLL7TVM7JOlGE5a7YtaRQUvugVeJj/NBD2TrLQJZJo9GE5mXikzmckuoZm9kJqs5LyoJHLWFdILgFM4Ksl1/wCmdnv7jue/2qrK/HjRklpJCYoao8d4kf7MUhxOWkVFNSdnPybj6Qvnp7HnTaOojSPTnINhkwycKJcJuWZm/KJQVJJQVLIJBKRzraRKQyYhkAMgNarSGkgNmVebal8gR0WiEtHSWsm8FDXDIcNLKL//ZCmWk4YX9Tjg6OMS+WmeqeEEK20CmeYcDJNkWmw8biWYiLtoCpoRlfQ4KBl+OTMqgRXUjGhlb7HdmgoyjcRKRMvbwZmfokafgJHHzutGgVIMJw0yJHGgv/3S+GlsA9MoahPINM9AA5wkAzGZErpwzyaePepKUQncvUGNd3D0MXGsRPnTqYahhWMjJGIloiW3kvkpajaf5urMKIU5aURMj+3Q7CXx03jPplHUJpBpubESkzSZMm4lhR70AVFJv4IxifrX6yc5K9EsNddKiH50gN/B6ZoWjXg0sRLR0lgJBemlKWrjPLFKkVKYk6ayUeyx0+B2fin8NK7oVIraVGSaH4wlWTfMZ4JW/VMGUZlb0CetpKKiknQzxX99MzLSafr8WC49r2SHnWP9/+2dzW8TRxiHxQp5L9ihQQHixFm1aqiwRH3hUCGEWsHBh0iIhgpVFCHl1kP+/2vnne/ZXW/G2UG1w/Pw5ezH2Lt4f3lnsvP4SD42aOLvK/lR2yxVwHyVHJlHWjWAXYuS7Sxq3icm7/SsViJPmm5g1l1e1J/m46trUetXpoWCwy6KgiLZyB61HhiNGhquShozVqKqkotRB1RhKYDvmdSTFqJkX/1p62021lGykDk4zeL+YsGN8wBwG3SUWC7OLy6oKgDgllFiOidNVVcVSQIAo6IEAGBclLxVYFEDgLFRUjVY1ABgdJRgUQOAIlGicRY1PngT4BsRbgbXd5U8nN+ZI9PT+SoTJc6iRpTAHlPGotZuxQnGhlvRt3/LXeBeN1hHE/VNQ+4+9deP1O9SUZJpUTtL7ls1BxdMcW5JtF9nwQ1R0tgkWTRECez7d/0SFrWeVrxybKgVUQnoG86dbtDMzjezbhLHmtjD1OJCUZJrUZOH7kZ5d4zeFOeWhP06C26OkubN5zefLz8vK6IE9p4yFrW0lUg5NtSKtpJMZ0E32Jrc6l1q6uGruqxqINOiFpnR/IkJklm3xNdOnQU3VSWSJL9fLkNVIlo0ySGpiz5YLfSpnX34j1ZEH/70QZ8FtwXAzkfJFha1tJXITzbUio8Spxt0EiRLcKkdnsxl44JjJZkWtdhNPZ3VG06V2i+dCpltUXtzfT27jKJEx67USKKD/iICRj+h+ocvpy/Mqlf31LO5LXgHw+5HyRYWtbSVszhKNrfiOzhON2j6OH4wIrjUzj6tJFfKRUmmRS0JP7vppFOnyH5JlGRb1BbXV1fX798fL1yU2AGjg4e2y+e+ru3f6i+peNSZcVvwDoY96ODkW9QGqpLNrchwiNV/Gd2guTLCkIF3qf37blXVBaMk16KmR0rcGLKvSlodnEia1lkwGCXnzeJK8XS1bEVJCAr3NVECex0l+Ra1VpTEmujNrVgpfdANmvXR6KNzrNV/rx76IdgCx5xrUZvOuscYHYXRMc5bm2Rb1FQHR6Lk6uWxsaj5Do79vJsj18HRPil9GlX1ZqPEbcE7GHYvSkZY1NJWgmBssJU4SoyzxBQGcZQ48fSqLleVZFvU0ujTB7dyKui6Tlyv4dxlW9RUVaI/BEfoDLvKh5JFw67mB136oY0SvwXAHkRJtkWt1Uo04DHQShIl5jus2jESsAWXWtEoybaopamgj/EsPgrzOXp6v3Du8i1qz22OLJe9FrV7afelZ+j7Hh0cgJtIXWpFo2QXMBa1ZmGn4bQtanL/SvQpoz1R0rMFAHx3xBY10ag9aHfCnrVvoWlXJd0tAOC7jBKhqprmgYIzAgAjoqRGFg8A46IEixoAlIiSBosaAIyNkuptZX5+g0UNAEZUJc9bFrUhhm435tOCAW7FXXCrRRa15cJa1Kb65rb5YJQcnnRvfyNKYGcI4q9IAbaFRc29390tU3mtBH2auVBkErC5VLxfbeLtHfElNtat1mtRS/1oG8RqdVc41+tVy1Mf1U7I2NiqZLP8yBlVZObNn4+HooRggf+PIP6KFWDZFjX/HnYWtcxWgj7NR4m9VCL9gLn0D2wFUsSt1mtRi/xodbomXlTLzbeJcC7ez6zLups9ETJai1pGlLSMLkQJ7GCc+M64e7SNRc0SzaTNaCXo03yU2EslSJHct+JAGbdar0XNhUB3TVj05OXXrvrI7Sfr7Myi7ChZHi+XaVXipvD9Yv7IlzPtTpv7UxHJ1ib6NEnhZzY8MdWfla25RvTcISdiM1v6fwCK9nF8Te7riS0sat0oyWgl6NOSqqQTJem3+TJutV6Lmo+Gzhq/SL2kro9B/SvT+cw6lScZF6ixqElFIr+SKHHmNJsCrhul3WkqOk+jTcw6USWpzpeeMnx04PNX72AbMRMTvYjNbMkUHvgGBPGXf7SNRa0TJTmtBH1aGCsxl4rv4OhhyNYM2RJutR6LWuRH6/jVwqLprGpFidlPLnOzTnpjZp7wjVWJlCQyO/g4iRJnTrMpYH1QVi0gnah5ncjWpKMoJ80UaLOonFI7+DySgR5nT7JbMq8YyhPEX+HRNha1dpRktRL0aSFKzKUS+dU6VUkJt1qvRU370VKLWkesJi+lpyrRL9Cu0692OsuIknNdlUgHZ9GNEp8C7SiRTk4iW5Pha4kue5p6o8SMcfsoMVsSJVCcMB4ajc7ufSwAAAG4SURBVIxuY1FrX1tZrQR9mnn727e2ulQSk0nnyUe71XotatETddfYRZdHybMlXjU7Ivz03cvcKHneeF+JtqglHRxtTtPWNNXnO/zokmGlny2WrR1+VC/152d2dPv1Yz1y8usjt4Np5Mlva933sSI2s6XZm3c/FOzdeBNYLPvZxqIWRUl+K7E+7dTYN+ylkkaJLSJmIUrGudX6LWqRHy1dEy9Ke3GRV812aaazB38czTI7OOeNlCTH3qLWGnaVodJPUlSIh8lVJWcTP25qZWunOjwOT1RePNPr1Al956PENrKeTnSx95ffbXJQx4YqgCJDrt4EFivAtrGopVGS2UqsT5vaH8OYS8VHycR/cp6/r2S8W63Xopb40dI10aJulNj9fJT030W2YazEFiXHi4sN04PXt/jfrKqWtEA1sl6va35ODBClzx1xqxmL2n31a9FnUftWZ48oAbhb3GRRI0oAIDNKbG8EixoAjI2SGosaABSJEgAAogQAiBIAIEoAgCjhFAAAUQIARAkAECUAAEQJABAlAECUAABRAgBAlAAAUQIARAkAECUAAEQJABAlAECUAABRAgCQyX9Y1WCyxrc+2gAAAABJRU5ErkJggg=="},2754:(t,e,l)=>{l.d(e,{Z:()=>A});const A="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA5YAAAB5CAMAAAB1L06GAAABCFBMVEX////7ODj7/f8AAAD5/f/9/f/9///1+//3+//z+f/7///1+f/z+f3/t2Zmt/+Q2//a/////9v/547//7f/6Zj/65692PIcHByQOQAaGhoAOZHrx0f/25EAZre2ZQD/55Lwzkk7kdv/5oq3///UjTjbkTplAADow0QAAGb/5YVmADr1s2Ww/P3/6ZU2jduROjoAZLZis/86Zrf2+7c5AFH1/NtkAGaKOmW0ZTkAADnh7/86AAA6OpEAAEDT6P5kOYn204+INxzw0WehkXhJZmb/29sARWZ2S3ZxkMJbRzDV25G2Zmb9+/Nmt7c2AAA2jbc2ZLfDw8NxZgA2OI+1/relYACR27c6kZECT7c9AAAMPUlEQVR42u2dC0Pa2BaFcwVJIDxFRwYhigaEYimO2qoz03rbTtuZ8fbt3P//T+7e5xECEp65NJD1oRADHCHJyton5CyM/Z9/eplNA7CehLPxRqkVxmBZYuWCNSX7ctNaGcjSTOOyWZcYuWUoC+aHtDLhYux/gVuCtcV8uWmteG55i7W7cbVdXEjfhrFcfkgrkCXYWG43rhWvb2nZF08Kes7dx/aZc471vd61XWz60LduQtNP332mORctufVePSuoq2nLZVIrArq3Wpyhle5NIX1dSLOauqKxard/9eJsQbfMXrTkS+qZbqJ9lr67PDMBWAOyt27P+4MUMNiS0+lutWg+kLiWaUXKtW+y6qa3knWrxevCResT9TIvnp9167dClvO/LSFLN0Ev3rbvvtEegVq5+rd8TTYAEcckQdGm2+3zH3cF9937P8ke7W7P8ewvUU0v3IrtnnuPmeG1sNFdF25turGFLE3llvO+LZalkDi9KPLpqwq/jzbbrnOOlQ6iDpWfbB8sKKo7acu9+/wgpKhqTjttLtWKr7id3srDYFfwqSJv37Is539bsojlSvqhL94Hifzig+X22Dqx1kHUIUFpYzxPP/TSD+e28CdRh94U3N7Fqxk25KBW0u485nRrX7R6DyxgPkbzrdjtW9ItF5Ol6NSeW0Lx3cTvBct2uTaHLEHUSd663AET5Sd3Ju8+nrui3iN74YJSyHLxVuaRpZmuyGfw0Z6+ReIW7S3ulkm9p+jZV+/ff3/V7bufKudQ5fpimTG52Fn3PMvl592HtE2b8c2feapH9VEb6ZYvTXPKcglshfqW7uMadnwrpn2btdP2dSFrq4KYfullVH3/fx5ZOon9nm1altXtJd1PL3hHQ+/mScECIOKksw/nvOXWpa+ZSXfglrZ2S3PeVsymdktugR9B9ehUzMqgbymeZLlcgprJ+d8WyzJrNmUr3Z719/cXZ2SULjlwNYu1DqIOyU+qhrzN6ib6JMtRtyymzYVbYYeaWZZZUkx3v30i/vIOBVen7xYCZOl6RSx/QJLNkiwtiBJEn6zUC1/bV5U+G9Sgb5mlgjI9i1uOtmLqVty+rYvYGV5LlhRdLZZbbdK4aUq35PmLuqXbS0q3TPLuIkt9VmoviQsuEb9Y1nWhO2RL7HOW9Lkuf9LxMdEns1y0FfLO2d3SqvCTTTNJTv2u5fvc1EouIst0UrG1RVekR7pKgrVmKx6XLTNretuqZXnb8ZbYhKVlmVOXS1Ar1v394HnTF7nJtqj+yBBLrD7hlr6/rS26YKtee1VaW/Jn06es7Jh3T+rgu2dfLmNbYS0ESGFrHMmkHdr6Y1maWwCsKeM23sx2GK1MxRr59bWSYbtc4l2xLJPbAKwpyai2srVMS5AlgCwj1YqWZbCuU7is58XYNuSPvh2e3JR585hS4HJJLWtt4RjkI1nSiwNgPdneuFYEJEusWwCiBWQJQFRleaQ5OHqNhQJANGS5J9glDrBQAIiQLEmUT59ClgBESJZClYcBsiw/P5ETpUpeDFq5KRhGTp2N659un2CpgnhDGlFTuQZf1fUdzfzcsuQK9vDwsSyb9SFZNukfOXmj/Kro/b/Ss8KQfJ0G1gyIM+UnShHXBfpZVpakyp1RWdZ+K/pkmap9KFUaJEsnbwzLsvar55Z+mQIQL6P0DekqknjIv4RMcoP5+dllqbxy55EsnfxQEUsFbJ3skP476c9fxPqL3cHuAYC4IS1RlK9UaSqNNIw/ivKuP4ozu+WB9sqd4xFZaucrt6T+U+yeTrUoqlifWzojOwmsHRBTar+o8pVEU2dtSJnUfq0Wm/ly691PM8vySIiSVXl8ej9cJSuX9N+Wnu3nRR9ztG+Zaww/CYAY1rGiT8fO1Hz7mTU63LfcTqVmdkthljs7O53XB6/HdS09pZEn3/zz/K9vVy9Oho/ENrmorUoHRecSxNkuqUcpjvm8+UsYp5DlUDk5s1sqrzw+7ZxOdEuDD/t8KzqJnjHiluXnX98mGlzfwi1BrMnpoy21X3J+KZbff0jO1IB2S6FKkmXn9JhlWbss0I+QozrU6yktl2h/bWRyidEjsVQ7N3L/bYnubu0SsgRxlqU62lobuKXUUrc/pyyFV5IsO6fbLDEty0dHYqtFKlWd9vdWfaiILVW4iG2UKrxbwJFYEF+cRJ2vGqOydNpnLJn8PLIUXnnc6QyK2Pt7XSj7ymLRcfyn0qBuq1MfOhKb5+o5z4quo2sJ4kqponXX5I8k/H3LvE+1M8pSibKj3NJPc7SVVGrKsSSc5QPAMmhZEqcKnKsOQCRkKRMPdJIIACASstRAlABERJaDcIIDpBMAEBFZqnSCPaQTABAtWfIoEqQTABAlWcqxXZAlAMsRZjrBXkA6gWpwMICz3PIPsAQAjBBeOsFuQDqBT/zyVNdSpWHkkNgDwFijDDWdYE+PuJwgS8c7D33g0gCA4cIyrHSC7aPdXTXiUqQTpMpP3nBLIpOgwVfiBHQ5Tkye4Yfz6wAYS3jpBAd7yit3OiKdoNzqZ2qXBS6RyRilN2qHbEKWAEyoY0NLJzg63H3qTycgPaaodWnADSlIPYgSbgnARLsMK53gYCSdQNgkyVI2IGWplcgz0bcEIJDQ0gmeqnSCY5lOoGRZ5rCBv0+ECKX+qbLlv3LTBQ9AfGUZbjqBHm+pZCkymfNqRKeoYTmzgGbi8xEAAvj/phMYY3um9/dY7gAEEW46wWFwOgEAYLUgnQCAqMpSDH/eRjwBAJGSpQaaBCAiskQ6AQDRkyXSCQCIpiyRTgBA1GSJdAIAwmB16QQGDytpyJQCfMMIAJNYZTpBk88nwtARACYZ5YrTCWq/PfRS+gu8AADjWWk6QalyTk7JOwOcpw5AMCtNJ3AaKfoRewOM6gIguI5dYTpBrlpMqX6l158FAIyxy5WlE6ierBxjDVkCMIEVphMY4ihs6aX4nnYseQAmyHJl6QRKlpVZPBiA+PIj0gkAAMEgnQCADcVLJzhFOgEA0ZKlZBvpBABETZZCmlgmAERAlv+KLFg/ALKELAGIhCy/QJYARNMtvXSCp9FJJ4AswZqyfDrBF0+Wu9PSCeak3PKGgIlcA8gSxIUw0gmkLKenE8y5x3hxYjh1+fT2V8gSxMQow0onELIUBezEdIIF0N+3l3J6kCWICSGlE7AsZb9yUjqBmBQzqDQtVf7T0rPU+ew8y3/L6OCflAO3BHEhpHQC2v4PtFceHwekE8juobjOtU+oLj0x9L3vi94s3y2r1TNZyBLEp44NIZ3gi3bLw6npBLoq1TEi6l4RUtmWgzL1Xars9UZmQpYgRnYZSjqBcMsp6QRDsnxWkLKU99Z+bRi1y7Gy9A5IQZYgRoSSTsCy1OkEnaB0Ap4sf5BFLMfg5Q1D3cvqbLJb0j7Bd8vu3eTvdi9AliBusgwhnYBlqbzyODidgCa5P6kP+YjkWHWsJ5F4y275Vt0lb2VpS4+BLEGsCCmdQMhyuXSCTMr7FGXhT1MgS7ABx3tCSydgWe4snU4AWQIQElqWxJLpBJAlAOHKUg5/jlY4AWQJYi9LTXTSCSBLEHNZHikOjsTZBJAlABGQ5Z78lva93V2MtwQgSrIU56tDlgBESJZyxOUissyNOcsvt+x3IkCWYE1ZPp1gWJaH4coyl9AnB5ZbegqyBBvPitMJAj6UDJBl+ZUY8iWe11BTkCXYbKMMNZ1gb1d9H3SIshzsN2qXJ3OfZwBZgrUk5HSC3YnpBHzm+XcxJc5QH3oID1sZZBTI2AI1qkx6pDwrsAFZgs0nxHSCPeWVO52AdAL2O+mWKo1AP4RHdznVoj+jQM8Tr0XsOpqQJYhNHRtCOoFyy0OZ5BOcTlBu/V7QRawYsqUfwuoTV4OMAt88dZwHbgliZJerSyfg6xuRSqDSCPwPyXFlO8go8GTp1H0dTfQtQUwIPZ3gOCid4M4rZ1Uage8hpUq16GUUqNgCnicLX1JrYRA7AlmCGMgy3HSCTnA6AZlwX0xdyTQCVcSKzybfcIyIyijIy5fF8+SeIs8BBTLbALIEm89K0wn0gK9MJmOkMtRtHdydycjpVOrxvMWBLMEaHu8JNZ3gcPZ0gtSK3iBkCeKKl05wumw6AWQJQFiy3PcNg96OVDwBZAliLkt87SwAkCVkCQBkCcB6yRIAEC1Z/gxZAgBZAgAm8j9E/WR5XCIZRQAAAABJRU5ErkJggg=="},8485:(t,e,l)=>{l.d(e,{Z:()=>A});const A="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsEAAABtCAMAAAB3Lkz6AAAA/1BMVEX1+//9/f/9///7/f/z+f/5/f/7ODj////3+//F3/n1+f/7//+91/EcHBzz+f0AAAD//7e3//+R2////9vH4fllt///t2ZmAGbb//8aGhpmAAD/25H/6ps4kNr/540AOpH8+/qQOgDuy0lmADrCwsQAAGb3+PgFZrf/+//39fi3ZgCGiomROjo6AGbX29//6JSdnp6nqamcma6PmJXq8PY5BQDbkTp6eXs6ADqw/Po5PZMAADqyu7mNPmVubXNUldDzs2XVjTijzubRjDjW6v4eMIhAbnSuYw6PkNup768vmm5kOYaK1/+RkWZEqcEVOTm1ZWXb25FmZgD22nvb/9vVlFBcAAAHdUlEQVR42u2dC1vaSBiFuYRNpEgCNIiwkYAhTMBGWEBLxUulrdXaq/v/f8t+kwsNqLVbARk5L14giT46vj3PmZChsU0i83JjYyOzsfK8nCcb4FkQ8wzGOKwUmbmyTgZn1ukvi38oMBgGg1Ux+F1WAkBIAoMxEEB0g2O4PavbWhm8jQwGaBFgtciuCzAYPIcW0Zckbfc63FYZNIYXOsZG7D/sutzCDNbKqocRG6uNoVR5NYwBIAKewf2xyjM3XXnzLiYVjoeFmq+zlAZgtfFbxLhaurhOS2fVkuTLSzEsZS90jA8QwWBvJqeV9Ytmlj83p20NtY/S2OCBHMMIAREMppmcREXCf275TD2iSd3YyGZjMBiIYbAkXajBTE4qnGxdfjprjo2ans1igERFia3LzevBF+pXf9Z2ZmTHX46H2qvh2NB2rxUAVpygRaTeGmn+8MxIf7s8HtZ0ahH9s2oWAwQEMHg7IylvwxaRVvrHw2w2OzYUxcb4ADEymAw2lCCDk4XjIc3mVJ1COZXCCAEhMjhFshLJZCqpKGmF7ij+FgBWGz+D03RPSXofFJNvVky6h9ERmeSa4GdwLLLlRRI8D0x6V57lB4V+N4V+QSUweDOTigMgJn4Gw2AgssGbmSQGAgidwXEZADHxMxjjAEQ2eBsGg2eQwfWf3JgYGCBcBtf/Dtjfr2NcgIAZrIUC79cxswPiZvD+/s49Gaxt5fw7hZre4heyHeVluRhc1Ba938hhYMHyMzhM4Dsy+KA5ZfCBIcstXdY+lcjapi/1Xn7K9JaBsQVPkMH7PIJvZXDlTSlqcOW0UDPIYHqbNrgymGRw1GgAlpbBPIHJ4OT0QZ6qPw2mBtGkkC3UuKrRFhFtG4HZACwzgz1/dyozLSLMU/91faolL5Nb9JnXiEgGt9QJ1VKQ2wAsMYP9BKYMdu6cwUU/F/Y2da8PF5uJqR5cNGamfQAsKYP3JwLXb+6qwRMpqTgcXW59f/PvcW76XMQBbxVVP5dRhMHSM9j3lwy+qZu/ymBZjicr70st1ZiZydERP05UgxcMZDBYfgbv+AZXyGAqwpXXeXrzzN3NTxtcVBs/jERRnT0XIVcGRvGq7M37Kq9gMFhuBgcRfMMzOBk1+Na5iGqJukKrcVluTrWIQq2RY0WjUKuWcC4CLDuD4/WdgJv67MkIKsKR8wxNOVHYO6/xCtFqTp2L0PnpCJ1RFDdRg8HSDP5LYPAHhMEwGMBgGAye2GD/PgtucfnBqysTicTT/+wwGEQN7na6HU6v2xdkiQYMBlGDO7IZj8dN1nE7fRgMBMxg0zRtunX7VgcGAwEz2EyRwLbTbfd6D31V+CzdXRRq+j17itWStpWb39PNMBjMtAjbalum45ht/rgVPH3xK4P59ZY6DAarYXDS7riu23NMM8jg+10LDNbKulw4zv3K4OgjGAwWa7DlZruOa9l+Bv+GwXdexQ6DwZMYHO+YPbeb6rptm00ZzJtCI+dda8bf+UND2/3MC4ZW1idlgq9P9vZxZyuDZnBg2VvUEazvgMFgoTM5y+UnInojJ2qwVuYLMRq5wGDvIW1s8mvX+GWWkUP8fWRw8SjvxTTdDTLYc70Fg8ECDe7FTerB1vm7cytqMF9zwVUMDC76icr19K4+O6AoDg/x9xVqJ43J2g0jMNjbhRYBFmows22r3SudS93bBu/l7zGYp2t4SGjw19fXwddNejAMBos32LRtW7LO++fu7RZRLfHScMCbgi5rHwODK01P5vAQfx/P64Hu94ZvOa8Vv857Zy1qMBgsOINtuz8aZfptdnsmR31B/cBzeECPwgymbfx8cHiIt4+cjWtlKs4Db9+BWv3uNWb16DMMBoszmPVMx3aIvhPO5G5h/s4rAibkZV22BoPBdIswFdtUTOJQjJ8dBoOowe1eO+CwDYOBeAbLXvllcaoKCRgMhDHYOBVWBBgMyOAPQQZbPzFhMBDH4B+hwSzcZI0cGAzEy2AWKmwxQRSGwYAMPvV7MCODA4WpR4we+Ko/W6Mx9R3m8LwGDAaRcxEjMpi5vVNLZq7LK8X812jAYLDIDDbdQ/nq8vqKHbrMesCyP1ujAYPBIjO4f8JY88uXDy/kQ2fEfsvg/7lGAwaDxRlMszf3kFlXVx8TlMGjiGVzWaPBX9291dR2ewNVL9J2GAzm3CLkkeM4LJ21bdMrxROD57NGQ24Z3uWX1VKRzOffBwaD+WZwlww2TZaU+YwuksHzWaNBlgdWB+8wGMy7BzvOPwGMddmMwY9dowGDwTIymKewyTO4K8+0iMeu0aAWcUAHwGCwsAzuUAZ3wgzu3J7JPW6NRqtaKtRoJpdPwGCwmAzuOSEUw/e8cNpj12jM+apNGAwiGdx2Igq3mQg/OwwGkQw+nEKGwUCwDGY0hTOZbFJXYDKDwUA0gwUEBgMYDGAwDAYwGAYDGAxgMAwGMBgGAxgMgwEMButlMP5vewCDYTCAwTAY/IHBm9sZjAMQ2eBNGAyQwQAggwFABgNkMADIYACQwQAggwEyGABkMADIYACQwQAZDMCK8R8aNMOTg6vtRgAAAABJRU5ErkJggg=="},2313:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-2-a43c6e900d91b577547b8fd8c6e9c610.png"},6365:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-3-9733695ccab25c40b67c0aee41a950b2.png"},164:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-4-e7a71340ebdf1e1e203cdccf0c48c466.png"},7375:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-5-7a6e55e24a82130b5a31a1079ad955ae.png"},8659:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-6-5ab3345890708d617b5bf98d105c52ae.png"},8614:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-7-57368c4a979c819f89d3d89d066a8a9a.png"},5397:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-8-c7cdec8201782abee3e623b2ca9f0f15.png"},6094:(t,e,l)=>{l.d(e,{Z:()=>A});const A=l.p+"assets/images/startguide-9-c2c31ae92c23dc68759264df69273c84.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/8c4cc064.297bda93.js b/handbook/build/assets/js/8c4cc064.297bda93.js new file mode 100644 index 000000000..ec611ba15 --- /dev/null +++ b/handbook/build/assets/js/8c4cc064.297bda93.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[3214],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(n),m=o,k=u["".concat(l,".").concat(m)]||u[m]||d[m]||a;return n?r.createElement(k,i(i({ref:t},s),{},{components:n})):r.createElement(k,i({ref:t},s))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=u;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>p});var r=n(7462),o=(n(7294),n(3905));const a={id:"resetid",title:"\u670d\u52a1\u5668\u91cd\u7f6eID"},i=void 0,c={unversionedId:"resetid",id:"resetid",title:"\u670d\u52a1\u5668\u91cd\u7f6eID",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/resetid.mdx",sourceDirName:".",slug:"/resetid",permalink:"/touchsocket/docs/resetid",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/resetid.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675609832,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"resetid",title:"\u670d\u52a1\u5668\u91cd\u7f6eID"},sidebar:"docs",previous:{title:"Tcp\u7aef\u53e3\u8f6c\u53d1",permalink:"/touchsocket/docs/natservice"},next:{title:"\u65ad\u7ebf\u91cd\u8fde",permalink:"/touchsocket/docs/reconnection"}},l={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u914d\u7f6e\u521d\u59cbID\u7b56\u7565",id:"\u4e8c\u914d\u7f6e\u521d\u59cbid\u7b56\u7565",level:2},{value:"\u4e09\u3001\u521b\u5efa\u80fd\u4ee3\u8868\u8fde\u63a5\u7684ID",id:"\u4e09\u521b\u5efa\u80fd\u4ee3\u8868\u8fde\u63a5\u7684id",level:2},{value:"\u56db\u3001\u5373\u65f6\u4fee\u6539ID",id:"\u56db\u5373\u65f6\u4fee\u6539id",level:2},{value:"4.1 \u901a\u8fc7Service\u76f4\u63a5\u4fee\u6539",id:"41-\u901a\u8fc7service\u76f4\u63a5\u4fee\u6539",level:3},{value:"4.2 \u901a\u8fc7SocketClient\u4fee\u6539",id:"42-\u901a\u8fc7socketclient\u4fee\u6539",level:3}],s={toc:p};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("p",null,"\u6bcf\u4e2a\u5ba2\u6237\u7aef\u5728\u8fde\u63a5\u65f6\uff0c\u670d\u52a1\u5668\u90fd\u4f1a\u4e3a\u8fde\u63a5\u7684\u5ba2\u6237\u7aef",(0,o.kt)("strong",{parentName:"p"},"\u65b0\u5206\u914d"),"\u4e00\u4e2a\u552f\u4e00\u7684ID\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u5728\u670d\u52a1\u5668\u4e2dID\u4e0eSocketClient\u5b9e\u4f8b\u5c31\u662f\u4e00\u4e00\u5bf9\u5e94\u7684\u3002"),(0,o.kt)("h2",{id:"\u4e8c\u914d\u7f6e\u521d\u59cbid\u7b56\u7565"},"\u4e8c\u3001\u914d\u7f6e\u521d\u59cbID\u7b56\u7565"),(0,o.kt)("p",null,"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u670d\u52a1\u5668\u90fd\u4f1a\u6839\u636e",(0,o.kt)("strong",{parentName:"p"},"\u5386\u53f2\u8fde\u63a5\u6570\u91cf"),"\uff0c\u4e3a\u8fde\u63a5\u7684\u5ba2\u6237\u7aef\u65b0\u5206\u914dID\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u7b2c\u4e00\u4e2a\u8fde\u63a5\u7684\uff0c\u5176ID\u5c31\u662f1\uff0c\u4ee5\u6b64\u7c7b\u63a8\u3002"),(0,o.kt)("p",null,"\u5f53\u7136\u6211\u4eec\u53ef\u4ee5\u81ea\u7531\u7684\u5b9a\u4e49ID\u7b56\u7565\uff0c\u53ea\u9700\u8981\u5728Config\u914d\u7f6e\u4e2d\uff0c\u914d\u7f6e",(0,o.kt)("a",{parentName:"p",href:"/touchsocket/docs/createtcpservice#setgetdefaultnewid"},"SetGetDefaultNewID"),"\uff0c\u81ea\u5b9a\u4e49\u65b0ID\u6765\u6e90\u5373\u53ef\u3002\u8981\u6c42\u4e0d\u548c\u73b0\u8fde\u63a5\u7684\u5ba2\u6237\u7aefID\u91cd\u590d\u3002"),(0,o.kt)("p",null,"\u4e0b\u5217\u793a\u4f8b\uff0c\u5c31\u662f\u4f7f\u7528Guid\u4f5c\u4e3a\u521d\u59cbID\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},".SetGetDefaultNewID(()=> { return new Guid().ToString(); })\n")),(0,o.kt)("h2",{id:"\u4e09\u521b\u5efa\u80fd\u4ee3\u8868\u8fde\u63a5\u7684id"},"\u4e09\u3001\u521b\u5efa\u80fd\u4ee3\u8868\u8fde\u63a5\u7684ID"),(0,o.kt)("p",null,"\u4e0a\u8ff0\u8fd9\u79cdID\u89c4\u8303\uff0c\u662f\u4e0e\u8fde\u63a5\u4fe1\u606f\u6ca1\u6709\u4efb\u4f55\u5173\u8054\u7684\uff0c\u8fd9\u4e5f\u5c31\u610f\u5473\u7740\uff0c\u8fd9\u79cd\u65b9\u5f0f\u662f\u65e0\u6cd5\u5173\u8054SocketClient\u7684\u3002"),(0,o.kt)("p",null,"\u4f46\u5f80\u5f80\uff0c\u6709\u65f6\u5019\uff0c\u6211\u4eec\u5e0c\u671b\uff0cSocketClient\u7684ID\uff0c\u80fd\u4e00\u5b9a\u7a0b\u5ea6\u7684\u4ee3\u8868\u4e00\u4e9b\u4fe1\u606f\u3002\u4f8b\u5982\uff1a\u4ee5\u5ba2\u6237\u7aef\u7684IP\u548c\u7aef\u53e3\uff0c\u4f5c\u4e3a\u552f\u4e00ID\u3002"),(0,o.kt)("p",null,"\u90a3\u8fd9\u65f6\u5019\uff0c",(0,o.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u53ef\u4ee5\u8ba2\u9605",(0,o.kt)("strong",{parentName:"p"},"Connecting"),"\uff0c\u7136\u540e\uff0c\u4e3a\u65b0\u8fde\u63a5\u7684SocketClient\uff0c\u8bbe\u7f6e\u4e0e\u4e4b\u6709\u5173\u8054\u4fe1\u606f\u7684ID\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'m_service.Connecting = (client, e) => \n{\n e.ID = $"{client.IP}:{client.Port}";\n};//\u6709\u5ba2\u6237\u7aef\u6b63\u5728\u8fde\u63a5\n')),(0,o.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u884c\u4e3a\u901a\u8fc7\u63d2\u4ef6\u5b9e\u73b0\u53ef\u80fd\u66f4\u52a0\u4f18\u96c5\u3002")),(0,o.kt)("h2",{id:"\u56db\u5373\u65f6\u4fee\u6539id"},"\u56db\u3001\u5373\u65f6\u4fee\u6539ID"),(0,o.kt)("p",null,"\u4e0a\u8ff0\u4fee\u6539ID\u7684\u65b9\u5f0f\uff0c\u5e94\u8be5\u8fd8\u4e0d\u8db3\u4ee5\u5e94\u5bf9\u6240\u6709\u60c5\u51b5\u3002\u6709\u65f6\u5019\u6211\u4eec\u5e0c\u671b\uff0c\u5728\u8be5\u8fde\u63a5\u5b8c\u6210\uff0c\u4e14\u7ecf\u8fc7\u67d0\u79cd\u9a8c\u8bc1\u4e4b\u540e\u518d\u8bbe\u7f6e\u65b0\u7684ID\uff0c\u90a3\u4e48\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7",(0,o.kt)("strong",{parentName:"p"},"ResetID"),"\u7684\u65b9\u6cd5\uff0c\u6765\u5b9e\u73b0\u9700\u6c42\u3002"),(0,o.kt)("h3",{id:"41-\u901a\u8fc7service\u76f4\u63a5\u4fee\u6539"},"4.1 \u901a\u8fc7Service\u76f4\u63a5\u4fee\u6539"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'service.ResetID("oldId","newId");\n')),(0,o.kt)("h3",{id:"42-\u901a\u8fc7socketclient\u4fee\u6539"},"4.2 \u901a\u8fc7SocketClient\u4fee\u6539"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'socketClient.ResetID("newId");\n')),(0,o.kt)("admonition",{title:"\u5907\u6ce8",type:"note"},(0,o.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u7684ID\u6807\u8bc6\uff0c\u4ec5\u4ec5\u662f\u670d\u52a1\u5668\uff08TcpService\uff09\u548c\u8f85\u52a9\u5ba2\u6237\u7aef\uff08SocketClient\uff09\u4e4b\u95f4\u7684\u5173\u8054\u3002\u4e0e\u5ba2\u6237\u7aef\uff08TcpClient\uff09\u662f\u6ca1\u6709\u4efb\u4f55\u5173\u7cfb\u7684\u3002")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/8e1e2f35.3b62d779.js b/handbook/build/assets/js/8e1e2f35.3b62d779.js new file mode 100644 index 000000000..40e48d158 --- /dev/null +++ b/handbook/build/assets/js/8e1e2f35.3b62d779.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9198],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=d(e,["components","mdxType","originalType","parentName"]),p=c(n),m=a,g=p["".concat(l,".").concat(m)]||p[m]||s[m]||o;return n?r.createElement(g,i(i({ref:t},u),{},{components:n})):r.createElement(g,i({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var d={};for(var l in t)hasOwnProperty.call(t,l)&&(d[l]=t[l]);d.originalType=e,d.mdxType="string"==typeof e?e:a,i[1]=d;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>s,frontMatter:()=>o,metadata:()=>d,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));const o={id:"bigfixedheadercustomdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668"},i=void 0,d={unversionedId:"bigfixedheadercustomdatahandlingadapter",id:"bigfixedheadercustomdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/bigfixedheadercustomdatahandlingadapter.mdx",sourceDirName:".",slug:"/bigfixedheadercustomdatahandlingadapter",permalink:"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/bigfixedheadercustomdatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675586056,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"bigfixedheadercustomdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u6a21\u677f\u89e3\u6790\u201c\u975e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/customunfixedheaderdatahandlingadapter"},next:{title:"\u6a21\u677f\u89e3\u6790\u201c\u533a\u95f4\u6570\u636e\u201d\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/custombetweenanddatahandlingadapter"}},l={},c=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2}],u={toc:c};function s(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\uff0c\u662f\u5bf9\u56fa\u5b9a\u7684\u5305\u5934\u6a21\u677f\u7684\u8865\u5145\uff0c\u4e00\u822c\u6765\u662f\uff0c\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668\uff0c\u4e0d\u80fd\u5de5\u4f5c\u4e8e\u8d85\u8fc72G\u7684\u6570\u636e\uff0c\u4f46\u662f\u5728\u5c11\u6570\u60c5\u51b5\u4e0b\uff0c\u4f1a\u6709\u5927\u91cf\u7684\u6570\u636e\u4f20\u8f93\u9700\u6c42\u3002\u6240\u4ee5\u8fd9\u90e8\u5206\u7684\u4e1a\u52a1\uff0c\u53ef\u4ee5\u7528\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u5b9e\u73b0\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u81ea\u7531\u9002\u914d",(0,a.kt)("strong",{parentName:"li"},"99%"),"\u7684\u6570\u636e\u534f\u8bae\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u968f\u610f\u5b9a\u5236\u6570\u636e\u534f\u8bae\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u4e0e",(0,a.kt)("strong",{parentName:"li"},"\u4efb\u610f\u8bed\u8a00\u3001\u6846\u67b6"),"\u5bf9\u63a5\u6570\u636e\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u63a5\u6536",(0,a.kt)("strong",{parentName:"li"},"\u7406\u8bba\u65e0\u9650\u5927"),"\u7684\u6570\u636e\u3002")),(0,a.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002\u4e0b\u5217\u4ee5\u670d\u52a1\u5668\u4e3a\u4f8b\u3002"),(0,a.kt)("p",null,"\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u5b9e\u73b0IBigFixedHeaderRequestInfo\u63a5\u53e3\uff0c\u6b64\u5bf9\u8c61\u5373\u4e3a\u5b58\u50a8\u6570\u636e\u7684\u5b9e\u4f53\u7c7b\uff0c\u53ef\u5728\u6b64\u7c7b\u4e2d\u58f0\u660e\u4e00\u4e9b\u5c5e\u6027\uff0c\u4ee5\u5907\u4f7f\u7528\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u7ee7\u627fBigFixedHeaderCustomDataHandlingAdapter\uff0c\u5e76\u4e14\u4ee5\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u4f5c\u4e3a\u6cdb\u578b\u3002\u5e76\u5b9e\u73b0\u5bf9\u5e94\u62bd\u8c61\u65b9\u6cd5\u3002"),(0,a.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684RequestInfo\u5bf9\u8c61\uff0c\u5f3a\u8f6c\u4e3a\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u578b\uff0c\u7136\u540e\u8bfb\u53d6\u5176\u5c5e\u6027\u503c\uff0c\u4ee5\u5907\u4f7f\u7528\u3002")),(0,a.kt)("p",null,"\u3010MyBigFixedHeaderRequestInfo\u3011\n\u9996\u5148\uff0c\u65b0\u5efaMyBigFixedHeaderRequestInfo\u7c7b\uff0c\u7136\u540e\u5b9e\u73b0IBigFixedHeaderRequestInfo\u7528\u6237\u81ea\u5b9a\u4e49\u56fa\u5b9a\u5305\u5934\u63a5\u53e3\u3002\n\u7136\u540e\u5728",(0,a.kt)("strong",{parentName:"p"},"OnParsingHeader"),"\u51fd\u6570\u6267\u884c\u7ed3\u675f\u65f6\uff0c\u5bf9\u5b9e\u73b0\u7684",(0,a.kt)("inlineCode",{parentName:"p"},"BodyLength"),"\u5c5e\u6027\u4f5c\u51fa\u8d4b\u503c\uff0c\u4ee5\u6b64\u6765\u51b3\u5b9a\uff0c\u540e\u7eed\u8fd8\u5e94\u8be5\u63a5\u6536\u591a\u5c11\u6570\u636e\u4f5c\u4e3aBody \u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"/// \n/// \u4e0b\u5217\u793a\u4f8b\uff0c\u6ca1\u6709\u5b9e\u73b0\u903b\u8f91\uff0c\u4ec5\u89e3\u91ca\u601d\u8def\u3002\n/// \nclass MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo\n{\n public long BodyLength => throw new NotImplementedException();//\u6b64\u5904\u8bf7\u4f7f\u7528\u5b57\u6bb5\u5b9e\u73b0\u3002\n\n public void OnAppendBody(byte[] buffer, int offset, int length)\n {\n //\u5728\u8fd9\u91cc\u4f1a\u4e00\u76f4\u8ffd\u52a0\u6570\u636e\u4f53\uff0c\u7528\u6237\u81ea\u884c\u5b9e\u73b0\u6570\u636e\u7684\u4fdd\u5b58\u3002\n //\u6ce8\u610f\uff0cbuffer\u53ef\u80fd\u4e3a\u5185\u5b58\u5757\u7684\u6210\u5458\uff0c\u6240\u4ee5\uff0c\u4e00\u5b9a\u4e00\u5b9a\u4e0d\u8981\u76f4\u63a5\u5f15\u7528\u3002\n }\n\n public bool OnFinished()\n {\n //\u89e6\u53d1\u8be5\u65b9\u6cd5\u65f6\uff0c\u8bf4\u660e\u6570\u636e\u4f53\u63a5\u6536\u5b8c\u6bd5\uff0c\u8fd4\u56detrue\u65f6\uff0c\u4f1a\u89e6\u53d1Receive\u76f8\u5173\u4e8b\u4ef6\uff0c\u5426\u5219\u4e0d\u4f1a\u3002\n return true;\n }\n\n public bool OnParsingHeader(byte[] header)\n {\n //\u89e3\u6790\u5934\u90e8\u3002\u8d4b\u503cBodyLength\n return true;\n }\n}\n\n")),(0,a.kt)("p",null,"\u65b0\u5efaMyBigFixedHeaderCustomDataHandlingAdapter\u7ee7\u627f",(0,a.kt)("strong",{parentName:"p"},"CustomBigFixedHeaderDataHandlingAdapter"),"\uff0c\u7136\u540e\u5bf9HeaderLength\u4f5c\u51fa\u8d4b\u503c\uff0c\u4ee5\u6b64\u8868\u660e\u56fa\u5b9a\u5305\u5934\u7684\u957f\u5ea6\u662f\u591a\u5c11\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"/// \n/// \u6a21\u677f\u89e3\u6790\u201c\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668\n/// \nclass MyBigFixedHeaderCustomDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter\n{\n public override int HeaderLength =>8;\n\n protected override MyBigFixedHeaderRequestInfo GetInstance()\n {\n return new MyBigFixedHeaderRequestInfo();\n }\n}\n")),(0,a.kt)("p",null,"\u3010\u63a5\u6536\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u63a5\u6536\u4fe1\u606f\uff0c\u5728CustomDataHandlingAdapter\u6d3e\u751f\u7684\u9002\u914d\u5668\u4e2d\uff0cbyteBlock\u5c06\u4e3anull\uff0crequestInfo\u5c06\u4e3a\u9002\u914d\u5668\u5b9a\u4e49\u7684\u6cdb\u578b\n if (requestInfo is MyBigFixedHeaderRequestInfo myRequestInfo)\n {\n //\u6b64\u5904\u53ef\u4ee5\u5904\u7406MyBigFixedHeaderRequestInfo\u7684\u76f8\u5173\u4fe1\u606f\u4e86\u3002\n string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);\n }\n \n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(() => { return new MyBigFixedHeaderCustomDataHandlingAdapter(); }))//\u914d\u7f6e\u9002\u914d\u5668\n .Start();//\u542f\u52a8\n")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u521b\u5efa\u7684\u9002\u914d\u5668\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/8e5f0e39.927d9bfc.js b/handbook/build/assets/js/8e5f0e39.927d9bfc.js new file mode 100644 index 000000000..41766d94f --- /dev/null +++ b/handbook/build/assets/js/8e5f0e39.927d9bfc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9954],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,p=a(e,["components","mdxType","originalType","parentName"]),f=s(n),d=o,m=f["".concat(c,".").concat(d)]||f[d]||u[d]||i;return n?r.createElement(m,l(l({ref:t},p),{},{components:n})):r.createElement(m,l({ref:t},p))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,l=new Array(i);l[0]=f;var a={};for(var c in t)hasOwnProperty.call(t,c)&&(a[c]=t[c]);a.originalType=e,a.mdxType="string"==typeof e?e:o,l[1]=a;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>s});var r=n(7462),o=(n(7294),n(3905));const i={id:"httpfiletransfer",title:"\u6587\u4ef6\u4f20\u8f93"},l=void 0,a={unversionedId:"httpfiletransfer",id:"httpfiletransfer",title:"\u6587\u4ef6\u4f20\u8f93",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/httpfiletransfer.mdx",sourceDirName:".",slug:"/httpfiletransfer",permalink:"/touchsocket/docs/httpfiletransfer",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/httpfiletransfer.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"httpfiletransfer",title:"\u6587\u4ef6\u4f20\u8f93"},sidebar:"docs",previous:{title:"\u9759\u6001\u9875\u9762\u63d2\u4ef6",permalink:"/touchsocket/docs/httpstaticpageplugin"},next:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/websocketdescription"}},c={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u670d\u52a1\u5668\u54cd\u5e94\u6587\u4ef6",id:"\u4e8c\u670d\u52a1\u5668\u54cd\u5e94\u6587\u4ef6",level:2},{value:"\u4e09\u3001\u670d\u52a1\u5668\u63a5\u6536\u4e0a\u4f20\u6587\u4ef6",id:"\u4e09\u670d\u52a1\u5668\u63a5\u6536\u4e0a\u4f20\u6587\u4ef6",level:2}],p={toc:s};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("p",null,"\u8be5Http\u670d\u52a1\u5668\u53ca\u5ba2\u6237\u7aef\uff0c\u4ec5\u4ec5\u662f\u8f7b\u91cf\u7ea7\u7684Http\u5de5\u5177\uff0c\u4e0d\u5177\u5907\u5e7f\u6cdb\u7684\u517c\u5bb9\u6027\uff0c\u6240\u4ee5\u8bf7\u614e\u91cd\u4f7f\u7528\u3002"),(0,o.kt)("h2",{id:"\u4e8c\u670d\u52a1\u5668\u54cd\u5e94\u6587\u4ef6"},"\u4e8c\u3001\u670d\u52a1\u5668\u54cd\u5e94\u6587\u4ef6"),(0,o.kt)("p",null,"\u8be5\u64cd\u4f5c\u652f\u6301\u5927\u578b\u6587\u4ef6\uff0c\u4e5f\u652f\u6301\u65ad\u70b9\u7eed\u4f20\u3001\u652f\u6301\u8fc5\u96f7\u52a0\u901f\u7b49\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'internal class MyHttpPlug : HttpPluginBase\n{\n protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e)\n {\n if (e.Context.Request.UrlEquals("/file"))\n {\n e.Context.Response\n .SetStatus()//\u5fc5\u987b\u8981\u6709\u72b6\u6001\n .FromFile(@"D:\\System\\Windows.iso", e.Context.Request);//\u76f4\u63a5\u56de\u5e94\u6587\u4ef6\u3002\n }\n base.OnGet(client, e);\n }\n}\n\n')),(0,o.kt)("h2",{id:"\u4e09\u670d\u52a1\u5668\u63a5\u6536\u4e0a\u4f20\u6587\u4ef6"},"\u4e09\u3001\u670d\u52a1\u5668\u63a5\u6536\u4e0a\u4f20\u6587\u4ef6"),(0,o.kt)("p",null,"\u8be5\u64cd\u4f5c\u76ee\u524d\u4ec5\u652f\u6301\u5c0f\u6587\u4ef6\u4e0a\u4f20\uff0c\u5b9e\u6d4b100Mb\u6ca1\u95ee\u9898\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'internal class MyHttpPlug : HttpPluginBase\n{\n protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e)\n {\n if (e.Context.Request.UrlEquals("/uploadfile"))\n {\n try\n {\n if (e.Context.Request.ContentLen>1024*1024*100)//\u5168\u90e8\u6570\u636e\u4f53\u8d85\u8fc7100Mb\u5219\u76f4\u63a5\u62d2\u7edd\u63a5\u6536\u3002\n {\n e.Context.Response\n .SetStatus("403", "\u6570\u636e\u8fc7\u5927")\n .Answer();\n return;\n }\n //\u6b64\u64cd\u4f5c\u4f1a\u5148\u63a5\u6536\u5168\u90e8\u6570\u636e\uff0c\u7136\u540e\u518d\u5206\u5272\u6570\u636e\u3002\n //\u6240\u4ee5\u4e0a\u4f20\u6587\u4ef6\u4e0d\u5b9c\u8fc7\u5927\uff0c\u4e0d\u7136\u4f1a\u5185\u5b58\u6ea2\u51fa\u3002\n var multifileCollection = e.Context.Request.GetMultifileCollection();\n\n foreach (var item in multifileCollection)\n {\n StringBuilder stringBuilder = new StringBuilder();\n stringBuilder.Append($"\u6587\u4ef6\u540d={item.FileName}\\t");\n stringBuilder.Append($"\u6570\u636e\u957f\u5ea6={item.Length}");\n client.Logger.Info(stringBuilder.ToString());\n }\n\n e.Context.Response\n .SetStatus()\n .FromText("Ok")\n .Answer();\n }\n catch (Exception ex)\n {\n client.Logger.Exception(ex);\n }\n }\n base.OnPost(client, e);\n }\n}\n\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/9106ea79.88d3dc8b.js b/handbook/build/assets/js/9106ea79.88d3dc8b.js new file mode 100644 index 000000000..e5f6728ee --- /dev/null +++ b/handbook/build/assets/js/9106ea79.88d3dc8b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9769],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),i=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=i(e.components);return r.createElement(p.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},s=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),s=i(n),k=a,m=s["".concat(p,".").concat(k)]||s[k]||d[k]||l;return n?r.createElement(m,c(c({ref:t},u),{},{components:n})):r.createElement(m,c({ref:t},u))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,c=new Array(l);c[0]=s;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o.mdxType="string"==typeof e?e:a,c[1]=o;for(var i=2;i{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>d,frontMatter:()=>l,metadata:()=>o,toc:()=>i});var r=n(7462),a=(n(7294),n(3905));const l={id:"createtouchrpcclient",title:"\u521b\u5efaTouchRpc\u5ba2\u6237\u7aef"},c=void 0,o={unversionedId:"createtouchrpcclient",id:"createtouchrpcclient",title:"\u521b\u5efaTouchRpc\u5ba2\u6237\u7aef",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/createtouchrpcclient.mdx",sourceDirName:".",slug:"/createtouchrpcclient",permalink:"/touchsocket/docs/createtouchrpcclient",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createtouchrpcclient.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675660193,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"createtouchrpcclient",title:"\u521b\u5efaTouchRpc\u5ba2\u6237\u7aef"},sidebar:"docs",previous:{title:"\u521b\u5efaTouchRpc\u670d\u52a1\u5668",permalink:"/touchsocket/docs/createtouchrpcservice"},next:{title:"\u57fa\u7840\u529f\u80fd",permalink:"/touchsocket/docs/touchrpcbase"}},p={},i=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u53ef\u914d\u7f6e\u9879",id:"\u4e8c\u53ef\u914d\u7f6e\u9879",level:2},{value:"SetVerifyTimeout",id:"setverifytimeout",level:4},{value:"SetVerifyToken",id:"setverifytoken",level:4},{value:"SetHeartbeatFrequency",id:"setheartbeatfrequency",level:4},{value:"SetSerializationSelector",id:"setserializationselector",level:4},{value:"SetResponseType",id:"setresponsetype",level:4},{value:"SetRootPath",id:"setrootpath",level:4},{value:"\u4e09\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",id:"\u4e09\u652f\u6301\u63d2\u4ef6\u63a5\u53e3",level:2},{value:"\u56db\u3001\u521b\u5efa",id:"\u56db\u521b\u5efa",level:2},{value:"4.1 TcpTouchRpcClient",id:"41-tcptouchrpcclient",level:3},{value:"4.2 HttpTouchRpcClient",id:"42-httptouchrpcclient",level:3},{value:"4.3 UdpTouchRpc",id:"43-udptouchrpc",level:3},{value:"4.4 WSTouchRpcClient",id:"44-wstouchrpcclient",level:3}],u={toc:i};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"TouchRpc\u5ba2\u6237\u7aef\u5bf9\u5e94\u7684\uff0c\u4e5f\u6709\u56db\u79cd\u4e0d\u540c\u534f\u8bae\u7684\u7248\u672c\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u53ef\u914d\u7f6e\u9879"},"\u4e8c\u3001\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("details",null,(0,a.kt)("summary",null,"\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("div",null,(0,a.kt)("h4",{id:"setverifytimeout"},"SetVerifyTimeout"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u9a8c\u8bc1\u8d85\u65f6\u65f6\u95f4\uff0c\u9ed8\u8ba43000ms\u3002\uff08\u4ec5TcpTouchRpc\u53ef\u7528\uff09 \u3002"),(0,a.kt)("h4",{id:"setverifytoken"},"SetVerifyToken"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u9a8c\u8bc1\u53e3\u4ee4\u3002 "),(0,a.kt)("h4",{id:"setheartbeatfrequency"},"SetHeartbeatFrequency"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u5fc3\u8df3\u3002\u9ed8\u8ba4\u4e3a\u95f4\u96942000ms\uff0c\u8fde\u7eed3\u6b21\u65e0\u54cd\u5e94\u5373\u89c6\u4e3a\u65ad\u5f00\u3002"),(0,a.kt)("h4",{id:"setserializationselector"},"SetSerializationSelector"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u5e8f\u5217\u5316\u9009\u62e9\u5668\u3002"),(0,a.kt)("h4",{id:"setresponsetype"},"SetResponseType"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u5141\u8bb8\u7684\u54cd\u5e94\u7c7b\u578b"),(0,a.kt)("h4",{id:"setrootpath"},"SetRootPath"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u6839\u8def\u5f84"))),(0,a.kt)("h2",{id:"\u4e09\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"},"\u4e09\u3001\u652f\u6301\u63d2\u4ef6\u63a5\u53e3"),(0,a.kt)("p",null,"\u58f0\u660e\u81ea\u5b9a\u4e49\u5b9e\u4f8b\u7c7b\uff0c\u7136\u540e\u5b9e\u73b0",(0,a.kt)("strong",{parentName:"p"},"ITouchRpcPlugin"),"\u63a5\u53e3\uff0c\u5373\u53ef\u5b9e\u73b0\u4e0b\u5217\u4e8b\u52a1\u7684\u89e6\u53d1\u3002\n\u6216\u8005\u7ee7\u627f\u81ea",(0,a.kt)("strong",{parentName:"p"},"TouchRpcPluginBase"),"\u7c7b\uff0c\u91cd\u5199\u76f8\u5e94\u65b9\u6cd5\u5373\u53ef\u3002"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"\u63d2\u4ef6\u65b9\u6cd5"),(0,a.kt)("th",{parentName:"tr",align:null},"\u529f\u80fd"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnHandshaking"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5ba2\u6237\u7aef\u5728\u9a8c\u8bc1\u8fde\u63a5\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6846\u67b6\u4f1a\u9996\u5148\u9a8c\u8bc1\u8fde\u63a5Token\u662f\u5426\u6b63\u786e\uff0c\u5982\u679c\u4e0d\u6b63\u786e\u5219\u76f4\u63a5\u62d2\u7edd\u3002\u4e0d\u4f1a\u6709\u4efb\u4f55\u6295\u9012\u3002\u7528\u6237\u4e5f\u53ef\u4ee5\u4f7f\u7528Metadata\u8fdb\u884c\u52a8\u6001\u9a8c\u8bc1\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnHandshaked"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5ba2\u6237\u7aef\u5b8c\u6210\u8fde\u63a5\u9a8c\u8bc1")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnFileTransfering"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u6587\u4ef6\u4f20\u8f93\u5373\u5c06\u8fdb\u884c\u65f6\u89e6\u53d1\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnFileTransfered"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u6587\u4ef6\u4f20\u8f93\u7ed3\u675f\u4e4b\u540e\u3002\u5e76\u4e0d\u610f\u5473\u7740\u5b8c\u6210\u4f20\u8f93\uff0c\u8bf7\u901a\u8fc7e.Result\u5c5e\u6027\u503c\u8fdb\u884c\u5224\u65ad\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnLoadingStream"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u8fdc\u7a0b\u8bf7\u6c42\u52a0\u8f7d\u6d41\u65f6\u89e6\u53d1\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnReceivedProtocolData"),(0,a.kt)("td",{parentName:"tr",align:null},"\u6536\u5230\u534f\u8bae\u6570\u636e")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnRemoteAccessing"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u8fdc\u7a0b\u64cd\u4f5c\u8bbf\u95ee\u4e4b\u524d\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnRemoteAccessed"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u8fdc\u7a0b\u64cd\u4f5c\u8bbf\u95ee\u4e4b\u540e\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnRouting"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u9700\u8981\u8f6c\u53d1\u8def\u7531\u5305\u65f6\u3002\u4e00\u822c\u6240\u6709\u7684",(0,a.kt)("strong",{parentName:"td"},"\u5ba2\u6237\u7aef\u4e4b\u95f4"),"\u7684\u6570\u636e\u4f20\u8f93\uff0c\u90fd\u9700\u8981\u7ecf\u8fc7\u8be5\u51fd\u6570\u7684\u8fd0\u884c\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnStreamTransfering"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5373\u5c06\u63a5\u6536\u6d41\u6570\u636e\uff0c\u7528\u6237\u9700\u8981\u5728\u6b64\u4e8b\u4ef6\u4e2d\u5bf9e.Bucket\u521d\u59cb\u5316\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnStreamTransfered"),(0,a.kt)("td",{parentName:"tr",align:null},"\u6d41\u6570\u636e\u5904\u7406\uff0c\u7528\u6237\u9700\u8981\u5728\u6b64\u4e8b\u4ef6\u4e2d\u5bf9e.Bucket\u624b\u52a8\u91ca\u653e\u3002 \u5f53\u6d41\u6570\u636e\u4f20\u8f93\u7ed3\u675f\u4e4b\u540e\u3002\u5e76\u4e0d\u610f\u5473\u7740\u5b8c\u6210\u4f20\u8f93\uff0c\u8bf7\u901a\u8fc7e.Result\u5c5e\u6027\u503c\u8fdb\u884c\u5224\u65ad\u3002")))),(0,a.kt)("h2",{id:"\u56db\u521b\u5efa"},"\u56db\u3001\u521b\u5efa"),(0,a.kt)("h3",{id:"41-tcptouchrpcclient"},"4.1 TcpTouchRpcClient"),(0,a.kt)("p",null,"\u57fa\u672c\u521b\u5efa\u5982\u4e0b\uff0c\u652f\u6301",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/createtcpclient"},"\u521b\u5efaTcpClient"),"\u7684\u6240\u6709\u914d\u7f6e\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClient client = new TcpTouchRpcClient();\nclient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("127.0.0.1:7789")\n .SetVerifyToken("TouchRpc"));\nclient.Connect();\n')),(0,a.kt)("h3",{id:"42-httptouchrpcclient"},"4.2 HttpTouchRpcClient"),(0,a.kt)("p",null,"\u57fa\u672c\u521b\u5efa\u5982\u4e0b\uff0c\u652f\u6301",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/createtcpclient"},"\u521b\u5efaTcpClient"),"\u7684\u6240\u6709\u914d\u7f6e\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'HttpTouchRpcClient client = new HttpTouchRpcClient();\nclient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("127.0.0.1:7789")\n .SetVerifyToken("TouchRpc"));\nclient.Connect();\n')),(0,a.kt)("h3",{id:"43-udptouchrpc"},"4.3 UdpTouchRpc"),(0,a.kt)("p",null,"\u57fa\u672c\u521b\u5efa\u5982\u4e0b\uff0c\u652f\u6301@\u7684\u6240\u6709\u914d\u7f6e\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'UdpTouchRpc client = new UdpTouchRpc();\nclient.Setup(new TouchSocketConfig()\n .SetBindIPHost(7794)\n .SetRemoteIPHost("127.0.0.1:7789"));//\u8bbe\u7f6e\u76ee\u6807\u5730\u5740\u3002\nclient.Start();\n')),(0,a.kt)("h3",{id:"44-wstouchrpcclient"},"4.4 WSTouchRpcClient"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},' WSTouchRpcClient client = new WSTouchRpcClient();\n client.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("ws://127.0.0.1:5000/wstouchrpc"));\n client.ConnectAsync();\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/915634cf.e91d55ad.js b/handbook/build/assets/js/915634cf.e91d55ad.js new file mode 100644 index 000000000..c99b5b2c1 --- /dev/null +++ b/handbook/build/assets/js/915634cf.e91d55ad.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2022],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var l=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,l)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=l.createContext({}),s=function(e){var t=l.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return l.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},d=l.forwardRef((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,i=e.parentName,p=a(e,["components","mdxType","originalType","parentName"]),d=s(n),h=r,m=d["".concat(i,".").concat(h)]||d[h]||u[h]||c;return n?l.createElement(m,o(o({ref:t},p),{},{components:n})):l.createElement(m,o({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,o=new Array(c);o[0]=d;var a={};for(var i in t)hasOwnProperty.call(t,i)&&(a[i]=t[i]);a.originalType=e,a.mdxType="string"==typeof e?e:r,o[1]=a;for(var s=2;s{n.d(t,{Z:()=>X});var l=n(7294),r=n(7462);const c=(e,t,n)=>e?"string"==typeof e?e:e[t]||n:n,o={display:"block"},a=e=>{let{size:t,color:n,style:a,...i}=e;const s=a?{...o,...a}:o;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},i),l.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:c(n,0,"#333333")}))};a.defaultProps={size:18};const i=a,s={display:"block"},p=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...s,...o}:s;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:c(n,0,"#333333")}),l.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:c(n,1,"#333333")}))};p.defaultProps={size:18};const u=p,d={display:"block"},h=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...d,...o}:d;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:c(n,0,"#333333")}),l.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:c(n,1,"#333333")}),l.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:c(n,2,"#333333")}))};h.defaultProps={size:18};const m=h,g={display:"block"},v=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...g,...o}:g;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:c(n,0,"#333333")}))};v.defaultProps={size:18};const f=v,y={display:"block"},b=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...y,...o}:y;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:c(n,0,"#333333")}))};b.defaultProps={size:18};const z=b,k={display:"block"},E=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...k,...o}:k;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:c(n,0,"#333333")}),l.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:c(n,1,"#333333")}),l.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:c(n,2,"#333333")}))};E.defaultProps={size:18};const x=E,C={display:"block"},w=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...C,...o}:C;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:c(n,0,"#333333")}),l.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:c(n,1,"#333333")}))};w.defaultProps={size:18};const M=w,P={display:"block"},O=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...P,...o}:P;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:c(n,0,"#333333")}),l.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:c(n,1,"#333333")}))};O.defaultProps={size:18};const N=O,L={display:"block"},j=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...L,...o}:L;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:c(n,0,"#333333")}),l.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:c(n,1,"#333333")}))};j.defaultProps={size:18};const Z=j,T={display:"block"},B=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...T,...o}:T;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:c(n,0,"#333333")}))};B.defaultProps={size:18};const A=B,H={display:"block"},V=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...H,...o}:H;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:c(n,0,"#333333")}))};V.defaultProps={size:18};const D=V,S={display:"block"},U=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...S,...o}:S;return l.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),l.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:c(n,0,"#333333")}))};U.defaultProps={size:18};const K=U,R=e=>{let{name:t,...n}=e;switch(t){case"youhua":return l.createElement(i,n);case"dayi":return l.createElement(u,n);case"shengji":return l.createElement(m,n);case"tiaozheng":return l.createElement(f,n);case"gengxin":return l.createElement(z,n);case"wendang":return l.createElement(x,n);case"shanchu":return l.createElement(M,n);case"bug":return l.createElement(N,n);case"xinzeng":return l.createElement(Z,n);case"fuwu":return l.createElement(A,n);case"down":return l.createElement(D,n);case"up":return l.createElement(K,n)}return null},F="label_p8vM",I="icon_knQK";function X(e){const{children:t}=e,n={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return l.createElement("label",{className:F,title:t,style:{backgroundColor:n[t].bgColor}},l.createElement(R,{name:n[t].icon,color:"white",size:14,className:I})," ",t)}},2859:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var l=n(7462),r=(n(7294),n(3905)),c=n(510);const o={id:"reconnection",title:"\u65ad\u7ebf\u91cd\u8fde"},a=void 0,i={unversionedId:"reconnection",id:"reconnection",title:"\u65ad\u7ebf\u91cd\u8fde",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/reconnection.mdx",sourceDirName:".",slug:"/reconnection",permalink:"/touchsocket/docs/reconnection",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/reconnection.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"reconnection",title:"\u65ad\u7ebf\u91cd\u8fde"},sidebar:"docs",previous:{title:"\u670d\u52a1\u5668\u91cd\u7f6eID",permalink:"/touchsocket/docs/resetid"},next:{title:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6",permalink:"/touchsocket/docs/tcpcommandlineplugin"}},s={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4f7f\u7528Reconnection\u63d2\u4ef6",id:"\u4e8c\u4f7f\u7528reconnection\u63d2\u4ef6",level:2},{value:"\u4e09\u3001\u4f7f\u7528PollingKeepAlive\u63d2\u4ef6 \u4f01\u4e1a\u7248",id:"\u4e09\u4f7f\u7528pollingkeepalive\u63d2\u4ef6-\u4f01\u4e1a\u7248",level:2}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,l.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"\u6240\u8c13\u65ad\u7ebf\u91cd\u8fde\uff0c\u5373tcp\u5ba2\u6237\u7aef\u5728\u65ad\u5f00\u670d\u52a1\u5668\u540e\uff0c\u4e3b\u52a8\u53d1\u8d77\u7684\u518d\u6b21\u8fde\u63a5\u8bf7\u6c42\u3002"),(0,r.kt)("h2",{id:"\u4e8c\u4f7f\u7528reconnection\u63d2\u4ef6"},"\u4e8c\u3001\u4f7f\u7528Reconnection\u63d2\u4ef6"),(0,r.kt)("p",null,"\u4f7f\u7528\u65ad\u7ebf\u91cd\u8fde\u975e\u5e38\u7b80\u5355\uff0c\u4ec5\u4e00\u884c\u4ee3\u7801\u5b8c\u6210\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},".UsePlugin()\n.ConfigurePlugins(a=> \n{\n a.UseReconnection(5, true, 1000);//\u5982\u9700\u6c38\u8fdc\u5c1d\u8bd5\u8fde\u63a5\uff0ctryCount\u8bbe\u7f6e\u4e3a-1\u5373\u53ef\u3002\n});\n")),(0,r.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("strong",{parentName:"p"},"\u65ad\u7ebf\u91cd\u8fde\uff0c\u5fc5\u987b\u6ee1\u8db3\u4ee5\u4e0b\u51e0\u4e2a\u8981\u6c42\uff1a")),(0,r.kt)("ol",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ol"},"\u5fc5\u987b\u5b8c\u6210\u7b2c\u4e00\u6b21\u8fde\u63a5"),(0,r.kt)("li",{parentName:"ol"},"\u5fc5\u987b\u662f\u88ab\u52a8\u65ad\u5f00\uff0c\u5982\u679c\u662f\u5ba2\u6237\u7aef\u4e3b\u52a8\u8c03\u7528Close\u3001Disconnect\u7b49\u65b9\u6cd5\u4e3b\u52a8\u65ad\u5f00\u7684\u8bdd\uff0c\u4e0d\u4f1a\u751f\u6548\u3002"),(0,r.kt)("li",{parentName:"ol"},"\u5fc5\u987b\u6709\u663e\u5f0f\u7684\u65ad\u5f00\u4fe1\u606f\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u76f4\u63a5\u62d4\u7f51\u7ebf\u7684\u8bdd\uff0c\u4e0d\u4f1a\u7acb\u5373\u751f\u6548\uff0c\u4f1a\u7b49tcp\u4fdd\u6d3b\u5230\u671f\u540e\u518d\u751f\u6548\u3002"))),(0,r.kt)("h2",{id:"\u4e09\u4f7f\u7528pollingkeepalive\u63d2\u4ef6-\u4f01\u4e1a\u7248"},"\u4e09\u3001\u4f7f\u7528PollingKeepAlive\u63d2\u4ef6 ",(0,r.kt)(c.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,r.kt)("p",null,"\u4f01\u4e1a\u7248\u4f7f\u7528\u65ad\u7ebf\u91cd\u8fde\uff0c\u5728\u517c\u5bb9\u4e0a\u8ff0\u65b9\u6cd5\u7684\u540c\u65f6\uff0c\u8fd8\u652f\u6301\u4e00\u79cd\u65e0\u4eba\u503c\u5b88\u7684\u8fde\u63a5\u65b9\u5f0f\uff0c\u5373\u8f6e\u8be2\u5f0f\u8fde\u63a5\uff0c\u4f7f\u7528\u4e5f\u975e\u5e38\u7b80\u5355\uff0c\u4ec5\u4e00\u884c\u4ee3\u7801\u5b8c\u6210\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},".UsePlugin()\n.ConfigurePlugins(a=> \n{\n a.Add>()\n .SetTick(1000);//\u6bcf\u79d2\u68c0\u67e5\n});\n")),(0,r.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("strong",{parentName:"p"},"PollingKeepAlive\u65ad\u7ebf\u91cd\u8fde\uff0c\u5fc5\u987b\u6ee1\u8db3\u4ee5\u4e0b\u51e0\u4e2a\u8981\u6c42\uff1a")),(0,r.kt)("ol",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ol"},"\u4e0d\u8981\u548cUseReconnection\u4e00\u540c\u4f7f\u7528"),(0,r.kt)("li",{parentName:"ol"},"\u5fc5\u987b\u6709\u663e\u5f0f\u7684\u65ad\u5f00\u4fe1\u606f\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u76f4\u63a5\u62d4\u7f51\u7ebf\u7684\u8bdd\uff0c\u4e0d\u4f1a\u7acb\u5373\u751f\u6548\uff0c\u4f1a\u7b49tcp\u4fdd\u6d3b\u5230\u671f\u540e\u518d\u751f\u6548\u3002"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/91a311b4.db72a3a2.js b/handbook/build/assets/js/91a311b4.db72a3a2.js new file mode 100644 index 000000000..e4993f1b0 --- /dev/null +++ b/handbook/build/assets/js/91a311b4.db72a3a2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[4850],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>b});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var a=o.createContext({}),l=function(e){var t=o.useContext(a),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(a.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,a=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=l(n),b=r,u=d["".concat(a,".").concat(b)]||d[b]||m[b]||c;return n?o.createElement(u,s(s({ref:t},p),{},{components:n})):o.createElement(u,s({ref:t},p))}));function b(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,s=new Array(c);s[0]=d;var i={};for(var a in t)hasOwnProperty.call(t,a)&&(i[a]=t[a]);i.originalType=e,i.mdxType="string"==typeof e?e:r,s[1]=i;for(var l=2;l{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>m,frontMatter:()=>c,metadata:()=>i,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const c={id:"jsonserialize",title:"Json\u5e8f\u5217\u5316"},s=void 0,i={unversionedId:"jsonserialize",id:"jsonserialize",title:"Json\u5e8f\u5217\u5316",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/jsonserialize.mdx",sourceDirName:".",slug:"/jsonserialize",permalink:"/touchsocket/docs/jsonserialize",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/jsonserialize.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"jsonserialize",title:"Json\u5e8f\u5217\u5316"},sidebar:"docs",previous:{title:"\u9ad8\u6027\u80fd\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316",permalink:"/touchsocket/docs/fastbinaryformatter"},next:{title:"\u4f9d\u8d56\u6ce8\u5165\u5bb9\u5668",permalink:"/touchsocket/docs/ioc"}},a={},l=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u52a8\u6001\u8c03\u6574\u7684Json\u7b56\u7565",id:"\u4e8c\u52a8\u6001\u8c03\u6574\u7684json\u7b56\u7565",level:2},{value:"\u4e09\u3001JsonFast\u6027\u80fd",id:"\u4e09jsonfast\u6027\u80fd",level:2}],p={toc:l};function m(e){let{components:t,...c}=e;return(0,r.kt)("wrapper",(0,o.Z)({},p,c,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"\u5728TouchSocket\u4e2d\uff0c\u5185\u7f6e\u4e86Json\u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5316\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"string jsonstr=SerializeConvert.ToJson(new object());//\u5e8f\u5217\u5316\nobject obj=SerializeConvert.FromJson(jsonstr);//\u53cd\u5e8f\u5217\u5316\n")),(0,r.kt)("h2",{id:"\u4e8c\u52a8\u6001\u8c03\u6574\u7684json\u7b56\u7565"},"\u4e8c\u3001\u52a8\u6001\u8c03\u6574\u7684Json\u7b56\u7565"),(0,r.kt)("p",null,"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff1a\n\u5728net45\u548cnetstandard2.0\u5e73\u53f0\u65f6\uff0c\u5e8f\u5217\u5316\u65b9\u5f0f\u662f\u7531",(0,r.kt)("a",{parentName:"p",href:"https://gitee.com/majorworld/jsonfast"},"JsonFast\uff08\u7fa4\u53cb\u8001\u6c5f\uff09"),"\u63d0\u4f9b\u7684\u5355\u6587\u4ef6json\u5e8f\u5217\u5316\u3002\u8be5json\u5de5\u5177\u80fd\u591f\u5e8f\u5217\u5316\u5927\u591a\u6570\u6570\u636e\u7ed3\u6784\uff0c\u4e14\u6027\u80fd\u548cNewtonsoft.Json\u4e0d\u76f8\u4e0a\u4e0b\uff08\u89c1\u4e0b\u6d4b\u8bd5\uff09\u3002\n\u5728netcoreapp3.1\u53ca\u4ee5\u4e0a\u5e73\u53f0\u65f6\uff0c\u5e8f\u5217\u5316\u65b9\u5f0f\u4f7f\u7528System.Text.Json\u3002"),(0,r.kt)("p",null,"\u4f46\u662f\n\u5f53\u5e94\u7528\u4e2d\u52a0\u8f7d\u4e86Newtonsoft.Json\u7684\u7a0b\u5e8f\u96c6\u540e\uff0c\u6240\u6709\u7684\u5e73\u53f0\u7684\u5e8f\u5217\u5316\uff0c\u5747\u4f1a\u4f7f\u7528Newtonsoft.Json\u3002\u53ef\u901a\u8fc7",(0,r.kt)("inlineCode",{parentName:"p"},"**SerializeConvert.NewtonsoftJsonIsSupported**"),"\u9759\u6001\u5c5e\u6027\u83b7\u53d6\u5f53\u524d\u662f\u5426\u652f\u6301Newtonsoft.Json\u3002"),(0,r.kt)("p",null,"\u4e5f\u53ef\u4ee5\u624b\u52a8\u52a0\u8f7dNewtonsoft.Json\uff08\u4e00\u822c\u5728",(0,r.kt)("strong",{parentName:"p"},"Unity3d"),"\u4e2d\u9700\u8981\u624b\u52a8\u52a0\u8f7d\uff09\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"bool IsSupported=SerializeConvert.LoadNewtonsoftJson(typeof(JsonConvert));//\u8fd4\u56de\u503c\u6307\u793a\u662f\u5426\u6210\u529f\u52a0\u8f7d\n")),(0,r.kt)("p",null,"\u5f53\u52a0\u8f7d\u4e86Newtonsoft.Json\u7684\u7a0b\u5e8f\u96c6\uff0c\u4f46\u662f\u4e0d\u60f3\u4f7f\u7528\u8be5\u5de5\u5177\u5e8f\u5217\u5316\u65f6\uff0c\u53ef\u5c06",(0,r.kt)("inlineCode",{parentName:"p"},"**SerializeConvert.NewtonsoftJsonFirst**"),"\u9759\u6001\u5c5e\u6027\u8bbe\u4e3afalse\u3002"),(0,r.kt)("h2",{id:"\u4e09jsonfast\u6027\u80fd"},"\u4e09\u3001JsonFast\u6027\u80fd"),(0,r.kt)("p",null,"\u3010\u7b80\u5355\u6570\u636e\u5bf9\u8c61\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"public class SimpleObject \n{\n public int Age { get; set; }\n public string Name { get; set; }\n}\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'[Benchmark]\npublic void JsonFast_SimpleObject()\n{\n var v = new SimpleObject { Age = 40, Name = "John" };\n for (int i = 0; i < Count; i++)\n {\n var str = JsonFastConverter.JsonTo(v);\n var val = JsonFastConverter.JsonFrom(str);\n }\n}\n')),(0,r.kt)("p",null,"\u4e0b\u56fe\u4e3a1w\u6b21\u7684\u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5316\u3002JsonFast\u7684\u6548\u7387\u751a\u81f3\u8fd8\u7a0d\u9ad8\u4e00\u4e9b\u3002\n",(0,r.kt)("img",{alt:"image.png",src:n(5229).Z,width:"1198",height:"183"})),(0,r.kt)("p",null,"\u3010\u590d\u6742\u5bf9\u8c61\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"public class ComplexObject\n{\n public Dictionary Dic1 { get; set; }\n public Dictionary Dic2 { get; set; }\n public Dictionary Dic3 { get; set; }\n public Dictionary Dic4 { get; set; }\n public List List1 { get; set; }\n public List List2 { get; set; }\n public List List3 { get; set; }\n public int P1 { get; set; }\n public string P2 { get; set; }\n public long P3 { get; set; }\n public byte P4 { get; set; }\n public DateTime P5 { get; set; }\n public double P6 { get; set; }\n public byte[] P7 { get; set; }\n}\n\npublic class Arg\n{\n public Arg()\n {\n }\n\n public Arg(int myProperty)\n {\n MyProperty = myProperty;\n }\n\n public int MyProperty { get; set; }\n}\n")),(0,r.kt)("p",null,"\u521d\u59cb\u5316"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'private ComplexObject GetComplexObject()\n{\n ComplexObject complexObject = new ComplexObject();\n complexObject.P1 = 10;\n complexObject.P2 = "\u5929\u4e0b\u65e0\u654c";\n complexObject.P3 = 100;\n complexObject.P4 = 0;\n complexObject.P5 = DateTime.Now;\n complexObject.P6 = 10;\n complexObject.P7 = new byte[1024 * 64];\n\n Random random = new Random();\n random.NextBytes(complexObject.P7);\n\n complexObject.List1 = new List();\n complexObject.List1.Add(1);\n complexObject.List1.Add(2);\n complexObject.List1.Add(3);\n\n complexObject.List2 = new List();\n complexObject.List2.Add("1");\n complexObject.List2.Add("2");\n complexObject.List2.Add("3");\n\n complexObject.List3 = new List();\n complexObject.List3.Add(new byte[1024]);\n complexObject.List3.Add(new byte[1024]);\n complexObject.List3.Add(new byte[1024]);\n\n complexObject.Dic1 = new Dictionary();\n complexObject.Dic1.Add(1, 1);\n complexObject.Dic1.Add(2, 2);\n complexObject.Dic1.Add(3, 3);\n\n complexObject.Dic2 = new Dictionary();\n complexObject.Dic2.Add(1, "1");\n complexObject.Dic2.Add(2, "2");\n complexObject.Dic2.Add(3, "3");\n\n complexObject.Dic3 = new Dictionary();\n complexObject.Dic3.Add("1", "1");\n complexObject.Dic3.Add("2", "2");\n complexObject.Dic3.Add("3", "3");\n\n complexObject.Dic4 = new Dictionary();\n complexObject.Dic4.Add(1, new Arg(1));\n complexObject.Dic4.Add(2, new Arg(2));\n complexObject.Dic4.Add(3, new Arg(3));\n return complexObject;\n}\n')),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"[Benchmark]\npublic void JsonFast_ComplexObject()\n{\n var v = GetComplexObject();\n for (int i = 0; i < Count; i++)\n {\n var str = JsonFastConverter.JsonTo(v);\n var val = JsonFastConverter.JsonFrom(str);\n }\n}\n")),(0,r.kt)("p",null,"\u4e0b\u56fe\u4e3a100\u6b21\u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5316\uff0cJsonFast\u6027\u80fd\u7a0d\u5f31\uff0c\u4f46\u662f\u57fa\u672c\u6ee1\u8db3\u8981\u6c42\u3002\n",(0,r.kt)("img",{alt:"image.png",src:n(7078).Z,width:"1262",height:"188"})))}m.isMDXComponent=!0},5229:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/jsonserialize-1-a32327fa8972eacb38ae1e5930655a90.png"},7078:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/jsonserialize-2-c45920c130f4a3cedcaad54fb9d8a389.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/935f2afb.f357c15a.js b/handbook/build/assets/js/935f2afb.f357c15a.js new file mode 100644 index 000000000..9e36034ac --- /dev/null +++ b/handbook/build/assets/js/935f2afb.f357c15a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"docs":[{"type":"link","label":"01\u3001\u8bf4\u660e\uff08\u4f7f\u7528\u524d\u5fc5\u8981\u9605\u8bfb\uff09","href":"/touchsocket/docs/","docId":"description"},{"type":"link","label":"02\u3001\u5386\u53f2\u66f4\u65b0","href":"/touchsocket/docs/upgrade","docId":"upgrade"},{"type":"category","label":"03\u3001\u652f\u6301\u4f5c\u8005\u53ca\u5546\u4e1a\u8fd0\u8425","items":[{"type":"link","label":"3.1 \u652f\u6301\u4f5c\u8005","href":"/touchsocket/docs/donate","docId":"donate"},{"type":"link","label":"3.2 \u4f01\u4e1a\u7248\u76f8\u5173","href":"/touchsocket/docs/enterprise","docId":"enterprise"},{"type":"category","label":"3.3 \u5546\u4e1a\u9879\u76ee","items":[{"type":"link","label":"a.\u5546\u4e1a\u5408\u4f5c","href":"/touchsocket/docs/cooperation","docId":"cooperation"},{"type":"link","label":"b.WPF\u754c\u9762\u3001\u6587\u4ef6\u4f20\u8f93\u9879\u76ee","href":"/touchsocket/docs/wpfuifiletransfer","docId":"wpfuifiletransfer"},{"type":"link","label":"c.\u8fdc\u7a0b\u76d1\u6d4b\u3001\u63a7\u5236\u9879\u76ee","href":"/touchsocket/docs/remotemonitoring","docId":"remotemonitoring"},{"type":"link","label":"d.\u6587\u4ef6\u540c\u6b65\u7cfb\u7edf","href":"/touchsocket/docs/filesynchronization","docId":"filesynchronization"},{"type":"link","label":"e.\u6570\u636e\u8f6c\u53d1\u9879\u76ee","href":"/touchsocket/docs/dataforwarding","docId":"dataforwarding"},{"type":"link","label":"f.Web\u6570\u636e\u8f6c\u53d1Winform\u9879\u76ee","href":"/touchsocket/docs/webdataforwarding","docId":"webdataforwarding"}],"collapsed":true,"collapsible":true},{"type":"category","label":"3.4 \u4f7f\u7528\u8005\u9879\u76ee","items":[{"type":"link","label":"a.FPS\u5b9e\u65f6\u6e38\u620f","href":"/touchsocket/docs/fpsgame","docId":"fpsgame"},{"type":"link","label":"b.\u5de5\u7a0b\u5e08\u8f6f\u4ef6\u5de5\u5177\u7bb1","href":"/touchsocket/docs/engineertoolbox","docId":"engineertoolbox"}],"collapsed":true,"collapsible":true}],"collapsed":true,"collapsible":true},{"type":"link","label":"04\u3001\u5165\u95e8\u6307\u5357","href":"/touchsocket/docs/startguide","docId":"startguide"},{"type":"category","label":"05\u3001Core","items":[{"type":"link","label":"5.1 \u5185\u5b58\u6c60","href":"/touchsocket/docs/bytepool","docId":"bytepool"},{"type":"link","label":"5.2 \u63a7\u5236\u53f0\u884c\u4e3a","href":"/touchsocket/docs/consoleaction","docId":"consoleaction"},{"type":"link","label":"5.3 \u5927\u5c0f\u7aef\u8f6c\u6362\u5668","href":"/touchsocket/docs/touchsocketbitconverter","docId":"touchsocketbitconverter"},{"type":"link","label":"5.4 \u6570\u636e\u52a0\u5bc6","href":"/touchsocket/docs/datasecurity","docId":"datasecurity"},{"type":"link","label":"5.5 \u65e5\u5fd7\u8bb0\u5f55\u5668","href":"/touchsocket/docs/ilog","docId":"ilog"},{"type":"link","label":"5.6 \u5e94\u7528\u4fe1\u4f7f","href":"/touchsocket/docs/appmessenger","docId":"appmessenger"},{"type":"link","label":"5.7 \u9ad8\u6027\u80fd\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316","href":"/touchsocket/docs/fastbinaryformatter","docId":"fastbinaryformatter"},{"type":"link","label":"5.8 Json\u5e8f\u5217\u5316","href":"/touchsocket/docs/jsonserialize","docId":"jsonserialize"},{"type":"link","label":"5.9 \u4f9d\u8d56\u6ce8\u5165\u5bb9\u5668","href":"/touchsocket/docs/ioc","docId":"ioc"},{"type":"link","label":"5.10 \u4f9d\u8d56\u5c5e\u6027","href":"/touchsocket/docs/dependencyproperty","docId":"dependencyproperty"},{"type":"link","label":"5.11 \u6587\u4ef6\u6d41\u6c60","href":"/touchsocket/docs/filepool","docId":"filepool"},{"type":"link","label":"5.12 \u63d2\u4ef6\u7cfb\u7edf","href":"/touchsocket/docs/pluginsmanager","docId":"pluginsmanager"},{"type":"link","label":"5.13 \u5305\u5e8f\u5217\u5316\u6a21\u5f0f","href":"/touchsocket/docs/ipackage","docId":"ipackage"},{"type":"link","label":"5.14 \u5176\u4ed6\u76f8\u5173\u529f\u80fd\u7c7b","href":"/touchsocket/docs/othercore","docId":"othercore"}],"collapsed":true,"collapsible":true},{"type":"category","label":"06\u3001Tcp\u7ec4\u4ef6","items":[{"type":"link","label":"6.1 \u521b\u5efaTcpService","href":"/touchsocket/docs/createtcpservice","docId":"createtcpservice"},{"type":"link","label":"6.2 \u521b\u5efaTcpClient","href":"/touchsocket/docs/createtcpclient","docId":"createtcpclient"},{"type":"link","label":"6.3 \u540c\u6b65\u8bf7\u6c42","href":"/touchsocket/docs/waitingclient","docId":"waitingclient"},{"type":"link","label":"6.4 Tcp\u7aef\u53e3\u8f6c\u53d1","href":"/touchsocket/docs/natservice","docId":"natservice"},{"type":"link","label":"6.5 \u670d\u52a1\u5668\u91cd\u7f6eID","href":"/touchsocket/docs/resetid","docId":"resetid"},{"type":"link","label":"6.6 \u65ad\u7ebf\u91cd\u8fde","href":"/touchsocket/docs/reconnection","docId":"reconnection"},{"type":"link","label":"6.7 \u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6","href":"/touchsocket/docs/tcpcommandlineplugin","docId":"tcpcommandlineplugin"},{"type":"link","label":"6.8 \u5fc3\u8df3\u8bbe\u8ba1","href":"/touchsocket/docs/heartbeat","docId":"heartbeat"},{"type":"link","label":"6.9 \u5176\u4ed6\u573a\u666f\u5e94\u7528","href":"/touchsocket/docs/tcpother","docId":"tcpother"}],"collapsed":true,"collapsible":true},{"type":"category","label":"07\u3001Udp\u7ec4\u4ef6","items":[{"type":"link","label":"7.1 \u521b\u5efaUdpSession","href":"/touchsocket/docs/createudpsession","docId":"createudpsession"},{"type":"link","label":"7.2 \u4f20\u8f93\u5927\u4e8e64K\u7684\u6570\u636e","href":"/touchsocket/docs/udptransmitbigdata","docId":"udptransmitbigdata"},{"type":"link","label":"7.3 \u7ec4\u64ad\u3001\u5e7f\u64ad","href":"/touchsocket/docs/udpbroadcast","docId":"udpbroadcast"}],"collapsed":true,"collapsible":true},{"type":"category","label":"08\u3001\u6570\u636e\u5904\u7406\u9002\u914d\u5668","items":[{"type":"link","label":"8.1 \u4ecb\u7ecd\u53ca\u4f7f\u7528","href":"/touchsocket/docs/adapterdescription","docId":"adapterdescription"},{"type":"category","label":"8.2 Tcp\u9002\u914d\u5668","items":[{"type":"link","label":"a.\u6b63\u5e38\u6570\u636e\u5904\u7406\u9002\u914d\u5668","href":"/touchsocket/docs/normaldatahandlingadapter","docId":"normaldatahandlingadapter"},{"type":"link","label":"b.\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668","href":"/touchsocket/docs/fixedheaderpackageadapter","docId":"fixedheaderpackageadapter"},{"type":"link","label":"c.\u56fa\u5b9a\u957f\u5ea6\u6570\u636e\u5904\u7406\u9002\u914d\u5668","href":"/touchsocket/docs/fixedsizepackageadapter","docId":"fixedsizepackageadapter"},{"type":"link","label":"d.\u7ec8\u6b62\u56e0\u5b50\u6570\u636e\u5904\u7406\u9002\u914d\u5668","href":"/touchsocket/docs/terminatorpackageadapter","docId":"terminatorpackageadapter"},{"type":"link","label":"e.\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668","href":"/touchsocket/docs/datahandleadapter","docId":"datahandleadapter"},{"type":"link","label":"f.\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668","href":"/touchsocket/docs/customdatahandlingadapter","docId":"customdatahandlingadapter"},{"type":"link","label":"g.\u6a21\u677f\u89e3\u6790\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668","href":"/touchsocket/docs/customfixedheaderdatahandlingadapter","docId":"customfixedheaderdatahandlingadapter"},{"type":"link","label":"h.\u6a21\u677f\u89e3\u6790\u975e\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668","href":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","docId":"customunfixedheaderdatahandlingadapter"},{"type":"link","label":"i.\u6a21\u677f\u89e3\u6790\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668","href":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","docId":"bigfixedheadercustomdatahandlingadapter"},{"type":"link","label":"j.\u6a21\u677f\u89e3\u6790\u533a\u95f4\u6570\u636e\u9002\u914d\u5668","href":"/touchsocket/docs/custombetweenanddatahandlingadapter","docId":"custombetweenanddatahandlingadapter"},{"type":"link","label":"k.Pipeline\u6570\u636e\u9002\u914d\u5668","href":"/touchsocket/docs/pipelinedatahandlingadapter","docId":"pipelinedatahandlingadapter"},{"type":"link","label":"l.\u4e09\u5143\u7ec4\u7f16\u7801TLV\u9002\u914d\u5668","href":"/touchsocket/docs/tlvdatahandlingadapter","docId":"tlvdatahandlingadapter"}],"collapsed":true,"collapsible":true},{"type":"category","label":"8.3 Udp\u9002\u914d\u5668","items":[{"type":"link","label":"a.\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668","href":"/touchsocket/docs/udpdatahandlingadapter","docId":"udpdatahandlingadapter"}],"collapsed":true,"collapsible":true},{"type":"category","label":"8.4 \u9002\u914d\u5668\u6848\u4f8b\u8d4f\u6790","items":[{"type":"link","label":"a.\u8bf4\u660e","href":"/touchsocket/docs/adapterdemodescription","docId":"adapterdemodescription"},{"type":"link","label":"b.\u56fd\u7f51\u8f93\u7535i1\u6807\u51c6\u7248","href":"/touchsocket/docs/stategridtransmission","docId":"stategridtransmission"}],"collapsed":true,"collapsible":true},{"type":"link","label":"8.5 \u72ec\u7acb\u4f7f\u7528\u9002\u914d\u5668","href":"/touchsocket/docs/independentusedatahandlingadapter","docId":"independentusedatahandlingadapter"},{"type":"link","label":"8.5 \u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5","href":"/touchsocket/docs/dataadaptertester","docId":"dataadaptertester"}],"collapsed":true,"collapsible":true},{"type":"category","label":"09\u3001Http\u7ec4\u4ef6","items":[{"type":"link","label":"9.1 \u521b\u5efaHttpService","href":"/touchsocket/docs/createhttpservice","docId":"createhttpservice"},{"type":"link","label":"9.2 \u521b\u5efaHttpClient","href":"/touchsocket/docs/createhttpclient","docId":"createhttpclient"},{"type":"link","label":"9.3 \u9759\u6001\u9875\u9762\u63d2\u4ef6","href":"/touchsocket/docs/httpstaticpageplugin","docId":"httpstaticpageplugin"},{"type":"link","label":"9.4 \u6587\u4ef6\u4f20\u8f93","href":"/touchsocket/docs/httpfiletransfer","docId":"httpfiletransfer"}],"collapsed":true,"collapsible":true},{"type":"category","label":"10\u3001WebSocket\u7ec4\u4ef6","items":[{"type":"link","label":"10.1 \u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","href":"/touchsocket/docs/websocketdescription","docId":"websocketdescription"},{"type":"link","label":"10.2 \u521b\u5efaWebSocket\u670d\u52a1\u5668","href":"/touchsocket/docs/createwebsocketservice","docId":"createwebsocketservice"},{"type":"link","label":"10.3 \u521b\u5efaWebSocket\u5ba2\u6237\u7aef","href":"/touchsocket/docs/createwebsocketclient","docId":"createwebsocketclient"},{"type":"link","label":"10.4 WSCommandLinePlugin","href":"/touchsocket/docs/wscommandlineplugin","docId":"wscommandlineplugin"},{"type":"link","label":"10.5 \u57fa\u4e8eWS\u7684JsonRpc","href":"/touchsocket/docs/wsjsonrpc","docId":"wsjsonrpc"}],"collapsed":true,"collapsible":true},{"type":"category","label":"11\u3001TouchRpc\u7ec4\u4ef6","items":[{"type":"link","label":"11.1 \u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","href":"/touchsocket/docs/touchrpcdescription","docId":"touchrpcdescription"},{"type":"link","label":"11.2 \u521b\u5efaTouchRpc\u670d\u52a1\u5668","href":"/touchsocket/docs/createtouchrpcservice","docId":"createtouchrpcservice"},{"type":"link","label":"11.3 \u521b\u5efaTouchRpc\u5ba2\u6237\u7aef","href":"/touchsocket/docs/createtouchrpcclient","docId":"createtouchrpcclient"},{"type":"link","label":"11.4 \u57fa\u7840\u529f\u80fd","href":"/touchsocket/docs/touchrpcbase","docId":"touchrpcbase"},{"type":"category","label":"11.5 Rpc\u529f\u80fd","items":[{"type":"link","label":"a.\u521b\u5efa\u3001\u8c03\u7528rpc\u670d\u52a1","href":"/touchsocket/docs/createandcallrpc","docId":"createandcallrpc"},{"type":"link","label":"b.Rpc\u5927\u6570\u636e\u6d41\u5f0f\u4f20\u8f93","href":"/touchsocket/docs/rpcstream","docId":"rpcstream"},{"type":"link","label":"c.\u8c03\u7528\u914d\u7f6e","href":"/touchsocket/docs/rpcoption","docId":"rpcoption"},{"type":"link","label":"d.\u5e8f\u5217\u5316\u9009\u62e9\u5668","href":"/touchsocket/docs/serializationselector","docId":"serializationselector"},{"type":"link","label":"e.\u8c03\u7528\u4e0a\u4e0b\u6587","href":"/touchsocket/docs/rpcallcontext","docId":"rpcallcontext"},{"type":"link","label":"f.Rpc\u670d\u52a1AOP","href":"/touchsocket/docs/rpcactionfilter","docId":"rpcactionfilter"},{"type":"link","label":"f.\u751f\u6210\u3001\u83b7\u53d6\u4ee3\u7406","href":"/touchsocket/docs/generateproxy","docId":"generateproxy"}],"collapsed":true,"collapsible":true},{"type":"category","label":"11.6 \u6587\u4ef6\u4f20\u8f93","items":[{"type":"link","label":"a.\u4f20\u8f93\u6587\u4ef6","href":"/touchsocket/docs/transferfile","docId":"transferfile"},{"type":"link","label":"c.\u5c0f\u6587\u4ef6\u4f20\u8f93","href":"/touchsocket/docs/smallfiletransfer","docId":"smallfiletransfer"},{"type":"link","label":"c.\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93","href":"/touchsocket/docs/multithreadingfiletransfer","docId":"multithreadingfiletransfer"}],"collapsed":true,"collapsible":true},{"type":"link","label":"11.7 \u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c","href":"/touchsocket/docs/remotefilecontrol","docId":"remotefilecontrol"},{"type":"link","label":"11.8 Stream\u4f20\u8f93","href":"/touchsocket/docs/streamtransfer","docId":"streamtransfer"},{"type":"link","label":"11.9 \u8fdc\u7a0b\u6d41\u8bbf\u95ee","href":"/touchsocket/docs/remotestreamaccess","docId":"remotestreamaccess"},{"type":"link","label":"11.10 EventBus","href":"/touchsocket/docs/eventbus","docId":"eventbus"}],"collapsed":true,"collapsible":true},{"type":"category","label":"12\u3001WebApi\u7ec4\u4ef6","items":[{"type":"link","label":"12.1 \u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","href":"/touchsocket/docs/webapidescription","docId":"webapidescription"},{"type":"link","label":"12.2 \u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1","href":"/touchsocket/docs/webapiservice","docId":"webapiservice"},{"type":"link","label":"12.3 \u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1","href":"/touchsocket/docs/callwebapi","docId":"callwebapi"}],"collapsed":true,"collapsible":true},{"type":"category","label":"13\u3001JsonRpc\u7ec4\u4ef6","items":[{"type":"link","label":"13.1 \u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","href":"/touchsocket/docs/jsonrpcdescription","docId":"jsonrpcdescription"},{"type":"link","label":"13.2 \u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1","href":"/touchsocket/docs/jsonrpcservice","docId":"jsonrpcservice"},{"type":"link","label":"13.3 \u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1","href":"/touchsocket/docs/calljsonrpc","docId":"calljsonrpc"}],"collapsed":true,"collapsible":true},{"type":"category","label":"14\u3001XmlRpc\u7ec4\u4ef6\u4ef6","items":[{"type":"link","label":"14.1 \u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","href":"/touchsocket/docs/xmlrpcdescription","docId":"xmlrpcdescription"},{"type":"link","label":"14.2 \u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1","href":"/touchsocket/docs/xmlrpcservice","docId":"xmlrpcservice"},{"type":"link","label":"14.3 \u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1","href":"/touchsocket/docs/callxmlrpc","docId":"callxmlrpc"}],"collapsed":true,"collapsible":true}]},"docs":{"adapterdemodescription":{"id":"adapterdemodescription","title":"\u8bf4\u660e","description":"\u8bf4\u660e","sidebar":"docs"},"adapterdescription":{"id":"adapterdescription","title":"\u4ecb\u7ecd\u53ca\u4f7f\u7528","description":"\u8bf4\u660e","sidebar":"docs"},"appmessenger":{"id":"appmessenger","title":"\u5e94\u7528\u4fe1\u4f7f","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"bigfixedheadercustomdatahandlingadapter":{"id":"bigfixedheadercustomdatahandlingadapter","title":"\u6a21\u677f\u89e3\u6790\u201c\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"bytepool":{"id":"bytepool","title":"\u5185\u5b58\u6c60","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"calljsonrpc":{"id":"calljsonrpc","title":"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1","description":"\u4e00\u3001\u76f4\u63a5\u8c03\u7528","sidebar":"docs"},"callwebapi":{"id":"callwebapi","title":"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1","description":"\u76f4\u63a5\u8c03\u7528","sidebar":"docs"},"callxmlrpc":{"id":"callxmlrpc","title":"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1","description":"\u76f4\u63a5\u8c03\u7528","sidebar":"docs"},"consoleaction":{"id":"consoleaction","title":"\u63a7\u5236\u53f0\u884c\u4e3a","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"cooperation":{"id":"cooperation","title":"\u5546\u4e1a\u5408\u4f5c","description":"RRQM\u627f\u63a5WPF\u53ca\u7f51\u7edc\u901a\u4fe1\u76f8\u5173\u7684\u5f00\u53d1\u4efb\u52a1\u3002\u4ef7\u683c\u8be6\u60c5\u54a8\u8be2\u82e5\u6c5d\u68cb\u8317\u3002QQ\uff1a505554090","sidebar":"docs"},"createandcallrpc":{"id":"createandcallrpc","title":"\u521b\u5efarpc\u670d\u52a1","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"createhttpclient":{"id":"createhttpclient","title":"\u521b\u5efaHttpClient","description":"\u8bf4\u660e","sidebar":"docs"},"createhttpservice":{"id":"createhttpservice","title":"\u521b\u5efaHttpService","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"createtcpclient":{"id":"createtcpclient","title":"\u521b\u5efaTcpClient","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"createtcpservice":{"id":"createtcpservice","title":"\u521b\u5efaTcpService","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"createtouchrpcclient":{"id":"createtouchrpcclient","title":"\u521b\u5efaTouchRpc\u5ba2\u6237\u7aef","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"createtouchrpcservice":{"id":"createtouchrpcservice","title":"\u521b\u5efaTouchRpc\u670d\u52a1\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"createudpsession":{"id":"createudpsession","title":"\u521b\u5efaUdpSession","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"createwebsocketclient":{"id":"createwebsocketclient","title":"\u521b\u5efaWebSocket\u5ba2\u6237\u7aef","description":"\u8bf4\u660e","sidebar":"docs"},"createwebsocketservice":{"id":"createwebsocketservice","title":"\u521b\u5efaWebSocket\u670d\u52a1\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"custombetweenanddatahandlingadapter":{"id":"custombetweenanddatahandlingadapter","title":"\u6a21\u677f\u89e3\u6790\u201c\u533a\u95f4\u6570\u636e\u201d\u6570\u636e\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"customdatahandlingadapter":{"id":"customdatahandlingadapter","title":"\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"customfixedheaderdatahandlingadapter":{"id":"customfixedheaderdatahandlingadapter","title":"\u6a21\u677f\u89e3\u6790\u201c\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"customunfixedheaderdatahandlingadapter":{"id":"customunfixedheaderdatahandlingadapter","title":"\u6a21\u677f\u89e3\u6790\u201c\u975e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"dataadaptertester":{"id":"dataadaptertester","title":"\u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"dataforwarding":{"id":"dataforwarding","title":"\u6570\u636e\u8f6c\u53d1\u9879\u76ee","description":"\u5b9a\u5236\u65b9","sidebar":"docs"},"datahandleadapter":{"id":"datahandleadapter","title":"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668","description":"\u8bf4\u660e","sidebar":"docs"},"datasecurity":{"id":"datasecurity","title":"\u6570\u636e\u52a0\u5bc6","description":"\u4e00\u30013DES","sidebar":"docs"},"dependencyproperty":{"id":"dependencyproperty","title":"\u4f9d\u8d56\u5c5e\u6027","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"description":{"id":"description","title":"\u8bf4\u660e","description":"\u5f53\u524d\u7248\u672c","sidebar":"docs"},"donate":{"id":"donate","title":"\u652f\u6301\u4f5c\u8005","description":"\u8d5e\u52a9TouchSocket\u9879\u76ee","sidebar":"docs"},"engineertoolbox":{"id":"engineertoolbox","title":"\u5de5\u7a0b\u5e08\u8f6f\u4ef6\u5de5\u5177\u7bb1","description":"\u8bf4\u660e","sidebar":"docs"},"enterprise":{"id":"enterprise","title":"\u4f01\u4e1a\u7248\u76f8\u5173","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"eventbus":{"id":"eventbus","title":"EventBus","description":"\u8bf4\u660e","sidebar":"docs"},"fastbinaryformatter":{"id":"fastbinaryformatter","title":"\u9ad8\u6027\u80fd\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"filepool":{"id":"filepool","title":"\u6587\u4ef6\u6d41\u6c60","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"filesynchronization":{"id":"filesynchronization","title":"\u6587\u4ef6\u540c\u6b65\u7cfb\u7edf","description":"\u5b9a\u5236\u65b9","sidebar":"docs"},"fixedheaderpackageadapter":{"id":"fixedheaderpackageadapter","title":"\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"fixedsizepackageadapter":{"id":"fixedsizepackageadapter","title":"\u56fa\u5b9a\u957f\u5ea6\u6570\u636e\u5904\u7406\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"fpsgame":{"id":"fpsgame","title":"FPS\u5b9e\u65f6\u6e38\u620f","description":"B\u7ad9\u9996\u9875","sidebar":"docs"},"generateproxy":{"id":"generateproxy","title":"\u751f\u6210\u3001\u83b7\u53d6\u4ee3\u7406","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"heartbeat":{"id":"heartbeat","title":"\u5fc3\u8df3\u8bbe\u8ba1","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"httpfiletransfer":{"id":"httpfiletransfer","title":"\u6587\u4ef6\u4f20\u8f93","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"httpstaticpageplugin":{"id":"httpstaticpageplugin","title":"\u9759\u6001\u9875\u9762\u63d2\u4ef6","description":"\u9759\u6001\u7f51\u9875\u6258\u7ba1\u63d2\u4ef6\u4ec5\u670d\u52a1\u5668\u652f\u6301","sidebar":"docs"},"ilog":{"id":"ilog","title":"\u65e5\u5fd7\u8bb0\u5f55\u5668","description":"\u4e00\u3001\u65e5\u5fd7\u8bb0\u5f55\u63a5\u53e3\uff08ILog\uff09","sidebar":"docs"},"independentusedatahandlingadapter":{"id":"independentusedatahandlingadapter","title":"\u72ec\u7acb\u4f7f\u7528\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"ioc":{"id":"ioc","title":"\u4f9d\u8d56\u6ce8\u5165\u5bb9\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"ipackage":{"id":"ipackage","title":"\u5305\u5e8f\u5217\u5316\u6a21\u5f0f","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"jsonrpcdescription":{"id":"jsonrpcdescription","title":"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"jsonrpcservice":{"id":"jsonrpcservice","title":"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1","description":"\u4e00\u3001\u5b9a\u4e49\u670d\u52a1","sidebar":"docs"},"jsonserialize":{"id":"jsonserialize","title":"Json\u5e8f\u5217\u5316","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"multithreadingfiletransfer":{"id":"multithreadingfiletransfer","title":"\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93","description":"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248","sidebar":"docs"},"natservice":{"id":"natservice","title":"Tcp\u7aef\u53e3\u8f6c\u53d1","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"normaldatahandlingadapter":{"id":"normaldatahandlingadapter","title":"a.\u6b63\u5e38\u6570\u636e\u5904\u7406\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"othercore":{"id":"othercore","title":"\u5176\u4ed6\u76f8\u5173\u529f\u80fd\u7c7b","description":"\u4e00\u3001Crc\u8ba1\u7b97","sidebar":"docs"},"pipelinedatahandlingadapter":{"id":"pipelinedatahandlingadapter","title":"Pipeline\u6570\u636e\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"pluginsmanager":{"id":"pluginsmanager","title":"\u63d2\u4ef6\u7cfb\u7edf","description":"\u8bf4\u660e","sidebar":"docs"},"reconnection":{"id":"reconnection","title":"\u65ad\u7ebf\u91cd\u8fde","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"remotefilecontrol":{"id":"remotefilecontrol","title":"\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c","description":"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248","sidebar":"docs"},"remotemonitoring":{"id":"remotemonitoring","title":"\u8fdc\u7a0b\u76d1\u6d4b\u3001\u63a7\u5236\u9879\u76ee","description":"\u5b9a\u5236\u65b9","sidebar":"docs"},"remotestreamaccess":{"id":"remotestreamaccess","title":"b.\u8fdc\u7a0b\u6d41\u8bbf\u95ee","description":"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248","sidebar":"docs"},"resetid":{"id":"resetid","title":"\u670d\u52a1\u5668\u91cd\u7f6eID","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"rpcactionfilter":{"id":"rpcactionfilter","title":"Rpc\u670d\u52a1AOP","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"rpcallcontext":{"id":"rpcallcontext","title":"\u8c03\u7528\u4e0a\u4e0b\u6587","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"rpcoption":{"id":"rpcoption","title":"\u8c03\u7528\u914d\u7f6e","description":"\u4e00\u3001\u8c03\u7528\u53cd\u9988\u7c7b\u578b","sidebar":"docs"},"rpcstream":{"id":"rpcstream","title":"Rpc\u5927\u6570\u636e\u6d41\u5f0f\u4f20\u8f93","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"serializationselector":{"id":"serializationselector","title":"\u5e8f\u5217\u5316\u9009\u62e9\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"smallfiletransfer":{"id":"smallfiletransfer","title":"\u5c0f\u6587\u4ef6\u4f20\u8f93","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"startguide":{"id":"startguide","title":"\u5165\u95e8\u6307\u5357","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"stategridtransmission":{"id":"stategridtransmission","title":"\u56fd\u7f51\u8f93\u7535i1\u6807\u51c6\u7248","description":"\u8bf4\u660e","sidebar":"docs"},"streamtransfer":{"id":"streamtransfer","title":"Stream\u4f20\u8f93","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"tcpcommandlineplugin":{"id":"tcpcommandlineplugin","title":"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"tcpother":{"id":"tcpother","title":"\u5176\u4ed6\u573a\u666f\u5e94\u7528","description":"- C# TCP\u5982\u4f55\u9650\u5236\u5355\u4e2a\u5ba2\u6237\u7aef\u7684\u8bbf\u95ee\u6d41\u91cf","sidebar":"docs"},"terminatorpackageadapter":{"id":"terminatorpackageadapter","title":"\u7ec8\u6b62\u56e0\u5b50\u5206\u5272\u6570\u636e\u5904\u7406\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"tlvdatahandlingadapter":{"id":"tlvdatahandlingadapter","title":"\u4e09\u5143\u7ec4\u7f16\u7801\uff08TLV\uff09\u9002\u914d\u5668","description":"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248","sidebar":"docs"},"touchrpcbase":{"id":"touchrpcbase","title":"\u57fa\u7840\u529f\u80fd","description":"\u4e00\u3001\u8fde\u63a5\u9a8c\u8bc1","sidebar":"docs"},"touchrpcdescription":{"id":"touchrpcdescription","title":"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"touchsocketbitconverter":{"id":"touchsocketbitconverter","title":"\u5927\u5c0f\u7aef\u8f6c\u6362\u5668","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"transferfile":{"id":"transferfile","title":"\u4f20\u8f93\u6587\u4ef6","description":"\u6f14\u793a\uff1a \u53ef\u4ee5\u770b\u5230\uff0c\u4e0b\u56fe\u6b63\u5728\u4e0a\u4f20\u4e00\u4e2aWindow\u7684\u7cfb\u7edf\u955c\u50cf\u6587\u4ef6\uff0c\u5927\u7ea64.2Gb\uff0c\u4f20\u8f93\u901f\u5ea6\u5df2\u8fbe\u5230800Mb/s\uff0cGC\u57fa\u672c\u4e0a\u6ca1\u6709\u91ca\u653e\uff0c\u6027\u80fd\u975e\u5e38\u5f3a\u608d\uff08\u4e2d\u95f4\u6709\u7a0d\u5fae\u505c\u987f\uff0c\u56e0\u4e3a\u7a0b\u5e8f\u5728\u83b7\u53d6\u6587\u4ef6MD5\u503c\uff09\u3002","sidebar":"docs"},"udpbroadcast":{"id":"udpbroadcast","title":"\u7ec4\u64ad\u3001\u5e7f\u64ad","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"udpdatahandlingadapter":{"id":"udpdatahandlingadapter","title":"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668","description":"\u8bf4\u660e","sidebar":"docs"},"udptransmitbigdata":{"id":"udptransmitbigdata","title":"\u4f20\u8f93\u5927\u4e8e64K\u7684\u6570\u636e","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"upgrade":{"id":"upgrade","title":"\u5386\u53f2\u66f4\u65b0","description":"\u5347\u7ea7\u524d\u91cd\u70b9\u5173\u6ce8\u53ef\u80fd\u9020\u6210\u3010\u7834\u574f\u6027\u3011\u7684\u6807\u7b7e\u7c7b\u578b\uff1a\u4fee\u590d\u3001\u8c03\u6574\u3001\u79fb\u9664\u3001\u5347\u7ea7","sidebar":"docs"},"waitingclient":{"id":"waitingclient","title":"\u540c\u6b65\u8bf7\u6c42","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"webapidescription":{"id":"webapidescription","title":"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","description":"\u4e00\u3001\u8bf4\u660e","sidebar":"docs"},"webapiservice":{"id":"webapiservice","title":"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1","description":"\u5b9a\u4e49\u670d\u52a1","sidebar":"docs"},"webdataforwarding":{"id":"webdataforwarding","title":"Web\u6570\u636e\u8f6c\u53d1Winform\u9879\u76ee","description":"\u5b9a\u5236\u65b9","sidebar":"docs"},"websocketdescription":{"id":"websocketdescription","title":"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","description":"\u4ea7\u54c1\u4ecb\u7ecd","sidebar":"docs"},"wpfuifiletransfer":{"id":"wpfuifiletransfer","title":"WPF\u754c\u9762\u3001\u6587\u4ef6\u4f20\u8f93\u9879\u76ee","description":"\u5b9a\u5236\u65b9","sidebar":"docs"},"wscommandlineplugin":{"id":"wscommandlineplugin","title":"WSCommandLinePlugin","description":"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6\u5ba2\u6237\u7aef\u3001\u670d\u52a1\u5668\u5747\u652f\u6301","sidebar":"docs"},"wsjsonrpc":{"id":"wsjsonrpc","title":"\u57fa\u4e8eWS\u7684JsonRpc","description":"","sidebar":"docs"},"xmlrpcdescription":{"id":"xmlrpcdescription","title":"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd","description":"XmlRpc\u662f\u901a\u7528\u7684\u5de5\u4f5c\u5728Internet\u4e0a\u7684RPC\u3002\u4e00\u4e2aXML-RPC\u6d88\u606f\u5c31\u662f\u4e00\u4e2a\u8bf7\u6c42\u4f53\u4e3axml\u7684http-post\u8bf7\u6c42\uff0c\u88ab\u8c03\u7528\u7684\u65b9\u6cd5\u5728\u670d\u52a1\u5668\u7aef\u6267\u884c\u5e76\u5c06\u6267\u884c\u7ed3\u679c\u4ee5xml\u683c\u5f0f\u7f16\u7801\u540e\u8fd4\u56de\u3002\u8fd9\u4e0e\u7f16\u7a0b\u8bed\u8a00\u65e0\u5173\uff0c\u4e0e\u64cd\u4f5c\u7cfb\u7edf\u65e0\u5173\u3002\u5728RRQM\u4e2d\u5c01\u88c5\u4e86\u524d\u540e\u7aef\uff0c\u4f7f\u5176\u4f7f\u7528\u66f4\u52a0\u65b9\u4fbf\u3001\u9ad8\u6548\u3002","sidebar":"docs"},"xmlrpcservice":{"id":"xmlrpcservice","title":"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1","description":"\u5b9a\u4e49\u670d\u52a1","sidebar":"docs"}}}')}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/94601e7d.5d94be73.js b/handbook/build/assets/js/94601e7d.5d94be73.js new file mode 100644 index 000000000..a3f275930 --- /dev/null +++ b/handbook/build/assets/js/94601e7d.5d94be73.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7278],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>f});var n=r(7294);function l(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(l[r]=e[r]);return l}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(l[r]=e[r])}return l}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},u=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,l=e.mdxType,a=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),m=s(r),f=l,d=m["".concat(c,".").concat(f)]||m[f]||p[f]||a;return r?n.createElement(d,o(o({ref:t},u),{},{components:r})):n.createElement(d,o({ref:t},u))}));function f(e,t){var r=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var a=r.length,o=new Array(a);o[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:l,o[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>a,metadata:()=>i,toc:()=>s});var n=r(7462),l=(r(7294),r(3905));const a={id:"smallfiletransfer",title:"\u5c0f\u6587\u4ef6\u4f20\u8f93"},o=void 0,i={unversionedId:"smallfiletransfer",id:"smallfiletransfer",title:"\u5c0f\u6587\u4ef6\u4f20\u8f93",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/smallfiletransfer.mdx",sourceDirName:".",slug:"/smallfiletransfer",permalink:"/touchsocket/docs/smallfiletransfer",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/smallfiletransfer.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"smallfiletransfer",title:"\u5c0f\u6587\u4ef6\u4f20\u8f93"},sidebar:"docs",previous:{title:"\u4f20\u8f93\u6587\u4ef6",permalink:"/touchsocket/docs/transferfile"},next:{title:"\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93",permalink:"/touchsocket/docs/multithreadingfiletransfer"}},c={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4f7f\u7528",id:"\u4e8c\u4f7f\u7528",level:2},{value:"\u4e09\u3001\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93",id:"\u4e09\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93",level:2}],u={toc:s};function p(e){let{components:t,...r}=e;return(0,l.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("a",{name:"jyzSl"}),(0,l.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,l.kt)("p",null,"\u5c0f\u6587\u4ef6\u4f20\u8f93\u662f\u6307\uff0c\u5f53\u4f20\u8f93\u6587\u4ef6\u5c0f\u4e8e\u8bbe\u5b9a\u5927\u5c0f\uff08\u9ed8\u8ba41024*1024\u5b57\u8282\uff09\u65f6\u7684\u4f20\u8f93\u3002"),(0,l.kt)("p",null,"\u4e3a\u4ec0\u4e48\u8981\u8bbe\u7acb\u5c0f\u6587\u4ef6\u4f20\u8f93\uff1f\u4e0e\u5e38\u89c4\u6587\u4ef6\u4f20\u8f93\u76f8\u6bd4\uff0c\u4f18\u70b9\u5728\u54ea\u91cc\uff1f\n\u5e38\u89c4\u4f20\u8f93\uff0c\u5efa\u7acb\u4e00\u4e2a\u4f20\u8f93\u901a\u9053\uff0c\u5927\u7ea6\u9700\u8981\u4f20\u8f93\u4e24\u7aef\uff0c\u5f80\u8fd4\u901a\u4fe14-6\u6b21\u3002\u8fd9\u5728\u672c\u5730\u5c40\u57df\u7f51\u4e2d\uff0c\u663e\u5f97\u65e0\u6240\u8c13\u3002\u4f46\u662f\u5728\u4e92\u8054\u7f51\u73af\u5883\u4e2d\uff0c\u4e00\u6b21ping\u5ef6\u8fdf\u5e73\u574750ms\uff0c\u90a3\u4e48\u5efa\u7acb\u4e00\u4e2a\u4f20\u8f93\uff0c\u5c31\u5927\u7ea6\u9700\u8981200-300ms\u3002\u8fd9\u4e5f\u5c31\u610f\u5473\u7740\uff0c\u5373\u4f7f\u4e00\u4e2a\u6587\u4ef6\u53ea\u6709\u4e00\u5b57\u8282\uff0c\u4e5f\u9700\u8981\u8fd9\u4e9b\u65f6\u95f4\u3002\u6240\u4ee5\uff0c\u8fd9\u660e\u663e\u662f\u4e0d\u5408\u7406\u7684\u3002\u6240\u4ee5TouchRpc\u53c8\u65b0\u589e\u4e86\u5c0f\u6587\u4ef6\u4f20\u8f93\uff0c\u53ea\u8981\u6587\u4ef6\u57281Mb\u4ee5\u5185\uff0c\u4ec5\u5f80\u8fd41\u6b21\uff0c\u5c31\u53ef\u4ee5\u5b8c\u6210\u4f20\u8f93\u3002"),(0,l.kt)("p",null,"\u5f53\u7136\uff0c\u5bf9\u4e8e\u5c0f\u6587\u4ef6\u7684\u6700\u9ad8\u6548\u4f20\u8f93\u65b9\u5f0f\u4f9d\u7136\u662f\u5148\u538b\u7f29\uff0c\u540e\u4f20\u8f93\u7684\u65b9\u5f0f\u3002"),(0,l.kt)("a",{name:"m2KIr"}),(0,l.kt)("h2",{id:"\u4e8c\u4f7f\u7528"},"\u4e8c\u3001\u4f7f\u7528"),(0,l.kt)("p",null,"\u3010\u62c9\u53d6\u6587\u4ef6\u3011"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"\u76f4\u63a5\u8c03\u7528PullSmallFile\u6216\u8005PullSmallFileAsync\uff0c\u83b7\u53d6\u5230\u5b9e\u9645\u7684\u6587\u4ef6\u6570\u636e\u3002"),(0,l.kt)("li",{parentName:"ol"},"\u901a\u8fc7Save\u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5199\u5165\u6587\u4ef6\u3002\u4e5f\u53ef\u4ee5\u81ea\u884c\u4fdd\u5b58\u3002")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},"var result = await this.fileClient.PullSmallFileAsync(path);//\u62c9\u53d6\u6587\u4ef6\nvar saveResult = result.Save(savePath);//\u5c06\u62c9\u53d6\u7684\u6570\u636e\u8fdb\u884c\u4fdd\u5b58\u3002\n")),(0,l.kt)("p",null,"\u3010\u63a8\u9001\u6587\u4ef6\u3011"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"\u76f4\u63a5\u8c03\u7528PushSmallFile\u6216\u8005PushSmallFileAsync\u3002"),(0,l.kt)("li",{parentName:"ol"},"\u8fd4\u56de\u503c\u5373\u8868\u793a\u662f\u5426\u6210\u529f\u3002")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},"var result = await this.fileClient.PushSmallFileAsync(savePath, fileInfo);\nif (result.IsSuccess())\n{\n}\n")),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"\u5176\u4ed6\u53ef\u9009\u53c2\u6570\u53ef\u4ee5\u81ea\u5df1\u5b9a\u4e49\u3002")),(0,l.kt)("a",{name:"WMSzi"}),(0,l.kt)("h2",{id:"\u4e09\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93"},"\u4e09\u3001\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93"),(0,l.kt)("p",null,"\u8be5\u529f\u80fd\u4e5f\u652f\u6301\u5ba2\u6237\u7aef\u4e4b\u95f4\u4e92\u76f8\u4f20\u8f93\u3002\u4f7f\u7528\u65b9\u6cd5\u57fa\u672c\u4e00\u81f4\uff0c\u9700\u8981\u989d\u5916\u6307\u5b9a\u76ee\u6807Id\u5373\u53ef\u3002"),(0,l.kt)("p",null,"\u6b64\u5916\uff0c",(0,l.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u4e5f\u9700\u8981\u540c\u610f\u8def\u7531"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},"internal class MyTouchRpcPlugin : TouchRpcPluginBase\n{\n protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)\n {\n if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile)\n {\n e.IsPermitOperation = true;\n }\n base.OnRouting(client, e);\n }\n}\n")),(0,l.kt)("a",{name:"aFn83"}),(0,l.kt)("h2",{id:""}))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/94e3a799.9dad8103.js b/handbook/build/assets/js/94e3a799.9dad8103.js new file mode 100644 index 000000000..036ce81a5 --- /dev/null +++ b/handbook/build/assets/js/94e3a799.9dad8103.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7453],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>h});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function c(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var i=a.createContext({}),s=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},p=function(e){var n=s(e.components);return a.createElement(i.Provider,{value:n},e.children)},u={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),m=s(t),h=r,k=m["".concat(i,".").concat(h)]||m[h]||u[h]||l;return t?a.createElement(k,c(c({ref:n},p),{},{components:t})):a.createElement(k,c({ref:n},p))}));function h(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,c=new Array(l);c[0]=m;var o={};for(var i in n)hasOwnProperty.call(n,i)&&(o[i]=n[i]);o.originalType=e,o.mdxType="string"==typeof e?e:r,c[1]=o;for(var s=2;s{t.r(n),t.d(n,{assets:()=>i,contentTitle:()=>c,default:()=>u,frontMatter:()=>l,metadata:()=>o,toc:()=>s});var a=t(7462),r=(t(7294),t(3905));const l={id:"rpcstream",title:"Rpc\u5927\u6570\u636e\u6d41\u5f0f\u4f20\u8f93"},c=void 0,o={unversionedId:"rpcstream",id:"rpcstream",title:"Rpc\u5927\u6570\u636e\u6d41\u5f0f\u4f20\u8f93",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/rpcstream.mdx",sourceDirName:".",slug:"/rpcstream",permalink:"/touchsocket/docs/rpcstream",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/rpcstream.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"rpcstream",title:"Rpc\u5927\u6570\u636e\u6d41\u5f0f\u4f20\u8f93"},sidebar:"docs",previous:{title:"\u521b\u5efarpc\u670d\u52a1",permalink:"/touchsocket/docs/createandcallrpc"},next:{title:"\u8c03\u7528\u914d\u7f6e",permalink:"/touchsocket/docs/rpcoption"}},i={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u8bbe\u7f6e\u9002\u914d\u5668\u53c2\u6570\uff08\u63a8\u8350\u6307\u6570\uff1a\u2b50\uff09",id:"\u4e8c\u8bbe\u7f6e\u9002\u914d\u5668\u53c2\u6570\u63a8\u8350\u6307\u6570",level:2},{value:"\u4e09\u3001RPC\u5d4c\u5957Channel\uff08\u63a8\u8350\u6307\u6570\uff1a\u2b50\u2b50\u2b50\u2b50\u2b50\uff09",id:"\u4e09rpc\u5d4c\u5957channel\u63a8\u8350\u6307\u6570",level:2},{value:"3.1 \u8bf7\u6c42\u6d41\u6570\u636e",id:"31-\u8bf7\u6c42\u6d41\u6570\u636e",level:3},{value:"3.2 \u63a8\u9001\u6d41\u6570\u636e",id:"32-\u63a8\u9001\u6d41\u6570\u636e",level:3}],p={toc:s};function u(e){let{components:n,...t}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},(0,r.kt)("strong",{parentName:"p"},"\u5728RPC\u4e2d\uff0c\u5e76\u6ca1\u6709\u5bf9\u4f20\u8f93\u7684\u6570\u636e\u505a\u9650\u5236\uff0c\u4f46\u662f\u56e0\u4e3aRPC\u9ed8\u8ba4\u4f7f\u7528\u7684\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668\u4e2d\uff0c\u9ed8\u8ba4\u8bbe\u7f6e\u7684\u53ef\u4f20\u9012\u6570\u636e\u4e3a10Mb\uff0c\u6240\u4ee5\u5728RPC\u4e2d\uff0c\u7528\u6237\u53ef\u4e00\u6b21\u6027\u4f20\u9012\u7684\u6570\u636e\u5305\u5927\u7ea6\u4e3a9.9Mb\u3002\u6240\u4ee5\uff0c\u5982\u679c\u7528\u6237\u4f20\u9012\u8d85\u51fa\u9608\u503c\u7684\u6570\u636e\uff0c\u9002\u914d\u5668\u5219\u4f1a\u89e6\u53d1\u5f02\u5e38\uff0c\u800c\u65e0\u6cd5\u63a5\u6536\u3002\u4f46\u5728\u5b9e\u9645\u4e0aRPC\u7684\u4f7f\u7528\u4e2d\uff0c\u5927\u6570\u636e\u7684\u4f20\u8f93\u4e5f\u662f\u5f88\u91cd\u8981\u7684\u4e00\u4e2a\u73af\u8282\uff0c\u6240\u4ee5RRQM\u5df2\u7ecf\u505a\u4e86\u5927\u6570\u636e\u7684\u4f20\u8f93\u601d\u8def\u5efa\u8bae\uff0c\u5e0c\u671b\u80fd\u6709\u6548\u89e3\u51b3\u5927\u5bb6\u7684\u9ebb\u70e6\u3002"))),(0,r.kt)("a",{name:"DU9Pj"}),(0,r.kt)("h2",{id:"\u4e8c\u8bbe\u7f6e\u9002\u914d\u5668\u53c2\u6570\u63a8\u8350\u6307\u6570"},"\u4e8c\u3001\u8bbe\u7f6e\u9002\u914d\u5668\u53c2\u6570\uff08\u63a8\u8350\u6307\u6570\uff1a\u2b50\uff09"),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"\u64cd\u4f5c\u539f\u7406\uff1a\u5728\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668\u4e2d\uff0c\u9ed8\u8ba4\u9650\u5236\u4e86\u5355\u6b21\u53ef\u53d1\u9001\u6570\u636e\u5305\u7684\u6700\u5927\u503c\uff0c\u6240\u4ee5\u53ef\u4ee5\u4fee\u6539\u6b64\u503c\u5b9e\u73b0\u76ee\u7684\u3002")),(0,r.kt)("p",null,"\u8be5\u65b9\u6cd5\u7b80\u5355\u7c97\u66b4\uff0c\u80fd\u591f\u89e3\u51b3\u4e00\u5b9a\u7a0b\u5ea6\u7684\u5927\u6570\u636e\u95ee\u9898\uff0c\u4f46\u5e76\u4e0d\u5efa\u8bae\u8fd9\u4e48\u505a\u3002"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("em",{parentName:"strong"},"\u6ce8\u610f\uff1a\u5ba2\u6237\u7aef\u5fc5\u987b\u540c\u6837\u8bbe\u7f6e\u3002"))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"TouchSocketConfig config = new TouchSocketConfig()//\u914d\u7f6e\n .SetMaxPackageSize(1024 * 1024 * 10)\n")),(0,r.kt)("a",{name:"p5kjo"}),(0,r.kt)("h2",{id:"\u4e09rpc\u5d4c\u5957channel\u63a8\u8350\u6307\u6570"},"\u4e09\u3001RPC\u5d4c\u5957Channel\uff08\u63a8\u8350\u6307\u6570\uff1a\u2b50\u2b50\u2b50\u2b50\u2b50\uff09"),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"\u64cd\u4f5c\u539f\u7406\uff1a\u5148\u5229\u7528RPC\u8ba9\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u7ea6\u5b9a\u7279\u5b9a\u7684Channel\uff0c\u7136\u540e\u540e\u7eed\u6570\u636e\u901a\u8fc7Channel\u4f20\u9012\uff0c\u6700\u540e\u7531RPC\u8fd4\u56de\u7ed3\u679c\u3002")),(0,r.kt)("a",{name:"FuEck"}),(0,r.kt)("h3",{id:"31-\u8bf7\u6c42\u6d41\u6570\u636e"},"3.1 \u8bf7\u6c42\u6d41\u6570\u636e"),(0,r.kt)("p",null,"\u3010Service\u7aef\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'/// \n/// "\u6d4b\u8bd5ServiceToClient\u521b\u5efa\u901a\u9053\uff0c\u4ece\u800c\u5b9e\u73b0\u6d41\u6570\u636e\u7684\u4f20\u8f93"\n/// \n/// \n/// \n[Description("\u6d4b\u8bd5ServiceToClient\u521b\u5efa\u901a\u9053\uff0c\u4ece\u800c\u5b9e\u73b0\u6d41\u6570\u636e\u7684\u4f20\u8f93")]\n[TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]\npublic int RpcPullChannel(ICallContext callContext, int channelID)\n{\n int size = 0;\n int package = 1024 * 1024;\n if (callContext.Caller is TcpTouchRpcSocketClient socketClient)\n {\n if (socketClient.TrySubscribeChannel(channelID, out Channel channel))\n {\n for (int i = 0; i < 1024; i++)\n {\n size += package;\n channel.Write(new byte[package]);\n }\n channel.Complete();//\u5fc5\u987b\u8c03\u7528\u6307\u4ee4\u51fd\u6570\uff0c\u5982Complete\uff0cCancel\uff0cDispose\n }\n }\n return size;\n}\n')),(0,r.kt)("p",null,"\u3010Client\u7aef\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'ChannelStatus status = ChannelStatus.Default;\nint size = 0;\nChannel channel = client.CreateChannel();//\u521b\u5efa\u901a\u9053\nTask task = Task.Run(() =>//\u8fd9\u91cc\u5fc5\u987b\u7528\u5f02\u6b65\n {\n using (channel)\n {\n while (channel.MoveNext())\n {\n byte[] data = channel.GetCurrent();\n size += data.Length;\n }\n status = channel.Status;\n }\n });\nint result = client.RpcPullChannel(channel.ID);//RpcPullChannel\u662f\u4ee3\u7406\u65b9\u6cd5\uff0c\u6b64\u5904\u4f1a\u963b\u585e\u81f3\u670d\u52a1\u5668\u5168\u90e8\u53d1\u9001\u5b8c\u6210\u3002\nawait task;//\u7b49\u5f85\u5f02\u6b65\u63a5\u6536\u5b8c\u6210\nConsole.WriteLine($"\u72b6\u6001\uff1a{status}\uff0csize={size}");\n')),(0,r.kt)("a",{name:"GmNPl"}),(0,r.kt)("h3",{id:"32-\u63a8\u9001\u6d41\u6570\u636e"},"3.2 \u63a8\u9001\u6d41\u6570\u636e"),(0,r.kt)("p",null,"\u3010Service\u7aef\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'/// \n/// "\u6d4b\u8bd5\u63a8\u9001"\n/// \n/// \n/// \n[Description("\u6d4b\u8bd5ServiceToClient\u521b\u5efa\u901a\u9053\uff0c\u4ece\u800c\u5b9e\u73b0\u6d41\u6570\u636e\u7684\u4f20\u8f93")]\n[TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]\npublic int RpcPushChannel(ICallContext callContext, int channelID)\n{\n int size = 0;\n \n if (callContext.Caller is TcpTouchRpcSocketClient socketClient)\n {\n if (socketClient.TrySubscribeChannel(channelID, out Channel channel))\n {\n while (channel.MoveNext())\n {\n size += channel.GetCurrent().Length;\n }\n }\n }\n return size;\n}\n')),(0,r.kt)("p",null,"\u3010Client\u7aef\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'ChannelStatus status = ChannelStatus.Default;\nint size = 0;\nint package = 1024 * 1024;\nChannel channel = client.CreateChannel();//\u521b\u5efa\u901a\u9053\nTask task = Task.Run(() =>//\u8fd9\u91cc\u5fc5\u987b\u7528\u5f02\u6b65\n{\n for (int i = 0; i < 1024; i++)\n {\n size += package;\n channel.Write(new byte[package]);\n }\n channel.Complete();//\u5fc5\u987b\u8c03\u7528\u6307\u4ee4\u51fd\u6570\uff0c\u5982Complete\uff0cCancel\uff0cDispose\n});\nint result = client.RpcPushChannel(channel.ID);//RpcPushChannel\u662f\u4ee3\u7406\u65b9\u6cd5\uff0c\u6b64\u5904\u4f1a\u963b\u585e\u81f3\u670d\u52a1\u5668\u5168\u90e8\u5b8c\u6210\u3002\nawait task;//\u7b49\u5f85\u5f02\u6b65\u63a5\u6536\u5b8c\u6210\nConsole.WriteLine($"\u72b6\u6001\uff1a{status}\uff0cresult={result}");\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/9523.5d56e621.js b/handbook/build/assets/js/9523.5d56e621.js new file mode 100644 index 000000000..23d063ee3 --- /dev/null +++ b/handbook/build/assets/js/9523.5d56e621.js @@ -0,0 +1 @@ +(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9523],{2503:(e,t,n)=>{"use strict";n.d(t,{Z:()=>m});var o=n(7462),a=n(7294),r=n(6010),l=n(5999),c=n(6668),s=n(9960);const i="anchorWithStickyNavbar_LWe7",u="anchorWithHideOnScrollNavbar_WYt5";function m(e){let{as:t,id:n,...m}=e;const{navbar:{hideOnScroll:d}}=(0,c.L)();if("h1"===t||!n)return a.createElement(t,(0,o.Z)({},m,{id:void 0}));const p=(0,l.I)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof m.children?m.children:n});return a.createElement(t,(0,o.Z)({},m,{className:(0,r.Z)("anchor",d?u:i,m.className),id:n}),m.children,a.createElement(s.Z,{className:"hash-link",to:`#${n}`,"aria-label":p,title:p},"\u200b"))}},9523:(e,t,n)=>{"use strict";n.d(t,{Z:()=>fe});var o=n(7462),a=n(7294),r=n(5742);var l=n(2389),c=n(6010),s=n(2949),i=n(6668);function u(){const{prism:e}=(0,i.L)(),{colorMode:t}=(0,s.I)(),n=e.theme,o=e.darkTheme||n;return"dark"===t?o:n}var m=n(5281),d=n(7594),p=n.n(d);const h=/title=(?["'])(?.*?)\1/,f=/\{(?<range>[\d,-]+)\}/,g={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function y(e,t){const n=e.map((e=>{const{start:n,end:o}=g[e];return`(?:${n}\\s*(${t.flatMap((e=>{var t,n;return[e.line,null==(t=e.block)?void 0:t.start,null==(n=e.block)?void 0:n.end].filter(Boolean)})).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function v(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:a,metastring:r}=t;if(r&&f.test(r)){const e=r.match(f).groups.range;if(0===a.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${r}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=a[0].className,o=p()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const l=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return y(["js","jsBlock"],t);case"jsx":case"tsx":return y(["js","jsBlock","jsx"],t);case"html":return y(["js","jsBlock","html"],t);case"python":case"py":case"bash":return y(["bash"],t);case"markdown":case"md":return y(["html","jsx","bash"],t);default:return y(Object.keys(g),t)}}(o,a),c=n.split("\n"),s=Object.fromEntries(a.map((e=>[e.className,{start:0,range:""}]))),i=Object.fromEntries(a.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let p=0;p<c.length;){const e=c[p].match(l);if(!e){p+=1;continue}const t=e.slice(1).find((e=>void 0!==e));i[t]?s[i[t]].range+=`${p},`:u[t]?s[u[t]].start=p:m[t]&&(s[m[t]].range+=`${s[m[t]].start}-${p-1},`),c.splice(p,1)}n=c.join("\n");const d={};return Object.entries(s).forEach((e=>{let[t,{range:n}]=e;p()(n).forEach((e=>{d[e]??=[],d[e].push(t)}))})),{lineClassNames:d,code:n}}const b="codeBlockContainer_Ckt0";function k(e){let{as:t,...n}=e;const r=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,a]=e;const r=t[o];r&&"string"==typeof a&&(n[r]=a)})),n}(u());return a.createElement(t,(0,o.Z)({},n,{style:r,className:(0,c.Z)(n.className,b,m.k.common.codeBlock)}))}const E={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function N(e){let{children:t,className:n}=e;return a.createElement(k,{as:"pre",tabIndex:0,className:(0,c.Z)(E.codeBlockStandalone,"thin-scrollbar",n)},a.createElement("code",{className:E.codeBlockLines},t))}var C=n(902);const B={attributes:!0,characterData:!0,childList:!0,subtree:!0};function T(e,t){const[n,o]=(0,a.useState)(),r=(0,a.useCallback)((()=>{var t;o(null==(t=e.current)?void 0:t.closest("[role=tabpanel][hidden]"))}),[e,o]);(0,a.useEffect)((()=>{r()}),[r]),function(e,t,n){void 0===n&&(n=B);const o=(0,C.zX)(t),r=(0,C.Ql)(n);(0,a.useEffect)((()=>{const t=new MutationObserver(o);return e&&t.observe(e,r),()=>t.disconnect()}),[e,o,r])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),r())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const w={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var L={Prism:n(7410).Z,theme:w};function Z(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function j(){return j=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},j.apply(this,arguments)}var x=/\r\n|\r|\n/,_=function(e){0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},S=function(e,t){var n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)},z=function(e,t){var n=e.plain,o=Object.create(null),a=e.styles.reduce((function(e,n){var o=n.languages,a=n.style;return o&&!o.includes(t)||n.types.forEach((function(t){var n=j({},e[t],a);e[t]=n})),e}),o);return a.root=n,a.plain=j({},n,{backgroundColor:null}),a};function A(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&-1===t.indexOf(o)&&(n[o]=e[o]);return n}const I=function(e){function t(){for(var t=this,n=[],o=arguments.length;o--;)n[o]=arguments[o];e.apply(this,n),Z(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?z(e.theme,e.language):void 0;return t.themeDict=n})),Z(this,"getLineProps",(function(e){var n=e.key,o=e.className,a=e.style,r=j({},A(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),l=t.getThemeDict(t.props);return void 0!==l&&(r.style=l.plain),void 0!==a&&(r.style=void 0!==r.style?j({},r.style,a):a),void 0!==n&&(r.key=n),o&&(r.className+=" "+o),r})),Z(this,"getStyleForToken",(function(e){var n=e.types,o=e.empty,a=n.length,r=t.getThemeDict(t.props);if(void 0!==r){if(1===a&&"plain"===n[0])return o?{display:"inline-block"}:void 0;if(1===a&&!o)return r[n[0]];var l=o?{display:"inline-block"}:{},c=n.map((function(e){return r[e]}));return Object.assign.apply(Object,[l].concat(c))}})),Z(this,"getTokenProps",(function(e){var n=e.key,o=e.className,a=e.style,r=e.token,l=j({},A(e,["key","className","style","token"]),{className:"token "+r.types.join(" "),children:r.content,style:t.getStyleForToken(r),key:void 0});return void 0!==a&&(l.style=void 0!==l.style?j({},l.style,a):a),void 0!==n&&(l.key=n),o&&(l.className+=" "+o),l})),Z(this,"tokenize",(function(e,t,n,o){var a={code:t,grammar:n,language:o,tokens:[]};e.hooks.run("before-tokenize",a);var r=a.tokens=e.tokenize(a.code,a.grammar,a.language);return e.hooks.run("after-tokenize",a),r}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,o=e.code,a=e.children,r=this.getThemeDict(this.props),l=t.languages[n];return a({tokens:function(e){for(var t=[[]],n=[e],o=[0],a=[e.length],r=0,l=0,c=[],s=[c];l>-1;){for(;(r=o[l]++)<a[l];){var i=void 0,u=t[l],m=n[l][r];if("string"==typeof m?(u=l>0?u:["plain"],i=m):(u=S(u,m.type),m.alias&&(u=S(u,m.alias)),i=m.content),"string"==typeof i){var d=i.split(x),p=d.length;c.push({types:u,content:d[0]});for(var h=1;h<p;h++)_(c),s.push(c=[]),c.push({types:u,content:d[h]})}else l++,t.push(u),n.push(i),o.push(0),a.push(i.length)}l--,t.pop(),n.pop(),o.pop(),a.pop()}return _(c),s}(void 0!==l?this.tokenize(t,o,l,n):[o]),className:"prism-code language-"+n,style:void 0!==r?r.root:{},getLineProps:this.getLineProps,getTokenProps:this.getTokenProps})},t}(a.Component),M="codeLine_lJS_",O="codeLineNumber_Tfdd",H="codeLineContent_feaV";function P(e){let{line:t,classNames:n,showLineNumbers:r,getLineProps:l,getTokenProps:s}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const i=l({line:t,className:(0,c.Z)(n,r&&M)}),u=t.map(((e,t)=>a.createElement("span",(0,o.Z)({key:t},s({token:e,key:t})))));return a.createElement("span",i,r?a.createElement(a.Fragment,null,a.createElement("span",{className:O}),a.createElement("span",{className:H},u)):u,a.createElement("br",null))}var V=n(5999);const D={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function R(e){let{code:t,className:n}=e;const[o,r]=(0,a.useState)(!1),l=(0,a.useRef)(void 0),s=(0,a.useCallback)((()=>{!function(e,{target:t=document.body}={}){const n=document.createElement("textarea"),o=document.activeElement;n.value=e,n.setAttribute("readonly",""),n.style.contain="strict",n.style.position="absolute",n.style.left="-9999px",n.style.fontSize="12pt";const a=document.getSelection();let r=!1;a.rangeCount>0&&(r=a.getRangeAt(0)),t.append(n),n.select(),n.selectionStart=0,n.selectionEnd=e.length;let l=!1;try{l=document.execCommand("copy")}catch{}n.remove(),r&&(a.removeAllRanges(),a.addRange(r)),o&&o.focus()}(t),r(!0),l.current=window.setTimeout((()=>{r(!1)}),1e3)}),[t]);return(0,a.useEffect)((()=>()=>window.clearTimeout(l.current)),[]),a.createElement("button",{type:"button","aria-label":o?(0,V.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,V.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,V.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,c.Z)("clean-btn",n,D.copyButton,o&&D.copyButtonCopied),onClick:s},a.createElement("span",{className:D.copyButtonIcons,"aria-hidden":"true"},a.createElement("svg",{className:D.copyButtonIcon,viewBox:"0 0 24 24"},a.createElement("path",{d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})),a.createElement("svg",{className:D.copyButtonSuccessIcon,viewBox:"0 0 24 24"},a.createElement("path",{d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))))}const $="wordWrapButtonIcon_Bwma",W="wordWrapButtonEnabled_EoeP";function q(e){let{className:t,onClick:n,isEnabled:o}=e;const r=(0,V.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return a.createElement("button",{type:"button",onClick:n,className:(0,c.Z)("clean-btn",t,o&&W),"aria-label":r,title:r},a.createElement("svg",{className:$,viewBox:"0 0 24 24","aria-hidden":"true"},a.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})))}function F(e){let{children:t,className:n="",metastring:r,title:l,showLineNumbers:s,language:m}=e;const{prism:{defaultLanguage:d,magicComments:p}}=(0,i.L)(),f=m??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return null==t?void 0:t.replace(/language-/,"")}(n)??d,g=u(),y=function(){const[e,t]=(0,a.useState)(!1),[n,o]=(0,a.useState)(!1),r=(0,a.useRef)(null),l=(0,a.useCallback)((()=>{const n=r.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[r,e]),c=(0,a.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=r.current,n=e>t||r.current.querySelector("code").hasAttribute("style");o(n)}),[r]);return T(r,c),(0,a.useEffect)((()=>{c()}),[e,c]),(0,a.useEffect)((()=>(window.addEventListener("resize",c,{passive:!0}),()=>{window.removeEventListener("resize",c)})),[c]),{codeBlockRef:r,isEnabled:e,isCodeScrollable:n,toggle:l}}(),b=function(e){var t;return(null==e||null==(t=e.match(h))?void 0:t.groups.title)??""}(r)||l,{lineClassNames:N,code:C}=v(t,{metastring:r,language:f,magicComments:p}),B=s??function(e){return Boolean(null==e?void 0:e.includes("showLineNumbers"))}(r);return a.createElement(k,{as:"div",className:(0,c.Z)(n,f&&!n.includes(`language-${f}`)&&`language-${f}`)},b&&a.createElement("div",{className:E.codeBlockTitle},b),a.createElement("div",{className:E.codeBlockContent},a.createElement(I,(0,o.Z)({},L,{theme:g,code:C,language:f??"text"}),(e=>{let{className:t,tokens:n,getLineProps:o,getTokenProps:r}=e;return a.createElement("pre",{tabIndex:0,ref:y.codeBlockRef,className:(0,c.Z)(t,E.codeBlock,"thin-scrollbar")},a.createElement("code",{className:(0,c.Z)(E.codeBlockLines,B&&E.codeBlockLinesWithNumbering)},n.map(((e,t)=>a.createElement(P,{key:t,line:e,getLineProps:o,getTokenProps:r,classNames:N[t],showLineNumbers:B})))))})),a.createElement("div",{className:E.buttonGroup},(y.isEnabled||y.isCodeScrollable)&&a.createElement(q,{className:E.codeButton,onClick:()=>y.toggle(),isEnabled:y.isEnabled}),a.createElement(R,{className:E.codeButton,code:C}))))}function G(e){let{children:t,...n}=e;const r=(0,l.Z)(),c=function(e){return a.Children.toArray(e).some((e=>(0,a.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),s="string"==typeof c?F:N;return a.createElement(s,(0,o.Z)({key:String(r)},n),c)}var U=n(9960);var Y=n(6043);const Q="details_lb9f",J="isBrowser_bmU9",K="collapsibleContent_i85q";function X(e){return!!e&&("SUMMARY"===e.tagName||X(e.parentElement))}function ee(e,t){return!!e&&(e===t||ee(e.parentElement,t))}function te(e){let{summary:t,children:n,...r}=e;const s=(0,l.Z)(),i=(0,a.useRef)(null),{collapsed:u,setCollapsed:m}=(0,Y.u)({initialState:!r.open}),[d,p]=(0,a.useState)(r.open);return a.createElement("details",(0,o.Z)({},r,{ref:i,open:d,"data-collapsed":u,className:(0,c.Z)(Q,s&&J,r.className),onMouseDown:e=>{X(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;X(t)&&ee(t,i.current)&&(e.preventDefault(),u?(m(!1),p(!0)):m(!0))}}),t??a.createElement("summary",null,"Details"),a.createElement(Y.z,{lazy:!1,collapsed:u,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{m(e),p(!e)}},a.createElement("div",{className:K},n)))}const ne="details_b_Ee";function oe(e){let{...t}=e;return a.createElement(te,(0,o.Z)({},t,{className:(0,c.Z)("alert alert--info",ne,t.className)}))}var ae=n(2503);function re(e){return a.createElement(ae.Z,e)}const le="containsTaskList_mC6p";const ce="img_ev3q";const se="admonition_LlT9",ie="admonitionHeading_tbUL",ue="admonitionIcon_kALy",me="admonitionContent_S0QG";const de={note:{infimaClassName:"secondary",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:a.createElement(V.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:a.createElement(V.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:a.createElement(V.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:a.createElement(V.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 16 16"},a.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:a.createElement(V.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},pe={secondary:"note",important:"info",success:"tip",warning:"danger"};function he(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=a.Children.toArray(e),n=t.find((e=>{var t;return a.isValidElement(e)&&"mdxAdmonitionTitle"===(null==(t=e.props)?void 0:t.mdxType)})),o=a.createElement(a.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:o}}(e.children);return{...e,title:e.title??t,children:n}}const fe={head:function(e){const t=a.Children.map(e.children,(e=>a.isValidElement(e)?function(e){var t;if(null!=(t=e.props)&&t.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...o}=e.props;return a.createElement(e.props.originalType,o)}return e}(e):e));return a.createElement(r.Z,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return a.Children.toArray(e.children).every((e=>{var n;return"string"==typeof e&&!e.includes("\n")||(0,a.isValidElement)(e)&&t.includes(null==(n=e.props)?void 0:n.mdxType)}))?a.createElement("code",e):a.createElement(G,e)},a:function(e){return a.createElement(U.Z,e)},pre:function(e){var t;return a.createElement(G,(0,a.isValidElement)(e.children)&&"code"===(null==(t=e.children.props)?void 0:t.originalType)?e.children.props:{...e})},details:function(e){const t=a.Children.toArray(e.children),n=t.find((e=>{var t;return a.isValidElement(e)&&"summary"===(null==(t=e.props)?void 0:t.mdxType)})),r=a.createElement(a.Fragment,null,t.filter((e=>e!==n)));return a.createElement(oe,(0,o.Z)({},e,{summary:n}),r)},ul:function(e){return a.createElement("ul",(0,o.Z)({},e,{className:(t=e.className,(0,c.Z)(t,(null==t?void 0:t.includes("contains-task-list"))&&le))}));var t},img:function(e){return a.createElement("img",(0,o.Z)({loading:"lazy"},e,{className:(t=e.className,(0,c.Z)(t,ce))}));var t},h1:e=>a.createElement(re,(0,o.Z)({as:"h1"},e)),h2:e=>a.createElement(re,(0,o.Z)({as:"h2"},e)),h3:e=>a.createElement(re,(0,o.Z)({as:"h3"},e)),h4:e=>a.createElement(re,(0,o.Z)({as:"h4"},e)),h5:e=>a.createElement(re,(0,o.Z)({as:"h5"},e)),h6:e=>a.createElement(re,(0,o.Z)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:o,icon:r}=he(e),l=function(e){const t=pe[e]??e;return de[t]||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),de.info)}(n),s=o??l.label,{iconComponent:i}=l,u=r??a.createElement(i,null);return a.createElement("div",{className:(0,c.Z)(m.k.common.admonition,m.k.common.admonitionType(e.type),"alert",`alert--${l.infimaClassName}`,se)},a.createElement("div",{className:ie},a.createElement("span",{className:ue},u),s),a.createElement("div",{className:me},t))},mermaid:()=>null}},7594:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,a,r]=t;if(o&&r){o=parseInt(o),r=parseInt(r);const e=o<r?1:-1;"-"!==a&&".."!==a&&"\u2025"!==a||(r+=e);for(let t=o;t!==r;t+=e)n.push(t)}}return n}t.default=n,e.exports=n}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/965c04d6.495d92e3.js b/handbook/build/assets/js/965c04d6.495d92e3.js new file mode 100644 index 000000000..629cb7299 --- /dev/null +++ b/handbook/build/assets/js/965c04d6.495d92e3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6505],{3905:(e,t,n)=>{n.d(t,{Zo:()=>i,kt:()=>d});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),l=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},i=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,i=s(e,["components","mdxType","originalType","parentName"]),m=l(n),d=o,g=m["".concat(p,".").concat(d)]||m[d]||u[d]||a;return n?r.createElement(g,c(c({ref:t},i),{},{components:n})):r.createElement(g,c({ref:t},i))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s.mdxType="string"==typeof e?e:o,c[1]=s;for(var l=2;l<a;l++)c[l]=n[l];return r.createElement.apply(null,c)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},646:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var r=n(7462),o=(n(7294),n(3905));const a={id:"jsonrpcservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1"},c=void 0,s={unversionedId:"jsonrpcservice",id:"jsonrpcservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",description:"\u4e00\u3001\u5b9a\u4e49\u670d\u52a1",source:"@site/docs/jsonrpcservice.mdx",sourceDirName:".",slug:"/jsonrpcservice",permalink:"/touchsocket/docs/jsonrpcservice",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/jsonrpcservice.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"jsonrpcservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1"},sidebar:"docs",previous:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/jsonrpcdescription"},next:{title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1",permalink:"/touchsocket/docs/calljsonrpc"}},p={},l=[{value:"\u4e00\u3001\u5b9a\u4e49\u670d\u52a1",id:"\u4e00\u5b9a\u4e49\u670d\u52a1",level:2},{value:"\u4e8c\u3001\u4f7f\u7528Tcp\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668",id:"\u4e8c\u4f7f\u7528tcp\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668",level:2},{value:"\u4e09\u3001\u4f7f\u7528Http\u6216Websocket\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668",id:"\u4e09\u4f7f\u7528http\u6216websocket\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668",level:2}],i={toc:l};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},i,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u5b9a\u4e49\u670d\u52a1"},"\u4e00\u3001\u5b9a\u4e49\u670d\u52a1"),(0,o.kt)("p",null,"\u5728",(0,o.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u7aef\u4e2d\u65b0\u5efa\u4e00\u4e2a\u7c7b\uff0c\u7ee7\u627f\u4e8e",(0,o.kt)("strong",{parentName:"p"},"RpcServer"),"\u7c7b\uff08\u6216\u5b9e\u73b0IRpcServer\uff09\uff0c\u7136\u540e\u5728\u8be5\u7c7b\u4e2d\u5199",(0,o.kt)("strong",{parentName:"p"},"\u516c\u5171\u65b9\u6cd5"),"\uff0c\u5e76\u7528",(0,o.kt)("strong",{parentName:"p"},"JsonRpc"),"\u5c5e\u6027\u6807\u7b7e\u6807\u8bb0\uff0c\u5982\u679c\u65b9\u6cd5\u6709",(0,o.kt)("strong",{parentName:"p"},"\u91cd\u8f7d"),"\uff0c\u9700\u8981\u91cd\u65b0\u6307\u5b9a",(0,o.kt)("strong",{parentName:"p"},"\u51fd\u6570\u952e"),"\u3002"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301\u4ee3\u7406\u751f\u6210",(0,o.kt)("strong",{parentName:"li"},"\u6ce8\u91ca"),"\u3002")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'public class JsonRpcServer : RpcServer\n{\n [JsonRpc]\n public string TestJsonRpc(string str)\n {\n return "TouchSocket" + str;\n }\n\n /// <summary>\n /// \u5f53\u6807\u8bb0\u4e3atrue\u65f6\u76f4\u63a5\u4f7f\u7528\u65b9\u6cd5\u540d\u79f0\n /// </summary>\n /// <param name="str"></param>\n /// <returns></returns>\n [JsonRpc(true)]\n public string TestJsonRpc1(string str)\n {\n return "TouchSocket" + str;\n }\n\n /// <summary>\n /// \u4f7f\u7528\u8c03\u7528\u4e0a\u4e0b\u6587\u3002\n /// \u53ef\u4ee5\u4ece\u4e0a\u4e0b\u6587\u83b7\u53d6\u8c03\u7528\u7684SocketClient\u3002\u4ece\u800c\u83b7\u5f97IP\u548cPort\u7b49\u76f8\u5173\u4fe1\u606f\u3002\n /// </summary>\n /// <param name="callContext"></param>\n /// <param name="str"></param>\n /// <returns></returns>\n [JsonRpc(MethodFlags = MethodFlags.IncludeCallContext)]\n public string TestGetContext(ICallContext callContext, string str)\n {\n if (callContext.Caller is HttpSocketClient)\n {\n Console.WriteLine("HTTP\u8bf7\u6c42");\n var client = callContext.Caller as HttpSocketClient;\n var ip = client.IP;\n var port = client.Port;\n Console.WriteLine($"HTTP\u8bf7\u6c42{ip}:{port}");\n\n }\n\n if (callContext.Caller is SocketClient)\n {\n Console.WriteLine("Tcp\u8bf7\u6c42");\n var client = callContext.Caller as SocketClient;\n var ip = client.IP;\n var port = client.Port;\n\n client.Send(Encoding.UTF8.GetBytes("Hello Word"));\n Console.WriteLine($"Tcp\u8bf7\u6c42{ip}:{port}");\n\n }\n return "TouchSocket" + str;\n }\n\n [JsonRpc]\n public JObject TestJObject(JObject obj)\n {\n return obj;\n }\n}\n')),(0,o.kt)("a",{name:"ai1L7"}),(0,o.kt)("h2",{id:"\u4e8c\u4f7f\u7528tcp\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668"},"\u4e8c\u3001\u4f7f\u7528Tcp\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668"),(0,o.kt)("p",null,"\u670d\u52a1\u89e3\u6790\u5668\u662f\u5b9e\u9645\u7684\u670d\u52a1\u63a5\u6536\u3001\u89e6\u53d1\u3001\u8c03\u7528\u3001\u53cd\u9988\u7684\u5b9e\u9645\u8f7d\u4f53\uff0c\u901a\u4fd7\u6765\u8bf4\u5c31\u662f",(0,o.kt)("strong",{parentName:"p"},"\u901a\u4fe1\u670d\u52a1\u5668"),"\u3002"),(0,o.kt)("p",null,"\u5f53",(0,o.kt)("strong",{parentName:"p"},"JsonRpcParserPlugin"),"\u63d2\u4ef6\u6dfb\u52a0\u5728",(0,o.kt)("strong",{parentName:"p"},"TcpService"),"\u670d\u52a1\u5668\u65f6\uff0c\u4f1a\u4f7f\u7528",(0,o.kt)("strong",{parentName:"p"},"TCP"),"\u534f\u8bae\u3002\u6b64\u65f6\u7684\u8c03\u7528\uff0c\u4f1a\u6839\u636e\u9002\u914d\u5668\u7c7b\u578b\uff0c\u51b3\u5b9a\u662f\u5426\u9700\u8981\u6709\u8c03\u7528\u7ed3\u675f\u6807\u8bc6\uff0c\u4e00\u822c\u4ee5\\r\\n\u7ed3\u5c3e\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpService service = new TcpService();\nservice.Setup(new TouchSocketConfig()\n .UsePlugin()\n .ConfigureRpcStore(a =>\n {\n a.RegisterServer<JsonRpcServer>();//\u914d\u7f6eRpcStore\u5fc5\u987b\u5728\u6700\u524d\u9762\u3002\n })\n .ConfigurePlugins(a =>\n {\n a.Add<JsonRpcParserPlugin>();//tcp\u4e2d\u8def\u7531\u8def\u5f84\u65e0\u6548\n })\n .SetDataHandlingAdapter(() =>\n {\n return new NormalDataHandlingAdapter();\n //return new TerminatorPackageAdapter("\\r\\n");\u4f7f\u7528\u8be5\u9002\u914d\u5668\u65f6\uff0c\u8c03\u7528\u65b9\u5fc5\u987b\u5728\u6700\u540e\u8ffd\u52a0\u76f8\u5e94\u7684\u7ed3\u675f\u8c03\u7528\u7b26\u3002\n })\n .SetListenIPHosts(new IPHost[] { new IPHost(7705) }))\n .Start();\n')),(0,o.kt)("a",{name:"X5yn3"}),(0,o.kt)("h2",{id:"\u4e09\u4f7f\u7528http\u6216websocket\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668"},"\u4e09\u3001\u4f7f\u7528Http\u6216Websocket\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668"),(0,o.kt)("p",null,"\u5f53",(0,o.kt)("strong",{parentName:"p"},"JsonRpcParserPlugin"),"\u63d2\u4ef6\u6dfb\u52a0\u5728",(0,o.kt)("strong",{parentName:"p"},"HttpService"),"\u670d\u52a1\u5668\u65f6\uff0c\u4f1a\u4f7f\u7528",(0,o.kt)("strong",{parentName:"p"},"Http\u3001Websocket"),"\u534f\u8bae\u3002"),(0,o.kt)("p",null,"\u521b\u5efa\u540e\uff0c\u5982\u679c\u60f3\u4f7f\u7528Http\u8c03\u7528\uff0c\u53ea\u9700\u8981\u4ee5Post\u65b9\u5f0f\uff0c\u5c06\u8c03\u7528Json\u5b57\u7b26\u4e32\u8def\u7531\u5230\u8bbe\u5b9a\u8def\u7531\u5730\u5740\u5373\u53ef\uff08\u4e0b\u6587\u793a\u4f8b\u201c/jsonRpc\u201d\uff09\u3002\n\u5982\u679c\u60f3\u4f7f\u7528Websocket\u8c03\u7528\uff0c\u53ea\u9700\u8981\u4ee5",(0,o.kt)("strong",{parentName:"p"},"\u6587\u672c"),"\u5f62\u5f0f\uff0c\u4f20\u9012\u5230\u670d\u52a1\u5668\u5373\u53ef\u3002\u670d\u52a1\u5668\u4f1a\u5224\u5b9a\uff1a\u5982\u679c\u5185\u5bb9\u4e2d\u5305\u542b\u201cjsonrpc\u201d\u5219\u8ba4\u5b9a\u4e3a\u8c03\u7528\uff0c\u4f1a\u505a\u8c03\u7528\u5904\u7406\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'HttpService service = new HttpService();\n\nservice.Setup(new TouchSocketConfig()\n .UsePlugin()\n .SetListenIPHosts(new IPHost[] { new IPHost(7706) })\n .ConfigureRpcStore(a =>//Rpc\u7684\u914d\u7f6e\u5fc5\u987b\u5728\u63d2\u4ef6\u4e4b\u524d\u3002\n {\n a.RegisterServer<JsonRpcServer>();\n })\n .ConfigurePlugins(a => \n {\n a.Add<WebSocketServerPlugin>()\n .SetWSUrl("/ws");//\u542f\u7528websocket\uff0c\u4f7f\u7528/ws\u8def\u7531\u8fde\u63a5\u3002\n\n a.Add<JsonRpcParserPlugin>()\n .SetJsonRpcUrl("/jsonRpc");\n }))\n .Start();\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/9a8bd036.135c0c4a.js b/handbook/build/assets/js/9a8bd036.135c0c4a.js new file mode 100644 index 000000000..e1dca4bbe --- /dev/null +++ b/handbook/build/assets/js/9a8bd036.135c0c4a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2416],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>f});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function d(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=r.createContext({}),s=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):d(d({},n),e)),t},c=function(e){var n=s(e.components);return r.createElement(l.Provider,{value:n},e.children)},u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},p=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=s(t),f=a,m=p["".concat(l,".").concat(f)]||p[f]||u[f]||o;return t?r.createElement(m,d(d({ref:n},c),{},{components:t})):r.createElement(m,d({ref:n},c))}));function f(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,d=new Array(o);d[0]=p;var i={};for(var l in n)hasOwnProperty.call(n,l)&&(i[l]=n[l]);i.originalType=e,i.mdxType="string"==typeof e?e:a,d[1]=i;for(var s=2;s<o;s++)d[s]=t[s];return r.createElement.apply(null,d)}return r.createElement.apply(null,t)}p.displayName="MDXCreateElement"},920:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>d,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>s});var r=t(7462),a=(t(7294),t(3905));const o={id:"customunfixedheaderdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u975e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668"},d=void 0,i={unversionedId:"customunfixedheaderdatahandlingadapter",id:"customunfixedheaderdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u975e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/customunfixedheaderdatahandlingadapter.mdx",sourceDirName:".",slug:"/customunfixedheaderdatahandlingadapter",permalink:"/touchsocket/docs/customunfixedheaderdatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/customunfixedheaderdatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675586056,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"customunfixedheaderdatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u975e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u6a21\u677f\u89e3\u6790\u201c\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/customfixedheaderdatahandlingadapter"},next:{title:"\u6a21\u677f\u89e3\u6790\u201c\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter"}},l={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2}],c={toc:s};function u(e){let{components:n,...t}=e;return(0,a.kt)("wrapper",(0,r.Z)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u6709\u65f6\u5019\uff0c\u6211\u4eec\u9700\u8981\u89e3\u6790\u7684\u6570\u636e\u7684\u5305\u5934\u662f\u4e0d\u5b9a\u7684\uff0c\u4f8b\u5982\uff1aHTTP\u6570\u636e\u683c\u5f0f\uff0c\u5176\u6570\u636e\u5934\u548c\u6570\u636e\u4f53\u7531\u201c\\r\\n\u201d\u9694\u5f00\uff0c\u800c\u6570\u636e\u5934\u53c8\u56e0\u4e3a\u8bf7\u6c42\u8005\u7684\u8bf7\u6c42\u4fe1\u606f\u7684\u4e0d\u540c\uff0c\u5934\u90e8\u6570\u636e\u91cf\u4e0d\u56fa\u5b9a\uff0c\u800c\u6570\u636e\u4f53\u7684\u957f\u5ea6\uff0c\u4e5f\u662f\u7531\u6570\u636e\u5934\u7684ContentLength\u7684\u503c\u663e\u5f0f\u6307\u5b9a\u7684\uff0c\u6240\u4ee5\uff0c\u53ef\u4ee5\u8003\u8651\u4f7f\u7528",(0,a.kt)("strong",{parentName:"p"},"CustomUnfixedHeaderDataHandlingAdapter"),"\u89e3\u6790\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u81ea\u7531\u9002\u914d",(0,a.kt)("strong",{parentName:"li"},"\u6240\u6709"),"\u7684\u6570\u636e\u534f\u8bae\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u968f\u610f\u5b9a\u5236\u6570\u636e\u534f\u8bae\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u4e0e",(0,a.kt)("strong",{parentName:"li"},"\u4efb\u610f\u8bed\u8a00\u3001\u6846\u67b6"),"\u5bf9\u63a5\u6570\u636e\u3002")),(0,a.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002\u4e0b\u5217\u4ee5\u670d\u52a1\u5668\u4e3a\u4f8b\u3002"),(0,a.kt)("p",null,"\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u5b9e\u73b0IFixedHeaderRequestInfo\u63a5\u53e3\uff0c\u6b64\u5bf9\u8c61\u5373\u4e3a\u5b58\u50a8\u6570\u636e\u7684\u5b9e\u4f53\u7c7b\uff0c\u53ef\u5728\u6b64\u7c7b\u4e2d\u58f0\u660e\u4e00\u4e9b\u5c5e\u6027\uff0c\u4ee5\u5907\u4f7f\u7528\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u7ee7\u627fCustomUnfixedHeaderDataHandlingAdapter\uff0c\u5e76\u4e14\u4ee5\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u4f5c\u4e3a\u6cdb\u578b\u3002\u5e76\u5b9e\u73b0\u5bf9\u5e94\u62bd\u8c61\u65b9\u6cd5\u3002"),(0,a.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684RequestInfo\u5bf9\u8c61\uff0c\u5f3a\u8f6c\u4e3a\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u578b\uff0c\u7136\u540e\u8bfb\u53d6\u5176\u5c5e\u6027\u503c\uff0c\u4ee5\u5907\u4f7f\u7528\u3002")),(0,a.kt)("p",null,"\u3010MyUnfixedHeaderRequestInfo\u3011\n\u9996\u5148\uff0c\u65b0\u5efaMyFixedHeaderRequestInfo\u7c7b\uff0c\u7136\u540e\u5b9e\u73b0",(0,a.kt)("strong",{parentName:"p"},"IUnfixedHeaderRequestInfo"),"\u7528\u6237\u81ea\u5b9a\u4e49\u56fa\u5b9a\u5305\u5934\u63a5\u53e3\u3002\n\u7136\u540e\u5728",(0,a.kt)("strong",{parentName:"p"},"OnParsingHeader"),"\u51fd\u6570\u6267\u884c\u7ed3\u675f\u65f6\uff0c\u5bf9\u5b9e\u73b0\u7684",(0,a.kt)("inlineCode",{parentName:"p"},"BodyLength"),"\u5c5e\u6027\u4f5c\u51fa\u8d4b\u503c\uff0c\u4ee5\u6b64\u6765\u51b3\u5b9a\uff0c\u540e\u7eed\u8fd8\u5e94\u8be5\u63a5\u6536\u591a\u5c11\u6570\u636e\u4f5c\u4e3aBody \u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo\n{\n private int bodyLength;\n /// <summary>\n /// \u63a5\u53e3\u5b9e\u73b0\uff0c\u6807\u8bc6\u6570\u636e\u957f\u5ea6\n /// </summary>\n public int BodyLength\n {\n get { return bodyLength; }\n }\n\n \n private byte[] body;\n /// <summary>\n /// \u81ea\u5b9a\u4e49\u5c5e\u6027\uff0c\u6807\u8bc6\u5b9e\u9645\u6570\u636e\n /// </summary>\n public byte[] Body\n {\n get { return body; }\n }\n\n\n public bool OnParsingBody(byte[] body)\n {\n if (body.Length == this.bodyLength)\n {\n this.body = body;\n return true;\n }\n return false;\n }\n\n\n public bool OnParsingHeader(ByteBlock byteBlock)\n {\n //\u6b64\u5904\u903b\u8f91\u548c\u56fa\u5b9a\u5305\u5934\u6a21\u677f\u57fa\u672c\u4e00\u81f4\u3002\u4e5f\u9700\u8981\u5bf9BodyLength\u4f5c\u51fa\u8d4b\u503c\u3002\n //\u4f46\u662f\u4e0d\u540c\u56fa\u5b9a\u5305\u5934\u7684\u662f\uff0c\u9700\u8981\u81ea\u5df1\u79fb\u52a8\u5df2\u8bfb\u7684\u6e38\u6807\u3002\u5e76\u4e14\u8fd4\u56de\u6b63\u786e\u7684\u503c\u3002\n \n //\u4e0b\u5217\u901a\u8fc7\u5047\u903b\u8f91\u5b9e\u73b0Http\u534f\u8bae\u7684\u89e3\u6790\u3002\n\n //\u4ece\u73b0\u6709\u7684\u53ef\u8bfb\u6570\u636e\u4e2d\uff0c\u8bfb\u53d6\u201c\\r\\n\\r\\n\u201d\uff0c\u4ee5\u6b64\u6765\u5206\u5272http\u7684headers\u548cbody\u3002\n int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, Encoding.UTF8.GetBytes("\\r\\n\\r\\n"));\n if (index > 0)\n {\n //\u7d22\u5f15\u5230\u4e86\u201c\\r\\n\\r\\n\u201d\uff0c\u4ee5\u6b64\u63a8\u65ad\u51fa\uff0c\u5728\u5f53\u524d\u7f13\u5b58\u533a\u4e2d\uff0c\u7531byteBlock.Pos\u81f3index\u7684\u6570\u636e\u5373\u4e3aheaders\u3002\n int headerLength = index - byteBlock.Pos;\n string headers = Encoding.UTF8.GetString(byteBlock.Buffer, byteBlock.Pos,headerLength);//\u89e3\u7801headers\n byteBlock.Pos += headerLength;//\u7136\u540e\u5c06\u7f13\u5b58\u533a\u7684\u6e38\u6807\u79fb\u81f3headers\u7ed3\u675f\u7684\u4f4d\u7f6e\u3002\n\n //\u6700\u540e\u901a\u8fc7headers\uff0c\u89e3\u6790\u51fa\u540e\u7eed\u7684body\u7684\u957f\u5ea6\uff0c\u7136\u540e\u5728\u6b64\u5904\u8d4b\u503c\u3002\n this.bodyLength = 0;//\u6b64\u5904\u76840\u662f\u5360\u4f4d\u503c\u3002\n return true;\n }\n else\n {\n //\u6ca1\u7d22\u5f15\u5230\u201c\\r\\n\\r\\n\u201d\uff0c\u4ee5\u6b64\u63a8\u65ad\u51fa\uff0c\u5728\u5f53\u524d\u7f13\u5b58\u533a\u4e2d\uff0cheader\u7684\u63a5\u6536\u5c1a\u672a\u5b8c\u6210\uff0c\n //\u6240\u4ee5\u8fd4\u56defalse\uff0c\u5e76\u4e14\u4e0d\u9700\u8981\u4fee\u6539\u6e38\u6807\u3002\n return false;\n }\n }\n}\n\n\n')),(0,a.kt)("p",null,"\u65b0\u5efaMyCustomUnfixedHeaderDataHandlingAdapter\u7ee7\u627f",(0,a.kt)("strong",{parentName:"p"},"CustomUnfixedHeaderDataHandlingAdapter"),"\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyCustomUnfixedHeaderDataHandlingAdapter : CustomUnfixedHeaderDataHandlingAdapter<MyUnfixedHeaderRequestInfo>\n{\n protected override MyUnfixedHeaderRequestInfo GetInstance()\n {\n return new MyUnfixedHeaderRequestInfo();\n }\n}\n")),(0,a.kt)("p",null,"\u3010\u63a5\u6536\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u63a5\u6536\u4fe1\u606f\uff0c\u5728CustomDataHandlingAdapter\u6d3e\u751f\u7684\u9002\u914d\u5668\u4e2d\uff0cbyteBlock\u5c06\u4e3anull\uff0crequestInfo\u5c06\u4e3a\u9002\u914d\u5668\u5b9a\u4e49\u7684\u6cdb\u578b\n if (requestInfo is MyUnfixedHeaderRequestInfo myRequestInfo)\n {\n //\u6b64\u5904\u53ef\u4ee5\u5904\u7406MyUnfixedHeaderRequestInfo\u7684\u76f8\u5173\u4fe1\u606f\u4e86\u3002\n string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);\n }\n \n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(() => { return new MyCustomUnfixedHeaderDataHandlingAdapter(); }))//\u914d\u7f6e\u9002\u914d\u5668\n .Start();//\u542f\u52a8\n")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u521b\u5efa\u7684\u9002\u914d\u5668\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/9bfb9f12.4a5babc4.js b/handbook/build/assets/js/9bfb9f12.4a5babc4.js new file mode 100644 index 000000000..bf3ea66ad --- /dev/null +++ b/handbook/build/assets/js/9bfb9f12.4a5babc4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[5264],{3905:(t,e,n)=>{n.d(e,{Zo:()=>c,kt:()=>p});var r=n(7294);function s(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function a(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function i(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?a(Object(n),!0).forEach((function(e){s(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function l(t,e){if(null==t)return{};var n,r,s=function(t,e){if(null==t)return{};var n,r,s={},a=Object.keys(t);for(r=0;r<a.length;r++)n=a[r],e.indexOf(n)>=0||(s[n]=t[n]);return s}(t,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);for(r=0;r<a.length;r++)n=a[r],e.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(s[n]=t[n])}return s}var o=r.createContext({}),u=function(t){var e=r.useContext(o),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},c=function(t){var e=u(t.components);return r.createElement(o.Provider,{value:e},t.children)},d={inlineCode:"code",wrapper:function(t){var e=t.children;return r.createElement(r.Fragment,{},e)}},f=r.forwardRef((function(t,e){var n=t.components,s=t.mdxType,a=t.originalType,o=t.parentName,c=l(t,["components","mdxType","originalType","parentName"]),f=u(n),p=s,v=f["".concat(o,".").concat(p)]||f[p]||d[p]||a;return n?r.createElement(v,i(i({ref:e},c),{},{components:n})):r.createElement(v,i({ref:e},c))}));function p(t,e){var n=arguments,s=e&&e.mdxType;if("string"==typeof t||s){var a=n.length,i=new Array(a);i[0]=f;var l={};for(var o in e)hasOwnProperty.call(e,o)&&(l[o]=e[o]);l.originalType=t,l.mdxType="string"==typeof t?t:s,i[1]=l;for(var u=2;u<a;u++)i[u]=n[u];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}f.displayName="MDXCreateElement"},9817:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>o,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>u});var r=n(7462),s=(n(7294),n(3905));const a={id:"fastbinaryformatter",title:"\u9ad8\u6027\u80fd\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316"},i=void 0,l={unversionedId:"fastbinaryformatter",id:"fastbinaryformatter",title:"\u9ad8\u6027\u80fd\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/fastbinaryformatter.mdx",sourceDirName:".",slug:"/fastbinaryformatter",permalink:"/touchsocket/docs/fastbinaryformatter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/fastbinaryformatter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"fastbinaryformatter",title:"\u9ad8\u6027\u80fd\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316"},sidebar:"docs",previous:{title:"\u5e94\u7528\u4fe1\u4f7f",permalink:"/touchsocket/docs/appmessenger"},next:{title:"Json\u5e8f\u5217\u5316",permalink:"/touchsocket/docs/jsonserialize"}},o={},u=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u5e8f\u5217\u5316\u3001\u53cd\u5e8f\u5217\u5316",id:"\u4e8c\u5e8f\u5217\u5316\u53cd\u5e8f\u5217\u5316",level:2},{value:"\u4e09\u3001\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668",id:"\u4e09\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668",level:2},{value:"\u56db\u3001\u6027\u80fd\u6d4b\u8bd5",id:"\u56db\u6027\u80fd\u6d4b\u8bd5",level:2},{value:"4.1 \u7b80\u5355\u6d4b\u8bd5",id:"41-\u7b80\u5355\u6d4b\u8bd5",level:3},{value:"4.2 \u590d\u6742\u7c7b\u578b\u6d4b\u8bd5",id:"42-\u590d\u6742\u7c7b\u578b\u6d4b\u8bd5",level:3}],c={toc:u};function d(t){let{components:e,...a}=t;return(0,s.kt)("wrapper",(0,r.Z)({},c,a,{components:e,mdxType:"MDXLayout"}),(0,s.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,s.kt)("p",null,"\u8be5\u5e8f\u5217\u5316\u4ee5\u4e8c\u8fdb\u5236\u65b9\u5f0f\u8fdb\u884c\u5e8f\u5217\u5316\uff0c\u4e0d\u8981\u6c42\u5e8f\u5217\u5316\u4e0e\u53cd\u5e8f\u5217\u5316\u7c7b\u578b\u76f8\u540c\uff0c\u4f7f\u7528\u4f53\u9a8c\u548c\u517c\u5bb9\u6027\u4e0ejson\u76f8\u4f3c\u3002\u652f\u6301",(0,s.kt)("strong",{parentName:"p"},"\u57fa\u7840\u7c7b\u578b"),"\u3001",(0,s.kt)("strong",{parentName:"p"},"\u81ea\u5b9a\u4e49\u5b9e\u4f53\u7c7b"),"\u3001",(0,s.kt)("strong",{parentName:"p"},"\u7ed3\u6784\u4f53"),"\u3001",(0,s.kt)("strong",{parentName:"p"},"\u5143\u7ec4"),"\u3001",(0,s.kt)("strong",{parentName:"p"},"\u6570\u7ec4"),"\u3001",(0,s.kt)("strong",{parentName:"p"},"\u5b57\u5178"),"\u3001",(0,s.kt)("strong",{parentName:"p"},"List"),"\u7b49\u3002"),(0,s.kt)("h2",{id:"\u4e8c\u5e8f\u5217\u5316\u53cd\u5e8f\u5217\u5316"},"\u4e8c\u3001\u5e8f\u5217\u5316\u3001\u53cd\u5e8f\u5217\u5316"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-csharp"},'var obj = "TouchSocket";\nvar data = SerializeConvert.FastBinarySerialize(obj);\nvar newobj = SerializeConvert.FastBinaryDeserialize<string>(data);\n')),(0,s.kt)("h2",{id:"\u4e09\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668"},"\u4e09\u3001\u81ea\u5b9a\u4e49\u8f6c\u6362\u5668"),(0,s.kt)("p",null,"\u81ea\u5b9a\u4e49\u8f6c\u5316\u5668\u7684\u4f7f\u7528\uff0c\u53ef\u4ee5\u89e3\u51b3",(0,s.kt)("strong",{parentName:"p"},"\u6240\u6709\u7c7b\u578b"),"\u7684\u5e8f\u5217\u5316\uff0c\u4f46\u662f\u8fd9\u9700\u8981\u81ea\u5df1\u7f16\u5199\u4e00\u4e9b\u4ee3\u7801\u3002\u5177\u4f53\u64cd\u4f5c\u5982\u4e0b\uff1a"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"\u58f0\u660e\u8f6c\u6362\u5668\u3002")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-csharp"},'/// <summary>\n/// \u7ee7\u627f<see cref="FastBinaryConverter{T}"/>\u6216\u8005\u5b9e\u73b0<see cref="IFastBinaryConverter"/>\n/// </summary>\nclass StudentFastBinaryConverter : FastBinaryConverter<Student>\n{\n protected override Student Read(byte[] buffer, int offset, int len)\n {\n var byteBlock = new ValueByteBlock(buffer);\n byteBlock.Pos = offset;\n var obj = new Student();\n obj.P1 = byteBlock.ReadInt32();\n obj.P2 = byteBlock.ReadString();\n return obj;\n }\n\n protected override int Write(ByteBlock byteBlock, Student obj)\n {\n //\u6b64\u5904\u53ef\u4ee5\u76f4\u63a5\u5d4c\u5957Json\u5e8f\u5217\u5316\uff0c\u4f46\u662f\u4e3a\u6f14\u793a\u6548\u679c\uff0c\u4e0b\u5217\u5c06\u4f9d\u7136\u4f7f\u7528\u4e8c\u8fdb\u5236\u65b9\u5f0f\n int pos = byteBlock.Pos;\n byteBlock.Write(obj.P1);\n byteBlock.Write(obj.P2);\n return byteBlock.Pos - pos;//\u8fd4\u56de\u7684\u5373\u662fobj\u6240\u6709\u7684\u5b57\u8282\u957f\u5ea6\n }\n}\n')),(0,s.kt)("ol",{start:2},(0,s.kt)("li",{parentName:"ol"},"\u9644\u52a0\u8f6c\u6362\u5668")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{1}","{1}":!0},"[FastConverter(typeof(StudentFastBinaryConverter))]\nclass Student\n{\n public int P1 { get; set; }\n public string P2 { get; set; }\n}\n")),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"\u5f53\u7c7b\u578b\u5df2\u7ecf\u5b9a\u4e49\uff0c\u65e0\u6cd5\u901a\u8fc7\u7279\u6027\u6dfb\u52a0\u8f6c\u6362\u5668\u65f6\uff0c\u53ef\u4ee5\u901a\u8fc7",(0,s.kt)("inlineCode",{parentName:"p"},"FastBinaryFormatter.AddFastBinaryConverter(typeof(Student),new StudentFastBinaryConverter());"),"\u76f4\u63a5\u6dfb\u52a0\u3002")),(0,s.kt)("h2",{id:"\u56db\u6027\u80fd\u6d4b\u8bd5"},"\u56db\u3001\u6027\u80fd\u6d4b\u8bd5"),(0,s.kt)("h3",{id:"41-\u7b80\u5355\u6d4b\u8bd5"},"4.1 \u7b80\u5355\u6d4b\u8bd5"),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"\u5f85\u6d4b\u8bd5\u7c7b\u578b")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-csharp"},"[Serializable]\npublic class MyPackPerson\n{\n public int Age { get; set; }\n public string Name { get; set; }\n}\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"\u7ed3\u679c")),(0,s.kt)("p",null,"\u4ee5\u4e0b\u6d4b\u8bd5\u662f\u6267\u884c10000\u6b21\u5e8f\u5217\u5316\u548c\u53cd\u5e8f\u5217\u7684\u7ed3\u679c\u3002"),(0,s.kt)("p",null,(0,s.kt)("img",{src:n(1884).Z,width:"1203",height:"228"})),(0,s.kt)("h3",{id:"42-\u590d\u6742\u7c7b\u578b\u6d4b\u8bd5"},"4.2 \u590d\u6742\u7c7b\u578b\u6d4b\u8bd5"),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"\u5f85\u6d4b\u8bd5\u7c7b")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-csharp"},' [Serializable]\npublic class Student\n{\n public int P1 { get; set; }\n public string P2 { get; set; }\n public long P3 { get; set; }\n public byte P4 { get; set; }\n public DateTime P5 { get; set; }\n public double P6 { get; set; }\n public byte[] P7 { get; set; }\n\n public List<int> List1 { get; set; }\n public List<string> List2 { get; set; }\n public List<byte[]> List3 { get; set; }\n\n public Dictionary<int, int> Dic1 { get; set; }\n public Dictionary<int, string> Dic2 { get; set; }\n public Dictionary<string, string> Dic3 { get; set; }\n public Dictionary<int, Arg> Dic4 { get; set; }\n}\n\n[Serializable]\npublic class Arg\n{\n public Arg(int myProperty)\n {\n this.MyProperty = myProperty;\n }\n\n public Arg()\n {\n Person person = new Person();\n person.Name = "\u5f20\u4e09";\n person.Age = 18;\n }\n\n public int MyProperty { get; set; }\n}\n[Serializable]\npublic class Person\n{\n public string Name { get; set; }\n public int Age { get; set; }\n}\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"\u8d4b\u503c")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-csharp"},'Student student = new Student();\nstudent.P1 = 10;\nstudent.P2 = "\u82e5\u6c5d\u68cb\u8317";\nstudent.P3 = 100;\nstudent.P4 = 0;\nstudent.P5 = DateTime.Now;\nstudent.P6 = 10;\nstudent.P7 = new byte[1024 * 64];\n\nRandom random = new Random();\nrandom.NextBytes(student.P7);\n\nstudent.List1 = new List<int>();\nstudent.List1.Add(1);\nstudent.List1.Add(2);\nstudent.List1.Add(3);\n\nstudent.List2 = new List<string>();\nstudent.List2.Add("1");\nstudent.List2.Add("2");\nstudent.List2.Add("3");\n\nstudent.List3 = new List<byte[]>();\nstudent.List3.Add(new byte[1024]);\nstudent.List3.Add(new byte[1024]);\nstudent.List3.Add(new byte[1024]);\n\nstudent.Dic1 = new Dictionary<int, int>();\nstudent.Dic1.Add(1, 1);\nstudent.Dic1.Add(2, 2);\nstudent.Dic1.Add(3, 3);\n\nstudent.Dic2 = new Dictionary<int, string>();\nstudent.Dic2.Add(1, "1");\nstudent.Dic2.Add(2, "2");\nstudent.Dic2.Add(3, "3");\n\nstudent.Dic3 = new Dictionary<string, string>();\nstudent.Dic3.Add("1", "1");\nstudent.Dic3.Add("2", "2");\nstudent.Dic3.Add("3", "3");\n\nstudent.Dic4 = new Dictionary<int, Arg>();\nstudent.Dic4.Add(1, new Arg(1));\nstudent.Dic4.Add(2, new Arg(2));\nstudent.Dic4.Add(3, new Arg(3));\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"\u7ed3\u679c")),(0,s.kt)("p",null,"Fast\u7684\u6548\u7387\u6bd4System\u81ea\u5e26\u7684\uff0c\u5feb\u4e86\u8fd17\u500d\uff0c\u6bd4System.Text.Json\u5feb\u4e864\u500d\u591a\uff0c\u6bd4NewtonsoftJson\u5feb\u4e86\u8fd130\u500d\u3002"),(0,s.kt)("p",null,(0,s.kt)("img",{src:n(6856).Z,width:"1402",height:"234"})))}d.isMDXComponent=!0},1884:(t,e,n)=>{n.d(e,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABLMAAADkAQMAAABZiPR9AAAABlBMVEVg19cMDAyB3G6/AAAVt0lEQVR42uybv4vkRhaAvWwwoRlHE9jROvF/YEcXXHB/jYNLzsEF10JBc9FwODRCQWMuWBYHy+7QFI+iqR3EMgwbblA0GuhAQTNUoECYQtS9V79U0qh7djHmFrYX26qnUknflqSqT6/aX5hP8s/dFyeuE9eJ69Ph6g7UdI8VH4SH6roPOXwSnbj+MNf56MCNKz7FzbtR8/PkoKejU2OTs9jqHRXsdnMWjxDGNDZQSkUuV/ZNZrh+NuYv5vdwjg4DLMIDrp8TFBhxgfmduRA8l90Ci0dgtXRcl5d2B13OleEIl+KmH7i4v4IyB7muxlyqh8CljOPCLUDK5YLG9pGyl3Nl3+TP4OLzXHzg+lfgep9wvX+MS+QrsYlc4r9UzH94ll8+ESmXqJ6FcHl+Ls5jXZ1vwIV5lV9SG7utEy7xLHKJXZXby9lyaDLHBaoY+ryDX6h4BYVSryHlAlbE/rq9hdtY1ygA9zBdMaWojd02CRcULpC4f8uUvZwthyYzXM+BzjtwgeOCCddzaGN4VddQxzo9cLWei7Z6aP33cAGB+3nruGw5NJnjyma4mOXKUq7sJh7ER1w9ts/e21Y3jstu+4Hrn5m/AHUOv1GZPchy+SZzXPwgF0+5OIsHwYiL+ps7Ln8f7TZ9H7kPgFiYsq8EOK4j9/EeYD15vmAN99P7+PIQ1/2agbKtXt5bLrtNxy8AGbm2L+/t5Ww5NJnh+k60F+LN5H38+s1Fm3/114TrO/H2Io73Z2diGM3z9s2ZsFxfv21zeh/tNh+OqMSFG+8v8lzs3rb2crYcmjw6P/70ic7bX5584sR14jpx/RGupjsUJOGw/8jh0+gT5spm/5jukeKD8FDdsP/I4dPo9NyfuD7T9/H0fJ24PnuuM0omme/dgd8/fWIal6lKivgnEybrwtkaI4QYTt2YrGlC2JnGt2lCqcPGVaY711Zk+K85P0v/FnTglItZrsKdtoAfjXSZqqRobMoIqnBtaeiTNXJhKGUIKyN9GxlKFX7EMt5Wri1+yUqMh09L32TKZS+gAteVMtxlhJIiZSDA6NhfMObCqiHsYtYLQqlDLuCt6y+OXLj/iqX9BXCI64U77YsB5sVRrv6jufYJV29+e5zr8lzs8hfiWwuzVGbluYYitcWe7swPG88ltQyBTbjhiX04x7XsDSyl41r1SwPaXC4f5VK3sFWv4B904CvspMLBJEVq2xBXyH3gg9oMWUrHFSBmuJg2a+a5Cs0MNB/SX6oGjlyvAgwMXBC5lDQK2/Okv4BHLkpn+XCOq+/Mdc8cF3Q99dcVfABXhlzZrxaGD1x8xAWWSyTPF4gxlzjMpUzfLzyX6un5+iAuztWaP6cD1xBhkuLA1SfvI/Rjrv4gF9SmBz9+QW33s0e5GN7H7f3apqdKgtmWk6LjKpFr7XOkJXGtw6llqXAA8mFXxvErlDoGpWSeawusnIxfrsmD8T4/E7v2G2FhvnlamV3ZjIuWS5RqY97kbswuabz3AYUKXwMfbso43ofSpsrKprpz7+suq8rJeO+anObtE9dnzvV93LsxR/wL56BMayO8Y9G72IgoXJpCHepwsqr8WkSGVVSqSLmyxr6comqaivYn7yO+nWKcByj8tjVBFWb9q8I5p21RssIgiPMQROFqKWxDXVWharnTceOWbZjEI7i0gxkwKRntT8YvCdNxtfBLefcqcs35V8eNJi4YuABnw4SLFo5cXRcn0cgFHOdD7hY/sB1u25F/kQXpEdcLz6Ui16x/Edd+H7n6nma4yLWncD/Lte+nXL3lwqMTn+C96Sdc4ttcPNuIPO824tlB/+pWqF+S+ts6lsZnDfQqCJekMNT1xOXVaolVlmuFirN0XBpWdNv71L9WmpQz5ULpUlDQ+hQKVHHQv7rCcjV+Irbu1RRhVpYU+mcEL4CTqO8KhlVWAAr85GeOq1kXsCbepL+KhnICY65XtBBGXH65a9a/OhQGfE6ldyzXX1G4GIXMh11HquUu2WMVla5Bouf4/roGuDaoYonn4F3WasyV/YpcgrgEwEH/Iq7FwgTHcs9XFK4FhQsfqo7qA9fClhApcvW4xf1qxIXP15gLpQu5euLqAQ76F3FRp3jHcu9jFC765rDdR2FNXNG/3Hqt5QL/PlouXaf+Re0nXCDvqYG671yzef/qtiVyleAdCw9Fg9oG4dIU6lDXoUyF56t0XHILqmR+/JJbKWl/Mn5toZxwoXS14iIXedvl4uKgf212tbq7K4V3LBzv0aB2QbjuKLzzddkGZcp9wJqqvLN3utkJVVZ+vG92TVPeZel4vxOlUAfmx5+Oz4/1/2ve/vI4Fz/5xInr47msdZknj/kXmlTVCVQof1AmcMwf8l+6Mk2mQ12GjhXyX5mIKS/vX/gy45mwmH4PaTp1yuV+xPVjuMDB/Bc3rILoXyQmbTvkc1qconjrQ8rWsJD/CjPo4F+4C8+ExfT7scXaKZdy/xz1L9rgmK/5AS6b3fKh5sn3tv99TuI5WIln4nyU/2rtD7ISLv6Aaz7/9ZBrvx+49ja79ZFcaT5nP+WqLza5eKLEv4/7F5oUUP4rKNeyxzvRx/wXecYypMO6ZTI/di4PkPiX6WXXm9VqlP+SWDvianBqhNcKPeSof6FJrSn/FZQL9UVKHftFrknbfdgxo9eRy+UBEv8yuum0KYpRf0k7iydcWnLL1Rz3LzSWa/yrq6BcPf1cafBldo2awHyo0CquA5fyPxUa/Au70KX30jwTs12ccPVSqOy1yprj/oVcPblOUC60pQUqVMh/LUjHFj5ELtVHLp9eHPwLd3VqyrWYckHTK/5a8ea4f+F/Apf7kKhx/Kpj/ksjFz7ZLsSD6jku71+mhq6e5r/09DsNGri3z9dx/0KTkh2UKigXg1LrIf+lJWW3fKhYCTH/5bkS/7LvY7ndjsYvjbUjrlzlrfjqb+I/x/3LVHWzEaUKylVl5R0qVMh/3TWU3fKhqsos5r+Uu9OJf+EUsMnK3W403t9h7Xh+VJ+of5Un/zpx/SlcT+PK44Z+Zq7eHfcv1CYjwuSeVfhdU6X+paugYyhifvaxX992iO8ajcolbFpMZ01GK5np+2gXJD0XxJVH+/P3y3fH/Qu1aVh/5DjpSJb6V8uCXkBL6TL3nWYqa4hVJVucUN081YLkdKZ0/KJ0WuC6oiEwWed7zL+AvlkHzwE+8q82rvPplj7PJ/2Fdgbcc2mUHN2N/EsnnjNw8ZTroH/1h7n2lNCKXPs5rn3k2nuu3w5wLatNvrx8Vp1f1OL8slKXzsUP+ZfEU8mw/oi21K8g9S8JQcdIuR5wrdCCaN2RkgLdakn7x+uPqz72FwPFVMFucY68xZJicMy/GlSoJixJsbXRxTr1L7kOOjbLVSAXrTtaroLR/vH6YxHzhVctqpeCtpYaatVSZu6Yf/n+8v6FggXXqX+x61CHD8dDLvwSAVp3pL+Twq5Vo/wXPkQQ83L8RhDXTS37rFY3SqnsmH/558v7F54Zz57416IPOqYWc1yUPHNatpjninkTznriYnUDvKb7qPgx//Lvo/evHjWqT/1L90HHlJ7jorvs/mcP+j8biIuNuerI9RLusU9fIhfex5dKbY/6F3KVENYfmSxhK1P/0jLomNKl/9owXRm4trqUW/dZqdWW0UpmOn6p/7V39jquKksUDnd405vdVx00gZ/CIvBDHFmohRCy0H4GZGGJgGCCDiaooNXiVlVX/9jNAHvOXN0TsI9mH0Mbe23Mz+dVtXrKezgf//P7/fPX+79//9Lv7a/33+/vfD5+yV9t25Strz92U1mMU8pfj8njmH6UjVzvm7LhU7Rpxkc5jQVfZB967KiSmV7vdTnmfY96z/3x/+B/lXt0Hfx16PoTXU3S+bXNXwXVFPE+VLhX68jg6sTwAmonngs/NhFdFdL1xbYWPpW+Ck3e/0IQQ5RLzkdo8Uog/KWSzq9t/qoRlxCZemGGCq9EXSXGEkIWu1vi9fT4oK6l64ttLXwqfXXs/fdHBDFEueT6Rdt3KujSnEncxV81boD3x9rE+iOoz7C/DHJKLbrogeiC2uUMgUt7KvhMfOtI+IvjXaKrTnRt89eiro+/oyvt/0p1OeNrL3+dXL3zIvxFRT1QYni5EtoJoYoXL/jgdJKuL7a18KmXRFevFHJJ2v8FFj9g4S9nfO3lrwpvjPjmZ+Gv63Sd4SqGl9NVnSu3eMYHcuhA5W7OcD0nuvCdCeXS/WXwhBD+csbXXv6i9i1qZtKOsW498tdNDC/8T5OLZN0iVcukzof7gJ1DuKmF/RU5B1wrHutyxtde/kJdVnRx/ZGIxhteia72C11WLRxfiS5yfYS/nPG1l79U1GWDLjG8nC71XJuUri/5pBd0pf4XEJgNXhcZX3v5q4Ky11DetWOsXvXIWGJ4IWRpXVb3yi3eka7C8cW2FhI/lRzT6xeiXHL9wvOx9OejM7728lfXDJNuylE7xpraCRlLDK9maFBXN3ZucUS6ct9m56ZjW2tuuOSYXu8R5ZLrfVO0ZeP5S/8Yfw0/et8uf4y/6oNzDl2HrkPXoevQdeg6dB26Dl2Hrn+Oriz/WET/q4j5R+6ml1cjw2qKLz1RW71fXMg/kg9misLldKj/q/hW/lFF/0uF/GPNXeuzz/N1sf+eG72qtfwjdY59UgWTt+0U+TzfyD+a6H+ZkLd60QVp/rFO45ALeavZ4MbG562AdX0j/2ii//Wk6+Pv6Prwuqijpv5W/hGi/wVB1+lEO1tKjha/3Mf643yhrqCV/CN1jvXgijKzATufvpV/hOgzRV0Vd9PLG1FtPb4rHpvmupZ/pM6xoIv6v6pv5R911KWDLmvnqo8ZR+hVmn+E21r+kfqaKspquP0FFJv4Rv5RR//rSddbaLnXLiCa5B/tWv6RdL15XRYoDPmd/KOO/lfUpbiLUUqOg9MV84+DXcs/ki7jdS30f+3MP+ry5aE7vsrY8kWGVaw/zvdSreYfZ30vE12qrL6Vf9TR/9Ih/9hxN72UHIuyaWP9cR7LYjX/OOuxfGjtzlfq/+qO/OOh69CV6VrOP2b8RR3zeAr5/i86+UL+kUqTBoFK6o8trpc8DEJWO+3IPxLKFWZH/jHjL+qYr+L8E4ozdL2vP1aK+tRDBhHHKukin10n60b+kVAOX2I7/5jxF0i+Sp5kVDL/BJUAP7mTfZ6f6x21f7SRfwRVc9fYZv4x4y/WRT3SX+j6iLqsXde1kH9kXR878o8Zf0HPDdBG6o98b/T8Bdyaf/K9YdSfLLpOUrfayj+CvXB31mb+MeMvQPC6TqH/i3V5/qLSZI9ABT4bieuvkj+UvMJG/hHMOde1lH/M+Iv21433FzOWlv0l9cebrmbba5+NxPU3ARrpbNrIPwLHK3fkHzP+ouPL8vHlMo4+Z+jqj1ZT/7yvTUbgsVr63Dfyj1R/pK6xzfxjxl8g82BI/5dO84+ky7gO+1B/lEkqhnnYk3+k+qM2O/KPGX8hMfW9Cv1fmsqJnr+oNGlKmnxVspGBuiolnfgb+UdQFK/ckX/M+Ktph2lqQ/+XpnKi5y8qTT4QqLTPRgbq6grpxN/IPzbFWOrHj+cfh//pfftfR/3x0PXjupbzj7n/hX9N7RxavvBc7KAIRgnFIUG8McD1k3Hr6ex0X4FwgxZc/z3Q7BVt95J/fJl/Yjn/mPtf/dzRlDe+5QsvS1VXB8OLwKUTvOhwfe9wruvCdE5EWJ3zCTq+8lYv+Uca28w/5v5X7abK8i1fzGJBF+BV8hM89uB69en3V9BFGzhdIIT215quejH/mPtfpIsmmfhCl50/nnR9vOiie5z1uqzT9Zx/fNG1nH/M/S8EpAtNMiHIxffKUzC8wMwUanRjuF5yYHEGA2NpUjPXf4//ip647Dn/SGOb+cfc/8Kh8zSHli8yKqAKhhfiWQ/Sfw+0Pugy7gyYcIMJXP890BQt5vqSfzTVjvxj7n+Rb2nm0PKFH9oNbDC88KZb+elDgNZXXlewCGl/uf57MMSAt5f8I9gd+cfc/yJdyF++5UvT4RL670EjUIHwF+t687q0FhKjDVz/PdCCti/5R2135B9z/8v5vKHla3B5SG94kbsF0n9P+1KF69cwxCm/wMEY0MJgX/KPw578Y+5/3Uu40yQTglzEWFAFw0urkj6pqxxfZe91lfH6hfDmPl56I+Ky5/yjqnbkH3P/axyakSaZEOQqkLGaLhheui0fjfTfN01Hz+P1TSmdvy1u0Dau/75pi5a47Dn/SGNH/vHgnPnIP+b99zl/4f8g+l9APfZTKEYC01Xhx/B7+eSvX84J28o/4raRv1byjzl/IVN10f8iFlO9ivzFdOXHPufP3vOXc8K28o+IbJEnVvKPS/xVQ/S/6F6ZTmxKU2GAZ1mEr0/1zDlb+UdY1lWnur7iL9Jlv9Bln3R9kLv1qms1//ikayX/mPPXab4gBUT/C2L/PRHChaf9kjGeJ+xF13r+kaasOO3IP+b8Vc1nSP0v+gnFSJjOXLyTsSdd1z35R5qyotqRf8z5y7Ip6P0voBu6isVIct9A+7HKowLpuu3JP9KA3ZF/zPnLcrXc+19OVyw4WgoOev5C+HqLuuye/CPYhL9W8o9L/KUg+l9Bl/AXPhxA+zHvXj7pWs0/4ktH/lrJP+b8VZV3iP4X9LrUIfDI/hVNwiFjpjSe78UJ28o/IrJF/lrJP+b81Q1jE/2vZkJdUyhGNu1YFo32Y4/yMXn+ck7YVv4Rke2Vv+Yj/3hwznzkH5f5i+b0MkxTjmUIuKZQf2zbLpYjOze7PUis0eUf6des4I/zoyc3k0U8H/HbEhtlm/nHjL9q8o6YpmaXf0wmvCeTq4rlyEopuT9yrNHlH13Ir3b+fe9msojXL1X3oa9jNf+Y8RfrguX5V91iUhc18tsVOT7obpmiy+XXJDn/V6KrDrrqtfxjxl+4of34A13u7kM3oS902ZQnWJfdkX/M+Ot0mk3PukL+sVcXX3/ET2a+9GEMaD5VNkgMT9yKuk4nCkWeLpwh4zhfyl8WB/y8sKv5x4y/8FiYeqYpyT8qfIGzrz9O03U++3LkFSHtPDlDiWcMo/xjVZGfyr87UuKP6f4yOGCmHfnHjL+sxY2ZpiT/qHgqO6k/9v0tliNvVIh0+wtkZgW40cSo1lqV7q+kzkcDZkf+MeMvetk3phbJPz7VH6lwFxatL/ixLeZ02URXOL6iLuod8/y1mn/M+IsnWHW6bKrLPuuyXpc7HwfldSX5x3A+Rv4aVOSv1fxjxl8VApJhmgr5R9Xfff2R3K27CmNuMgmJNd4ZyfDYKvHnLtcvnskiuX5V91LtyT9m/NV1Q/tgmgr5x3Yaff2RSo5jG8Y0LjB1UaxxZCTrOgpFdqNc73kmi3i9Lzrkt/bIP/65rvkf+efQdeg6dB26Dl2HrkPXgq7/AjWt5qKNoVm5AAAAAElFTkSuQmCC"},6856:(t,e,n)=>{n.d(e,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABXoAAADqAQMAAAAmpm+mAAAABlBMVEVg19cMDAyB3G6/AAAVPUlEQVR42uybP2/cOBrGN3DhcuGtXOxW3ma/Qbba4or7NFtcc1tcsRZUDK4yDikPgorB4oogVZAYA+GFTmAMIQiMlCmIwRiYgsXAYKGCCAiB9/KvKI1mLF9wSIKT4VgPKYr6haLIZ15yvlFf18+/v5mBZ+AZeAaegWfgGXgGnoG/ZGBx4Ix4TFo8oMXkkse0Ts3AnwH4bL9kFaVP8N/7KH3WFT7pLsQrTo0+MaXdsTr1lxGlWKRFpAlqznlAtNrXMwL8TKlf1MfBf/OXkIYB8LMOGDpgUB8Lo8HdyByh8JfhSRrpOtKgIa+uTPJj0HAMmJeqHQCXMTBX48DXETBvwQHz7ggwAPNaDPKZaVVuMKz29fyvgMtR4DJA/h4B/x4Bu/wPEfCHB4FJuiRVH5j8K6TTny/SqyekAyb1hUsszs7ImdWbtAKj0zq9Iv646SDJRaxFpB0k2dapwTA61DMGDDzrnp0Fhn+G9DVknL/uzj+DIvMtfHsLt1YzDmB67HXBOfgj6yAhi7WItERNsfC64AbD6FDPCPBz0DcbAEMEDD3g59D4xPVmAxurZQBuHLA+ynDZX6JboBYDTbBw2Vhgo0M9Y8DJUeDCACcdcPLOnyw74BbrSD6gLt7ZG5ljG6r5WwKxFpHmurSGfMcT8DrUMwZcTgDuXsLnZeFPQgesn1JpgN2jNMdolCh7WkRa1wAasuDmJQULfKxL3AOsDvZhWMF9v0u8HAO+XxWmreDlvbmROUbjMACNtIi0h1y/vDcYRod6RoB/Is05eXNwlPj+zXmTfvenkP6JvD33M93pKXFzWdq8OSUa+Pu3TUr8MQ0zXU3OWaSrSOvedp6mZPu2MRhGh3qmeYnfvjbz8+3s1mbgGXgG/v8CZuK47vIeKnlMm9TXCJyM/ijxiHScGNNd3kMlj2mdml+6GXgeJb5O4LkPz8Az8H8NfKojqeppVPLpyROVdMHcXlpIgsoVJiohXkslhdNCMXcxc0oQ/PjLEhuLIZhLhBhCJgljgqnTLt/VMwQuDHAWAWfwq4IumNtL141WrjDoaKrTjWpqp2tF3cXUqRrL1bS0sRjAXKjrITAApTVVRZfv6hkCm1vyHvA1xwaD0bRAYOiAZQzctbCP8YBTJo4EHrhUJey3sJRQijIGdvWMA7+IgF8MgOO02LXjwDu1OwbcdsDtpwJfnZFt+oL82AEuTMRpNC2oRv/Zxm2QgnqNz1k4PQKMVwlYLGxvX6pluw8sBCzFUi0eBua3sOav4K+h5KvrPnCcFpQFDGx2fEucNsAObx9Yvz1Q2NZjmcpkDzhxwJnIprQw30CJwK96gHwA7NOi0C0M9uEKxanXhSqE04dauLWrEtiNsEfstbAOdQqIbnsEOEHg5I8OsBwAR2lxqfsw2PUDzA76Ul0Kpw/1YQfcYi7/NOCy5KvyeSi5gj5wnBa6fRTYW28McNuNw1YfGiVcLh5g8wnABXaJ9f2qC97mBjAfTyMwqpW7dY7ATsscga0WeRiHnULYXFDXh2Gdr2EMmK7FuteH89Fx+DQ9JdvmB9IB/nBSIyAbTVd3BNWb1CSSnBOv7/K7yukqDzOdUxUhecXcZEG2+Tapqn1gtq228Uzn6pnNzww8A38+4Kchu1KT/DBDM0uU88BC1EoGnWifazTm1W5hGhN6ZBBEoHVm5p0/pGvCJCEiGiWEsds94MwdG1/9Q34YJ2Ia7GVdF6oJGrTPNRrz/MJjrRo9rtaAp0tqRtVDugDaANTROFzD3sSRuX0F97wPfNAPl+gWAjC6lQAshAxmvgnmyCbwrJ7CSjvTHdL4t9HLjR2wMO61B/zCAfM+8GE/XKKZ7QGjOw7ArcvXjjkA7x4BvHsYmPyYkouKpKmoyMUEP7xEM9sq54E1MLowp4Wu3WjtmKkHpgaMilYtHOQBjX2N0lZEfhjP6d8YGE0wh0wvfeNkn03wwxmaWamcBxZipWjQ+Ea6roB5KxaA9dqxYPgA3JryIb1iQJnstbA0v33gV3oJXgNHS+1H/LB+SObVKw3kjdLu2GpufK7WmHcTWri4sS0psMf4Vh3VNxQKnexuiwkuBsDJHwhMNDABmOCHAavn3g8LfGDaHRMH3Lp8zGtDH75sbV/lAfKAxsMl2uQYGO/K+8BoghG41cAtwAQ/rB/6xvthDSyD5sbnai0hApYOeKPfKjiiEUCiTY6B0W5vBsBA73V5fi+inRhH/PA6hzXkzgMLQXMZNM/B+WTtmD1wLqkbDfLCjreHNL5zcjhK5MP9EmiCG3KekrQRKTmf4Ie3G7JNcueBq4rld0HznDifrB2zm+mq/E5fVpEqyWs7ox3SjLA7klTRTIfn+MFFmd8meonNl2J+vp0IXM5ubQb+ooCNC1ZPpvth9Hys9n5YoQdmIQCINjlxGl2z8PFhYsYLtLoqSWxuIrUbtflSG16S6KpJQmqBo0v0qZkoNvDDdvfvr551Sny4oEWIXqJhpXWnoXQap+7ax4ft8I5WV7syk1s2aHoLm9+g96uhpNatFTWO31FcAqx16gNz+zvRD+uwTRcfRmtShhaOgNE1i37kp9TA0uaWjfCzmwEWYHcD6mkDBsDlALgcBz4WH54G3A6BdxHwrgPele0R4HYPeHNepeQJJ3+f6octsI8Jo51ahpgwVXTh9FKH2RywDQAuKfpe9GZaL0xY1ubTBfrHdmG8hKAITOP4sFTLgR9maCPgNQc61Q9r+7HyflgDZyEmzBQrnM70u+iApTQ5aOoLYXPRRKrVyubTAt83aT4BSsFWAljcwkxlAz8saWmA2VQ/rNQN3Hg/rP0fhJgwtnDrNEQtbIN+UGATctvCLeqbG5tftFKbPmOfOL3RLQxxC8PAD7eU8OQ1T9hUP6yDu1182AET34edN9YdIQAbR6vgkuv9xRb4EuFbm3+pewY3wHqvsYBeuBXrG/hhYC0vX/OSTfXDAbiNgFsP7PMhGiU2ZrMuyI3eX2xbW2pgmy/1XTfm1pt9YB1HHgLDvenDU/0w9jpKvR9G4HwdYsJokwun0TULHx+21a7RIxcOuJA67mvzsfvmAj8amT3DQMVgHM7Xg1Ei5WlDvvsz+cdUP4wvAmPeDyv0wNsQEyY5qZ3e5v4rCyy3q5/bO/S93ObWdzrua/PvapJXSa2rTjhh1WCmy7dDP8wf64c/t/nJH+uHZ7c2A38xwCdhp0SlvwXG30/0wwQdD+n2S5BIJywsjkvS3y+ho8pMWA+s5+2EEDmEJEwHiPv7JUTnhyHslDBfW7t6P9EPQ93Eq/kQ6ZKG/RL+qz9+v4SOKtPar0rX2hs3e/slqA4Q9/dL1N04fI1jWhFtP5jsh8Vh4DK0cNOthFp3geVK/+UbtKSjwCUMgHWkZQS43AM+6ofFTrW+cHsIeLcHjN5WuLVmA9zuRoB37WHgRV2li6uL+ux8Q86uan6VkEl+GG2rkn6PhET71O2dWCzDfgm/dIvAS2N4AL2tsJZSe+hFK+kQmC6Byra/XyKKD18XwAueFbfoJ25R8QIm+WGJwGGPBFOSdXsniizsl6AsAGfW5KC3FW5BN9MRWUaH+yVYpgPEgxbu/PB1g1aYQ7OhEja80SHtafslRKGk3yMhtQ0OeydaCPslCjpczdfe1rUw6I8XsthrYfwUKv/T3hnzuo1jUbhMPd10+1Nj4RX+FYYK/4RUAXEhCEIgBMHUWwiGDLhQYSxYuLgFQWh5JfKSlOjQyttMJgtNMaCMl7wTRaG+d3TuEcZP89HzcPWtIcHf+k4XvfwmpSxe4mGJh9Fxr1nIIDuhmZPHwyJ+IAlK3TVMgqU+rFNVcNByIdjzcCU0CRb9AFVPl4SsXuLhHpXPSxjcDbITzMM4qoVgQl5wuwQxdA8qIVhN5nMo2PNw9Qn+Ywj1kxFsLolPUl5e42HzF8s8bIAVgrW4cF7CCe7K7mL3YYPOVvAFSwEJwRcyiOO8RLBL/Ovr2+PD259fP8i35sPb17c3v0t8l4eL+so8bIC1aHx2or1xXuLacF7iNrk9g2Hb2t7pbnXZFs11dae7kUEc5yXqhD8sfzf4KXda2wX/joJnY3g7D+Pk6DoGNv+mi3BteZhcKxX7w8p8hoV9toQFe8WBLCwaQ8lD7A837tY8G8PbebidDFLgrZ7sRcdanJdoDQU/Yn/4YT5rK/v0rvVecSC4JUcTuthunSDUCpZTs8NGHsZYsIoEq4qZ0NGuu9M96A5QVS5cyNZreIYVGa7VE8FVIHgLD+Pk6IaCdVrwne3W2QeeBeucYL0UfLeCZ2N4Ow/j5Ohqy72UbnBsrA3HWh5G4LwEjDP3diT4eFYW+NgrDgWjQW0V5Yc14fYseDaGt/MwTo6usn/RlG5wPEy4aHk4Ejwz8CRYnAYn2HnFAQ8jmn+ZQ5QfVvMflwTPxvB2HsbZ0fX+sHZsjDNqVlawiM+woN9dW+ChXybXZ1ii7NQi3YrCCp6N4e08jJOjKy33SklPBOzaszEJPsTX8GEWrL3g9TUs5zaKQLD5rge3S0zG8HYexsnR7S339j4jQWDsssQkWMW7hMIgP0y2ckpwLyH2h/ux5314Moa387AhXcF5CfNtDdi6tSil5WE0FKxif9j8JFiiuDjB7BVHgqlR4xL7w+AEz8bwdh6ue3J0C8u9hSxbx8NFW0rLw7Wh4Kvj4flOdzWf1e1t/ha1ZK84EFzLQjZNlB8uyuLqWEL+IA//srxE+YM8vOcldsG74F3wLngXvAveBe+Cd8G74F3wLvgfJTjqlyAruJ69WUwcq7FpfX7Y/ESsOEvc8Dxdol+iKQrKYw3OHx7mzHDsD7fN0Gzul5it4MkCaRPHj5EG7AN/+BFkicHnJZb9EuSjdp39tDXrOTMc+cOVoPmprf0SZAVbgZg4fkRx3FAwBtmJ9eQ4qIojuCNSXUMFyzNMY2qwuV+CrOCPs9WJieN7LFjzPB0J1s8F6xcF6839EmQFf2z+aOhBfeKYykJ8flgrnqejx/puni4hWOExEHwcz3NmOBJ8BA1qc78EOasf4S+wj2CWx904fPb5YTXwPN30JAae9ksMKALBYjwpAUt/WHxWMGzul5gF9uDO8OJYjN2XID+seJ7OnuFn/RJK6kDwFEVYnWH9BUFt7pcgK9gILNw1vDg+jJQFB+8Ju3k6ew0/65fQS8EyIVgv/eFX+iXIWQXoK7dLLI6VE+w8YQWJ/HBilyDvmAVTLhhWgkH3C3/4hX6JyQoWdAlAiYljVUKQHwbgebopP9w97ZcAKUreh1GUFxDLfRiF2YVha7/EZAW3zQdz2yrrxPG1b4L8cNHwPN2UHx6e9ks0si35Tle35W3ODEf+cDsUQ/M/75fofzf42f3hXfA/S/C6XyLDw0Sy3LeGCjk/TMDL2Qnk0R5zvy429EsMgwp3iYFu+Jl+iQwPg4WfmWAfLSMlNX0xXrYUEXY8XG3ol+i6R7gPdxS9yPRLZHiYAhK+rmEajPOClcfLCqM47sv9ElUkuCISzfRLZHiYAhKcl8D7QrB+p+A7VPeM4FW/RIaHcTwr7lujzENnsxOautSYjSki7AQfN/RLwDmapztTBCPTL5HhYRxPA/etkeDBZicU9VAxG48nL1hs6JeAU/Qz3YkiGJl+iQwPmwtacd8aCpxK4aoZDkepPA97wXpDvwS9qiGa9kLI9UtkeFiGPIxUsGazE5IEa8/DC8Gv9kvA4fuC1/0SGR6W9ofQWQblqW12gvhWBjwcD7G+3C8BKiN42S+R42FpSJb71oxgzg+DEL57DWnMzvGw2NAv0V2iDPylxEumXyLHw7K/Ndy3Vl/rsrHZiaJtffdaTWN2jofbDf0Sw+0a3uluZX3b+yV2WtsF/1LB636JDA8zSEt/kFz7IGfzLsHZfokMD/NdPhCZXEPw6rX3CM72S2R4mIUFrkJy/ZMEVyvBGR5mLv23P0iufZXC6V2CT7l+iQwPvyzYD+6odwlWuX6JDA8z5gXOWHKNwW6xmJvbsJ5/9Xf7JTI8zMKCf/vJdVrwj2xxmX6JDA+zsICpkuufJHjdL5HhYc+lI2bWP+XGseqXyPHwy4L9Vje8S/CQ6ZfI8TCD9J/+ILn+SYL3fomd1nbBf5/gJ/0SWR4uiqBfguzixJpm59b9EugyEkVL795o1v0SDRZF7A8XKtcvkeVhckS58YCCD4k1zc6t+yVal5GoxFhBB+t+CWjjueZurB65foksD6tYcBWs2dCG2SYNn4QC96pNb0SuFECiroGm9+O+tUeuXyLLw6q6PxWsvyNYLwXrtWC9FnzP9UtkeRiPHc/Tjcfx3Pk1OH+YZucWD8eBe9XMV8J4xPWoe3dWVAp8DAUfu1y/RJaHUXQ8T2fOxmnwa3BrmMfKwvgBcK+a+crPNK42rPslBhIcnWHR5folsjwsteB5Oupt6IK14r411Ot+CXQZCf2FxtPWZxgUShm7l1rk+iWyPEzFENL3SwAEa9+3thRM/RLoMhJak+D1NQx6LfiQ65fI8jCdmt73SwAk1tbXHeN+CXQZCfqDycQuAbASDCrTL5HnYSmCfgkKPvh159Y0O7fIS3Tcq0algaWQiX34MgkO9+FSqEy/RJ6HZXvlebqxLW+NXw9uTbNzcV6C+iVql5Foh7KViTvdramN4PBOV7bXvV9ip7Vd8K8R/LRfIsPD01vm+P10TUNsO666JgZbgDrxMM7ZS2XIuLHvp6N4xbDODw/NMCz71jDXL5HNS1BFcMdbPT1Kdqzlya0bH9wvMScnHu3DkLG9iUNrvrpb5Yenty8s+9baXL9EhocJHFWYH1aQEAws2HWMPqilrXKCiUXWyUBVTZ+K5BmunvVLZHj4VcH3eyz4jncvWP+A4Kf9EhkeNrLPyO+no/YH8P0SR808HPSt4VzXYKjurO376ShesRaMZ32GZd8a5volMjxsZJ/QU6758LPvlxCKeTgp+GQrywaKV8AqP4wndQL15Aw/7ZfI8DA9z5ZcrGdUyC++X0Ij87AQsWAxBZ4tdFI5sV6fYUl1Yc/61p72S2TzEujfx0F5Axn0S2jJPHw4xIIPeDCCpXbXsEwKNswpnwh+2i+R4eHeCeZOCe3XLjvBRdResJpe6tNz31oPKcH9/LKPtOB0v0SOh83/L5LfTwdQys73SwjPw4r7JTonuOwutogEsDRovMoPGwWXbtm3hpl+iRwPF319k/x+uqIp5eD7JdqCefjK/RJDPfdLXMvhVtj309WlQeNVfljeituw7Fur936Jv0Xw+Hv9twveBe+Cd8G74F3w/7ng/wJTwfTjifXtAQAAAABJRU5ErkJggg=="}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/9e2cc891.072979a0.js b/handbook/build/assets/js/9e2cc891.072979a0.js new file mode 100644 index 000000000..1e6b1c8f0 --- /dev/null +++ b/handbook/build/assets/js/9e2cc891.072979a0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1895],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function d(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,s=d(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,k=u["".concat(l,".").concat(m)]||u[m]||c[m]||o;return n?r.createElement(k,i(i({ref:t},s),{},{components:n})):r.createElement(k,i({ref:t},s))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=u;var d={};for(var l in t)hasOwnProperty.call(t,l)&&(d[l]=t[l]);d.originalType=e,d.mdxType="string"==typeof e?e:a,i[1]=d;for(var p=2;p<o;p++)i[p]=n[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},7688:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>d,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const o={id:"udpbroadcast",title:"\u7ec4\u64ad\u3001\u5e7f\u64ad"},i=void 0,d={unversionedId:"udpbroadcast",id:"udpbroadcast",title:"\u7ec4\u64ad\u3001\u5e7f\u64ad",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/udpbroadcast.mdx",sourceDirName:".",slug:"/udpbroadcast",permalink:"/touchsocket/docs/udpbroadcast",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/udpbroadcast.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675572697,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"udpbroadcast",title:"\u7ec4\u64ad\u3001\u5e7f\u64ad"},sidebar:"docs",previous:{title:"\u4f20\u8f93\u5927\u4e8e64K\u7684\u6570\u636e",permalink:"/touchsocket/docs/udptransmitbigdata"},next:{title:"\u4ecb\u7ecd\u53ca\u4f7f\u7528",permalink:"/touchsocket/docs/adapterdescription"}},l={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7ec4\u64ad\u4f7f\u7528",id:"\u4e8c\u7ec4\u64ad\u4f7f\u7528",level:2},{value:"2.1 \u521b\u5efa\u7ec4\u64ad\u670d\u52a1\u5668",id:"21-\u521b\u5efa\u7ec4\u64ad\u670d\u52a1\u5668",level:3},{value:"2.2 \u53d1\u9001\u7ec4\u64ad\u6570\u636e",id:"22-\u53d1\u9001\u7ec4\u64ad\u6570\u636e",level:3},{value:"\u4e09\u3001\u5e7f\u64ad",id:"\u4e09\u5e7f\u64ad",level:2},{value:"3.1 \u521b\u5efa\u5e7f\u64ad\u670d\u52a1\u5668",id:"31-\u521b\u5efa\u5e7f\u64ad\u670d\u52a1\u5668",level:3},{value:"3.2 \u53d1\u9001\u5e7f\u64ad\u6570\u636e",id:"32-\u53d1\u9001\u5e7f\u64ad\u6570\u636e",level:3}],s={toc:p};function c(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u5e7f\u64adBroadCast\uff1a\u4e3b\u673a\u4e4b\u95f4\u201c\u4e00\u5bf9\u6240\u6709\u201d\u7684\u901a\u8baf\u6a21\u5f0f\uff0c\u5e7f\u64ad\u8005\u53ef\u4ee5\u5411\u7f51\u7edc\u4e2d\u6240\u6709\u4e3b\u673a\u53d1\u9001\u4fe1\u606f\u3002\u5e7f\u64ad\u7981\u6b62\u5728Internet\u5bbd\u5e26\u7f51\u4e0a\u4f20\u8f93\uff08\u5e7f\u64ad\u98ce\u66b4\uff09\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u591a\u64adMultiCast\uff1a\u4e3b\u673a\u4e4b\u95f4\u201c\u4e00\u5bf9\u4e00\u7ec4\u201d\u7684\u901a\u8baf\u6a21\u5f0f\uff0c\u4e5f\u5c31\u662f\u52a0\u5165\u4e86\u540c\u4e00\u4e2a\u7ec4\u7684\u4e3b\u673a\u53ef\u4ee5\u63a5\u53d7\u5230\u6b64\u7ec4\u5185\u7684\u6240\u6709\u6570\u636e\u3002")),(0,a.kt)("h2",{id:"\u4e8c\u7ec4\u64ad\u4f7f\u7528"},"\u4e8c\u3001\u7ec4\u64ad\u4f7f\u7528"),(0,a.kt)("p",null,"\u7ec4\u64ad\u4f7f\u7528\u975e\u5e38\u7b80\u5355\uff0c"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u914d\u7f6e\u4e2d\u542f\u7528\u5e7f\u64ad",(0,a.kt)("strong",{parentName:"li"},"UseBroadcast"),"\u91cd\u8981"),(0,a.kt)("li",{parentName:"ol"},"\u5728UdpSession",(0,a.kt)("strong",{parentName:"li"},"\u542f\u52a8"),"\u540e\u3002\u8c03\u7528",(0,a.kt)("strong",{parentName:"li"},"JoinMulticastGroup"),"\u5373\u53ef\u52a0\u5165\u7ec4\u64ad\u3002\u8c03\u7528",(0,a.kt)("strong",{parentName:"li"},"DropMulticastGroup"),"\uff0c\u9000\u51fa\u7ec4\u64ad\u3002")),(0,a.kt)("h3",{id:"21-\u521b\u5efa\u7ec4\u64ad\u670d\u52a1\u5668"},"2.1 \u521b\u5efa\u7ec4\u64ad\u670d\u52a1\u5668"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{9}","{9}":!0},'//\u521b\u5efaudpService\nUdpSession udpService = new UdpSession();\nudpService.Received = (remote, byteBlock, requestInfo) =>\n{\n Console.WriteLine(byteBlock.ToString());\n};\nudpService.Setup(new TouchSocketConfig()\n .SetBindIPHost(new IPHost(7789))\n .UseBroadcast()\n .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))\n .Start();\n\n//\u52a0\u5165\u7ec4\u64ad\u7ec4\nudpService.JoinMulticastGroup(IPAddress.Parse("224.5.6.7"));\n')),(0,a.kt)("h3",{id:"22-\u53d1\u9001\u7ec4\u64ad\u6570\u636e"},"2.2 \u53d1\u9001\u7ec4\u64ad\u6570\u636e"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{7}","{7}":!0},'UdpSession udpClient = new UdpSession();\nudpClient.Setup(new TouchSocketConfig()\n .SetBindIPHost(new IPHost(7788))\n .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))\n .Start();\n\nudpClient.Send(new IPEndPoint(IPAddress.Parse("224.5.6.7"), 7789), Encoding.UTF8.GetBytes("\u6211\u662f\u7ec4\u64ad"));\n')),(0,a.kt)("h2",{id:"\u4e09\u5e7f\u64ad"},"\u4e09\u3001\u5e7f\u64ad"),(0,a.kt)("p",null,"\u5e7f\u64ad\u4f7f\u7528\u975e\u5e38\u7b80\u5355\uff0c"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u914d\u7f6e\u4e2d\u542f\u7528\u5e7f\u64ad",(0,a.kt)("strong",{parentName:"li"},"UseBroadcast"),"\u91cd\u8981")),(0,a.kt)("h3",{id:"31-\u521b\u5efa\u5e7f\u64ad\u670d\u52a1\u5668"},"3.1 \u521b\u5efa\u5e7f\u64ad\u670d\u52a1\u5668"),(0,a.kt)("p",null,"\u5e7f\u64ad\u63a5\u6536\u65f6\uff0c\u662f\u4e0d\u9700\u8981\u52a0\u5165\u7ec4\u64ad\u7ec4\u7684\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{9}","{9}":!0},"//\u521b\u5efaudpService\nUdpSession udpService = new UdpSession();\nudpService.Received = (remote, byteBlock, requestInfo) =>\n{\n Console.WriteLine(byteBlock.ToString());\n};\nudpService.Setup(new TouchSocketConfig()\n .SetBindIPHost(new IPHost(7789))\n .UseBroadcast()\n .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))\n .Start();\n")),(0,a.kt)("h3",{id:"32-\u53d1\u9001\u5e7f\u64ad\u6570\u636e"},"3.2 \u53d1\u9001\u5e7f\u64ad\u6570\u636e"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{3,8}","{3,8}":!0},'UdpSession udpClient = new UdpSession();\nudpClient.Setup(new TouchSocketConfig()\n .UseBroadcast()//\u8be5\u914d\u7f6e\u5728\u53d1\u9001\u5e7f\u64ad\u65f6\u662f\u5fc5\u987b\u7684\n .SetBindIPHost(new IPHost(7788))\n .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))\n .Start();\n\nudpClient.Send(new IPEndPoint(IPAddress.Parse("255.255.255.255"), 7789), Encoding.UTF8.GetBytes("\u6211\u662f\u5e7f\u64ad"));\n')),(0,a.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"\u5728\u53d1\u9001\u5e7f\u64ad\u6570\u636e\u65f6\uff0c\u53d1\u9001\u7aef\u914d\u7f6eUseBroadcast\u662f\u5fc5\u987b\u7684\u3002")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/a14859b4.eb042ba8.js b/handbook/build/assets/js/a14859b4.eb042ba8.js new file mode 100644 index 000000000..437f7cdda --- /dev/null +++ b/handbook/build/assets/js/a14859b4.eb042ba8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9660],{3905:(e,r,t)=>{t.d(r,{Zo:()=>s,kt:()=>d});var n=t(7294);function c(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?a(Object(t),!0).forEach((function(r){c(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function l(e,r){if(null==e)return{};var t,n,c=function(e,r){if(null==e)return{};var t,n,c={},a=Object.keys(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||(c[t]=e[t]);return c}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(c[t]=e[t])}return c}var p=n.createContext({}),i=function(e){var r=n.useContext(p),t=r;return e&&(t="function"==typeof e?e(r):o(o({},r),e)),t},s=function(e){var r=i(e.components);return n.createElement(p.Provider,{value:r},e.children)},u={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,c=e.mdxType,a=e.originalType,p=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),m=i(t),d=c,v=m["".concat(p,".").concat(d)]||m[d]||u[d]||a;return t?n.createElement(v,o(o({ref:r},s),{},{components:t})):n.createElement(v,o({ref:r},s))}));function d(e,r){var t=arguments,c=r&&r.mdxType;if("string"==typeof e||c){var a=t.length,o=new Array(a);o[0]=m;var l={};for(var p in r)hasOwnProperty.call(r,p)&&(l[p]=r[p]);l.originalType=e,l.mdxType="string"==typeof e?e:c,o[1]=l;for(var i=2;i<a;i++)o[i]=t[i];return n.createElement.apply(null,o)}return n.createElement.apply(null,t)}m.displayName="MDXCreateElement"},7409:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>i});var n=t(7462),c=(t(7294),t(3905));const a={id:"xmlrpcservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1"},o=void 0,l={unversionedId:"xmlrpcservice",id:"xmlrpcservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",description:"\u5b9a\u4e49\u670d\u52a1",source:"@site/docs/xmlrpcservice.mdx",sourceDirName:".",slug:"/xmlrpcservice",permalink:"/touchsocket/docs/xmlrpcservice",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/xmlrpcservice.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238253,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"xmlrpcservice",title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1"},sidebar:"docs",previous:{title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",permalink:"/touchsocket/docs/xmlrpcdescription"},next:{title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1",permalink:"/touchsocket/docs/callxmlrpc"}},p={},i=[{value:"\u5b9a\u4e49\u670d\u52a1",id:"\u5b9a\u4e49\u670d\u52a1",level:2},{value:"\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668",id:"\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668",level:2},{value:"\u6ce8\u518c\u3001\u53d1\u5e03\u670d\u52a1",id:"\u6ce8\u518c\u53d1\u5e03\u670d\u52a1",level:2}],s={toc:i};function u(e){let{components:r,...t}=e;return(0,c.kt)("wrapper",(0,n.Z)({},s,t,{components:r,mdxType:"MDXLayout"}),(0,c.kt)("h2",{id:"\u5b9a\u4e49\u670d\u52a1"},"\u5b9a\u4e49\u670d\u52a1"),(0,c.kt)("p",null,"\u5728",(0,c.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u7aef\u4e2d\u65b0\u5efa\u4e00\u4e2a\u7c7b\uff0c\u7ee7\u627f\u4e8e",(0,c.kt)("strong",{parentName:"p"},"ServerProvider"),"\u7c7b\uff08\u6216\u5b9e\u73b0IServerProvider\uff09\uff0c\u7136\u540e\u5728\u8be5\u7c7b\u4e2d\u5199",(0,c.kt)("strong",{parentName:"p"},"\u516c\u5171\u65b9\u6cd5"),"\uff0c\u5e76\u7528",(0,c.kt)("strong",{parentName:"p"},"XmlRpc"),"\u5c5e\u6027\u6807\u7b7e\u6807\u8bb0\uff0c\u5982\u679c\u65b9\u6cd5\u6709",(0,c.kt)("strong",{parentName:"p"},"\u91cd\u8f7d"),"\uff0c\u9700\u8981\u91cd\u65b0\u6307\u5b9a",(0,c.kt)("strong",{parentName:"p"},"\u51fd\u6570\u952e"),"\u3002"),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},"\u652f\u6301\u4ee3\u7406\u751f\u6210",(0,c.kt)("strong",{parentName:"li"},"\u6ce8\u91ca"),"\u3002")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-csharp"},"public class Server : ServerProvider\n{\n [XmlRpc]\n public int Sum(int a, int b)\n {\n return a + b;\n }\n\n [XmlRpc]\n public int TestClass(MyClass myClass)\n {\n return myClass.A + myClass.B;\n }\n}\n\npublic class MyClass\n{\n public int A { get; set; }\n public int B { get; set; }\n}\n\n")),(0,c.kt)("a",{name:"ai1L7"}),(0,c.kt)("h2",{id:"\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668"},"\u521b\u5efa\u670d\u52a1\u89e3\u6790\u5668"),(0,c.kt)("p",null,"\u670d\u52a1\u89e3\u6790\u5668\u662f\u5b9e\u9645\u7684\u670d\u52a1\u63a5\u6536\u3001\u89e6\u53d1\u3001\u8c03\u7528\u3001\u53cd\u9988\u7684\u5b9e\u9645\u8f7d\u4f53\uff0c\u901a\u4fd7\u6765\u8bf4\u5c31\u662f",(0,c.kt)("strong",{parentName:"p"},"\u901a\u4fe1\u670d\u52a1\u5668"),"\u3002"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-csharp"},'static IRpcParser CreateXmlRpcRpcParser()\n{\n HttpService service = new HttpService();\n\n service.Setup(new RRQMConfig().UsePlugin()\n .SetListenIPHosts(new IPHost[] { new IPHost(7706) }))\n .Start();\n\n return service.AddPlugin<XmlRpcParserPlugin>()\n .SetProxyToken("RPC")\n .SetXmlRpcUrl("/xmlRpc");\n}\n')),(0,c.kt)("a",{name:"iLCoX"}),(0,c.kt)("h2",{id:"\u6ce8\u518c\u53d1\u5e03\u670d\u52a1"},"\u6ce8\u518c\u3001\u53d1\u5e03\u670d\u52a1"),(0,c.kt)("p",null,"\u6dfb\u52a0\u89e3\u6790\u5668\uff08\u6dfb\u52a0\u65f6\u9700\u8981\u4ee5\u952e\u3001\u503c\u65b9\u5f0f\u6dfb\u52a0\uff0c\u65b9\u4fbf\u540e\u7eed\u67e5\u627e\uff09\uff0c\u7136\u540e",(0,c.kt)("inlineCode",{parentName:"p"},"\u6ce8\u518c\u670d\u52a1"),"\u5373\u53ef\u3002"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-csharp"},'static void Main(string[] args)\n{\n RpcService rpcService = new RpcService();\n\n //\u6dfb\u52a0\u89e3\u6790\u5668\uff0c\u89e3\u6790\u5668\u6839\u636e\u4f20\u8f93\u534f\u8bae\uff0c\u5e8f\u5217\u5316\u65b9\u5f0f\u7684\u4e0d\u540c\uff0c\u8c03\u7528RPC\u670d\u52a1\n rpcService.AddRpcParser("xmlRpcParser ", CreateXmlRpcRpcParser());\n\n //\u6ce8\u518c\u5f53\u524d\u7a0b\u5e8f\u96c6\u7684\u6240\u6709\u670d\u52a1\n rpcService.RegisterAllServer();\n\n //\u5206\u4eab\u4ee3\u7406\uff0c\u4ee3\u7406\u6587\u4ef6\u53ef\u901a\u8fc7RRQMTool\u8fdc\u7a0b\u83b7\u53d6\u3002\n rpcService.ShareProxy(new IPHost(8848));\n\n //\u6216\u8005\u76f4\u63a5\u672c\u5730\u5bfc\u51fa\u4ee3\u7406\u6587\u4ef6\u3002\n //RpcProxyInfo proxyInfo = rpcService.GetProxyInfo(RpcType.RRQMRPC, "RPC");\n //string codeString = CodeGenerator.ConvertToCode("RRQMProxy", proxyInfo.Codes);\n\n Console.WriteLine("\u670d\u52a1\u5668\u5df2\u542f\u52a8");\n Console.ReadKey();\n\n}\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/a2c90a25.03170d44.js b/handbook/build/assets/js/a2c90a25.03170d44.js new file mode 100644 index 000000000..6d58168d8 --- /dev/null +++ b/handbook/build/assets/js/a2c90a25.03170d44.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8719],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},c=Object.keys(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,c=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),k=o,f=d["".concat(i,".").concat(k)]||d[k]||s[k]||c;return n?r.createElement(f,a(a({ref:t},u),{},{components:n})):r.createElement(f,a({ref:t},u))}));function k(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=n.length,a=new Array(c);a[0]=d;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l.mdxType="string"==typeof e?e:o,a[1]=l;for(var p=2;p<c;p++)a[p]=n[p];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},8610:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>a,default:()=>s,frontMatter:()=>c,metadata:()=>l,toc:()=>p});var r=n(7462),o=(n(7294),n(3905));const c={id:"touchrpcbase",title:"\u57fa\u7840\u529f\u80fd"},a=void 0,l={unversionedId:"touchrpcbase",id:"touchrpcbase",title:"\u57fa\u7840\u529f\u80fd",description:"\u4e00\u3001\u8fde\u63a5\u9a8c\u8bc1",source:"@site/docs/touchrpcbase.mdx",sourceDirName:".",slug:"/touchrpcbase",permalink:"/touchsocket/docs/touchrpcbase",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/touchrpcbase.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675660193,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"touchrpcbase",title:"\u57fa\u7840\u529f\u80fd"},sidebar:"docs",previous:{title:"\u521b\u5efaTouchRpc\u5ba2\u6237\u7aef",permalink:"/touchsocket/docs/createtouchrpcclient"},next:{title:"\u521b\u5efarpc\u670d\u52a1",permalink:"/touchsocket/docs/createandcallrpc"}},i={},p=[{value:"\u4e00\u3001\u8fde\u63a5\u9a8c\u8bc1",id:"\u4e00\u8fde\u63a5\u9a8c\u8bc1",level:2},{value:"1.1 Token\u9a8c\u8bc1",id:"11-token\u9a8c\u8bc1",level:3},{value:"1.2 \u52a8\u6001\u9a8c\u8bc1",id:"12-\u52a8\u6001\u9a8c\u8bc1",level:3},{value:"\u4e8c\u3001ID\u540c\u6b65",id:"\u4e8cid\u540c\u6b65",level:2},{value:"\u4e09\u3001\u534f\u8bae\u6269\u5c55",id:"\u4e09\u534f\u8bae\u6269\u5c55",level:2},{value:"3.1 \u4f7f\u7528",id:"31-\u4f7f\u7528",level:3}],u={toc:p};function s(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8fde\u63a5\u9a8c\u8bc1"},"\u4e00\u3001\u8fde\u63a5\u9a8c\u8bc1"),(0,o.kt)("p",null,"\u8fde\u63a5\u9a8c\u8bc1\u53ef\u4ee5\u521d\u6b65\u4fdd\u8bc1\u8fde\u63a5\u5ba2\u6237\u7aef\u7684\u5b89\u5168\u6027\u3002\u6846\u67b6\u5185\u90e8\u9ed8\u8ba4\u4f7f\u7528\u4e00\u4e2astring\u7c7b\u578b\u7684Token\u4f5c\u4e3a\u9a8c\u8bc1\u51ed\u8bc1\u3002\u5f53\u7136\u4e5f\u5141\u8bb8\u670d\u52a1\u5668\u8fdb\u884c\u5176\u4ed6\u9a8c\u8bc1\u3002\u5177\u4f53\u5982\u4e0b\uff1a"),(0,o.kt)("h3",{id:"11-token\u9a8c\u8bc1"},"1.1 Token\u9a8c\u8bc1"),(0,o.kt)("p",null,"\u5728\u670d\u52a1\u5668\u6216\u5ba2\u6237\u7aef\u7684\u914d\u7f6e\u4e0a\uff0c\u8bbe\u7f6eVerifyToken\uff0c\u5373\u53ef\u5b9e\u73b0\u5b57\u7b26\u4e32Token\u9a8c\u8bc1\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'var config = new TouchSocketConfig()//\u914d\u7f6e\n .SetVerifyToken("TouchRpc");\n\n')),(0,o.kt)("h3",{id:"12-\u52a8\u6001\u9a8c\u8bc1"},"1.2 \u52a8\u6001\u9a8c\u8bc1"),(0,o.kt)("p",null,"\u4f7f\u7528\u63d2\u4ef6\uff0c\u91cd\u5199",(0,o.kt)("strong",{parentName:"p"},"OnHandshaking"),"\u76f8\u5173\u3002\u7136\u540e\u53ef\u4ee5\u81ea\u884c\u5224\u65ad\u4e00\u4e9b\u4fe1\u606f\uff0c\u6bd4\u5982\uff1aIP\u5730\u5740\u3001\u5143\u6570\u636e\u7b49\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'internal class MyTouchRpcPlugin : TouchRpcPluginBase\n{\n protected override void OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e)\n {\n if (e.Metadata["a"] != "a")\n {\n e.IsPermitOperation = false;//\u4e0d\u5141\u8bb8\u8fde\u63a5\n e.Message = "\u5143\u6570\u636e\u4e0d\u5bf9";//\u540c\u65f6\u8fd4\u56de\u6d88\u606f\n e.Handled= true;//\u8868\u793a\u8be5\u6d88\u606f\u5df2\u5728\u6b64\u5904\u5904\u7406\u3002\n return;\n }\n if (e.Token == "123")\n {\n e.IsPermitOperation = true;\n e.Handled = true;\n return;\n }\n base.OnHandshaking(client, e);\n }\n}\n')),(0,o.kt)("h2",{id:"\u4e8cid\u540c\u6b65"},"\u4e8c\u3001ID\u540c\u6b65"),(0,o.kt)("p",null,"\u5728TouchRpc\u4e2d\uff0c\u5b58\u5728\u4e8e\u670d\u52a1\u5668\u7684\u8f85\u52a9\u5ba2\u6237\u7aef\uff08SocketClient\uff09\uff0c\u4e0e\u8fdc\u7a0b\u5ba2\u6237\u7aef\uff08Client\uff09\u662f\u4e00\u4e00\u5bf9\u5e94\u5173\u7cfb\uff0c\u5176ID\u4e5f",(0,o.kt)("strong",{parentName:"p"},"\u5b8c\u5168\u4e00\u81f4"),"\u3002\u6240\u4ee5\u5728\u4efb\u610f\u4e00\u65b9\u4fee\u6539ID\uff08\u8c03\u7528ResetID\uff09\uff0c\u90fd\u4f1a\u540c\u65f6\u4fee\u6539\u8fdc\u7a0bID\u3002\u6240\u4ee5\u5408\u7406\u4f7f\u7528\u8be5\u64cd\u4f5c\uff0c\u53ef\u4ee5\u5b8c\u6210\u590d\u7528ID\uff08\u91cd\u7f6eID\uff09\u7684\u9700\u6c42\u3002"),(0,o.kt)("h2",{id:"\u4e09\u534f\u8bae\u6269\u5c55"},"\u4e09\u3001\u534f\u8bae\u6269\u5c55"),(0,o.kt)("p",null,"\u534f\u8bae\u6269\u5c55\u529f\u80fd\uff0c\u5c31\u662f\u5bf9\u73b0\u6709\u7684TouchRpc\u8fdb\u884c\u81ea\u5b9a\u4e49\u7684\u6269\u5c55\u534f\u8bae\u3002\u5176\u76ee\u7684\u5c31\u662f\u4e3a\u4e86\u5e94\u5bf9\u66f4\u52a0\u590d\u6742\uff0c\u9ad8\u8981\u6c42\u7684\u9700\u6c42\u3002"),(0,o.kt)("p",null,"\u4f8b1\uff1a\u5f53\u9700\u8981\u5e7f\u64ad\u6d88\u606f\u65f6\uff0c\u53ef\u80fd\u5927\u5bb6\u90fd\u4f1a\u60f3\u5230\u4f7f\u7528rpc\u76f4\u63a5\u8fdb\u884c\u5e7f\u64ad\u3002\u4f46\u662f\u5982\u6b64\u4e00\u6765\uff0c\u6bcf\u5e7f\u64ad\u4e00\u4e2a\u5ba2\u6237\u7aef\uff0c\u5c31\u9700\u8981\u5e8f\u5217\u5316\u4e00\u6b21\u3002\u56e0\u4e3a\u6570\u636e\u90fd\u662f\u4e00\u6837\u7684\uff0c\u6240\u4ee5\u591a\u6b21\u5e8f\u5217\u5316\u663e\u5f97\u975e\u5e38\u6ca1\u6709\u5fc5\u8981\u3002\u90a3\u4e48\u8fd9\u65f6\u5019\uff0c\u53ef\u4ee5\u81ea\u5b9a\u4e49\u534f\u8bae\uff0c\u7136\u540e\u5148\u5e8f\u5217\u5316\uff0c\u7136\u540e\u76f4\u63a5\u5e7f\u64ad\u6570\u636e\u3002"),(0,o.kt)("p",null,"\u81ea\u5b9a\u4e49\u534f\u8bae\u6548\u7387\u5982\u4f55\u5462\uff1f\n\u81ea\u5b9a\u4e49\u534f\u8bae\u7684\u6548\u7387\u662f\u975e\u5e38\u9ad8\u7684\uff0c99%\u63a5\u8fd1\u4e8e\u5e95\u5c42\u534f\u8bae\uff08\u53ef\u80fd\u662ftcp\u3001udp\u3001websocket\uff09\u6548\u7387\u3002"),(0,o.kt)("h3",{id:"31-\u4f7f\u7528"},"3.1 \u4f7f\u7528"),(0,o.kt)("p",null,"\u4f7f\u7528\u8d77\u6765\u662f\u975e\u5e38\u7b80\u5355\u7684\uff0c\u6bcf\u4e2aTouchRpc\u5ba2\u6237\u7aef\u6216\u8005TouchRpc\u670d\u52a1\u7aef\uff0c\u90fd\u5b9e\u73b0\u4e86Send\u65b9\u6cd5\u63a5\u53e3\u3002\n\u7b2c\u4e00\u4e2a\u53c2\u6570\u4e3ashort\u7c7b\u578b\uff0c\u4f7f\u7528\u8005\u53ef\u4ee5",(0,o.kt)("strong",{parentName:"p"},"\u7ea6\u5b9a\u4efb\u610f\u6570\u503c"),"\uff08",(0,o.kt)("strong",{parentName:"p"},"\u4e0d\u8981\u4f7f\u7528\u5c0f\u4e8e0\u7684\uff0c\u56e0\u4e3a\u6846\u67b6\u5185\u90e8\u5728\u4f7f\u7528"),"\uff09\u3002"),(0,o.kt)("p",null,"\u5728",(0,o.kt)("strong",{parentName:"p"},"\u63a5\u6536\u65b9"),"\u5728OnReceivedProtocolData\u51fd\u6570\u4e2d\uff0c\u5df2\u7ecf\u5305\u542b\u4e86\u534f\u8bae\u53c2\u6570\uff0c\u6240\u4ee5\u76f4\u63a5\u81ea\u884c\u7b5b\u9009\u5373\u53ef\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},"internal class MyTouchRpcPlugin : TouchRpcPluginBase\n{\n protected override void OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e)\n {\n if (e.Protocol == 10)\n {\n //\u5224\u65ad\u5b8c\u534f\u8bae\u4ee5\u540e\uff0c\u4ecee.ByteBlock\u53ef\u4ee5\u62ff\u5230\u5b9e\u9645\u7684\u6570\u636e\n //\u4f46\u662f\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u771f\u5b9e\u6570\u636e\u4f1a\u6574\u4f53\u5411\u53f3\u504f\u79fb2\u4e2a\u5b57\u8282\u3002\n string msg = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 2, e.ByteBlock.Len - 2);\n }\n base.OnReceivedProtocolData(client, e);\n }\n}\n")),(0,o.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"\u4eceProtocolDataEventArgs\u89e3\u6790\u7684ByteBlock\uff0c\u5176\u771f\u5b9e\u6570\u636e\u4f1a\u6574\u4f53\u5411\u53f3\u504f\u79fb2\u4e2a\u5b57\u8282\u3002\u56e0\u4e3a\u524d\u4e24\u4e2a\u5b57\u8282\u662fushort\u7684Protocol\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/a46d2111.e7fd3370.js b/handbook/build/assets/js/a46d2111.e7fd3370.js new file mode 100644 index 000000000..5583ed28a --- /dev/null +++ b/handbook/build/assets/js/a46d2111.e7fd3370.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8835],{3905:(t,e,r)=>{r.d(e,{Zo:()=>i,kt:()=>m});var l=r(7294);function n(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function a(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);e&&(l=l.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,l)}return r}function p(t){for(var e=1;e<arguments.length;e++){var r=null!=arguments[e]?arguments[e]:{};e%2?a(Object(r),!0).forEach((function(e){n(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function c(t,e){if(null==t)return{};var r,l,n=function(t,e){if(null==t)return{};var r,l,n={},a=Object.keys(t);for(l=0;l<a.length;l++)r=a[l],e.indexOf(r)>=0||(n[r]=t[r]);return n}(t,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);for(l=0;l<a.length;l++)r=a[l],e.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(t,r)&&(n[r]=t[r])}return n}var o=l.createContext({}),u=function(t){var e=l.useContext(o),r=e;return t&&(r="function"==typeof t?t(e):p(p({},e),t)),r},i=function(t){var e=u(t.components);return l.createElement(o.Provider,{value:e},t.children)},k={inlineCode:"code",wrapper:function(t){var e=t.children;return l.createElement(l.Fragment,{},e)}},d=l.forwardRef((function(t,e){var r=t.components,n=t.mdxType,a=t.originalType,o=t.parentName,i=c(t,["components","mdxType","originalType","parentName"]),d=u(r),m=n,s=d["".concat(o,".").concat(m)]||d[m]||k[m]||a;return r?l.createElement(s,p(p({ref:e},i),{},{components:r})):l.createElement(s,p({ref:e},i))}));function m(t,e){var r=arguments,n=e&&e.mdxType;if("string"==typeof t||n){var a=r.length,p=new Array(a);p[0]=d;var c={};for(var o in e)hasOwnProperty.call(e,o)&&(c[o]=e[o]);c.originalType=t,c.mdxType="string"==typeof t?t:n,p[1]=c;for(var u=2;u<a;u++)p[u]=r[u];return l.createElement.apply(null,p)}return l.createElement.apply(null,r)}d.displayName="MDXCreateElement"},9170:(t,e,r)=>{r.r(e),r.d(e,{assets:()=>o,contentTitle:()=>p,default:()=>k,frontMatter:()=>a,metadata:()=>c,toc:()=>u});var l=r(7462),n=(r(7294),r(3905));const a={id:"touchrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},p=void 0,c={unversionedId:"touchrpcdescription",id:"touchrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/touchrpcdescription.mdx",sourceDirName:".",slug:"/touchrpcdescription",permalink:"/touchsocket/docs/touchrpcdescription",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/touchrpcdescription.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675660193,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"touchrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},sidebar:"docs",previous:{title:"\u57fa\u4e8eWS\u7684JsonRpc",permalink:"/touchsocket/docs/wsjsonrpc"},next:{title:"\u521b\u5efaTouchRpc\u670d\u52a1\u5668",permalink:"/touchsocket/docs/createtouchrpcservice"}},o={},u=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"1.1 TouchRpc\u548cTcp\u3001Udp\u6709\u4ec0\u4e48\u5173\u7cfb\uff1f",id:"11-touchrpc\u548ctcpudp\u6709\u4ec0\u4e48\u5173\u7cfb",level:3},{value:"1.2 Tcp\u672c\u8eab\u5c31\u662f\u53ef\u9760\u4f20\u8f93\u534f\u8bae\u4e86\uff0c\u90a3TouchRpc\u7684\u53ef\u9760\u53c8\u4f53\u73b0\u5728\u4ec0\u4e48\u5730\u65b9\u5462\uff1f",id:"12-tcp\u672c\u8eab\u5c31\u662f\u53ef\u9760\u4f20\u8f93\u534f\u8bae\u4e86\u90a3touchrpc\u7684\u53ef\u9760\u53c8\u4f53\u73b0\u5728\u4ec0\u4e48\u5730\u65b9\u5462",level:3},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"2.1 \u57fa\u7840\u529f\u80fd",id:"21-\u57fa\u7840\u529f\u80fd",level:3},{value:"2.2 Rpc\u529f\u80fd",id:"22-rpc\u529f\u80fd",level:3},{value:"2.3 \u6587\u4ef6\u4f20\u8f93",id:"23-\u6587\u4ef6\u4f20\u8f93",level:3},{value:"2.4 \u8fdc\u7a0b\u64cd\u4f5c",id:"24-\u8fdc\u7a0b\u64cd\u4f5c",level:3},{value:"2.5 \u6d41\u6570\u636e\u65b9\u9762",id:"25-\u6d41\u6570\u636e\u65b9\u9762",level:3},{value:"2.6 Channel\u6570\u636e",id:"26-channel\u6570\u636e",level:3},{value:"2.7 EventBus",id:"27-eventbus",level:3},{value:"2.8 Redis",id:"28-redis",level:3},{value:"\u4e09\u3001\u573a\u666f",id:"\u4e09\u573a\u666f",level:2}],i={toc:u};function k(t){let{components:e,...r}=t;return(0,n.kt)("wrapper",(0,l.Z)({},i,r,{components:e,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,n.kt)("p",null,"TouchRpc\u662f\u4e00\u4e2a\u7b80\u5355\u6613\u7528\uff0c\u4fbf\u6377\u9ad8\u6548\uff0c\u4e14\u6613\u4e8e\u6269\u5c55\u7684",(0,n.kt)("strong",{parentName:"p"},"\u81ea\u5b9a\u4e49\u6570\u636e\u683c\u5f0f"),"\u7684",(0,n.kt)("strong",{parentName:"p"},"\u53ef\u9760\u6267\u884c\u4f20\u8f93\u534f\u8bae"),"\u3002"),(0,n.kt)("p",null,"\u3010\u534f\u8bae\u683c\u5f0f\u3011"),(0,n.kt)("p",null,"| 2\u5b57\u8282 | n\u5b57\u8282 |"),(0,n.kt)("p",null,"\u534f\u8bae\u683c\u5f0f\u975e\u5e38\u7b80\u5355\u3002\n\u524d\u4e24\u4e2a\u5b57\u8282\u4e3a\u9ed8\u8ba4\u7aef\u5e8f\u7684\u5c0f\u7aef\uff0cint16\u6709\u7b26\u53f7\u7c7b\u578b\u3002\u5176\u4e2d\u5c0f\u4e8e0\u7684\u534f\u8bae\u4e00\u822c\u4e0d\u8981\u5360\u7528\uff0c\u56e0\u4e3a\u6846\u67b6\u5728\u4f7f\u7528\u3002\n\u540e\u7eed\u5b57\u8282\u5219\u4e3a\u672c\u6b21\u534f\u8bae\u7684\u8f7d\u8377\u6570\u636e\u3002"),(0,n.kt)("p",null,"\u7ec6\u5fc3\u7684\u5c0f\u4f19\u4f34\u53ef\u80fd\u4f1a\u95ee\uff0c\u8fd9\u4e2a\u6570\u636e\u534f\u8bae\u6ca1\u6709\u5206\u5305\u6807\u8bc6\u554a\uff0c\u4e5f\u5c31\u662f\u65e0\u6cd5\u5206\u8fa8\u4e00\u4e2a\u6570\u636e\u5305\u662f\u4e0d\u662f\u5b8c\u6574\u7684\u3002\u8fd9\u662f\u56e0\u4e3aTouchRpc\u652f\u6301\u591a\u79cd\u534f\u8bae\u8fd0\u884c\uff0c\u53ef\u80fd\u5728\u4e00\u4e9b\u534f\u8bae\u4e0a\uff0c\u5c31\u5df2\u7ecf\u6db5\u76d6\u4e86\u5206\u5305\u673a\u5236\uff0c\u6240\u4ee5\u4e3a\u907f\u514d\u8fc7\u5ea6\u5c01\u88c5\uff0c\u6240\u4ee5TouchRpc\u5e76\u672a\u5236\u5b9a\u5206\u5305\u3002\u6240\u4ee5TouchRpc\u5728\u4e0d\u540c\u534f\u8bae\u5de5\u4f5c\u65f6\uff0c\u53ef\u80fd\u5b9e\u9645\u7684\u6570\u636e\u683c\u5f0f\u4e5f\u4e0d\u76f8\u540c\u3002"),(0,n.kt)("p",null,"\u4f8b\u5982\uff1a\u5728Tcp\u5de5\u4f5c\u65f6\uff0c\u5176\u5206\u5305\u7b97\u6cd5\u4f7f\u7528\u7684\u662f",(0,n.kt)("a",{parentName:"p",href:"/touchsocket/docs/fixedheaderpackageadapter"},"\u56fa\u5b9a\u5305\u5934"),"\u3002\u5728websocket\u5de5\u4f5c\u65f6\uff0c\u4f7f\u7528\u7684\u5c31\u662f\u5176\u81ea\u8eab\u7684\u5206\u5305\u7b97\u6cd5\u3002"),(0,n.kt)("p",null,"\u53ef\u80fd\u597d\u591a\u4eba\u4f1a\u7591\u60d1\uff0cTouchRpc\u548ctcp\u3001udp\u6709\u4ec0\u4e48\u5173\u7cfb\uff1f\u6216\u8005\u8bf4\uff0c\u7c7b\u4f3ctcp\uff0c\u672c\u8eab\u5c31\u662f\u53ef\u9760\u4f20\u8f93\u534f\u8bae\u4e86\uff0c\u90a3TouchRpc\u7684\u53ef\u9760\u53c8\u4f53\u73b0\u5728\u4ec0\u4e48\u5730\u65b9\u5462\uff1f"),(0,n.kt)("h3",{id:"11-touchrpc\u548ctcpudp\u6709\u4ec0\u4e48\u5173\u7cfb"},"1.1 TouchRpc\u548cTcp\u3001Udp\u6709\u4ec0\u4e48\u5173\u7cfb\uff1f"),(0,n.kt)("p",null,"TouchRpc\u50cfhttp\u548cwebsocket\u4e00\u6837\uff0c\u4e5f\u662f\u5c01\u88c5\u7684\u5e94\u7528\u5c42\u534f\u8bae\u3002\u5b83\u53ef\u4ee5\u57fa\u4e8e\u6700\u57fa\u672c\u7684tcp\u6216udp\u5de5\u4f5c\uff0c\u4e5f\u80fd\u57fa\u4e8ehttp\u548cwebsocket\u5de5\u4f5c\u3002\u6240\u4ee5\uff0c\u53ef\u4ee5\u8ba4\u4e3aTouchRpc\u662f\u66f4\u4e3a\u9ad8\u7ea7\u7684\u5e94\u7528\u5c42\u534f\u8bae\u3002"),(0,n.kt)("h3",{id:"12-tcp\u672c\u8eab\u5c31\u662f\u53ef\u9760\u4f20\u8f93\u534f\u8bae\u4e86\u90a3touchrpc\u7684\u53ef\u9760\u53c8\u4f53\u73b0\u5728\u4ec0\u4e48\u5730\u65b9\u5462"},"1.2 Tcp\u672c\u8eab\u5c31\u662f\u53ef\u9760\u4f20\u8f93\u534f\u8bae\u4e86\uff0c\u90a3TouchRpc\u7684\u53ef\u9760\u53c8\u4f53\u73b0\u5728\u4ec0\u4e48\u5730\u65b9\u5462\uff1f"),(0,n.kt)("p",null,"\u9996\u5148\u5462\uff0c\u6211\u4eec\u5f97\u660e\u786e\uff0ctcp\u7684\u53ef\u9760\uff0c\u662f\u5728\u4fdd\u6301\u8fde\u63a5\u7684\u65f6\u5019\uff0c\u624d\u53ef\u9760\u3002\u5f53\u7a81\u7136\u65ad\u7f51\u65f6\uff0c\u8fd9\u79cd\u53ef\u9760\u5c06\u88ab\u6253\u7834\u3002\u5176\u6b21\u8fd9\u79cd\u53ef\u9760\u662f\u5355\u9879\u7684\uff0c\u4e3e\u4f8b\u6765\u8bf4\uff0c\u53d1\u9001\u65b9\u53ea\u662f\u8d1f\u8d23\u5c06\u6570\u636e\u53d1\u7ed9\u63a5\u6536\u65b9\uff0c\u81f3\u4e8e\u63a5\u6536\u65b9\u5904\u7406\u4e86\u6ca1\u6709\uff0c\u6216\u8005\u5904\u7406\u7ed3\u679c\u5982\u4f55\uff0c\u90fd\u662f\u672a\u77e5\u7684\u3002\u90a3\u4e48\u8fd9\u65f6\u5019\u806a\u660e\u7684\u5c0f\u4f19\u4f34\u5c31\u4f1a\u60f3\u5230\u8ba9\u63a5\u6536\u65b9\u56de\u590d\u4e00\u4e2a\u72b6\u6001\u4e0d\u5c31\u884c\u4e86\uff1f\u662f\u7684\uff0c\u8fd9\u5c31\u662fTouchRpc\u5de5\u4f5c\u7684\u573a\u666f\u4e4b\u4e00\u4e86\u3002"),(0,n.kt)("p",null,"\u5f53\u7136\uff0cTouchRpc\u7684\u529f\u80fd\u8fdc\u975e\u4e0a\u8ff0\u7684\u4e24\u4e2a\u573a\u666f\uff0c\u8be6\u7ec6\u6982\u89c8\u5982\u4e0b\uff1a"),(0,n.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,n.kt)("h3",{id:"21-\u57fa\u7840\u529f\u80fd"},"2.1 \u57fa\u7840\u529f\u80fd"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301",(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/touchrpcbase"},"\u8fde\u63a5\u9a8c\u8bc1"),"\uff0c\u4e5f\u652f\u6301\u52a8\u6001\u4fe1\u606f\u9a8c\u8bc1\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301",(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/touchrpcbase"},"ID\u540c\u6b65"),"\uff0c\u6bcf\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5\u5230\u670d\u52a1\u5668\u540e\uff0c\u81ea\u8eabID\u4f1a\u4e0e\u670d\u52a1\u5668ID\u540c\u6b65\uff0c\u4e14\u652f\u6301\u91cd\u7f6e\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301ssl\u52a0\u5bc6\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301",(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/touchrpcbase"},"\u534f\u8bae\u6269\u5c55"),"\u3002")),(0,n.kt)("h3",{id:"22-rpc\u529f\u80fd"},"2.2 Rpc\u529f\u80fd"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5e38\u89c4",(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/touchrpcbase"},"rpc"),"\u64cd\u4f5c\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u4ee3\u7406\u4ee3\u7801\u751f\u6210\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u81ea\u5b9a\u4e49\u7c7b\u578b\u7684\u53c2\u6570\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301out\u3001ref\u5173\u952e\u5b57\u53c2\u6570\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u670d\u52a1\u5668\u4e3b\u52a8Call\u5ba2\u6237\u7aef\u548c\u5ba2\u6237\u7aef\u4e4b\u95f4\u4e92Call\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u8c03\u7528\u4e0a\u4e0b\u6587\uff0c\u53ef\u8fdb\u884c\u670d\u52a1AOP\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5f02\u6b65\u8c03\u7528\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u8c03\u7528\u8d85\u65f6\u3001\u8c03\u7528\u4e2d\u65ad\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5168\u5f02\u5e38\u53cd\u9988\uff0c\u88ab\u8c03\u7528\u65b9\u53d1\u751f\u7684\u4e00\u5207\u5f02\u5e38\uff0c\u90fd\u4f1a\u4f20\u9012\u5230\u8c03\u7528\u65b9\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301.NET\u4e8c\u8fdb\u5236\u5e8f\u5217\u5316\u3001Json\u5e8f\u5217\u5316\u3001xml\u5e8f\u5217\u5316\u3001Fast\u5e8f\u5217\u5316\uff0c\u4ee5\u53ca\u81ea\u5b9a\u4e49\u5e8f\u5217\u5316\u6269\u5c55\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u9ad8\u6027\u80fd\u8c03\u7528\uff0c\u5728\u4fdd\u8bc1\u9001\u8fbe\u4f46\u4e0d\u8fd4\u56de\u7684\u60c5\u51b5\u4e0b\uff0c10w\u6b21\u8c03\u7528\u7528\u65f60.8s\uff0c\u5728\u8fd4\u56de\u7684\u60c5\u51b5\u4e0b\uff0c\u7528\u65f63.9s\u3002")),(0,n.kt)("h3",{id:"23-\u6587\u4ef6\u4f20\u8f93"},"2.3 \u6587\u4ef6\u4f20\u8f93"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u4efb\u610f\u5927\u5c0f\u7684\u6587\u4ef6\u4f20\u8f93\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u65ad\u70b9\u7eed\u4f20\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u4f20\u8f93\u9650\u901f\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u670d\u52a1\u5668\u4e3b\u52a8\u5411\u5ba2\u6237\u7aef\u8bf7\u6c42\u3001\u53d1\u9001\u6587\u4ef6\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5ba2\u6237\u7aef\u4e4b\u95f4\u4e92\u76f8\u8bf7\u6c42\u3001\u53d1\u9001\u6587\u4ef6\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5c0f\u6587\u4ef6\u5feb\u901f\u4f20\u8f93\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u8d85\u5927\u6587\u4ef6\u591a\u94fe\u8def\u3001\u591a\u7ebf\u7a0b\u4f20\u8f93\u3002")),(0,n.kt)("h3",{id:"24-\u8fdc\u7a0b\u64cd\u4f5c"},"2.4 \u8fdc\u7a0b\u64cd\u4f5c"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u521b\u5efa\u6587\u4ef6\u5939\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u6587\u4ef6\u7684\u5220\u9664\u3001\u79fb\u52a8\u3001\u91cd\u547d\u540d\u7b49\u64cd\u4f5c\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u670d\u52a1\u5668\u5bf9\u5ba2\u6237\u7aef\u7684\u4e3b\u52a8\u64cd\u4f5c\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5ba2\u6237\u7aef\u4e4b\u95f4\u7684\u64cd\u4f5c\u3002")),(0,n.kt)("h3",{id:"25-\u6d41\u6570\u636e\u65b9\u9762"},"2.5 \u6d41\u6570\u636e\u65b9\u9762"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u53d1\u9001\u4efb\u610f\u7c7b\u578b\u7684Stream\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5c06\u8fdc\u7a0b\u7684\u6d41\u6570\u636e\u6620\u5c04\u5230\u672c\u5730\uff0c\u7136\u540e\u76f4\u63a5Read\u6216Write\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5b9e\u65bd\u4f20\u8f93\u538b\u7f29\u3002")),(0,n.kt)("h3",{id:"26-channel\u6570\u636e"},"2.6 Channel\u6570\u636e"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u72ec\u7acb\u901a\u9053\u6570\u636e\uff0c\u53ef\u8fdb\u884c\u6570\u636e\u9694\u79bb\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u670d\u52a1\u5668\u5230\u5ba2\u6237\u7aef\uff0c\u5ba2\u6237\u7aef\u5230\u5ba2\u6237\u7aef\u7684\u64cd\u4f5c\u3002")),(0,n.kt)("h3",{id:"27-eventbus"},"2.7 EventBus"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u4e8b\u4ef6\u7684\u521b\u5efa\u3001\u8ba2\u9605\u3001\u53d6\u6d88\u3001\u89e6\u53d1\u7b49\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u89e6\u53d1\u6743\u9650\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u4e8b\u4ef6\u5e7f\u64ad\u3002")),(0,n.kt)("h3",{id:"28-redis"},"2.8 Redis"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301string\u4e3a\u952e\u7684\u4efb\u610f\u7c7b\u578b\u7684\u6570\u636e\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u670d\u52a1\u5668\u5411\u5ba2\u6237\u7aef\u5b58\u50a8\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u652f\u6301\u5b58\u50a8\u6301\u4e45\u5316\u3002")),(0,n.kt)("h2",{id:"\u4e09\u573a\u666f"},"\u4e09\u3001\u573a\u666f"),(0,n.kt)("p",null,"\u4ec0\u4e48\u60c5\u51b5\u4e0b\u4f7f\u7528TouchRpc\u6bd4\u8f83\u597d\u5462\uff1f\u9996\u5148\uff0c\u4f60\u5f97\u5148\u4e86\u89e3RPC\uff0c\u4e86\u89e3\u5b8c\u540e\uff0c\u56e0\u4e3aTouchRpc\u65e0\u6cd5\u8de8\u8bed\u8a00\uff0c\u6240\u4ee5\uff0c\u5efa\u8bae\u4ee5\u4e0b\u573a\u666f\u4f7f\u7528TouchRpc\u6bd4\u8f83\u7a33\u59a5\u3002"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u4e0d\u9700\u8981\u8de8\u8bed\u8a00\u7684\u7ec8\u7aef\uff0c\u4f8b\u5982\uff1aUnity\u6e38\u620f\uff0cWinform\u3001WPF\u3001MAUI\u7b49\u8f6f\u4ef6\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u670d\u52a1\u5668\u4e4b\u95f4\u96c6\u7fa4\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u6269\u5c55\u5fae\u670d\u52a1\uff0c\u6b64\u65f6\u53ef\u4ee5\u4f7f\u7528\u53cd\u5411RPC\u5b9e\u73b0\u3002")),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"\u5b9e\u9645\u4e0aTouchRpc\u6709\u56db\u4e2a\u7248\u672c\uff0c\u5206\u522b\u4e3a\uff1a")),(0,n.kt)("table",null,(0,n.kt)("thead",{parentName:"table"},(0,n.kt)("tr",{parentName:"thead"},(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u7c7b\u578b")),(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u7279\u6027")))),(0,n.kt)("tbody",{parentName:"table"},(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"Tcp\u7248")),(0,n.kt)("td",{parentName:"tr",align:null},"\u57fa\u4e8eTCP\u534f\u8bae\uff0c\u8fde\u63a5\u6027\u80fd\u6700\u597d\uff0c\u6267\u884c\u6548\u7387\u6700\u9ad8\uff0c\u652f\u6301TouchRpc\u6240\u6709\u529f\u80fd\u3002")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"Udp\u7248")),(0,n.kt)("td",{parentName:"tr",align:null},"\u57fa\u4e8eUDP Package\u534f\u8bae\uff0c\u65e0\u8fde\u63a5\uff0c\u6267\u884c\u6548\u7387\u9ad8\uff0c\u4ec5\u652f\u6301TouchRpc\u7684Rpc\u529f\u80fd\u3002")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"Http\u7248")),(0,n.kt)("td",{parentName:"tr",align:null},"\u57fa\u4e8eHttp\u63e1\u624b\u8fde\u63a5\uff0c\u6570\u636e\u4ea4\u4e92\u4ecd\u7136\u4f7f\u7528TCP\u3002\u8fde\u63a5\u6027\u80fd\u4e00\u822c\uff0c\u4f46\u517c\u5bb9\u6027\u5f3a\uff0c\u652f\u6301JsonRpc\uff0cWebApi\uff0cXmlRpc\uff0cWebSocket\u7b49\u4e00\u7cfb\u5217Http\u7ec4\u4ef6\uff0c\u4e14\u6267\u884c\u6548\u7387\u548cTCP\u7248\u4e00\u6837\u9ad8\uff0c\u652f\u6301TouchRpc\u6240\u6709\u529f\u80fd\u3002")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"WebSocket\u7248")),(0,n.kt)("td",{parentName:"tr",align:null},"\u8be5\u7248\u672c\u662f\u4ec5\u9002\u7528\u4e8eAsp.Net Core\u7684\u7248\u672c\uff0c\u7279\u70b9\u5c31\u662f\u548cAsp.Net Core\u5171\u7528\u7aef\u53e3\u3002\u4f46\u662f\u6267\u884c\u6570\u636e\u4f7f\u7528\u7684\u662fWebSocket\uff0c\u6240\u6709\u6548\u7387\u53ea\u6709Tcp\u7248\u768480%\u3002\u652f\u6301TouchRpc\u6240\u6709\u529f\u80fd")))))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/a81d4448.6d40d457.js b/handbook/build/assets/js/a81d4448.6d40d457.js new file mode 100644 index 000000000..0d1fac58c --- /dev/null +++ b/handbook/build/assets/js/a81d4448.6d40d457.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6191],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var l=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,l)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,l,a=function(e,t){if(null==e)return{};var n,l,a={},r=Object.keys(e);for(l=0;l<r.length;l++)n=r[l],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(l=0;l<r.length;l++)n=r[l],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=l.createContext({}),c=function(e){var t=l.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return l.createElement(p.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},d=l.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,p=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=c(n),k=a,m=d["".concat(p,".").concat(k)]||d[k]||s[k]||r;return n?l.createElement(m,i(i({ref:t},u),{},{components:n})):l.createElement(m,i({ref:t},u))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=d;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o.mdxType="string"==typeof e?e:a,i[1]=o;for(var c=2;c<r;c++)i[c]=n[c];return l.createElement.apply(null,i)}return l.createElement.apply(null,n)}d.displayName="MDXCreateElement"},1413:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>s,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var l=n(7462),a=(n(7294),n(3905));const r={id:"createtcpclient",title:"\u521b\u5efaTcpClient"},i=void 0,o={unversionedId:"createtcpclient",id:"createtcpclient",title:"\u521b\u5efaTcpClient",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/createtcpclient.mdx",sourceDirName:".",slug:"/createtcpclient",permalink:"/touchsocket/docs/createtcpclient",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createtcpclient.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675609832,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"createtcpclient",title:"\u521b\u5efaTcpClient"},sidebar:"docs",previous:{title:"\u521b\u5efaTcpService",permalink:"/touchsocket/docs/createtcpservice"},next:{title:"\u540c\u6b65\u8bf7\u6c42",permalink:"/touchsocket/docs/waitingclient"}},p={},c=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4ea7\u54c1\u5e94\u7528\u573a\u666f",id:"\u4e09\u4ea7\u54c1\u5e94\u7528\u573a\u666f",level:2},{value:"\u56db\u3001\u53ef\u914d\u7f6e\u9879",id:"\u56db\u53ef\u914d\u7f6e\u9879",level:2},{value:"SetBufferLength",id:"setbufferlength",level:4},{value:"SetMaxPackageSize",id:"setmaxpackagesize",level:4},{value:"SetThreadCount",id:"setthreadcount",level:4},{value:"SetGetDefaultNewID",id:"setgetdefaultnewid",level:4},{value:"SetListenIPHosts",id:"setlisteniphosts",level:4},{value:"SetServerName",id:"setservername",level:4},{value:"SetBacklogProperty",id:"setbacklogproperty",level:4},{value:"SetMaxCount",id:"setmaxcount",level:4},{value:"SetReceiveType",id:"setreceivetype",level:4},{value:"UsePlugin",id:"useplugin",level:4},{value:"SetServiceSslOption",id:"setservicessloption",level:4},{value:"UseNoDelay",id:"usenodelay",level:4},{value:"UseDelaySender",id:"usedelaysender",level:4},{value:"UseReuseAddress",id:"usereuseaddress",level:4},{value:"SetRemoteIPHost",id:"setremoteiphost",level:4},{value:"SetClientSslOption",id:"setclientssloption",level:4},{value:"SetKeepAliveValue",id:"setkeepalivevalue",level:4},{value:"SetBindIPHost",id:"setbindiphost",level:4},{value:"UseDelaySender",id:"usedelaysender-1",level:4},{value:"UseNoDelay",id:"usenodelay-1",level:4},{value:"UseBroadcast",id:"usebroadcast",level:4},{value:"\u4e94\u3001\u652f\u6301\u63d2\u4ef6",id:"\u4e94\u652f\u6301\u63d2\u4ef6",level:2},{value:"\u516d\u3001\u521b\u5efaTcpClient",id:"\u516d\u521b\u5efatcpclient",level:2},{value:"\u4e03\u3001\u63a5\u6536\u6570\u636e",id:"\u4e03\u63a5\u6536\u6570\u636e",level:2},{value:"7.1 Received\u59d4\u6258\u5904\u7406",id:"71-received\u59d4\u6258\u5904\u7406",level:3},{value:"7.2 \u63d2\u4ef6\u5904\u7406\u63a8\u8350",id:"72-\u63d2\u4ef6\u5904\u7406\u63a8\u8350",level:3},{value:"\u516b\u3001\u53d1\u9001\u6570\u636e",id:"\u516b\u53d1\u9001\u6570\u636e",level:2}],u={toc:c};function s(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,l.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"TcpClient\u662fTcp\u7cfb\u5ba2\u6237\u7aef\u57fa\u7c7b\uff0c\u4ed6\u76f4\u63a5\u53c2\u4e0etcp\u7684\u8fde\u63a5\u3001\u53d1\u9001\u3001\u63a5\u6536\u3001\u5904\u7406\u3001\u65ad\u5f00\u7b49\uff0c\u4ed6\u7684\u4e1a\u52a1\u4e0e\u670d\u52a1\u5668\u7684",(0,a.kt)("strong",{parentName:"p"},"SocketClient"),"\u662f\u4e00\u4e00\u5bf9\u5e94\u7684\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u7b80\u5355\u6613\u7528\u3002"),(0,a.kt)("li",{parentName:"ul"},"IOCP\u591a\u7ebf\u7a0b\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u5185\u5b58\u6c60\u652f\u6301"),(0,a.kt)("li",{parentName:"ul"},"\u9ad8\u6027\u80fd"),(0,a.kt)("li",{parentName:"ul"},"\u9002\u914d\u5668\u9884\u5904\u7406\uff0c\u4e00\u952e\u5f0f\u89e3\u51b3",(0,a.kt)("strong",{parentName:"li"},"\u5206\u5305"),"\u3001",(0,a.kt)("strong",{parentName:"li"},"\u7c98\u5305"),"\u3001\u5bf9\u8c61\u89e3\u6790(\u5982HTTP\uff0cJson)\u7b49\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u8d85\u7b80\u5355\u7684\u540c\u6b65\u53d1\u9001\u3001\u5f02\u6b65\u53d1\u9001\u3001\u63a5\u6536\u7b49\u64cd\u4f5c\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u57fa\u4e8e\u59d4\u6258\u3001\u63d2\u4ef6\u9a71\u52a8\uff0c\u8ba9\u6bcf\u4e00\u6b65\u90fd\u80fd\u6267\u884cAOP\u3002")),(0,a.kt)("h2",{id:"\u4e09\u4ea7\u54c1\u5e94\u7528\u573a\u666f"},"\u4e09\u3001\u4ea7\u54c1\u5e94\u7528\u573a\u666f"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u6240\u6709Tcp\u57fa\u7840\u4f7f\u7528\u573a\u666f\uff1a\u53ef\u8de8\u5e73\u53f0\u3001\u8de8\u8bed\u8a00\u4f7f\u7528\u3002"),(0,a.kt)("li",{parentName:"ul"},"\u81ea\u5b9a\u4e49\u534f\u8bae\u89e3\u6790\u573a\u666f\uff1a\u53ef\u89e3\u6790\u4efb\u610f\u6570\u636e\u683c\u5f0f\u7684TCP\u6570\u636e\u62a5\u6587\u3002")),(0,a.kt)("h2",{id:"\u56db\u53ef\u914d\u7f6e\u9879"},"\u56db\u3001\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("details",null,(0,a.kt)("summary",null,"\u53ef\u914d\u7f6e\u9879"),(0,a.kt)("div",null,(0,a.kt)("h4",{id:"setbufferlength"},"SetBufferLength"),(0,a.kt)("p",null,"\u53d1\u9001\u3001\u63a5\u6536\u7f13\u5b58\u5bb9\u91cf\uff08\u5355\u4f4d\uff1abyte\uff09\uff0c\u9ed8\u8ba41024\xd764\u3002\u8bbe\u7f6e\u5efa\u8bae\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5982\u679c\u6570\u636e\u5305\u8f83\u5c0f\uff0c\u5efa\u8bae10k\u5de6\u53f3\u7684\u503c\u3002\u66f4\u52a0\u8282\u7ea6\u5185\u5b58\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u5982\u679c\u6570\u636e\u5305\u8f83\u5927\uff0c\u4f8b\u5982\u6587\u4ef6\u4f20\u8f93\u7b49\uff0c\u5efa\u8bae64k\uff0c\u751a\u81f3\u66f4\u5927\u7684\u503c\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u8be5\u503c\u867d\u7136\u65e0\u4e0a\u9650\uff0c\u4f46\u662f\u4e00\u822c\u4e0d\u8981\u8d85\u8fc71Mb\uff0c\u4e0d\u7136\u4e0d\u4ec5\u6ca1\u610f\u4e49\uff0c\u8fd8\u5f88\u6d6a\u8d39")),(0,a.kt)("h4",{id:"setmaxpackagesize"},"SetMaxPackageSize"),(0,a.kt)("p",null,"\u6570\u636e\u5305\u6700\u5927\u503c\uff08\u5355\u4f4d\uff1abyte\uff09\uff0c\u9ed8\u8ba41024\xd71024\xd710\u3002\u8be5\u503c\u4f1a\u5728\u9002\u5f53\u65f6\u95f4\uff0c\u76f4\u63a5\u4f5c\u7528DataHandlingAdapter.MaxPackageSize\u3002 "),(0,a.kt)("h4",{id:"setthreadcount"},"SetThreadCount"),(0,a.kt)("p",null,"\u591a\u7ebf\u7a0b\u6570\u91cf\u3002\u8be5\u503c\u5728Auto\u6a21\u5f0f\u4e0b\u6307\u793a\u7ebf\u7a0b\u6c60\u7684\u6700\u5c11\u7ebf\u7a0b\u6570\u91cf\u548cIO\u7ebf\u7a0b\u6570\u91cf\u3002"),(0,a.kt)("p",null,"\u8bbe\u7f6e\u5efa\u8bae\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5f02\u6b65\u5904\u7406\u63a5\u6536\u6570\u636e\uff0c\u6b64\u65f6\u7ebf\u7a0b\u6570\u91cf\u8bbe\u7f6e\u4e3a\u5185\u6838\u7ebf\u7a0b\u5de6\u53f3\u7684\u503c\u5373\u53ef\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u540c\u6b65\u5904\u7406\u63a5\u6536\u6570\u636e\uff0c\u6b64\u65f6\u5e94\u5f53\u8003\u8651\u4e24\u4e2a\u56e0\u7d20\u3002\u8be5\u64cd\u4f5c\u662f\u5426\u4e3a\u8017\u65f6\u64cd\u4f5c\uff0c\u5982\u679c\u662f\uff0c\u5219\u8be5\u503c\u5728\u5141\u8bb8\u8303\u56f4\u5185\uff0c\u5e94\u5f53\u8bbe\u7f6e\u66f4\u53ef\u80fd\u5927\u7684\u503c\u3002\u5982\u679c\u4e0d\u662f\uff0c\u5219\u8bbe\u7f6e\u4e3a\u5185\u6838\u7ebf\u7a0b\u5de6\u53f3\u7684\u503c\u5373\u53ef\u3002")),(0,a.kt)("h4",{id:"setgetdefaultnewid"},"SetGetDefaultNewID"),(0,a.kt)("p",null,"\u914d\u7f6e\u521d\u59cbID\u7684\u5206\u914d\u7b56\u7565"),(0,a.kt)("h4",{id:"setlisteniphosts"},"SetListenIPHosts"),(0,a.kt)("p",null,"\u76d1\u542cIP\u548c\u7aef\u53e3\u53f7\u7ec4\uff0c\u53ef\u4ee5\u4e00\u6b21\u6027\u8bbe\u7f6e\u591a\u4e2a\u5730\u5740\u3002 "),(0,a.kt)("h4",{id:"setservername"},"SetServerName"),(0,a.kt)("p",null,"\u670d\u52a1\u5668\u6807\u8bc6\u540d\u79f0\uff0c\u65e0\u5b9e\u9645\u4f7f\u7528\u610f\u4e49\u3002"),(0,a.kt)("h4",{id:"setbacklogproperty"},"SetBacklogProperty"),(0,a.kt)("p",null,"Tcp\u534a\u8fde\u63a5\u6302\u8d77\u8fde\u63a5\u961f\u5217\u7684\u6700\u5927\u957f\u5ea6\u3002\u9ed8\u8ba4\u4e3a30 "),(0,a.kt)("h4",{id:"setmaxcount"},"SetMaxCount"),(0,a.kt)("p",null,"\u6700\u5927\u53ef\u8fde\u63a5\u6570\uff0c\u9ed8\u8ba4\u4e3a10000 "),(0,a.kt)("h4",{id:"setreceivetype"},"SetReceiveType"),(0,a.kt)("p",null,"\u63a5\u6536\u7c7b\u578b\u3002"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"AUTO\uff1a\u81ea\u52a8\u63a5\u6536\u6a21\u5f0f\u3002"),(0,a.kt)("li",{parentName:"ul"},"None\uff1a\u4e0d\u6295\u9012IO\u63a5\u6536\u7533\u8bf7\uff0c\u7528\u6237\u53ef\u901a\u8fc7GetStream\uff0c\u83b7\u53d6\u5230\u6d41\u4ee5\u540e\uff0c\u81ea\u5df1\u5904\u7406\u63a5\u6536\u3002\u6ce8\u610f\uff1a\u8fde\u63a5\u7aef\u4e0d\u4f1a\u611f\u77e5\u4e3b\u52a8\u65ad\u5f00\u3002")),(0,a.kt)("h4",{id:"useplugin"},"UsePlugin"),(0,a.kt)("p",null,"\u662f\u5426\u542f\u7528\u63d2\u4ef6\u3002\u5728\u542f\u7528\u65f6\u6216\u8bb8\u4f1a\u5e26\u6765\u4e00\u70b9\u70b9\u6027\u80fd\u635f\u8017\uff0c\u57fa\u672c\u4e0a\u4e0d\u662f\u5343\u4e07\u6570\u636e\u4ea4\u4e92\u6839\u672c\u4e0d\u503c\u4e00\u63d0\u3002"),(0,a.kt)("h4",{id:"setservicessloption"},"SetServiceSslOption"),(0,a.kt)("p",null,"Ssl\u914d\u7f6e\uff0c\u4e3aNull\u65f6\u5219\u4e0d\u542f\u7528\u3002 "),(0,a.kt)("h4",{id:"usenodelay"},"UseNoDelay"),(0,a.kt)("p",null,"\u8bbe\u7f6eSocket\u7684NoDelay\u5c5e\u6027\uff0c\u9ed8\u8ba4false\u3002 "),(0,a.kt)("h4",{id:"usedelaysender"},"UseDelaySender"),(0,a.kt)("p",null,"\u4f7f\u7528\u5ef6\u8fdf\u53d1\u9001\u3002\u4f17\u6240\u5468\u77e5\uff0ctcp\u6570\u636e\u62a5\u6587\u4e3a\u4e86\u53d1\u9001\u6548\u7387\uff0c\u4f1a\u9ed8\u8ba4\u542f\u7528",(0,a.kt)("strong",{parentName:"p"},"\u5ef6\u8fdf\u7b97\u6cd5"),"\u3002\u4f46\u662f\u8fd9\u79cd\u8bbe\u7f6e\uff0c\u53ea\u80fd\u4e00\u5b9a\u7a0b\u5ea6\u7684\u7f13\u89e3\u5c0f\u6570\u636e\u53d1\u9001\u6548\u7387\u4f4e\u7684\u95ee\u9898\uff0c\u56e0\u4e3a\u5b83\u4e3a\u4e86\u4fdd\u8bc1\u591a\u7ebf\u7a0b\u53d1\u9001\u7684\u6709\u5e8f\u6027\uff0c\u5728send\u51fd\u6570\u4e2d\u8bbe\u7f6e\u4e86\u7ebf\u7a0b\u540c\u6b65\uff0c\u6240\u4ee5\u8bf4\uff0c\u6bcf\u8c03\u7528\u4e00\u6b21send\uff0c\u5b9e\u9645\u4e0a\u90fd\u662f\u5de8\u5927\u7684\u6027\u80fd\u6d88\u8017\uff08\u6b64\u5904\u7528iocp\u53d1\u9001\u4ea6\u7136\uff09\u3002\u6240\u4ee5\uff0c\u8981\u89e3\u51b3\u8be5\u95ee\u9898\uff0c \u6700\u7ec8\u8fd8\u662f\u8981\u5c06\u5c0f\u6570\u636e\uff0c\u7ec4\u5408\u6210\u5927\u6570\u636e\uff0c\u8fd9\u6837\u624d\u80fd\u66f4\u9ad8\u6548\u7387\u7684\u53d1\u9001\u3002\u6240\u4ee5\uff0cDelaySender\u6b63\u662f\u8d1f\u8d23\u6b64\u7c7b\u5de5\u4f5c\u7684\u3002"),(0,a.kt)("p",null,"\u4f7f\u7528DelaySender\uff0c\u4f1a\u4e00\u5b9a\u7a0b\u5ea6\u7684\u964d\u4f4e\u53d1\u9001\u7684\u53ca\u65f6\u6027\uff0c\u4f46\u662f\u964d\u4f4e\u7a0b\u5ea6\u5e76\u4e0d\u9ad8\uff0c\u7b80\u5355\u6765\u8bf4\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5982\u679c\u4e00\u4e2a\u5305\u5927\u4e8e512kb\uff0c\u5219\u4e0d\u4f1a\u5ef6\u8fdf\uff0c\u76f4\u63a5\u53d1\u9001\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u5982\u679c\u53d1\u9001\u7b2c\u4e00\u4e2a\u5305\uff0c\u4e0e\u7b2c\u4e8c\u4e2a\u5305\u7684\u65f6\u95f4\u95f4\u9694\u5c0f\u4e8e\u4e00\u4e2a\u7ebf\u7a0b\u6c60\u7ebf\u7a0b\u8c03\u5ea6\u7684\u65f6\u95f4\uff08\u8fd9\u4e2a\u65f6\u95f4\u6781\u77ed\uff0c\u4e00\u822c\u6765\u8bf4\u4f1a\u572810",(0,a.kt)("strong",{parentName:"li"},"\u5fae\u79d2"),"\u5de6\u53f3\uff09\uff0c\u5219\u4f1a\u5c06\u8fd9\u4e24\u4e2a\u5305\u538b\u7f29\u4e3a\u4e00\u4e2a\u5305\u53d1\u9001\u3002")),(0,a.kt)("h4",{id:"usereuseaddress"},"UseReuseAddress"),(0,a.kt)("p",null,"\u542f\u7528\u7aef\u53e3\u590d\u7528\u3002\u8be5\u914d\u7f6e\u53ef\u5728\u670d\u52a1\u5668\u3001\u6216\u5ba2\u6237\u7aef\u5728\u76d1\u542c\u7aef\u53e3\u65f6\uff0c\u8fd0\u884c\u76d1\u542c\u540c\u4e00\u4e2a\u7aef\u53e3\u3002\u53ef\u4ee5\u4e00\u5b9a\u7a0b\u5ea6\u7f13\u89e3\u7aef\u53e3\u6765\u4e0d\u53ca\u91ca\u653e\u7684\u95ee\u9898\u3002"),(0,a.kt)("h4",{id:"setremoteiphost"},"SetRemoteIPHost"),(0,a.kt)("p",null,"\u94fe\u63a5\u5230\u7684\u8fdc\u7a0bIPHost\uff0c\u652f\u6301\u57df\u540d\u3002\u652f\u6301\u7c7b\u578b\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u4f7f\u7528IP&Port\uff0c\u4f20\u5165\u5f62\u5982\uff1a127.0.0.1:7789\u7684\u5b57\u7b26\u4e32\u5373\u53ef\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u4f7f\u7528\u57df\u540d\uff0c\u5fc5\u987b\u5305\u542b\u534f\u8bae\u7c7b\u578b\uff0c\u5f62\u5982\uff1a",(0,a.kt)("a",{parentName:"li",href:"http://baidu.com%E6%88%96%E8%80%85https://baidu.com:80"},"http://baidu.com\u6216\u8005https://baidu.com:80"))),(0,a.kt)("h4",{id:"setclientssloption"},"SetClientSslOption"),(0,a.kt)("p",null,"\u5ba2\u6237\u7aefSsl\u914d\u7f6e\uff0c\u4e3aNull\u65f6\u5219\u4e0d\u542f\u7528\u3002\n\u6ce8\u610f\uff0c\u5f53RemoteIPHost\u4f7f\u7528https\u3001wss\u7684\u57df\u540d\u65f6\uff0c\u8be5\u914d\u7f6e\u4f1a\u4f7f\u7528\u7cfb\u7edf\u9ed8\u8ba4\u914d\u7f6e\u751f\u6548\u3002"),(0,a.kt)("h4",{id:"setkeepalivevalue"},"SetKeepAliveValue"),(0,a.kt)("p",null,"\u4e3aSocket\u8bbe\u7f6e\u7684\u5c5e\u6027\u3002\n\u6ce8\u610f\uff1a\u8be5\u914d\u7f6e\u4ec5\u5728window\u5e73\u53f0\u751f\u6548\u3002"),(0,a.kt)("h4",{id:"setbindiphost"},"SetBindIPHost"),(0,a.kt)("p",null,"\u7ed1\u5b9a\u7aef\u53e3\u3002"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u5728UdpSessionBase\u4e2d\u8868\u793a\u672c\u5730\u76d1\u542c\u5730\u5740"),(0,a.kt)("li",{parentName:"ul"},"\u5728TcpClient\u4e2d\u8868\u793a\u56fa\u5b9a\u5ba2\u6237\u7aef\u7aef\u53e3\u53f7\u3002")),(0,a.kt)("h4",{id:"usedelaysender-1"},"UseDelaySender"),(0,a.kt)("p",null,"\u4f7f\u7528\u5ef6\u8fdf\u53d1\u9001\u3002\u4f17\u6240\u5468\u77e5\uff0ctcp\u6570\u636e\u62a5\u6587\u4e3a\u4e86\u53d1\u9001\u6548\u7387\uff0c\u4f1a\u9ed8\u8ba4\u542f\u7528\u5ef6\u8fdf\u7b97\u6cd5\u3002\u4f46\u662f\u8fd9\u79cd\u8bbe\u7f6e\uff0c\u53ea\u80fd\u4e00\u5b9a\u7a0b\u5ea6\u7684\u7f13\u89e3\u5c0f\u6570\u636e\u53d1\u9001\u6548\u7387\u4f4e\u7684\u95ee\u9898\uff0c\u56e0\u4e3a\u5b83\u4e3a\u4e86\u4fdd\u8bc1\u591a\u7ebf\u7a0b\u53d1\u9001\u7684\u6709\u5e8f\u6027\uff0c\u5728send\u51fd\u6570\u4e2d\u8bbe\u7f6e\u4e86\u7ebf\u7a0b\u540c\u6b65\uff0c\u6240\u4ee5\u8bf4\uff0c\u6bcf\u8c03\u7528\u4e00\u6b21send\uff0c\u5b9e\u9645\u4e0a\u90fd\u662f\u5de8\u5927\u7684\u6027\u80fd\u6d88\u8017\uff08\u6b64\u5904\u7528iocp\u53d1\u9001\u4ea6\u7136\uff09\u3002\u6240\u4ee5\uff0c\u8981\u89e3\u51b3\u8be5\u95ee\u9898\uff0c \u6700\u7ec8\u8fd8\u662f\u8981\u5c06\u5c0f\u6570\u636e\uff0c\u7ec4\u5408\u6210\u5927\u6570\u636e\uff0c\u8fd9\u6837\u624d\u80fd\u66f4\u9ad8\u6548\u7387\u7684\u53d1\u9001\u3002\u6240\u4ee5\uff0cDelaySender\u6b63\u662f\u8d1f\u8d23\u6b64\u7c7b\u5de5\u4f5c\u7684\u3002"),(0,a.kt)("p",null,"\u4f7f\u7528DelaySender\uff0c\u4f1a\u4e00\u5b9a\u7a0b\u5ea6\u7684\u964d\u4f4e\u53d1\u9001\u7684\u53ca\u65f6\u6027\uff0c\u4f46\u662f\u964d\u4f4e\u7a0b\u5ea6\u5e76\u4e0d\u9ad8\uff0c\u7b80\u5355\u6765\u8bf4\uff1a"),(0,a.kt)("p",null,"\u5982\u679c\u4e00\u4e2a\u5305\u5927\u4e8e512kb\uff0c\u5219\u4e0d\u4f1a\u5ef6\u8fdf\uff0c\u76f4\u63a5\u53d1\u9001\u3002\n\u5982\u679c\u53d1\u9001\u7b2c\u4e00\u4e2a\u5305\uff0c\u4e0e\u7b2c\u4e8c\u4e2a\u5305\u7684\u65f6\u95f4\u95f4\u9694\u5c0f\u4e8e\u4e00\u4e2a\u7ebf\u7a0b\u6c60\u7ebf\u7a0b\u8c03\u5ea6\u7684\u65f6\u95f4\uff08\u8fd9\u4e2a\u65f6\u95f4\u6781\u77ed\uff0c\u4e00\u822c\u6765\u8bf4\u4f1a\u572810\u5fae\u79d2\u5de6\u53f3\uff09\uff0c\u5219\u4f1a\u5c06\u8fd9\u4e24\u4e2a\u5305\u538b\u7f29\u4e3a\u4e00\u4e2a\u5305\u53d1\u9001\u3002"),(0,a.kt)("h4",{id:"usenodelay-1"},"UseNoDelay"),(0,a.kt)("p",null,"\u8bbe\u7f6eSocket\u7684NoDelay\u5c5e\u6027\uff0c\u9ed8\u8ba4false\u3002"),(0,a.kt)("h4",{id:"usebroadcast"},"UseBroadcast"),(0,a.kt)("p",null,"\u8be5\u503c\u6307\u5b9a\u53ef\u4ee5\u53d1\u9001\u6216\u63a5\u6536\u5e7f\u64ad\u6570\u636e\u5305\u3002"))),(0,a.kt)("h2",{id:"\u4e94\u652f\u6301\u63d2\u4ef6"},"\u4e94\u3001\u652f\u6301\u63d2\u4ef6"),(0,a.kt)("p",null,"\u652f\u6301",(0,a.kt)("strong",{parentName:"p"},"ITcpPlugin"),"\u63a5\u53e3\uff0c\u6216\u8005\u7ee7\u627f\u81ea",(0,a.kt)("strong",{parentName:"p"},"TcpPluginBase"),"\u7c7b\uff0c\u91cd\u5199\u76f8\u5e94\u65b9\u6cd5\u5373\u53ef\u3002"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"\u63d2\u4ef6\u65b9\u6cd5"),(0,a.kt)("th",{parentName:"tr",align:null},"\u529f\u80fd"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnConnecting"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728Socket\u5b8c\u6210\u521d\u59cb\u5316\uff0c\u4f46\u662f\u5e76\u672a\u8fde\u63a5\u65f6\u89e6\u53d1\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnConnected"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728Socket\u5b8c\u6210\u8fde\u63a5\uff0c\u4e14\u6210\u529f\u540e\u89e6\u53d1")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnDisconnecting"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u5ba2\u6237\u7aef\u4e3b\u52a8\u8c03\u7528Close\u65f6\u89e6\u53d1")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnDisconnected"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u5ba2\u6237\u7aef\u65ad\u5f00\u8fde\u63a5\u540e\u89e6\u53d1")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnReceivingData"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u6536\u5230\u539f\u59cb\u6570\u636e\u65f6\u89e6\u53d1\uff0c\u6240\u6709\u7684\u6570\u636e\u5747\u5728ByteBlock\u91cc\u9762\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnReceivedData"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5728\u6536\u5230\u9002\u914d\u5668\u6570\u636e\u65f6\u89e6\u53d1\uff0c\u6839\u636e\u9002\u914d\u5668\u7c7b\u578b\uff0c\u6570\u636e\u53ef\u80fd\u5728ByteBlock\u6216\u8005IRequestInfo\u91cc\u9762\u3002")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"OnSendingData"),(0,a.kt)("td",{parentName:"tr",align:null},"\u5f53\u5373\u5c06\u53d1\u9001\u6570\u636e\u65f6\uff0c\u8c03\u7528\u8be5\u65b9\u6cd5\u5728\u9002\u914d\u5668\u4e4b\u540e\uff0c\u63a5\u4e0b\u6765\u5373\u4f1a\u53d1\u9001\u6570\u636e\u3002")))),(0,a.kt)("h2",{id:"\u516d\u521b\u5efatcpclient"},"\u516d\u3001\u521b\u5efaTcpClient"),(0,a.kt)("p",null,"\u7b80\u5355\u7684\u5904\u7406\u903b\u8f91\u53ef\u901a\u8fc7",(0,a.kt)("strong",{parentName:"p"},"Connecting"),"\u3001",(0,a.kt)("strong",{parentName:"p"},"Connected"),"\u3001",(0,a.kt)("strong",{parentName:"p"},"Received"),"\u7b49\u59d4\u6258\u76f4\u63a5\u5b9e\u73b0\u3002"),(0,a.kt)("p",null,"\u4ee3\u7801\u5982\u4e0b\uff1a"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpClient tcpClient = new TcpClient();\ntcpClient.Connected += (client, e) => { };//\u6210\u529f\u8fde\u63a5\u5230\u670d\u52a1\u5668\ntcpClient.Disconnected += (client, e) => { };//\u4ece\u670d\u52a1\u5668\u65ad\u5f00\u8fde\u63a5\uff0c\u5f53\u8fde\u63a5\u4e0d\u6210\u529f\u65f6\u4e0d\u4f1a\u89e6\u53d1\u3002\ntcpClient.Received += (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u670d\u52a1\u5668\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n Console.WriteLine($"\u63a5\u6536\u5230\u4fe1\u606f\uff1a{mes}");\n};\n\n//\u58f0\u660e\u914d\u7f6e\nTouchSocketConfig config = new TouchSocketConfig();\nconfig.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))\n .UsePlugin();\n\n//\u8f7d\u5165\u914d\u7f6e\ntcpClient.Setup(config);\ntcpClient.Connect();\ntcpClient.Send("RRQM");\n')),(0,a.kt)("h2",{id:"\u4e03\u63a5\u6536\u6570\u636e"},"\u4e03\u3001\u63a5\u6536\u6570\u636e"),(0,a.kt)("p",null,"\u5728TcpClient\u4e2d\uff0c\u63a5\u6536\u6570\u636e\u7684\u65b9\u5f0f\u6709\u5f88\u591a\u79cd\u3002\u591a\u79cd\u65b9\u5f0f\u53ef\u4ee5\u7ec4\u5408\u4f7f\u7528\u3002"),(0,a.kt)("h3",{id:"71-received\u59d4\u6258\u5904\u7406"},"7.1 Received\u59d4\u6258\u5904\u7406"),(0,a.kt)("p",null,"\u5f53\u4f7f\u7528TcpClient\u521b\u5efa\u5ba2\u6237\u7aef\u65f6\uff0c\u5185\u90e8\u5df2\u7ecf\u5b9a\u4e49\u597d\u4e86\u4e00\u4e2a\u5916\u7f6e\u59d4\u6258Received\uff0c\u53ef\u4ee5\u901a\u8fc7\u8be5\u59d4\u6258\u76f4\u63a5\u63a5\u6536\u6570\u636e\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpClient tcpClient = new TcpClient();\ntcpClient.Received += (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u670d\u52a1\u5668\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n Console.WriteLine($"\u63a5\u6536\u5230\u4fe1\u606f\uff1a{mes}");\n};\n\n//\u58f0\u660e\u914d\u7f6e\nTouchSocketConfig config = new TouchSocketConfig();\nconfig.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))\n .UsePlugin();\n\n//\u8f7d\u5165\u914d\u7f6e\ntcpClient.Setup(config);\ntcpClient.Connect();\n')),(0,a.kt)("h3",{id:"72-\u63d2\u4ef6\u5904\u7406\u63a8\u8350"},"7.2 \u63d2\u4ef6\u5904\u7406\u63a8\u8350"),(0,a.kt)("p",null,"\u6309\u7167TouchSocket\u7684\u8bbe\u8ba1\u7406\u5ff5\uff0c\u4f7f\u7528\u63d2\u4ef6\u5904\u7406\u6570\u636e\uff0c\u662f\u4e00\u9879\u975e\u5e38\u7b80\u5355\uff0c\u4e14\u9ad8\u5ea6\u89e3\u8026\u7684\u65b9\u5f0f\u3002\u6b65\u9aa4\u5982\u4e0b\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u670d\u52a1\u5668\u914d\u7f6e\u542f\u7528\u63d2\u4ef6\uff08UsePlugin\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u65b0\u5efa\u63d2\u4ef6\u7c7b"),(0,a.kt)("li",{parentName:"ol"},"\u6dfb\u52a0\u63d2\u4ef6")),(0,a.kt)("p",null,"\u4ee3\u7801\u5982\u4e0b\uff1a"),(0,a.kt)("p",null,"\uff081\uff09\u58f0\u660e\u63d2\u4ef6"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyPlugin : TcpPluginBase<TcpClient>\n{\n public MyPlugin()\n {\n this.Order = 0;//\u6b64\u503c\u8868\u793a\u63d2\u4ef6\u7684\u6267\u884c\u987a\u5e8f\uff0c\u5f53\u591a\u4e2a\u63d2\u4ef6\u5e76\u5b58\u65f6\uff0c\u8be5\u503c\u8d8a\u5927\uff0c\u8d8a\u5728\u524d\u6267\u884c\u3002\n }\n \n protected override void OnReceivedData(TcpClient client, ReceivedDataEventArgs e)\n {\n //\u8fd9\u91cc\u5904\u7406\u6570\u636e\u63a5\u6536\n //\u6839\u636e\u9002\u914d\u5668\u7c7b\u578b\uff0ce.ByteBlock\u4e0ee.RequestInfo\u4f1a\u5448\u73b0\u4e0d\u540c\u7684\u503c\uff0c\u5177\u4f53\u770b\u6587\u6863=\u300b\u9002\u914d\u5668\u90e8\u5206\u3002\n ByteBlock byteBlock = e.ByteBlock;\n IRequestInfo requestInfo = e.RequestInfo;\n\n //e.Handled = true;//\u8868\u793a\u8be5\u6570\u636e\u5df2\u7ecf\u88ab\u672c\u63d2\u4ef6\u5904\u7406\uff0c\u65e0\u9700\u518d\u6295\u9012\u5230\u5176\u4ed6\u63d2\u4ef6\u3002\n base.OnReceivedData(client, e);\n }\n}\n")),(0,a.kt)("p",null,"\uff082\uff09\u521b\u5efa\u4f7f\u7528\u63d2\u4ef6\u5904\u7406\u7684\u5ba2\u6237\u7aef"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpClient client = new TcpClient();\nclient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost(new IPHost("127.0.0.1:7789"))\n .UsePlugin()\n .ConfigureContainer(a=>\n {\n a.AddConsoleLogger();\n })\n .ConfigurePlugins(a => \n {\n a.Add<MyPlugin>();\n }))\n .Connect();\n')),(0,a.kt)("h2",{id:"\u516b\u53d1\u9001\u6570\u636e"},"\u516b\u3001\u53d1\u9001\u6570\u636e"),(0,a.kt)("p",null,"\u3010\u540c\u6b65\u53d1\u9001\u3011"),(0,a.kt)("p",null,"TcpClient\u5df2\u7ecf\u5185\u7f6e\u4e86\u4e09\u79cd\u540c\u6b65\u53d1\u9001\u65b9\u6cd5\uff0c\u76f4\u63a5\u8c03\u7528\u5c31\u53ef\u4ee5\u53d1\u9001\uff0c\u4f46\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u901a\u8fc7\u8be5\u65b9\u6cd5\u53d1\u9001\u7684\u6570\u636e\uff0c\u4f1a\u7ecf\u8fc7",(0,a.kt)("strong",{parentName:"p"},"\u9002\u914d\u5668"),"\uff0c\u5982\u679c\u60f3\u8981\u76f4\u63a5\u53d1\u9001\uff0c\u8bf7\u4f7f\u7528",(0,a.kt)("strong",{parentName:"p"},"DefaultSend"),"\u3002\u5982\u679c\u53d1\u9001\u5931\u8d25\uff0c\u5219\u4f1a\u7acb\u5373\u629b\u51fa\u5f02\u5e38\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public virtual void Send(byte[] buffer);\npublic virtual void Send(ByteBlock byteBlock);\npublic virtual void Send(byte[] buffer, int offset, int length);\n")),(0,a.kt)("p",null,"\u3010\u5f02\u6b65\u53d1\u9001\u3011"),(0,a.kt)("p",null,"TcpClient\u5df2\u7ecf\u5185\u7f6e\u4e86\u4e09\u79cd\u5f02\u6b65\u53d1\u9001\u65b9\u6cd5\uff0c\u76f4\u63a5\u8c03\u7528\u5c31\u53ef\u4ee5\u53d1\u9001\u3002\u5982\u679c\u53d1\u9001\u5931\u8d25\uff0cawait\u5c31\u4f1a\u89e6\u53d1\u5f02\u5e38\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public virtual Task SendAsync(byte[] buffer);\npublic virtual Task SendAsync(byte[] buffer, int offset, int length);\n")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/a82e3754.6c72fa9c.js b/handbook/build/assets/js/a82e3754.6c72fa9c.js new file mode 100644 index 000000000..02306bdd9 --- /dev/null +++ b/handbook/build/assets/js/a82e3754.6c72fa9c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1592],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function p(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,s=p(e,["components","mdxType","originalType","parentName"]),d=l(r),m=o,f=d["".concat(c,".").concat(m)]||d[m]||u[m]||a;return r?n.createElement(f,i(i({ref:t},s),{},{components:r})):n.createElement(f,i({ref:t},s))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p.mdxType="string"==typeof e?e:o,i[1]=p;for(var l=2;l<a;l++)i[l]=r[l];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},6435:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>p,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"webapidescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},i=void 0,p={unversionedId:"webapidescription",id:"webapidescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/webapidescription.mdx",sourceDirName:".",slug:"/webapidescription",permalink:"/touchsocket/docs/webapidescription",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/webapidescription.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"webapidescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},sidebar:"docs",previous:{title:"EventBus",permalink:"/touchsocket/docs/eventbus"},next:{title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",permalink:"/touchsocket/docs/webapiservice"}},c={},l=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2}],s={toc:l};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("p",null,"WebApi\u662f",(0,o.kt)("strong",{parentName:"p"},"\u901a\u7528"),"\u7684RPC\u8c03\u7528\uff0c\u4e0e",(0,o.kt)("strong",{parentName:"p"},"\u7f16\u7a0b\u8bed\u8a00\u65e0\u5173"),"\uff0c\u4e0e",(0,o.kt)("strong",{parentName:"p"},"\u64cd\u4f5c\u7cfb\u7edf\u65e0\u5173"),"\u3002\u5176\u8def\u7531\u673a\u5236\u6a21\u4effAspNetCore\uff0c\u53ef\u5b9e\u73b0\u5f88\u591a\u8def\u7531\u673a\u5236\u3002\u4f46\u662f\u56e0\u4e3ahttp\u517c\u5bb9\u6027\u9519\u7efc\u590d\u6742\uff0c\u6240\u4ee5\u76ee\u524dTouchSocket\u7684WebApi\u4ec5\u652f\u6301",(0,o.kt)("strong",{parentName:"p"},"GET"),"\u3001",(0,o.kt)("strong",{parentName:"p"},"POST"),"\u51fd\u6570\u3002\u4f7f\u7528\u4f53\u9a8c\u63a5\u8fd1\u4e8eAspNetCore\u3002"),(0,o.kt)("a",{name:"C6IwW"}),(0,o.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"\u9ad8\u6027\u80fd\uff0c100\u4e2a\u5ba2\u6237\u7aef\uff0c10w\u6b21\u8c03\u7528\uff0c\u4ec5\u7528\u65f617s\u3002"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"\u5168\u5f02\u5e38\u53cd\u9988")," \u3002"),(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301\u5927\u90e8\u5206\u8def\u7531\u89c4\u5219\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301js\u3001Android\u7b49\u8c03\u7528\u3002")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/aa2c2bac.f10823d9.js b/handbook/build/assets/js/aa2c2bac.f10823d9.js new file mode 100644 index 000000000..d625a298f --- /dev/null +++ b/handbook/build/assets/js/aa2c2bac.f10823d9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8411],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},s=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),d=u(r),m=o,f=d["".concat(l,".").concat(m)]||d[m]||p[m]||a;return r?n.createElement(f,c(c({ref:t},s),{},{components:r})):n.createElement(f,c({ref:t},s))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,c[1]=i;for(var u=2;u<a;u++)c[u]=r[u];return n.createElement.apply(null,c)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},6244:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>p,frontMatter:()=>a,metadata:()=>i,toc:()=>u});var n=r(7462),o=(r(7294),r(3905));const a={id:"touchsocketbitconverter",title:"\u5927\u5c0f\u7aef\u8f6c\u6362\u5668"},c=void 0,i={unversionedId:"touchsocketbitconverter",id:"touchsocketbitconverter",title:"\u5927\u5c0f\u7aef\u8f6c\u6362\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/touchsocketbitconverter.mdx",sourceDirName:".",slug:"/touchsocketbitconverter",permalink:"/touchsocket/docs/touchsocketbitconverter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/touchsocketbitconverter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675577572,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"touchsocketbitconverter",title:"\u5927\u5c0f\u7aef\u8f6c\u6362\u5668"},sidebar:"docs",previous:{title:"\u63a7\u5236\u53f0\u884c\u4e3a",permalink:"/touchsocket/docs/consoleaction"},next:{title:"\u6570\u636e\u52a0\u5bc6",permalink:"/touchsocket/docs/datasecurity"}},l={},u=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7edd\u5bf9\u5927\u7aef",id:"\u4e8c\u7edd\u5bf9\u5927\u7aef",level:2},{value:"\u4e09\u3001\u7edd\u5bf9\u5c0f\u7aef",id:"\u4e09\u7edd\u5bf9\u5c0f\u7aef",level:2},{value:"\u56db\u3001\u9ed8\u8ba4\u7aef",id:"\u56db\u9ed8\u8ba4\u7aef",level:2}],s={toc:u};function p(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("p",null,"\u5927\u5c0f\u7aef\u5728\u8ba1\u7b97\u673a\u4e1a\u754c\uff0c",(0,o.kt)("strong",{parentName:"p"},"Endian"),"\u8868\u793a\u6570\u636e\u5728\u5b58\u50a8\u5668\u4e2d\u7684\u5b58\u653e\u987a\u5e8f\u3002"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"\u5927\u7aef\u6a21\u5f0f"),"\uff0c\u662f\u6307",(0,o.kt)("strong",{parentName:"li"},"\u6570\u636e\u7684\u9ad8\u5b57\u8282\u4fdd\u5b58\u5728\u5185\u5b58\u7684\u4f4e\u5730\u5740\u4e2d\uff0c\u800c\u6570\u636e\u7684\u4f4e\u5b57\u8282\u4fdd\u5b58\u5728\u5185\u5b58\u7684\u9ad8\u5730\u5740\u4e2d"),"\uff0c\u8fd9\u6837\u7684\u5b58\u50a8\u6a21\u5f0f\u6709\u70b9\u513f\u7c7b\u4f3c\u4e8e\u628a\u6570\u636e\u5f53\u4f5c\u5b57\u7b26\u4e32\u987a\u5e8f\u5904\u7406\uff1a\u5730\u5740\u7531\u5c0f\u5411\u5927\u589e\u52a0\uff0c\u800c\u6570\u636e\u4ece\u9ad8\u4f4d\u5f80\u4f4e\u4f4d\u653e\uff1b"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"\u5c0f\u7aef\u6a21\u5f0f"),"\uff0c\u662f\u6307",(0,o.kt)("strong",{parentName:"li"},"\u6570\u636e\u7684\u9ad8\u5b57\u8282\u4fdd\u5b58\u5728\u5185\u5b58\u7684\u9ad8\u5730\u5740\u4e2d\uff0c\u800c\u6570\u636e\u7684\u4f4e\u5b57\u8282\u4fdd\u5b58\u5728\u5185\u5b58\u7684\u4f4e\u5730\u5740\u4e2d"),"\uff0c\u8fd9\u79cd\u5b58\u50a8\u6a21\u5f0f\u5c06\u5730\u5740\u7684\u9ad8\u4f4e\u548c\u6570\u636e\u4f4d\u6743\u6709\u6548\u5730\u7ed3\u5408\u8d77\u6765\uff0c\u9ad8\u5730\u5740\u90e8\u5206\u6743\u503c\u9ad8\uff0c\u4f4e\u5730\u5740\u90e8\u5206\u6743\u503c\u4f4e\uff0c\u548c\u6211\u4eec\u7684\u903b\u8f91\u65b9\u6cd5\u4e00\u81f4\u3002")),(0,o.kt)("h2",{id:"\u4e8c\u7edd\u5bf9\u5927\u7aef"},"\u4e8c\u3001\u7edd\u5bf9\u5927\u7aef"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},"byte[] data= TouchSocketBitConverter.BigEndian.GetBytes(10);\n//\u7ed3\u679c {0,0,0,10}\n")),(0,o.kt)("h2",{id:"\u4e09\u7edd\u5bf9\u5c0f\u7aef"},"\u4e09\u3001\u7edd\u5bf9\u5c0f\u7aef"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},"byte[] data= TouchSocketBitConverter.LittleEndian.GetBytes(10);\n//\u7ed3\u679c {10,0,0,0}\n")),(0,o.kt)("h2",{id:"\u56db\u9ed8\u8ba4\u7aef"},"\u56db\u3001\u9ed8\u8ba4\u7aef"),(0,o.kt)("p",null,"TouchSocket\u7cfb\u5168\u91c7\u7528\u9ed8\u8ba4\u201c\u5c0f\u7aef\u201d\u6a21\u5f0f\u3002\u53ef\u901a\u8fc7DefaultEndianType\u5c5e\u6027\uff0c\u4fee\u6539\u4e3a\u5927\u7aef\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},"TouchSocketBitConverter.DefaultEndianType = EndianType.Big;\nbyte[] data= TouchSocketBitConverter.Default.GetBytes(10);\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/aa4c723b.34e57568.js b/handbook/build/assets/js/aa4c723b.34e57568.js new file mode 100644 index 000000000..1e4de5c97 --- /dev/null +++ b/handbook/build/assets/js/aa4c723b.34e57568.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6487],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},d=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,f=u["".concat(c,".").concat(m)]||u[m]||s[m]||o;return n?r.createElement(f,l(l({ref:t},d),{},{components:n})):r.createElement(f,l({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=u;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:a,l[1]=i;for(var p=2;p<o;p++)l[p]=n[p];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}u.displayName="MDXCreateElement"},5009:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>s,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const o={id:"normaldatahandlingadapter",title:"a.\u6b63\u5e38\u6570\u636e\u5904\u7406\u9002\u914d\u5668"},l=void 0,i={unversionedId:"normaldatahandlingadapter",id:"normaldatahandlingadapter",title:"a.\u6b63\u5e38\u6570\u636e\u5904\u7406\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/normaldatahandlingadapter.mdx",sourceDirName:".",slug:"/normaldatahandlingadapter",permalink:"/touchsocket/docs/normaldatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/normaldatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675577572,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"normaldatahandlingadapter",title:"a.\u6b63\u5e38\u6570\u636e\u5904\u7406\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u4ecb\u7ecd\u53ca\u4f7f\u7528",permalink:"/touchsocket/docs/adapterdescription"},next:{title:"\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668",permalink:"/touchsocket/docs/fixedheaderpackageadapter"}},c={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2}],d={toc:p};function s(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u6b63\u5e38\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u5c31\u662f\u5904\u7406",(0,a.kt)("strong",{parentName:"p"},"\u666e\u901a"),"\u7684TCP\u62a5\u6587\uff0c\u5185\u90e8\u4e0d\u8fdb\u884c\u4efb\u4f55\u6570\u636e\u5904\u7406\uff0c\u8fd9\u4e5f\u5c31\u610f\u5473\u7740\u5b83\u5e76",(0,a.kt)("strong",{parentName:"p"},"\u4e0d\u80fd\u89e3\u51b3\u7c98\u3001\u5206\u5305"),"\u7684\u95ee\u9898\uff0c\u5b83\u53ea\u662f\u80fd\u591f\u5c06\u6570\u636e\u8fdb\u884c\u63a5\u6536\u548c\u5904\u7406\u800c\u5df2\u3002 ",(0,a.kt)("a",{name:"TrOBm"})),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u80fd\u591f\u63a5\u6536\u6240\u6709TCP\u62a5\u6587\uff0c\u4e0e\u8bed\u8a00\u3001\u6846\u67b6\u65e0\u5173\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u76f8\u5f53\u4e8e\u52a0\u5f3a\u7248\u7684Socket\uff0c\u4f46\u662f\u6570\u636e\u53d1\u9001\u4e0e\u63a5\u6536\u662f\u5b8c\u5168\u4e00\u81f4\u7684\u3002")),(0,a.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e"),(0,a.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684ByteBlock\u8bfb\u53d6\u6570\u636e\uff08\u6ce8\u610f\uff1a\u6570\u636e\u957f\u5ea6\u662fbyteBlock.Len\uff09\u3002")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{10}","{10}":!0},"TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u5ba2\u6237\u7aef\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(()=> { return new NormalDataHandlingAdapter(); }))//\u914d\u7f6e\u9002\u914d\u5668\n .Start();//\u542f\u52a8\n")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u8be5\u9002\u914d\u5668\uff0c\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/adf44bc8.1067b890.js b/handbook/build/assets/js/adf44bc8.1067b890.js new file mode 100644 index 000000000..de7267e2d --- /dev/null +++ b/handbook/build/assets/js/adf44bc8.1067b890.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[9253],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>d});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},l=Object.keys(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,l=e.originalType,p=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),f=c(n),d=o,m=f["".concat(p,".").concat(d)]||f[d]||s[d]||l;return n?r.createElement(m,a(a({ref:t},u),{},{components:n})):r.createElement(m,a({ref:t},u))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var l=n.length,a=new Array(l);a[0]=f;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:o,a[1]=i;for(var c=2;c<l;c++)a[c]=n[c];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}f.displayName="MDXCreateElement"},7157:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>s,frontMatter:()=>l,metadata:()=>i,toc:()=>c});var r=n(7462),o=(n(7294),n(3905));const l={id:"filepool",title:"\u6587\u4ef6\u6d41\u6c60"},a=void 0,i={unversionedId:"filepool",id:"filepool",title:"\u6587\u4ef6\u6d41\u6c60",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/filepool.mdx",sourceDirName:".",slug:"/filepool",permalink:"/touchsocket/docs/filepool",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/filepool.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"filepool",title:"\u6587\u4ef6\u6d41\u6c60"},sidebar:"docs",previous:{title:"\u4f9d\u8d56\u5c5e\u6027",permalink:"/touchsocket/docs/dependencyproperty"},next:{title:"\u63d2\u4ef6\u7cfb\u7edf",permalink:"/touchsocket/docs/pluginsmanager"}},p={},c=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4f7f\u7528\u8bfb",id:"\u4e8c\u4f7f\u7528\u8bfb",level:2},{value:"\u4e09\u3001\u4f7f\u7528\u5199",id:"\u4e09\u4f7f\u7528\u5199",level:2},{value:"\u56db\u3001\u624b\u52a8\u91ca\u653e\u6587\u4ef6\u8d44\u6e90",id:"\u56db\u624b\u52a8\u91ca\u653e\u6587\u4ef6\u8d44\u6e90",level:2}],u={toc:c};function s(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("p",null,"\u6587\u4ef6\u5728\u8bfb\uff0c\u6216\u5199\u7684\u65f6\u5019\uff0c\u4e00\u76f4\u90fd\u662f\u72ec\u5360\u72b6\u6001\u3002\u8fd9\u4e2a\u95ee\u9898\u5728\u4e0d\u540c\u8fdb\u7a0b\u4e2d\uff0c\u4f3c\u4e4e\u662f\u5408\u7406\u7684\uff0c\u4f46\u662f\u5982\u679c\u5728\u76f8\u540c\u8fdb\u7a0b\u91cc\uff0c\u5c31\u4f1a\u663e\u5f97\u5f88\u5446\u3002\u4f8b\u5982\uff1a\u6211\u4eec\u5728\u4e0b\u8f7d\u6587\u4ef6\u7684\u65f6\u5019\uff0c\u5e0c\u671b\u80fd\u540c\u4e00\u65f6\u95f4\u591a\u4e2a\u8bfb\u53d6\u540c\u4e00\u4e2a\u6587\u4ef6\u3002\u4e14\u80fd\u6709\u4e00\u4e2a\u95ed\u73af\u7684\u7ba1\u7406\u3002\u90a3\u4e48\uff0c\u4f7f\u7528FilePool\uff0c\u5c31\u663e\u5f97\u975e\u5e38\u5fc5\u8981\u4e86\u3002"),(0,o.kt)("h2",{id:"\u4e8c\u4f7f\u7528\u8bfb"},"\u4e8c\u3001\u4f7f\u7528\u8bfb"),(0,o.kt)("p",null,"\u4eceFilePool.GetReader\u7684\u9759\u6001\u51fd\u6570\u4e2d\uff0c\u83b7\u53d6\u4e00\u4e2a",(0,o.kt)("strong",{parentName:"p"},"\u7ebf\u7a0b\u5b89\u5168"),"\u7684\u6587\u4ef6\u8bfb\u53d6\u8bbf\u95ee\u5668\uff0c\u8be5\u8bbf\u95ee\u5668\u5177\u6709\u8bfb\uff0c\u548c\u76f8\u5173\u7684\u64cd\u4f5c\u5c5e\u6027\u3002\u5728\u6bcf\u6b21\u8bfb\u53d6\u540e\uff0cPosition\u4f1a\u9012\u589e\u3002"),(0,o.kt)("p",null,"\u4f7f\u7528\u5b8c\u6210\u540e\uff0c\u53ef\u4ee5\u968f\u65f6\u91ca\u653e\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},"int len = 0;\nbyte[] buffer = new byte[1024 * 1024];\n\nusing (var reader = FilePool.GetReader(path))\n{\n while (true)\n {\n int r = reader.Read(buffer, 0, buffer.Length);\n if (r == 0)\n {\n break;\n }\n len += r;\n }\n}\n\nConsole.WriteLine(len);\n")),(0,o.kt)("h2",{id:"\u4e09\u4f7f\u7528\u5199"},"\u4e09\u3001\u4f7f\u7528\u5199"),(0,o.kt)("p",null,"\u4eceFilePool.GetWriter\u7684\u9759\u6001\u51fd\u6570\u4e2d\uff0c\u83b7\u53d6\u4e00\u4e2a\u6587\u4ef6\u5199\u5165\u8bbf\u95ee\u5668\u7ebf\u7a0b\u5b89\u5168\uff0c\u8be5\u8bbf\u95ee\u5668\uff0c\u5177\u6709\u5199\uff0c\u548c\u76f8\u5173\u7684\u64cd\u4f5c\u5c5e\u6027\u3002\u5728\u6bcf\u6b21\u5199\u5165\u540e\uff0cPosition\u4f1a\u9012\u589e\u3002"),(0,o.kt)("p",null,"\u4f7f\u7528\u5b8c\u6210\u540e\uff0c\u53ef\u4ee5\u968f\u65f6\u91ca\u653e\u3002"),(0,o.kt)("p",null,"\u6ce8\u610f\u9ed8\u8ba4\u8c03\u7528",(0,o.kt)("strong",{parentName:"p"},"Dispose"),"\u540e\uff0c\u6587\u4ef6\u4f1a\u6839\u636e\u521b\u5efa\u7c7b\u578b\u662f\u5426\u4e3a",(0,o.kt)("strong",{parentName:"p"},"\u5355\u4e00\u8bbf\u95ee"),"\u800c\u51b3\u5b9a\u662f\u5426\u7acb\u5373\u91ca\u653e\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'byte[] buffer = new byte[1024];\n\nusing (var writer = FilePool.GetWriter(path,true))\n{\n writer.Position = num * package;\n int surLen = package;\n while (surLen > 0)\n {\n int r = Math.Min(surLen, buffer.Length);\n writer.Write(buffer, 0, r);\n surLen -= r;\n }\n}\nConsole.WriteLine("\u5b8c\u6210");\n')),(0,o.kt)("h2",{id:"\u56db\u624b\u52a8\u91ca\u653e\u6587\u4ef6\u8d44\u6e90"},"\u56db\u3001\u624b\u52a8\u91ca\u653e\u6587\u4ef6\u8d44\u6e90"),(0,o.kt)("p",null,"\u5f53\u67d0\u4e2a\u6587\u4ef6\u6ca1\u6709\u53ca\u65f6\u91ca\u653e\uff0c\u6216\u8005\u7531\u4e8e\u4e0d\u53ef\u77e5\u5f02\u5e38\u800c\u6ca1\u6709\u91ca\u653e\u65f6\uff0c\u53ef\u4ee5\u8c03\u7528FilePool.TryReleaseFile\u51cf\u5c11\u5f15\u7528\uff0c\u5e76\u5c1d\u8bd5\u91ca\u653e\u8d44\u6e90\u3002"),(0,o.kt)("p",null,"\u51cf\u5c11\u5f15\u7528\u7684\u610f\u601d\u662f\uff0c\u5f53\u67d0\u4e2a\u6587\u4ef6\uff0c\u88ab\u521b\u5efa\u591a\u4e2a\u8bbf\u95ee\u5668\u65f6\uff0c\u4f1a\u9012\u589e\u5176\u5f15\u7528\u6570\uff0c\u5f53\u5f15\u7528\u6570\u4e0d\u4e3a0\u65f6\uff0c\u662f\u4e0d\u4f1a\u91ca\u653e\u7684\u3002\u6240\u4ee5\u5f53\u8c03\u7528FilePool.TryReleaseFile\u65f6\uff0c\u9996\u5148\u4f1a\u51cf\u5c11\u5f15\u7528\uff0c\u7136\u540e\u624d\u4f1a\u5224\u65ad\u662f\u5426\u53ef\u4ee5\u91ca\u653e\u3002"),(0,o.kt)("p",null,"\u5f53\u9700\u8981\u5f3a\u5236\u91ca\u653e\u67d0\u4e2a\u6587\u4ef6\u65f6\uff0c\u53ef\u4ee5\u91c7\u53d6\u4e0b\u5217\u63aa\u65bd\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},"while (FilePool.TryReleaseFile(fileName, 0).ResultCode!= ResultCode.Success)\n{\n\n}\n")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/b0d79caf.06a5a0f4.js b/handbook/build/assets/js/b0d79caf.06a5a0f4.js new file mode 100644 index 000000000..75e7c4ac5 --- /dev/null +++ b/handbook/build/assets/js/b0d79caf.06a5a0f4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1971],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=s(r),f=o,m=d["".concat(l,".").concat(f)]||d[f]||u[f]||a;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,i[1]=c;for(var s=2;s<a;s++)i[s]=r[s];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},4734:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={id:"engineertoolbox",title:"\u5de5\u7a0b\u5e08\u8f6f\u4ef6\u5de5\u5177\u7bb1"},i=void 0,c={unversionedId:"engineertoolbox",id:"engineertoolbox",title:"\u5de5\u7a0b\u5e08\u8f6f\u4ef6\u5de5\u5177\u7bb1",description:"\u8bf4\u660e",source:"@site/docs/engineertoolbox.mdx",sourceDirName:".",slug:"/engineertoolbox",permalink:"/touchsocket/docs/engineertoolbox",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/engineertoolbox.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675265724,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"engineertoolbox",title:"\u5de5\u7a0b\u5e08\u8f6f\u4ef6\u5de5\u5177\u7bb1"},sidebar:"docs",previous:{title:"FPS\u5b9e\u65f6\u6e38\u620f",permalink:"/touchsocket/docs/fpsgame"},next:{title:"\u5165\u95e8\u6307\u5357",permalink:"/touchsocket/docs/startguide"}},l={},s=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u754c\u9762\u5c55\u793a",id:"\u754c\u9762\u5c55\u793a",level:2}],p={toc:s};function u(e){let{components:t,...a}=e;return(0,o.kt)("wrapper",(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,o.kt)("p",null,"\u8fd9\u662f\u7fa4\u53cb\u5f00\u53d1\u8005\uff0c\u4f7f\u7528",(0,o.kt)("strong",{parentName:"p"},"TouchRpc"),"\u5f00\u53d1\u7684\u4e00\u4e2a\u5185\u90e8\u5de5\u7a0b\u5e08\u8f6f\u4ef6\u5de5\u5177\u7bb1 \u3002"),(0,o.kt)("h2",{id:"\u754c\u9762\u5c55\u793a"},"\u754c\u9762\u5c55\u793a"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"1",src:r(9319).Z,width:"1500",height:"1202"}),"\n",(0,o.kt)("img",{alt:"2",src:r(1882).Z,width:"1500",height:"711"}),"\n",(0,o.kt)("img",{alt:"3",src:r(7434).Z,width:"1500",height:"611"})))}u.isMDXComponent=!0},9319:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/engineertoolbox-1-f4ef22b000dfa103a5211d15e8591fae.jpg"},1882:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/engineertoolbox-2-4adfa904169e408a00e38870aa82a0c4.jpg"},7434:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/engineertoolbox-3-e6f715f5501aebfc7fd7dec0b21bff0f.jpg"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/b1f68223.1dcbed2c.js b/handbook/build/assets/js/b1f68223.1dcbed2c.js new file mode 100644 index 000000000..06a796662 --- /dev/null +++ b/handbook/build/assets/js/b1f68223.1dcbed2c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[3285],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function d(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,p=d(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,f=u["".concat(i,".").concat(m)]||u[m]||s[m]||o;return n?a.createElement(f,l(l({ref:t},p),{},{components:n})):a.createElement(f,l({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=u;var d={};for(var i in t)hasOwnProperty.call(t,i)&&(d[i]=t[i]);d.originalType=e,d.mdxType="string"==typeof e?e:r,l[1]=d;for(var c=2;c<o;c++)l[c]=n[c];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},3387:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>s,frontMatter:()=>o,metadata:()=>d,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const o={id:"custombetweenanddatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u533a\u95f4\u6570\u636e\u201d\u6570\u636e\u9002\u914d\u5668"},l=void 0,d={unversionedId:"custombetweenanddatahandlingadapter",id:"custombetweenanddatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u533a\u95f4\u6570\u636e\u201d\u6570\u636e\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/custombetweenanddatahandlingadapter.mdx",sourceDirName:".",slug:"/custombetweenanddatahandlingadapter",permalink:"/touchsocket/docs/custombetweenanddatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/custombetweenanddatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675586056,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"custombetweenanddatahandlingadapter",title:"\u6a21\u677f\u89e3\u6790\u201c\u533a\u95f4\u6570\u636e\u201d\u6570\u636e\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u6a21\u677f\u89e3\u6790\u201c\u5927\u6570\u636e\u56fa\u5b9a\u5305\u5934\u201d\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter"},next:{title:"Pipeline\u6570\u636e\u9002\u914d\u5668",permalink:"/touchsocket/docs/pipelinedatahandlingadapter"}},i={},c=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2}],p={toc:c};function s(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"\u533a\u95f4\u9002\u914d\u5668\uff0c\u4e00\u822c\u7528\u4e8e\u5b57\u7b26\u4e32\u7c7b\u7684\u6d88\u606f\uff0c\u7c7b\u4f3c\u201c",(0,r.kt)("strong",{parentName:"p"},"Hello##\u201d\uff0c\u8be5\u6570\u636e\uff0c\u4ee5"),"\u5f00\u5934\uff0c\u4ee5##\u7ed3\u5c3e\u3002\u5f53\u7136\uff0c\u533a\u95f4\u9002\u914d\u5668\u4e5f\u80fd\u7528\u4e8e\u4e8c\u8fdb\u5236\u6570\u636e\uff0c\u4f46\u662f\u4f1a\u6709\u6982\u7387\u53d1\u751f\u6807\u8bc6\u91cd\u590d\u7684\u60c5\u51b5\u3002\u6240\u4ee5\uff0c\u7528\u4e8e\u4e8c\u8fdb\u5236\u65f6\uff0c\u5e94\u5f53\u8bbe\u7f6e\u8f83\u590d\u6742\u7684\u533a\u95f4\u6807\u8bc6\u3002"),(0,r.kt)("p",null,"\u8be5\u9002\u914d\u5668\u4e0e","[\u7ec8\u6b62\u56e0\u5b50\u5206\u5272\u9002\u914d\u5668]","(../8.2 Tcp\u9002\u914d\u5668/d.\u7ec8\u6b62\u56e0\u5b50\u5206\u5272\u6570\u636e\u5904\u7406\u9002\u914d\u5668.mdx)\u76f8\u6bd4\uff0c\u53ef\u4ee5\u8bbe\u7f6e\u5f00\u5934\u7684\u5b57\u7b26\u533a\u95f4\u3002"),(0,r.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u81ea\u7531\u9002\u914d",(0,r.kt)("strong",{parentName:"li"},"\u5f88\u591a"),"\u7684\u5b57\u7b26\u4e32\u6570\u636e\u534f\u8bae\u3002"),(0,r.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u968f\u610f\u5b9a\u5236\u6570\u636e\u534f\u8bae\u3002"),(0,r.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u4e0e",(0,r.kt)("strong",{parentName:"li"},"\u4efb\u610f\u8bed\u8a00\u3001\u6846\u67b6"),"\u5bf9\u63a5\u6570\u636e\u3002")),(0,r.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,r.kt)("p",null,"\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002\u4e0b\u5217\u4ee5\u670d\u52a1\u5668\u4e3a\u4f8b\u3002"),(0,r.kt)("p",null,"\u6b65\u9aa4"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u5b9e\u73b0",(0,r.kt)("strong",{parentName:"li"},"IBetweenAndRequestInfo"),"\u63a5\u53e3\uff0c\u6b64\u5bf9\u8c61\u5373\u4e3a\u5b58\u50a8\u6570\u636e\u7684\u5b9e\u4f53\u7c7b\uff0c\u53ef\u5728\u6b64\u7c7b\u4e2d\u58f0\u660e\u4e00\u4e9b\u5c5e\u6027\uff0c\u4ee5\u5907\u4f7f\u7528\u3002"),(0,r.kt)("li",{parentName:"ol"},"\u58f0\u660e\u65b0\u5efa\u7c7b\uff0c\u7ee7\u627f",(0,r.kt)("strong",{parentName:"li"},"CustomBetweenAndDataHandlingAdapter"),"\uff0c\u5e76\u4e14\u4ee5\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u4f5c\u4e3a\u6cdb\u578b\u3002\u5e76\u5b9e\u73b0\u5bf9\u5e94\u62bd\u8c61\u65b9\u6cd5\u3002"),(0,r.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e\u3002"),(0,r.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684RequestInfo\u5bf9\u8c61\uff0c\u5f3a\u8f6c\u4e3a\u6b65\u9aa41\u58f0\u660e\u7684\u7c7b\u578b\uff0c\u7136\u540e\u8bfb\u53d6\u5176\u5c5e\u6027\u503c\uff0c\u4ee5\u5907\u4f7f\u7528\u3002")),(0,r.kt)("p",null,"\u3010MyBetweenAndRequestInfo\u3011\n\u9996\u5148\uff0c\u65b0\u5efaMyBetweenAndRequestInfo\u7c7b\uff0c\u7136\u540e\u5b9e\u73b0",(0,r.kt)("strong",{parentName:"p"},"IBetweenAndRequestInfo"),"\u63a5\u53e3\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"/// <summary>\n/// \u4ee5**12##12##\uff0cMin=5\u4e3a\u4f8b\u3002\n/// </summary>\nclass MyBetweenAndRequestInfo : IBetweenAndRequestInfo\n{\n public void OnParsingBody(byte[] body)\n {\n //\u8fd9\u91cc\u7684Body\u5e94\u8be5\u4e3a12##12\n }\n\n public bool OnParsingEndCode(byte[] endCode)\n {\n return true;//\u8be5\u8fd4\u56de\u503c\u51b3\u5b9a\uff0c\u662f\u5426\u6267\u884cReceive\n }\n\n public bool OnParsingStartCode(byte[] startCode)\n {\n return true;\n }\n}\n\n")),(0,r.kt)("p",null,"\u65b0\u5efaMyCustomBetweenAndDataHandlingAdapter\u7ee7\u627f",(0,r.kt)("strong",{parentName:"p"},"CustomBetweenAndDataHandlingAdapter"),"\uff0c\u7136\u540e\u5bf9StartCode\u3001EndCode\u4f5c\u51fa\u8d4b\u503c\uff0c\u4ee5\u6b64\u8868\u660e\u8d77\u59cb\u5b57\u7b26\u4e0e\u7ed3\u675f\u5b57\u7b26\u7684\u503c\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'class MyCustomBetweenAndDataHandlingAdapter : CustomBetweenAndDataHandlingAdapter<MyBetweenAndRequestInfo>\n{\n public MyCustomBetweenAndDataHandlingAdapter()\n {\n this.MinSize = 5;//\u8868\u793a\uff0c\u5b9e\u9645\u6570\u636e\u4f53\u4e0d\u4f1a\u5c0f\u4e8e5\uff0c\u4f8b\u5982\u201c**12##12##\u201d\u6570\u636e\uff0c\u89e3\u6790\u540e\u4f1a\u89e3\u6790\u6210\u201c12##12\u201d\n }\n\n public override byte[] StartCode => Encoding.UTF8.GetBytes("**");//\u53ef\u4ee5\u4e3a0\u957f\u5ea6\u5b57\u8282\uff0c\u610f\u5473\u7740\u6ca1\u6709\u8d77\u59cb\u6807\u8bc6\u3002\n\n public override byte[] EndCode => Encoding.UTF8.GetBytes("##");//\u5fc5\u987b\u4e3a\u6709\u6548\u503c\u3002\n\n protected override MyBetweenAndRequestInfo GetInstance()\n {\n return new MyBetweenAndRequestInfo();\n }\n}\n')),(0,r.kt)("p",null,"\u3010\u63a5\u6536\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u63a5\u6536\u4fe1\u606f\uff0c\u5728CustomDataHandlingAdapter\u6d3e\u751f\u7684\u9002\u914d\u5668\u4e2d\uff0cbyteBlock\u5c06\u4e3anull\uff0crequestInfo\u5c06\u4e3a\u9002\u914d\u5668\u5b9a\u4e49\u7684\u6cdb\u578b\n if (requestInfo is MyBetweenAndRequestInfo myRequestInfo)\n {\n //\u6b64\u5904\u53ef\u4ee5\u5904\u7406MyBigFixedHeaderRequestInfo\u7684\u76f8\u5173\u4fe1\u606f\u4e86\u3002\n }\n \n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(() => { return new MyCustomBetweenAndDataHandlingAdapter(); }))//\u914d\u7f6e\u9002\u914d\u5668\n .Start();//\u542f\u52a8\n")),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u521b\u5efa\u7684\u9002\u914d\u5668\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/b4d3dab5.b452fab0.js b/handbook/build/assets/js/b4d3dab5.b452fab0.js new file mode 100644 index 000000000..29a0f7a69 --- /dev/null +++ b/handbook/build/assets/js/b4d3dab5.b452fab0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[4724],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>d});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?c(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):c(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},c=Object.keys(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},s=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,c=e.originalType,p=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),f=l(r),d=o,m=f["".concat(p,".").concat(d)]||f[d]||u[d]||c;return r?n.createElement(m,a(a({ref:t},s),{},{components:r})):n.createElement(m,a({ref:t},s))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=r.length,a=new Array(c);a[0]=f;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:o,a[1]=i;for(var l=2;l<c;l++)a[l]=r[l];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},3245:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>u,frontMatter:()=>c,metadata:()=>i,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const c={id:"cooperation",title:"\u5546\u4e1a\u5408\u4f5c"},a=void 0,i={unversionedId:"cooperation",id:"cooperation",title:"\u5546\u4e1a\u5408\u4f5c",description:"RRQM\u627f\u63a5WPF\u53ca\u7f51\u7edc\u901a\u4fe1\u76f8\u5173\u7684\u5f00\u53d1\u4efb\u52a1\u3002\u4ef7\u683c\u8be6\u60c5\u54a8\u8be2\u82e5\u6c5d\u68cb\u8317\u3002QQ\uff1a505554090",source:"@site/docs/cooperation.mdx",sourceDirName:".",slug:"/cooperation",permalink:"/touchsocket/docs/cooperation",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/cooperation.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675229490,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"cooperation",title:"\u5546\u4e1a\u5408\u4f5c"},sidebar:"docs",previous:{title:"\u4f01\u4e1a\u7248\u76f8\u5173",permalink:"/touchsocket/docs/enterprise"},next:{title:"WPF\u754c\u9762\u3001\u6587\u4ef6\u4f20\u8f93\u9879\u76ee",permalink:"/touchsocket/docs/wpfuifiletransfer"}},p={},l=[],s={toc:l};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"RRQM\u627f\u63a5WPF\u53ca\u7f51\u7edc\u901a\u4fe1\u76f8\u5173\u7684\u5f00\u53d1\u4efb\u52a1\u3002\u4ef7\u683c\u8be6\u60c5\u54a8\u8be2\u82e5\u6c5d\u68cb\u8317\u3002QQ\uff1a505554090"),(0,o.kt)("p",null,"\u652f\u4ed8\u53ef\u901a\u8fc7\u6dd8\u5b9d\u3002\u5b89\u5168\u6709\u4fdd\u969c\u3002"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/b7e03a75.33d2c017.js b/handbook/build/assets/js/b7e03a75.33d2c017.js new file mode 100644 index 000000000..d0cb078b6 --- /dev/null +++ b/handbook/build/assets/js/b7e03a75.33d2c017.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[3503],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>g});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),d=p(n),g=i,f=d["".concat(l,".").concat(g)]||d[g]||u[g]||o;return n?r.createElement(f,a(a({ref:t},s),{},{components:n})):r.createElement(f,a({ref:t},s))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:i,a[1]=c;for(var p=2;p<o;p++)a[p]=n[p];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},8744:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>p});var r=n(7462),i=(n(7294),n(3905));const o={id:"waitingclient",title:"\u540c\u6b65\u8bf7\u6c42"},a=void 0,c={unversionedId:"waitingclient",id:"waitingclient",title:"\u540c\u6b65\u8bf7\u6c42",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/waitingclient.mdx",sourceDirName:".",slug:"/waitingclient",permalink:"/touchsocket/docs/waitingclient",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/waitingclient.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675527977,formattedLastUpdatedAt:"Feb 4, 2023",frontMatter:{id:"waitingclient",title:"\u540c\u6b65\u8bf7\u6c42"},sidebar:"docs",previous:{title:"\u521b\u5efaTcpClient",permalink:"/touchsocket/docs/createtcpclient"},next:{title:"Tcp\u7aef\u53e3\u8f6c\u53d1",permalink:"/touchsocket/docs/natservice"}},l={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u521b\u5efa\u53ca\u4f7f\u7528",id:"\u4e8c\u521b\u5efa\u53ca\u4f7f\u7528",level:2},{value:"2.1 \u4ee5TcpClient\u4e3a\u4f8b",id:"21-\u4ee5tcpclient\u4e3a\u4f8b",level:3},{value:"2.2 \u4ee5TcpService\u4e3a\u4f8b",id:"22-\u4ee5tcpservice\u4e3a\u4f8b",level:3}],s={toc:p};function u(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,i.kt)("p",null,"\u6709\u5f88\u591a\u5c0f\u4f19\u4f34\u4e00\u76f4\u6709\u4e00\u4e9b\u9700\u6c42\uff1a"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"\u5ba2\u6237\u7aef\u53d1\u9001\u4e00\u4e2a\u6570\u636e\uff0c\u7136\u540e\u7b49\u5f85\u670d\u52a1\u5668\u56de\u5e94\u3002"),(0,i.kt)("li",{parentName:"ol"},"\u670d\u52a1\u5668\u5411\u5ba2\u6237\u7aef\u53d1\u9001\u4e00\u4e2a\u6570\u636e\uff0c\u7136\u540e\u7b49\u5f85\u5ba2\u6237\u7aef\u56de\u5e94\u3002")),(0,i.kt)("p",null,"\u90a3\u9488\u5bf9\u8fd9\u4e9b\u9700\u6c42\uff0c\u53ef\u4ee5\u4f7f\u7528",(0,i.kt)("strong",{parentName:"p"},"WaitingClient\u3002"),"\u5176\u5185\u90e8\u5b9e\u73b0\u4e86",(0,i.kt)("strong",{parentName:"p"},"IWaitSender"),"\u63a5\u53e3\uff0c\u80fd\u591f\u5728\u53d1\u9001\u5b8c\u6210\u540e\uff0c\u7b49\u5f85\u8fd4\u56de\u3002"),(0,i.kt)("h2",{id:"\u4e8c\u521b\u5efa\u53ca\u4f7f\u7528"},"\u4e8c\u3001\u521b\u5efa\u53ca\u4f7f\u7528"),(0,i.kt)("h3",{id:"21-\u4ee5tcpclient\u4e3a\u4f8b"},"2.1 \u4ee5TcpClient\u4e3a\u4f8b"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpClient m_tcpClient = new TcpClient();\nvar config = new TouchSocketConfig();\nconfig.SetRemoteIPHost(new IPHost("127.0.0.1:7789"));\n\n//\u8f7d\u5165\u914d\u7f6e\nm_tcpClient.Setup(config);\nm_tcpClient.Connect();\n\n//\u8c03\u7528GetWaitingClient\u83b7\u53d6\u5230IWaitingClient\u7684\u5bf9\u8c61\u3002\nvar waitClient = m_tcpClient.GetWaitingClient(new WaitingOptions()\n{\n AdapterFilter = AdapterFilter.AllAdapter,//\u8868\u793a\u53d1\u9001\u548c\u63a5\u6536\u7684\u6570\u636e\u90fd\u4f1a\u7ecf\u8fc7\u9002\u914d\u5668\n BreakTrigger = true,//\u8868\u793a\u5f53\u8fde\u63a5\u65ad\u5f00\u65f6\uff0c\u4f1a\u7acb\u5373\u89e6\u53d1\n ThrowBreakException = true//\u8868\u793a\u5f53\u8fde\u63a5\u65ad\u5f00\u65f6\uff0c\u662f\u5426\u89e6\u53d1\u5f02\u5e38\n});\n\n//\u7136\u540e\u4f7f\u7528SendThenReturn\u3002\nbyte[] returnData = waitClient.SendThenReturn(Encoding.UTF8.GetBytes("RRQM"));\nm_tcpClient.Logger.Info($"\u6536\u5230\u56de\u5e94\u6d88\u606f\uff1a{Encoding.UTF8.GetString(returnData)}");\n\n//\u540c\u65f6\uff0c\u5982\u679c\u9002\u914d\u5668\u6536\u5230\u6570\u636e\u540e\uff0c\u8fd4\u56de\u7684\u5e76\u4e0d\u662f\u5b57\u8282\uff0c\u800c\u662fIRequestInfo\u5bf9\u8c61\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528SendThenResponse.\nResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes("RRQM"));\nIRequestInfo requestInfo = responsedData.RequestInfo;//\u540c\u6b65\u6536\u5230\u7684RequestInfo\n')),(0,i.kt)("h3",{id:"22-\u4ee5tcpservice\u4e3a\u4f8b"},"2.2 \u4ee5TcpService\u4e3a\u4f8b"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-csharp"},'var service = new TcpService();\nservice.Received = (client, byteBlock, requestInfo) =>\n{\n //\u8c03\u7528GetWaitingClient\u83b7\u53d6\u5230IWaitingClient\u7684\u5bf9\u8c61\u3002\n var waitClient = client.GetWaitingClient(new WaitingOptions()\n {\n AdapterFilter = AdapterFilter.AllAdapter,//\u8868\u793a\u53d1\u9001\u548c\u63a5\u6536\u7684\u6570\u636e\u90fd\u4f1a\u7ecf\u8fc7\u9002\u914d\u5668\n BreakTrigger = true,//\u8868\u793a\u5f53\u8fde\u63a5\u65ad\u5f00\u65f6\uff0c\u4f1a\u7acb\u5373\u89e6\u53d1\n ThrowBreakException = true//\u8868\u793a\u5f53\u8fde\u63a5\u65ad\u5f00\u65f6\uff0c\u662f\u5426\u89e6\u53d1\u5f02\u5e38\n });\n\n //\u7136\u540e\u4f7f\u7528SendThenReturn\u3002\n byte[] returnData = waitClient.SendThenReturn(Encoding.UTF8.GetBytes("RRQM"));\n client.Logger.Info($"\u6536\u5230\u56de\u5e94\u6d88\u606f\uff1a{Encoding.UTF8.GetString(returnData)}");\n\n //\u540c\u65f6\uff0c\u5982\u679c\u9002\u914d\u5668\u6536\u5230\u6570\u636e\u540e\uff0c\u8fd4\u56de\u7684\u5e76\u4e0d\u662f\u5b57\u8282\uff0c\u800c\u662fIRequestInfo\u5bf9\u8c61\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528SendThenResponse.\n ResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes("RRQM"));\n IRequestInfo responseRequestInfo = responsedData.RequestInfo;//\u540c\u6b65\u6536\u5230\u7684RequestInfo\n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .ConfigureContainer(a =>//\u5bb9\u5668\u7684\u914d\u7f6e\u987a\u5e8f\u5e94\u8be5\u5728\u6700\u524d\u9762\n {\n a.AddConsoleLogger();//\u6dfb\u52a0\u4e00\u4e2a\u63a7\u5236\u53f0\u65e5\u5fd7\u6ce8\u5165\uff08\u6ce8\u610f\uff1a\u5728maui\u4e2d\u63a7\u5236\u53f0\u65e5\u5fd7\u4e0d\u53ef\u7528\uff09\n })\n .ConfigurePlugins(a =>\n {\n //a.Add();//\u6b64\u5904\u53ef\u4ee5\u6dfb\u52a0\u63d2\u4ef6\n }))\n .Start();//\u542f\u52a8\n')),(0,i.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"\u5b9e\u9645\u4e0a\u4e0a\u8ff0\u884c\u4e3a\uff0c\u53ea\u8981\u5b9e\u73b0IClient, IDefaultSender, ISend\u4e09\u4e2a\u63a5\u53e3\u7684\u7c7b\u5747\u53ef\u4ee5\u4f7f\u7528\u3002")),(0,i.kt)("admonition",{title:"\u6ce8\u610f\u4e8b\u9879",type:"danger"},(0,i.kt)("ol",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ol"},"\u53d1\u9001\u5b8c\u6570\u636e\uff0c\u5728\u7b49\u5f85\u65f6\uff0c\u5982\u679c\u6536\u5230\u5176\u4ed6\u8fd4\u56de\u6570\u636e\uff0c\u5219\u53ef\u80fd\u5f97\u5230\u9519\u8bef\u7ed3\u679c\u3002"),(0,i.kt)("li",{parentName:"ol"},"\u53d1\u9001\u91c7\u7528Lock\u9501\uff0c\u4e00\u4e2a\u4e8b\u52a1\u6ca1\u7ed3\u675f\uff0c\u53e6\u4e00\u4e2a\u8bf7\u6c42\u4e5f\u53d1\u4e0d\u51fa\u53bb\u3002"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/b806365f.9ff05ec5.js b/handbook/build/assets/js/b806365f.9ff05ec5.js new file mode 100644 index 000000000..f8571fe78 --- /dev/null +++ b/handbook/build/assets/js/b806365f.9ff05ec5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1601],{3905:(e,t,r)=>{r.d(t,{Zo:()=>m,kt:()=>u});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function c(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?l(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):l(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function o(e,t){if(null==e)return{};var r,a,n=function(e,t){if(null==e)return{};var r,a,n={},l=Object.keys(e);for(a=0;a<l.length;a++)r=l[a],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)r=l[a],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),i=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},m=function(e){var t=i(e.components);return a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,l=e.originalType,s=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),d=i(r),u=n,h=d["".concat(s,".").concat(u)]||d[u]||p[u]||l;return r?a.createElement(h,c(c({ref:t},m),{},{components:r})):a.createElement(h,c({ref:t},m))}));function u(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=r.length,c=new Array(l);c[0]=d;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o.mdxType="string"==typeof e?e:n,c[1]=o;for(var i=2;i<l;i++)c[i]=r[i];return a.createElement.apply(null,c)}return a.createElement.apply(null,r)}d.displayName="MDXCreateElement"},510:(e,t,r)=>{r.d(t,{Z:()=>W});var a=r(7294),n=r(7462);const l=(e,t,r)=>e?"string"==typeof e?e:e[t]||r:r,c={display:"block"},o=e=>{let{size:t,color:r,style:o,...s}=e;const i=o?{...c,...o}:c;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},s),a.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:l(r,0,"#333333")}))};o.defaultProps={size:18};const s=o,i={display:"block"},m=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...i,...c}:i;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:l(r,0,"#333333")}),a.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:l(r,1,"#333333")}))};m.defaultProps={size:18};const p=m,d={display:"block"},u=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...d,...c}:d;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:l(r,0,"#333333")}),a.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:l(r,1,"#333333")}),a.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:l(r,2,"#333333")}))};u.defaultProps={size:18};const h=u,v={display:"block"},f=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...v,...c}:v;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:l(r,0,"#333333")}))};f.defaultProps={size:18};const g=f,y={display:"block"},b=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...y,...c}:y;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:l(r,0,"#333333")}))};b.defaultProps={size:18};const z=b,E={display:"block"},k=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...E,...c}:E;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:l(r,0,"#333333")}),a.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:l(r,1,"#333333")}),a.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:l(r,2,"#333333")}))};k.defaultProps={size:18};const x=k,w={display:"block"},C=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...w,...c}:w;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:l(r,0,"#333333")}),a.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:l(r,1,"#333333")}))};C.defaultProps={size:18};const M=C,S={display:"block"},O=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...S,...c}:S;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:l(r,0,"#333333")}),a.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:l(r,1,"#333333")}))};O.defaultProps={size:18};const P=O,L={display:"block"},T=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...L,...c}:L;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:l(r,0,"#333333")}),a.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:l(r,1,"#333333")}))};T.defaultProps={size:18};const j=T,Z={display:"block"},A=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...Z,...c}:Z;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:l(r,0,"#333333")}))};A.defaultProps={size:18};const B=A,R={display:"block"},N=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...R,...c}:R;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:l(r,0,"#333333")}))};N.defaultProps={size:18};const D=N,H={display:"block"},V=e=>{let{size:t,color:r,style:c,...o}=e;const s=c?{...H,...c}:H;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},o),a.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:l(r,0,"#333333")}))};V.defaultProps={size:18};const U=V,q=e=>{let{name:t,...r}=e;switch(t){case"youhua":return a.createElement(s,r);case"dayi":return a.createElement(p,r);case"shengji":return a.createElement(h,r);case"tiaozheng":return a.createElement(g,r);case"gengxin":return a.createElement(z,r);case"wendang":return a.createElement(x,r);case"shanchu":return a.createElement(M,r);case"bug":return a.createElement(P,r);case"xinzeng":return a.createElement(j,r);case"fuwu":return a.createElement(B,r);case"down":return a.createElement(D,r);case"up":return a.createElement(U,r)}return null},F="label_p8vM",I="icon_knQK";function W(e){const{children:t}=e,r={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return a.createElement("label",{className:F,title:t,style:{backgroundColor:r[t].bgColor}},a.createElement(q,{name:r[t].icon,color:"white",size:14,className:I})," ",t)}},4359:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>d,frontMatter:()=>c,metadata:()=>s,toc:()=>m});var a=r(7462),n=(r(7294),r(3905)),l=r(510);const c={id:"remotestreamaccess",title:"b.\u8fdc\u7a0b\u6d41\u8bbf\u95ee"},o=void 0,s={unversionedId:"remotestreamaccess",id:"remotestreamaccess",title:"b.\u8fdc\u7a0b\u6d41\u8bbf\u95ee",description:"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248",source:"@site/docs/remotestreamaccess.mdx",sourceDirName:".",slug:"/remotestreamaccess",permalink:"/touchsocket/docs/remotestreamaccess",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/remotestreamaccess.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675745725,formattedLastUpdatedAt:"Feb 7, 2023",frontMatter:{id:"remotestreamaccess",title:"b.\u8fdc\u7a0b\u6d41\u8bbf\u95ee"},sidebar:"docs",previous:{title:"Stream\u4f20\u8f93",permalink:"/touchsocket/docs/streamtransfer"},next:{title:"EventBus",permalink:"/touchsocket/docs/eventbus"}},i={},m=[{value:"\u4e00\u3001\u8bf4\u660e <Tag>\u4f01\u4e1a\u7248</Tag>",id:"\u4e00\u8bf4\u660e-\u4f01\u4e1a\u7248",level:2},{value:"\u4e8c\u3001\u573a\u666f",id:"\u4e8c\u573a\u666f",level:2},{value:"\u4e09\u3001\u4ee3\u7801\u793a\u4f8b",id:"\u4e09\u4ee3\u7801\u793a\u4f8b",level:2},{value:"\u56db\u3001\u8bfb\u5199",id:"\u56db\u8bfb\u5199",level:2},{value:"\u4e94\u3001\u91ca\u653e",id:"\u4e94\u91ca\u653e",level:2},{value:"\u516d\u3001\u6027\u80fd",id:"\u516d\u6027\u80fd",level:2}],p={toc:m};function d(e){let{components:t,...c}=e;return(0,n.kt)("wrapper",(0,a.Z)({},p,c,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"\u4e00\u8bf4\u660e-\u4f01\u4e1a\u7248"},"\u4e00\u3001\u8bf4\u660e ",(0,n.kt)(l.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("p",null,"\u53ef\u4ee5\u5728\u901a\u4fe1\u5bf9\u65b9\uff0c\u521b\u5efa\u4e00\u4e2aStream\uff0c\u7136\u540e\u6620\u5c04\u5230\u672c\u5730\uff0c\u7531\u672c\u5730\u76f4\u63a5\u8fdb\u884c\u8bfb\u3001\u5199\u7b49\u64cd\u4f5c\u3002"),(0,n.kt)("h2",{id:"\u4e8c\u573a\u666f"},"\u4e8c\u3001\u573a\u666f"),(0,n.kt)("p",null,"\u5f53\u8fdc\u7a0b\u4e3b\u673a\u62e5\u6709\u4e00\u4e2a\u8d85\u5927\u6d41\u6570\u636e\uff08\u53ef\u80fd\u662f\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\uff09\u65f6\uff0c\u672c\u5730\u53ea\u60f3\u8bbf\u95ee\u5176\u90e8\u5206\u6570\u636e\u7684\u8bdd\uff0c\u5c31\u53ef\u4ee5\u4f7f\u7528\u8be5\u529f\u80fd\u3002\n\u4f8b\u5982\uff0c\u5047\u8bbeC\u670d\u52a1\u5668\u6709\u4e2a10Gb\u7684\u6587\u4ef6\u3002A\u5ba2\u6237\u7aef\u9700\u8981\u517610000-20000\u5b57\u8282\u4e4b\u95f4\u7684\u6570\u636e\uff0c\u90a3\u4f60\u6b64\u65f6\u53ef\u4ee5\u4f7f\u7528\u8be5\u529f\u80fd\uff0c\u76f4\u63a5\u8fdb\u884c\u8bfb\u53d6\u3002"),(0,n.kt)("h2",{id:"\u4e09\u4ee3\u7801\u793a\u4f8b"},"\u4e09\u3001\u4ee3\u7801\u793a\u4f8b"),(0,n.kt)("p",null,"\u4e0b\u5217\u4ee5\u5ba2\u6237\u7aef\u4f5c\u4e3a\u8bf7\u6c42\u7aef\uff0c\u4ee5\u670d\u52a1\u5668\u4f5c\u4e3a\u54cd\u5e94\u7aef\u3002\u5b9e\u9645\u4e0a\u670d\u52a1\u5668\u4e5f\u53ef\u4ee5\u505a\u8bf7\u6c42\u7aef\u3002"),(0,n.kt)("p",null,"\u3010\u8bf7\u6c42\u7aef\u3011\n\u4efb\u610fTouchRpc\u7ec8\u7aef\uff08\u9664udp\u534f\u8bae\uff09\u5747\u53ef\u4ee5\u8c03\u7528LoadRemoteStream\u521b\u5efa\u4e00\u4e2a\u6d41\u6570\u636e\u6620\u5c04\u3002\n\u540c\u65f6\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u5143\u6570\u636e\u7ec4\u3002\u7528\u4e8e\u8f7d\u5165\u81ea\u5b9a\u4e49\u6d88\u606f\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},'RemoteStream remoteStream = client.LoadRemoteStream(new Metadata().AddOrUpdate("1", "1"));\n')),(0,n.kt)("p",null,"\u3010\u54cd\u5e94\u7aef\u3011\n\u54cd\u5e94\u7aef\u5b9a\u4e49\u4e00\u4e2a\u63d2\u4ef6\uff0c\u91cd\u5199OnLoadingStream\uff0c\u7136\u540e\u5b9e\u73b0\u9700\u8981\u8f7d\u5165\u7684\u5177\u4f53\u6d41\u4fe1\u606f\u3002\u793a\u4f8b\u4e2d\u662f\u4ee5MemoryStream\u4f5c\u4e3a\u6d41\u4e3b\u4f53\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},'class MyTcpTouchRpcPlugin : TouchRpcPluginBase\n{\n protected override void OnLoadingStream(ITouchRpc client, LoadingStreamEventArgs e)\n {\n if (e.Metadata["1"]=="1")\n {\n e.Stream = new MemoryStream();\n }\n base.OnLoadingStream(client, e);\n }\n}\n\n')),(0,n.kt)("h2",{id:"\u56db\u8bfb\u5199"},"\u56db\u3001\u8bfb\u5199"),(0,n.kt)("p",null,"\u5f53RemoteStream\u88ab\u6210\u529f\u521b\u5efa\u4ee5\u540e\uff0c\u5373\u53ef\u76f4\u63a5Read\u3001Write\u3002\u56e0\u4e3aRemoteStream\u7ee7\u627f\u81eaStream\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},'var client = GetClient();\nRemoteStream remoteStream = client.LoadRemoteStream(new Metadata().AddOrUpdate("1", "1"));\n\nbyte[] data = new byte[] { 0, 1, 2, 3, 4 };\nremoteStream.Write(data);\nAssert.True(remoteStream.Length==5);\nAssert.True(remoteStream.Position==5);\n\nremoteStream.Position = 0;\nbyte[] buffer=new byte[5];\nremoteStream.Read(buffer);\nAssert.True(buffer.SequenceEqual(data));\nAssert.True(remoteStream.Position == 5);\nAssert.True(remoteStream.Length == 5);\n\nremoteStream.SafeDispose();\n')),(0,n.kt)("h2",{id:"\u4e94\u91ca\u653e"},"\u4e94\u3001\u91ca\u653e"),(0,n.kt)("p",null,"\u5f53",(0,n.kt)("strong",{parentName:"p"},"\u65ad\u5f00\u8fde\u63a5"),"\uff0c\u6216\u8005\u8bf7\u6c42\u65b9\u4e3b\u52a8\u8c03\u7528Dispose\u65f6\uff0c\u54cd\u5e94\u65b9\u7684Stream\u5747\u4f1a\u88ab\u5b9e\u9645\u7684Dispose\u6389\u3002"),(0,n.kt)("h2",{id:"\u516d\u6027\u80fd"},"\u516d\u3001\u6027\u80fd"),(0,n.kt)("p",null,"\u56fe\u4e2d\u793a\u4f8b\u4e3a\u76f4\u63a5\u8bfb\u53d6\u4e00\u4e2aWindow.iso\u6587\u4ef6\u6240\u793a\u3002"),(0,n.kt)("img",{src:r(2777).Z}))}d.isMDXComponent=!0},2777:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/remotestreamaccess-1-9ac54f0c1895cfe875a59449dc1db695.gif"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/b992e8b3.07f49565.js b/handbook/build/assets/js/b992e8b3.07f49565.js new file mode 100644 index 000000000..64dd28ae9 --- /dev/null +++ b/handbook/build/assets/js/b992e8b3.07f49565.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6128],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>y});var l=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,l)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,l,a=function(e,t){if(null==e)return{};var n,l,a={},r=Object.keys(e);for(l=0;l<r.length;l++)n=r[l],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(l=0;l<r.length;l++)n=r[l],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=l.createContext({}),s=function(e){var t=l.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return l.createElement(c.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},k=l.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),k=s(n),y=a,d=k["".concat(c,".").concat(y)]||k[y]||p[y]||r;return n?l.createElement(d,o(o({ref:t},u),{},{components:n})):l.createElement(d,o({ref:t},u))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=k;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i.mdxType="string"==typeof e?e:a,o[1]=i;for(var s=2;s<r;s++)o[s]=n[s];return l.createElement.apply(null,o)}return l.createElement.apply(null,n)}k.displayName="MDXCreateElement"},8496:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>i,toc:()=>s});var l=n(7462),a=(n(7294),n(3905));const r={id:"ipackage",title:"\u5305\u5e8f\u5217\u5316\u6a21\u5f0f"},o=void 0,i={unversionedId:"ipackage",id:"ipackage",title:"\u5305\u5e8f\u5217\u5316\u6a21\u5f0f",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/ipackage.mdx",sourceDirName:".",slug:"/ipackage",permalink:"/touchsocket/docs/ipackage",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/ipackage.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675315991,formattedLastUpdatedAt:"Feb 2, 2023",frontMatter:{id:"ipackage",title:"\u5305\u5e8f\u5217\u5316\u6a21\u5f0f"},sidebar:"docs",previous:{title:"\u63d2\u4ef6\u7cfb\u7edf",permalink:"/touchsocket/docs/pluginsmanager"},next:{title:"\u5176\u4ed6\u76f8\u5173\u529f\u80fd\u7c7b",permalink:"/touchsocket/docs/othercore"}},c={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2},{value:"\u56db\u3001\u6027\u80fd\u8bc4\u6d4b",id:"\u56db\u6027\u80fd\u8bc4\u6d4b",level:2}],u={toc:s};function p(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,l.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u5305\u5e8f\u5217\u5316\u6a21\u5f0f\u662f\u4e3a\u4e86\u89e3\u51b3",(0,a.kt)("strong",{parentName:"p"},"\u6781\u9650\u5e8f\u5217\u5316"),"\u7684\u95ee\u9898\u3002\u5e38\u89c4\u5e8f\u5217\u5316\u7684\u74f6\u9888\uff0c\u4e3b\u8981\u662f\u53cd\u5c04\u3001\u8868\u8fbe\u5f0f\u6811\u3001\u521b\u5efa\u5bf9\u8c61\u7b49\u51e0\u4e2a\u65b9\u9762\uff0c\u8fd9\u51e0\u4e2a\u95ee\u9898\u5728\u8fd0\u884c\u65f6\u9636\u6bb5\uff0c\u90fd\u6ca1\u6709\u4e00\u4e2a\u597d\u7684\u89e3\u51b3\u65b9\u6848\u3002\u76ee\u524d\u5728net6\u4ee5\u540e\uff0c\u5fae\u8f6f\u5927\u529b\u652f\u6301\u6e90\u4ee3\u7801\u751f\u6210\uff0c\u8fd9\u4f7f\u5f97\u8fd9\u7c7b\u95ee\u9898\u5f97\u5230\u4e86\u5f88\u5927\u7a0b\u5ea6\u7684\u89e3\u51b3\u3002\u4f46\u662f\u5bf9\u4e8e\u8001\u9879\u76ee\uff0c\u6216\u8005\u65e0\u6cd5\u4f7f\u7528net6\u548cvs2022\u4ee5\u4e0a\u7684\u9879\u76ee\uff0c\u662f\u65e0\u6cd5\u4f7f\u7528\u7684\u3002\u6240\u4ee5\uff0c\u8fd9\u65f6\u5019\u5305\u5e8f\u5217\u5316\u6a21\u5f0f\u5c31\u663e\u5f97\u975e\u5e38\u9700\u8981\u4e86\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("p",null,"\u3010\u4f18\u70b9\u3011"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u7b80\u5355\u3001\u53ef\u9760\u3001\u9ad8\u6548"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u4ee5\u652f\u6301\u6240\u6709\u7c7b\u578b\uff08\u9700\u8981\u81ea\u5df1\u7f16\u5199\u4ee3\u7801\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u6570\u636e\u91cf\u6700\u5c11\uff08\u4ece\u7406\u8bba\u6765\u8bf4\u8fd9\u662f\u5360\u6570\u636e\u91cf\u6700\u8f7b\u91cf\u7684\u8bbe\u8ba1\uff09")),(0,a.kt)("p",null,"\u3010\u7f3a\u70b9\u3011"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u8981\u6c42\u5e8f\u5217\u5316\u7aef\u548c\u53cd\u5e8f\u5217\u5316\u7aef\u5fc5\u987b\u4fdd\u6301\u4e00\u81f4\uff0c\u53ef\u4ee5\u5b58\u5728\u6570\u636e\u5dee\u5f02\uff0c\u4f46\u662f\u4e0d\u80fd\u51fa\u73b0\u6570\u636e\u65ad\u5c42\u3002")),(0,a.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u3010\u5b9e\u4f53\u7c7b\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyClass : IPackage\n{\n public int P1 { get; set; }\n public string P2 { get; set; }\n public char P3 { get; set; }\n public double P4 { get; set; }\n public List<int> P5 { get; set; }\n public Dictionary<int, MyClassModel> P6 { get; set; }\n public void Package(ByteBlock byteBlock)\n {\n //\u57fa\u7840\u7c7b\u578b\u76f4\u63a5\u5199\u5165\u3002\n byteBlock.Write(P1);\n byteBlock.Write(P2);\n byteBlock.Write(P3);\n byteBlock.Write(P4);\n\n //\u96c6\u5408\u7c7b\u578b\uff0c\u53ef\u4ee5\u5148\u5224\u65ad\u662f\u5426\u4e3anull\n byteBlock.WriteIsNull(P5);\n if (P5 != null)\n {\n //\u5982\u679c\u4e0d\u4e3anull\n //\u5c31\u5148\u5199\u5165\u96c6\u5408\u957f\u5ea6\n //\u7136\u540e\u904d\u5386\u5c06\u6bcf\u4e2a\u9879\u5199\u5165\n byteBlock.Write(P5.Count);\n foreach (var item in P5)\n {\n byteBlock.Write(item);\n }\n }\n\n //\u5b57\u5178\u7c7b\u578b\uff0c\u53ef\u4ee5\u5148\u5224\u65ad\u662f\u5426\u4e3anull\n byteBlock.WriteIsNull(P6);\n if (P6 != null)\n {\n //\u5982\u679c\u4e0d\u4e3anull\n //\u5c31\u5148\u5199\u5165\u5b57\u5178\u957f\u5ea6\n //\u7136\u540e\u904d\u5386\u5c06\u6bcf\u4e2a\u9879\uff0c\u6309\u952e\u3001\u503c\u5199\u5165\n byteBlock.Write(P6.Count);\n foreach (var item in P6)\n {\n byteBlock.Write(item.Key);\n byteBlock.WritePackage(item.Value);//\u56e0\u4e3a\u503cMyClassModel\u5b9e\u73b0\u4e86IPackage\uff0c\u6240\u4ee5\u53ef\u4ee5\u76f4\u63a5\u5199\u5165\n }\n }\n }\n\n public void Unpackage(ByteBlock byteBlock)\n {\n //\u57fa\u7840\u7c7b\u578b\u6309\u5e8f\u8bfb\u53d6\u3002\n this.P1 = byteBlock.ReadInt32();\n this.P2 = byteBlock.ReadString();\n this.P3 = byteBlock.ReadChar();\n this.P4 = byteBlock.ReadDouble();\n\n var isNull = byteBlock.ReadIsNull();\n if (!isNull)\n {\n int count = byteBlock.ReadInt32();\n var list = new List<int>(count);\n for (int i = 0; i < count; i++)\n {\n list.Add(byteBlock.ReadInt32());\n }\n this.P5 = list;\n }\n\n\n isNull = byteBlock.ReadIsNull();//\u590d\u7528\u524d\u9762\u7684\u53d8\u91cf\uff0c\u7701\u7684\u91cd\u65b0\u58f0\u660e\n if (!isNull)\n {\n int count = byteBlock.ReadInt32();\n var dic = new Dictionary<int, MyClassModel>(count);\n for (int i = 0; i < count; i++)\n {\n dic.Add(byteBlock.ReadInt32(), byteBlock.ReadPackage<MyClassModel>());\n }\n this.P6 = dic;\n }\n }\n}\n\nclass MyClassModel : PackageBase\n{\n public DateTime P1 { get; set; }\n public override void Package(ByteBlock byteBlock)\n {\n byteBlock.Write(P1);\n }\n\n public override void Unpackage(ByteBlock byteBlock)\n {\n this.P1 = byteBlock.ReadDateTime();\n }\n}\n")),(0,a.kt)("p",null,"\u3010\u6253\u5305\u548c\u89e3\u5305\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"var myClass = new MyClass();\nmyClass.P1 = 1;\nmyClass.P2 = \"\u82e5\u6c5d\u68cb\u8317\";\nmyClass.P3 = 'a';\nmyClass.P4= 3;\n\nmyClass.P5=new List<int> { 1, 2, 3 };\n\nmyClass.P6= new Dictionary<int, MyClassModel>() \n{\n { 1,new MyClassModel(){ P1=DateTime.Now} },\n { 2,new MyClassModel(){ P1=DateTime.Now} }\n};\n\nusing (ByteBlock byteBlock=new ByteBlock())\n{\n myClass.Package(byteBlock);//\u6253\u5305\uff0c\u76f8\u5f53\u4e8e\u5e8f\u5217\u5316\n\n byteBlock.Seek(0);//\u5c06\u6d41\u4f4d\u7f6e\u91cd\u7f6e\u4e3a0\n\n var myNewClass = new MyClass();\n myNewClass.Unpackage(byteBlock);//\u89e3\u5305\uff0c\u76f8\u5f53\u4e8e\u53cd\u5e8f\u5217\u5316\n}\n")),(0,a.kt)("h2",{id:"\u56db\u6027\u80fd\u8bc4\u6d4b"},"\u56db\u3001\u6027\u80fd\u8bc4\u6d4b"),(0,a.kt)("p",null,"\u57fa\u51c6\u6d4b\u8bd5\u8868\u660e\uff1a"),(0,a.kt)("p",null,"\u5305\u5e8f\u5217\u5316\u6a21\u5f0f\u548c\u4f7f\u7528\u6e90\u4ee3\u7801\u751f\u6210\u65b9\u5f0f\u5de5\u4f5c\u7684MemoryPack\u51e0\u4e4e\u4e00\u6837\u3002\u6bd4json\u65b9\u5f0f\u5feb\u4e8610\u500d\u591a\uff0c\u6bd4\u5fae\u8f6f\u7684json\u5feb\u4e86\u8fd14\u500d\u3002"),(0,a.kt)("p",null,(0,a.kt)("img",{src:n(4635).Z,width:"1176",height:"275"})))}p.isMDXComponent=!0},4635:(e,t,n)=>{n.d(t,{Z:()=>l});const l=n.p+"assets/images/ipackage-1-2f48a97c1a2568b875aab9b5a51de765.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/ba9c7ecd.ed9c972b.js b/handbook/build/assets/js/ba9c7ecd.ed9c972b.js new file mode 100644 index 000000000..a6f482264 --- /dev/null +++ b/handbook/build/assets/js/ba9c7ecd.ed9c972b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[487],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),u=p(r),f=a,m=u["".concat(l,".").concat(f)]||u[f]||d[f]||o;return r?n.createElement(m,i(i({ref:t},s),{},{components:r})):n.createElement(m,i({ref:t},s))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=u;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var p=2;p<o;p++)i[p]=r[p];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}u.displayName="MDXCreateElement"},6923:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>p});var n=r(7462),a=(r(7294),r(3905));const o={id:"fixedsizepackageadapter",title:"\u56fa\u5b9a\u957f\u5ea6\u6570\u636e\u5904\u7406\u9002\u914d\u5668"},i=void 0,c={unversionedId:"fixedsizepackageadapter",id:"fixedsizepackageadapter",title:"\u56fa\u5b9a\u957f\u5ea6\u6570\u636e\u5904\u7406\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/fixedsizepackageadapter.mdx",sourceDirName:".",slug:"/fixedsizepackageadapter",permalink:"/touchsocket/docs/fixedsizepackageadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/fixedsizepackageadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675577572,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"fixedsizepackageadapter",title:"\u56fa\u5b9a\u957f\u5ea6\u6570\u636e\u5904\u7406\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u56fa\u5b9a\u5305\u5934\u6570\u636e\u5904\u7406\u9002\u914d\u5668",permalink:"/touchsocket/docs/fixedheaderpackageadapter"},next:{title:"\u7ec8\u6b62\u56e0\u5b50\u5206\u5272\u6570\u636e\u5904\u7406\u9002\u914d\u5668",permalink:"/touchsocket/docs/terminatorpackageadapter"}},l={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2}],s={toc:p};function d(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("p",null,"\u56fa\u5b9a\u957f\u5ea6\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u662f\u5c06\u53d1\u9001\u7684\u6570\u636e\u901a\u8fc7\u5206\u5272\u3001\u586b\u8865\u7684\u64cd\u4f5c\uff0c\u4ee5\u8fbe\u5230\u6bcf\u6b21\u53d1\u9001\u3001\u63a5\u6536\u7684\u6570\u636e\u90fd\u662f\u56fa\u5b9a\u7684\u957f\u5ea6\u6765\u5904\u7406\u7c98\u5305\u3001\u5206\u5305\u95ee\u9898\u3002\u8fd9\u79cd\u65b9\u6848\u4e00\u822c\u9002\u7528\u4e8e\u673a\u68b0\u81c2\uff0c\u673a\u5668\u4eba\u63a7\u5236\u7b49\u573a\u666f\u3002 ",(0,a.kt)("a",{name:"AF60y"})),(0,a.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u65e0\u8bba\u4f55\u65f6\uff0c\u53d1\u9001\u4e0e\u63a5\u6536\u7684\u6570\u636e\u957f\u5ea6\u6c38\u8fdc\u4e3a\u8bbe\u5b9a\u503c\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u7b97\u6cd5\u7b80\u5355\uff0c\u53ef\u4ee5\u6bd4\u8f83\u8f7b\u677e\u7684\u5b9e\u73b0\u8de8\u8bed\u8a00\u3001\u8de8\u6846\u67b6\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u4e00\u822c\u9002\u7528\u4e8e\u4e1a\u52a1\u6570\u636e\u56fa\u5b9a\u573a\u666f\uff0c")),(0,a.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,a.kt)("p",null,"\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002\u4e0b\u5217\u4ee5\u670d\u52a1\u5668\u4e3a\u4f8b\u3002"),(0,a.kt)("p",null,"\u6b65\u9aa4"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"TouchSocketConfig\u914d\u7f6e\u4e2d\u8bbe\u7f6e\uff0c\u540c\u65f6\u6307\u5b9a\u6570\u636e\u7684\u957f\u5ea6\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u901a\u8fc7Received\uff08\u4e8b\u4ef6\u3001\u65b9\u6cd5\u3001\u63d2\u4ef6\uff09\u4e2d\u7684ByteBlock\u8bfb\u53d6\u6570\u636e\uff08\u6ce8\u610f\uff1a\u6570\u636e\u957f\u5ea6\u662fbyteBlock.Len\uff09\u3002")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{10}","{10}":!0},"TcpService service = new TcpService();\nservice.Received += (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u5ba2\u6237\u7aef\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e \n .SetListenIPHosts(new IPHost[] { new IPHost(7790) })\n .SetDataHandlingAdapter(()=> { return new FixedSizePackageAdapter(10); }))//\u914d\u7f6e\u9002\u914d\u5668\uff0c\u56fa\u5b9a\u6570\u636e\u957f\u5ea6\u4e3a10\u5b57\u8282\u3002\n .Start();//\u542f\u52a8\n")),(0,a.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"\u63a5\u6536\u7684\u6570\u636e\u957f\u5ea6\u662fbyteBlock.Len\uff0c\u800c\u4e0d\u662fbyteBlock.Buffer.Length\u3002")),(0,a.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"\u8be5\u9002\u914d\u5668\uff0c\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u5747\u9002\u7528\u3002")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/babdfbe3.955f3817.js b/handbook/build/assets/js/babdfbe3.955f3817.js new file mode 100644 index 000000000..2e8f96eab --- /dev/null +++ b/handbook/build/assets/js/babdfbe3.955f3817.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[3420],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function d(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},s={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,p=d(e,["components","mdxType","originalType","parentName"]),u=c(n),f=r,m=u["".concat(i,".").concat(f)]||u[f]||s[f]||o;return n?a.createElement(m,l(l({ref:t},p),{},{components:n})):a.createElement(m,l({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=u;var d={};for(var i in t)hasOwnProperty.call(t,i)&&(d[i]=t[i]);d.originalType=e,d.mdxType="string"==typeof e?e:r,l[1]=d;for(var c=2;c<o;c++)l[c]=n[c];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},2257:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>s,frontMatter:()=>o,metadata:()=>d,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const o={id:"independentusedatahandlingadapter",title:"\u72ec\u7acb\u4f7f\u7528\u9002\u914d\u5668"},l=void 0,d={unversionedId:"independentusedatahandlingadapter",id:"independentusedatahandlingadapter",title:"\u72ec\u7acb\u4f7f\u7528\u9002\u914d\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/independentusedatahandlingadapter.mdx",sourceDirName:".",slug:"/independentusedatahandlingadapter",permalink:"/touchsocket/docs/independentusedatahandlingadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/independentusedatahandlingadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675586056,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"independentusedatahandlingadapter",title:"\u72ec\u7acb\u4f7f\u7528\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u56fd\u7f51\u8f93\u7535i1\u6807\u51c6\u7248",permalink:"/touchsocket/docs/stategridtransmission"},next:{title:"8.5 \u9002\u914d\u5668\u5b8c\u6574\u6027\u3001\u6027\u80fd\u6d4b\u8bd5",permalink:"/touchsocket/docs/dataadaptertester"}},i={},c=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4f7f\u7528",id:"\u4e8c\u4f7f\u7528",level:2}],p={toc:c};function s(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"\u9002\u914d\u5668\u7684\u673a\u5236\uff0c\u662f\u975e\u5e38\u597d\u7684\u89e3\u5c01\u5305\u673a\u5236\uff0c\u90a3\u8fd9\u4e48\u597d\u7684\u673a\u5236\uff0c\u6211\u4eec\u5728\u8bbe\u8ba1\u7684\u65f6\u5019\uff0c\u4e5f\u60f3\u5230\u4e86\u5355\u72ec\u4f7f\u7528\u9002\u914d\u5668\u7684\u60c5\u51b5\u3002\u4f8b\u5982\uff1a"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"\u5bf9\u4e8e\u4e32\u53e3\u901a\u4fe1\uff0c\u53ef\u4ee5\u4f7f\u7528\u9002\u914d\u5668\u89e3\u5305\u3002"),(0,r.kt)("li",{parentName:"ol"},"\u6709\u65f6\u5019\u53ef\u80fd\u5927\u5bb6\u53ea\u60f3\u7528\u539f\u751f",(0,r.kt)("inlineCode",{parentName:"li"},"Socket"),"\u5b9e\u73b0\u3002\u90a3\u4e48\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9002\u914d\u5668\u89e3\u5305\uff0c\u6216\u8005\u5c01\u5305\u3002")),(0,r.kt)("h2",{id:"\u4e8c\u4f7f\u7528"},"\u4e8c\u3001\u4f7f\u7528"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'FixedHeaderPackageAdapter adapter = new FixedHeaderPackageAdapter();\n\nbool sendCallBack = false;\nbool receivedCallBack = false;\n\nbyte[] sentData = null;\nadapter.SendCallBack = (buffer, offset, length) =>\n{\n //\u6b64\u5904\u4f1a\u56de\u8c03\u53d1\u9001\u7684\u6700\u7ec8\u8c03\u7528\u3002\u4f8b\u5982\uff1a\u6b64\u5904\u4f7f\u7528\u56fa\u5b9a\u5305\u5934\uff0c\u5219\u53d1\u9001\u7684\u6570\u636e\u4e3a4+n\u7684\u5c01\u88c5\u3002\n sentData = new byte[length];\n Array.Copy(buffer, offset, sentData, 0, length);\n if (length == 4 + 4)\n {\n sendCallBack = true;\n }\n};\n\nadapter.ReceivedCallBack += (byteBlock, requestInfo) =>\n{\n //\u6b64\u5904\u4f1a\u56de\u8c03\u63a5\u6536\u7684\u6700\u7ec8\u89e6\u53d1\uff0c\u4f8b\u5982\uff1a\u6b64\u5904\u4f7f\u7528\u7684\u56fa\u5b9a\u5305\u5934\uff0c\u4f1a\u89e3\u67904+n\u7684\u6570\u636e\u4e3an\u3002\n\n if (byteBlock.Len == 4)\n {\n receivedCallBack = true;\n }\n};\n\nbyte[] data = Encoding.UTF8.GetBytes("RRQM");\n\nadapter.SendInput(data, 0, data.Length);//\u6a21\u62df\u8f93\u5165\uff0c\u4f1a\u5728SendCallBack\u4e2d\u8f93\u51fa\u6700\u7ec8\u8981\u53d1\u9001\u7684\u6570\u636e\u3002\n\nusing (ByteBlock block = new ByteBlock())\n{\n block.Write(sentData);\n block.Pos = 0;\n adapter.ReceivedInput(block);//\u6a21\u62df\u8f93\u51fa\uff0c\u4f1a\u5728ReceivedCallBack\u4e2d\u8f93\u51fa\u6700\u7ec8\u6536\u5230\u7684\u5b9e\u9645\u6570\u636e\u3002\n}\n')),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u4ec5\u4ec5\u662f\u4ee5\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668\u793a\u4f8b\u7684\uff0c\u5b9e\u9645\u4e0a\u5bf9\u4e8e\u5176\u4ed6\u6240\u6709\u7684\u9002\u914d\u5668\u5747\u53ef\u4ee5\u4f7f\u7528\u3002")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/bc87ecb9.45ae90f0.js b/handbook/build/assets/js/bc87ecb9.45ae90f0.js new file mode 100644 index 000000000..1c9090061 --- /dev/null +++ b/handbook/build/assets/js/bc87ecb9.45ae90f0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7586],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>d});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?c(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):c(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},c=Object.keys(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(r=0;r<c.length;r++)n=c[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,c=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),f=p(n),d=o,m=f["".concat(i,".").concat(d)]||f[d]||u[d]||c;return n?r.createElement(m,a(a({ref:t},s),{},{components:n})):r.createElement(m,a({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=n.length,a=new Array(c);a[0]=f;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l.mdxType="string"==typeof e?e:o,a[1]=l;for(var p=2;p<c;p++)a[p]=n[p];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}f.displayName="MDXCreateElement"},7112:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>a,default:()=>u,frontMatter:()=>c,metadata:()=>l,toc:()=>p});var r=n(7462),o=(n(7294),n(3905));const c={id:"rpcactionfilter",title:"Rpc\u670d\u52a1AOP"},a=void 0,l={unversionedId:"rpcactionfilter",id:"rpcactionfilter",title:"Rpc\u670d\u52a1AOP",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/rpcactionfilter.mdx",sourceDirName:".",slug:"/rpcactionfilter",permalink:"/touchsocket/docs/rpcactionfilter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/rpcactionfilter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675696587,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"rpcactionfilter",title:"Rpc\u670d\u52a1AOP"},sidebar:"docs",previous:{title:"\u8c03\u7528\u4e0a\u4e0b\u6587",permalink:"/touchsocket/docs/rpcallcontext"},next:{title:"\u751f\u6210\u3001\u83b7\u53d6\u4ee3\u7406",permalink:"/touchsocket/docs/generateproxy"}},i={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u58f0\u660e\u7279\u6027",id:"\u4e8c\u58f0\u660e\u7279\u6027",level:2},{value:"\u4e09\u3001\u4f7f\u7528",id:"\u4e09\u4f7f\u7528",level:2}],s={toc:p};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("p",null,"RPC\u670d\u52a1\u5728\u88ab\u8c03\u7528\u662f\uff0c\u53ef\u4ee5\u4f7f\u7528\u5b9e\u73b0",(0,o.kt)("strong",{parentName:"p"},"IRpcActionFilter"),"\u7684",(0,o.kt)("strong",{parentName:"p"},"\u7279\u6027\uff08Attribute\uff09"),"\uff0c\u8fdb\u884c\u76f8\u5173AOP\u64cd\u4f5c\u3002"),(0,o.kt)("h2",{id:"\u4e8c\u58f0\u660e\u7279\u6027"},"\u4e8c\u3001\u58f0\u660e\u7279\u6027"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyRpcActionFilterAttribute : RpcActionFilterAttribute\n{\n public override void Executing(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult)\n {\n //invokeResult = new InvokeResult()\n //{\n // Status = InvokeStatus.UnEnable,\n // Message = "\u4e0d\u5141\u8bb8\u6267\u884c",\n // Result = default\n //};\n if (callContext.Caller is TcpTouchRpcSocketClient client)\n {\n client.Logger.Info($"\u5373\u5c06\u6267\u884cRPC-{callContext.MethodInstance.Name}");\n }\n base.Executing(callContext, parameters, ref invokeResult);\n }\n\n public override void Executed(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult)\n {\n if (callContext.Caller is TcpTouchRpcSocketClient client)\n {\n client.Logger.Info($"\u6267\u884cRPC-{callContext.MethodInstance.Name}\u5b8c\u6210\uff0c\u72b6\u6001={invokeResult.Status}");\n }\n base.Executed(callContext, parameters, ref invokeResult);\n }\n\n public override void ExecutException(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception)\n {\n if (callContext.Caller is TcpTouchRpcSocketClient client)\n {\n client.Logger.Info($"\u6267\u884cRPC-{callContext.MethodInstance.Name}\u5f02\u5e38\uff0c\u4fe1\u606f={invokeResult.Message}");\n }\n\n base.ExecutException(callContext, parameters, ref invokeResult, exception);\n }\n}\n')),(0,o.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u6709\u8be6\u7ec6\u7684\u6ce8\u91ca\uff0c\u4ed4\u7ec6\u67e5\u770b\u53ef\u80fd\u4f1a\u4e8b\u534a\u529f\u500d\u3002")),(0,o.kt)("h2",{id:"\u4e09\u4f7f\u7528"},"\u4e09\u3001\u4f7f\u7528"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},' [Description("\u6027\u80fd\u6d4b\u8bd5")]\n [TouchRpc]\n [MyRpcActionFilter]\n public int Performance(int a)\n {\n return a;\n }\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/bcf858d2.0c59ed82.js b/handbook/build/assets/js/bcf858d2.0c59ed82.js new file mode 100644 index 000000000..82b3e1fd5 --- /dev/null +++ b/handbook/build/assets/js/bcf858d2.0c59ed82.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7986],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=s(r),f=o,m=d["".concat(l,".").concat(f)]||d[f]||u[f]||i;return r?n.createElement(m,a(a({ref:t},p),{},{components:r})):n.createElement(m,a({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var s=2;s<i;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},9620:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const i={id:"filesynchronization",title:"\u6587\u4ef6\u540c\u6b65\u7cfb\u7edf"},a=void 0,c={unversionedId:"filesynchronization",id:"filesynchronization",title:"\u6587\u4ef6\u540c\u6b65\u7cfb\u7edf",description:"\u5b9a\u5236\u65b9",source:"@site/docs/filesynchronization.mdx",sourceDirName:".",slug:"/filesynchronization",permalink:"/touchsocket/docs/filesynchronization",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/filesynchronization.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675263272,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"filesynchronization",title:"\u6587\u4ef6\u540c\u6b65\u7cfb\u7edf"},sidebar:"docs",previous:{title:"\u8fdc\u7a0b\u76d1\u6d4b\u3001\u63a7\u5236\u9879\u76ee",permalink:"/touchsocket/docs/remotemonitoring"},next:{title:"\u6570\u636e\u8f6c\u53d1\u9879\u76ee",permalink:"/touchsocket/docs/dataforwarding"}},l={},s=[{value:"\u5b9a\u5236\u65b9",id:"\u5b9a\u5236\u65b9",level:2},{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u6280\u672f\u70b9",id:"\u6280\u672f\u70b9",level:2},{value:"\u6548\u679c",id:"\u6548\u679c",level:2}],p={toc:s};function u(e){let{components:t,...i}=e;return(0,o.kt)("wrapper",(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u5b9a\u5236\u65b9"},"\u5b9a\u5236\u65b9"),(0,o.kt)("p",null,"\u7f51\u53cb\u201c\u9676\u201d"),(0,o.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,o.kt)("p",null,"\u5e94\u8be5\u7f51\u53cb\u8981\u6c42\uff0c\u9700\u8981\u5f00\u53d1\u4e00\u4e2a\u670d\u52a1\u5668\uff0c\u4e00\u4e2a\u5ba2\u6237\u7aef\uff0c\u5ba2\u6237\u7aef\u7684\u804c\u80fd\u5c31\u662f\u540c\u6b65\u672c\u5730\u6587\u4ef6\u670d\u52a1\u5668\u3002\u6709\u70b9\u7c7b\u4f3c",(0,o.kt)("strong",{parentName:"p"},"OneDrive"),"\u3002"),(0,o.kt)("h2",{id:"\u6280\u672f\u70b9"},"\u6280\u672f\u70b9"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"\u6570\u636e\u540c\u6b65\uff1a\u8bbe\u7f6e\u914d\u7f6e\u6570\u636e\u3001\u9879\u76ee\u6587\u4ef6\u6570\u636e\u7b49\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u6587\u4ef6\uff1a\u65ad\u70b9\u7eed\u4f20\u3001\u6362\u7f51\u7eed\u4f20\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u767b\u5f55\uff1a\u767b\u5f55\u6388\u6743\u3002\u767b\u5f55\u9a8c\u8bc1\u3002")),(0,o.kt)("h2",{id:"\u6548\u679c"},"\u6548\u679c"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"image.png",src:r(3924).Z,width:"1500",height:"677"})))}u.isMDXComponent=!0},3924:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/filesynchronization-1-d586ade9a477965b397c0387e95f9fbe.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/c4f5d8e4.90ede736.js b/handbook/build/assets/js/c4f5d8e4.90ede736.js new file mode 100644 index 000000000..a65f64c8d --- /dev/null +++ b/handbook/build/assets/js/c4f5d8e4.90ede736.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[4195],{6959:(e,t,a)=>{a.r(t),a.d(t,{default:()=>J});var c,l,n=a(7462),r=a(9960),i=a(2949),s=a(4996),o=a(2263),m=a(3929),h=a(9523),d=a(7294);function u(){return u=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(e[c]=a[c])}return e},u.apply(this,arguments)}const p=e=>{let{title:t,titleId:a,...n}=e;return d.createElement("svg",u({className:"icon",viewBox:"0 0 1026 1024",xmlns:"http://www.w3.org/2000/svg",width:200.391,height:200,"aria-labelledby":a},n),t?d.createElement("title",{id:a},t):null,c||(c=d.createElement("path",{d:"M2.438 0h975.238v975.238H2.438z",fill:"none"})),l||(l=d.createElement("path",{d:"M266.386 774.095c0 20.675 18.725 37.547 41.594 37.547h41.643V943.25c0 31.208 27.843 56.369 62.415 56.369 34.524 0 62.415-25.21 62.415-56.369V811.69h83.188v131.56c0 31.208 27.892 56.369 62.415 56.369 34.524 0 62.416-25.21 62.416-56.369V811.69h41.594c22.918 0 41.593-16.92 41.593-37.546V398.19H266.386v375.856zM162.377 398.238c-34.523 0-62.415 25.21-62.415 56.37v263.118c0 31.208 27.892 56.37 62.415 56.37 34.524 0 62.415-25.162 62.415-56.37V454.607c0-31.207-27.891-56.369-62.415-56.369zm707.292 0c-34.524 0-62.416 25.21-62.416 56.37v263.118c0 31.208 27.892 56.37 62.416 56.37 34.523 0 62.415-25.162 62.415-56.37V454.607c0-31.207-27.892-56.369-62.415-56.369zm-206.75-219.477 54.271-49.054a17.457 17.457 0 0 0 0-26.478 22.333 22.333 0 0 0-29.306 0l-61.586 55.393a269.897 269.897 0 0 0-110.25-23.454c-39.986 0-77.386 8.63-110.885 23.65l-61.782-55.784a22.333 22.333 0 0 0-29.354 0 17.457 17.457 0 0 0 0 26.478l54.515 49.25c-61.78 41.154-102.156 107.275-102.156 181.881h499.322c0-74.752-40.618-140.922-102.79-181.882zM432.81 285.501h-41.594v-37.547h41.594v37.547zm208.018 0h-41.594v-37.547h41.594v37.547z",fill:"#2FC2B0"})))};var E,f;function g(){return g=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(e[c]=a[c])}return e},g.apply(this,arguments)}const v=e=>{let{title:t,titleId:a,...c}=e;return d.createElement("svg",g({className:"icon",viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg",width:200,height:200,"aria-labelledby":a},c),t?d.createElement("title",{id:a},t):null,E||(E=d.createElement("path",{d:"M944.9 471.64a141.947 141.947 0 0 0-105.047-9.506 139.64 139.64 0 0 0-56.784-88.959l-11.25-8.86-9.535 10.688a117.675 117.675 0 0 0-22.218 84.656 108.59 108.59 0 0 0 21.206 56.87 164.925 164.925 0 0 1-30.544 13.443 204.272 204.272 0 0 1-62.972 10.153H73.925l-1.266 13.303a248.428 248.428 0 0 0 20.897 129.375l8.128 16.116.928 1.519c55.829 92.193 167.204 139.95 274.05 139.95 206.888 0 364.191-98.747 442.575-288.479 52.37 2.672 105.947-12.403 131.57-61.003l6.524-12.403-12.431-6.975zM246.978 711.689a46.434 46.434 0 1 1 47.813-46.435 47.166 47.166 0 0 1-47.813 46.434z",fill:"#1296db"})),f||(f=d.createElement("path",{d:"M246.978 640.7a24.44 24.44 0 1 0 25.144 24.469 24.806 24.806 0 0 0-25.144-24.469M118.25 427.625h84.375V512H118.25zm112.5 0h84.375V512H230.75zm0-112.5h84.375V399.5H230.75zm112.5 0h84.375V399.5H343.25zm0 112.5h84.375V512H343.25zm112.5 0h84.375V512H455.75zm112.5 0h84.375V512H568.25zm-112.5-112.5h84.375V399.5H455.75zm0-112.5h84.375V287H455.75z",fill:"#1296db"})))};var b;function w(){return w=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(e[c]=a[c])}return e},w.apply(this,arguments)}const k=e=>{let{title:t,titleId:a,...c}=e;return d.createElement("svg",w({className:"icon",viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg",width:200,height:200,"aria-labelledby":a},c),t?d.createElement("title",{id:a},t):null,b||(b=d.createElement("path",{d:"m444.65 600.125.262.375-37.462 90.487a193.912 193.912 0 0 1-77.813-97.387l96.676-16.388.15.188a16.5 16.5 0 0 1 18.15 22.725zm-31.238-79.838a16.5 16.5 0 0 0 6.488-28.35l.075-.412-73.537-65.775a192.863 192.863 0 0 0-27.375 122.063l94.275-27.188.074-.338zm42.938-74.25a16.5 16.5 0 0 0 26.213-12.637l.374-.188 5.625-98.25a192.9 192.9 0 0 0-112.874 54.076L456.2 446.15l.15-.075zm28.5 103.126 27.112 13.087 27.076-13.013 6.75-29.25-18.75-23.362h-30.15l-18.75 23.362 6.712 29.213zM541.1 433.1a16.5 16.5 0 0 0 26.25 12.6l.3.112 80.025-56.737A194.55 194.55 0 0 0 535.475 335l5.55 98.063.075.037zm407.85 223.875L732.462 926.263a60 60 0 0 1-46.8 22.275l-347.287.112a60 60 0 0 1-46.763-22.35l-216.6-269.25A59.362 59.362 0 0 1 63.5 606.8l77.25-335.813c4.05-17.625 15.937-32.4 32.362-40.237L485.938 81.238a60.225 60.225 0 0 1 51.937 0l312.937 149.437c16.425 7.838 28.313 22.65 32.363 40.238L960.5 606.725a59.041 59.041 0 0 1-11.55 50.25zm-123.338-77.138c-1.575-.375-3.862-.974-5.437-1.275-6.525-1.237-11.812-.937-17.963-1.425-13.124-1.387-23.924-2.512-33.562-5.55-3.937-1.5-6.75-6.187-8.1-8.1l-7.537-2.212a241.875 241.875 0 0 0-3.938-87.45 242.438 242.438 0 0 0-35.1-81.113c1.95-1.762 5.625-4.987 6.638-5.962.3-3.375.037-6.863 3.524-10.575 7.388-6.937 16.65-12.675 27.863-19.575 5.325-3.15 10.238-5.137 15.562-9.075 1.2-.9 2.85-2.325 4.126-3.337 9-7.163 11.062-19.5 4.612-27.6-6.45-8.1-18.975-8.85-27.937-1.688-1.276 1.013-3 2.325-4.163 3.3-5.025 4.35-8.138 8.625-12.375 13.125-9.225 9.375-16.875 17.175-25.238 22.838-3.637 2.1-8.962 1.387-11.362 1.237l-7.125 5.063a245.437 245.437 0 0 0-155.475-75.113l-.45-8.362c-2.437-2.325-5.362-4.313-6.112-9.376-.826-10.05.562-20.887 2.137-33.937.862-6.113 2.288-11.175 2.55-17.813.037-1.5-.038-3.712-.037-5.324 0-11.475-8.4-20.813-18.75-20.813-10.313 0-18.713 9.338-18.713 20.813l.037.525c0 1.537-.074 3.45 0 4.8.225 6.637 1.65 11.7 2.513 17.812 1.575 13.05 2.925 23.888 2.1 33.975a20.437 20.437 0 0 1-6.075 9.675l-.45 7.913A240.9 240.9 0 0 0 335.15 360.35a313.988 313.988 0 0 1-6.75-4.8c-3.375.45-6.75 1.5-11.137-1.088-8.363-5.625-16.013-13.425-25.238-22.8-4.237-4.5-7.313-8.774-12.337-13.087a100.912 100.912 0 0 0-4.163-3.3 22.275 22.275 0 0 0-13.05-4.95 18.038 18.038 0 0 0-14.925 6.6c-6.45 8.1-4.387 20.475 4.613 27.637l.262.188 3.9 3.113c5.325 3.937 10.2 5.962 15.525 9.074 11.213 6.938 20.475 12.675 27.863 19.575 2.85 3.076 3.375 8.476 3.75 10.8l6 5.363a242.325 242.325 0 0 0-38.25 168.975l-7.8 2.25c-2.063 2.7-4.988 6.9-8.063 8.137-9.637 3.038-20.475 4.125-33.562 5.513-6.15.525-11.438.225-18 1.462-1.388.263-3.375.75-4.988 1.125l-.15.076-.262.075c-11.063 2.662-18.15 12.825-15.863 22.8 2.288 10.012 13.088 16.087 24.188 13.687l.262-.037.375-.113 4.838-1.087c6.374-1.725 11.025-4.238 16.8-6.45 12.375-4.426 22.65-8.138 32.625-9.6 4.2-.338 8.625 2.587 10.8 3.787l8.137-1.387a243.75 243.75 0 0 0 108 134.85l-3.375 8.175c1.237 3.15 2.587 7.462 1.65 10.575-3.637 9.45-9.862 19.387-16.95 30.487-3.413 5.1-6.937 9.075-10.05 14.963-.75 1.387-1.687 3.562-2.4 5.025-4.8 10.312-1.275 22.162 7.988 26.624 9.3 4.5 20.85-.262 25.875-10.575v-.074c.75-1.463 1.725-3.375 2.324-4.763 2.626-6.075 3.526-11.288 5.4-17.175 4.95-12.45 7.688-25.5 14.513-33.637 1.875-2.25 4.875-3.076 8.063-3.938l4.237-7.688a241.988 241.988 0 0 0 172.838.45l3.974 7.2c3.225 1.05 6.75 1.575 9.6 5.813 5.1 8.7 8.588 19.013 12.826 31.5 1.874 5.85 2.774 11.063 5.437 17.137.6 1.388 1.613 3.375 2.325 4.838 4.988 10.35 16.575 15.075 25.875 10.575 9.263-4.425 12.787-16.313 7.988-26.625-.75-1.462-1.688-3.6-2.438-5.025-3.112-5.85-6.637-9.787-10.05-14.925-7.125-11.1-12.975-20.288-16.612-29.737-1.5-4.875.262-7.875 1.425-11.025-.675-.825-2.213-5.4-3.113-7.575a243.713 243.713 0 0 0 108-135.826c2.4.376 6.6 1.125 7.988 1.426 2.812-1.875 5.4-4.275 10.5-3.9 9.974 1.462 20.25 5.174 32.624 9.6 5.776 2.25 10.388 4.8 16.8 6.487 1.35.375 3.3.713 4.876 1.05l.337.113.262.037c11.138 2.4 21.9-3.675 24.188-13.688 2.25-9.974-4.8-20.137-15.863-22.8zM677 425.787l-73.125 65.475v.188a16.5 16.5 0 0 0 6.488 28.387l.112.376 94.725 27.3a194.963 194.963 0 0 0-4.05-62.776A195.3 195.3 0 0 0 677 425.75zM526.512 625.475a16.387 16.387 0 0 0-15.15-8.7 16.5 16.5 0 0 0-13.95 8.738h-.075l-47.55 85.95a193.65 193.65 0 0 0 124.725.112l-47.624-86.1h-.375zm70.8-48.488a16.5 16.5 0 0 0-10.124 1.35 16.5 16.5 0 0 0-8.025 21.45l-.113.15 37.875 91.426a193.125 193.125 0 0 0 78.038-98.063l-97.5-16.5-.15.187z",fill:"#0092ff"})))};var y,N,S,T,z,M,O,j,C,V,H,x,F,B;function I(){return I=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(e[c]=a[c])}return e},I.apply(this,arguments)}const A=e=>{let{title:t,titleId:a,...c}=e;return d.createElement("svg",I({className:"icon",viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg",width:200,height:200,"aria-labelledby":a},c),t?d.createElement("title",{id:a},t):null,y||(y=d.createElement("path",{d:"M524.375 217.906c-8.063 5.25-14.25 12.938-17.719 21.938-3.562 11.625-3 24 1.406 35.344A59.437 59.437 0 0 0 528.875 305a37.347 37.347 0 0 0 17.063 6.563c6.187.75 12.375-.282 17.906-3.094a35.218 35.218 0 0 0 14.906-16.219c3-6.938 4.688-14.344 4.875-21.844a73.847 73.847 0 0 0-3.563-28.219c-3.28-9.937-9.656-18.468-18.28-24.28-4.407-2.813-9.282-4.688-14.438-5.438a30.339 30.339 0 0 0-15.282 1.687 41.666 41.666 0 0 0-7.78 4.219",fill:"#FFF"})),N||(N=d.createElement("path",{d:"M791.563 600.594a395.632 395.632 0 0 0-22.313-77.438c-6.844-18.562-16.125-36.187-27.656-52.312-11.625-15.469-26.344-28.5-37.688-44.156-6-8.157-11.062-17.25-17.343-25.22-2.532-5.25-4.97-10.5-7.407-15.75-7.5-16.406-14.343-33.187-23.25-48.75-1.406-2.437-2.906-4.874-4.312-7.218-1.125-15-2.719-30-3.563-45a425.74 425.74 0 0 0-7.593-89.906c-3.938-14.156-9.938-27.75-17.813-40.125-9.188-14.625-21-27.375-34.875-37.594a134.301 134.301 0 0 0-77.25-24.75c-20.344-.469-40.5 4.125-58.594 13.5-19.031 10.406-34.406 26.438-44.062 45.844a153.998 153.998 0 0 0-14.063 62.344c-.75 21.187 1.219 42.187 2.063 63.375.844 21.937.375 43.968 2.156 65.906.563 7.031 1.406 14.062 1.406 21.187 0 3.563-.187 7.125-.281 10.594l-.281.75a450.215 450.215 0 0 1-31.688 46.781c-8.062 10.219-16.125 20.344-24.281 30.375-10.594 11.906-19.594 25.125-26.719 39.375-4.781 12.375-8.625 25.125-11.625 38.063l-.281 1.031a296.022 296.022 0 0 1-16.875 43.313 142.935 142.935 0 0 0-1.875 3.937c-4.031 8.344-8.25 16.688-12.656 24.844l-5.063 9.468a159.66 159.66 0 0 0-8.437 17.625c-1.406 3.657-2.531 7.407-3.188 11.25-1.219 8.157-.656 16.407 1.5 24.282.469 1.968 1.125 3.937 1.781 5.906 2.063 5.813 4.5 11.531 7.407 16.969 1.312 2.531 2.719 4.968 4.031 7.5l1.219 1.781a169.016 169.016 0 0 0 4.125 6.938l.187.28c1.594 2.626 3.375 5.157 5.063 7.688l.281.375c1.781 2.438 3.563 4.969 5.438 7.407 6.937 27.093 19.687 52.312 37.218 74.062-2.719 4.781-5.156 9.469-7.875 14.156A216.887 216.887 0 0 0 293 853.72c-2.531 8.062-3.188 16.593-1.781 24.937 1.312 8.438 5.625 16.032 12.187 21.563 4.406 3.375 9.469 5.718 14.813 6.843 5.344 1.125 10.875 1.688 16.406 1.407 20.813-1.594 41.438-5.719 61.313-12.094 12-3.188 24-6 36.187-8.438 12.656-2.906 25.5-4.687 38.438-5.25 3.187.094 6.375-.093 9.468-.28 8.813.937 17.625 1.312 26.531.937l3.282-.188c2.25.282 4.594.375 6.937.563a480.306 480.306 0 0 1 46.407 4.781c13.5 2.063 27 4.688 40.312 7.969 20.531 6.187 41.625 10.312 63.094 12.093 5.625.282 11.25-.187 16.875-1.312 5.531-1.125 10.781-3.563 15.281-6.938 6.563-5.437 10.875-13.03 12.281-21.468 1.407-8.344.75-16.875-1.781-24.938-6.188-15.656-14.156-30.562-23.906-44.343-3.375-5.72-6.563-11.625-9.938-17.344a307.557 307.557 0 0 0 38.157-52.969c6.562.375 13.03-.375 19.312-2.438a81.136 81.136 0 0 0 40.594-30.468c3-4.219 5.343-8.907 6.75-13.875a89.449 89.449 0 0 0 12.937-33.094c3-19.5 2.532-39.469-1.406-58.781h-.188zm0 0",fill:"#020204"})),S||(S=d.createElement("path",{d:"M431 335a32.58 32.58 0 0 0-6 12.75c-1.031 4.594-1.688 9.375-1.781 14.063.281 9.468-.469 18.937-2.344 28.218-3.281 9.656-8.25 18.563-14.625 26.531-10.969 13.782-19.594 29.25-25.5 45.75-3 10.22-4.031 20.907-2.906 31.594a337.236 337.236 0 0 0-29.344 53.156c-12.563 28.032-20.625 57.938-23.906 88.5-4.031 37.594 1.5 75.563 15.937 110.438a182.552 182.552 0 0 0 47.156 65.719c10.5 9.093 22.032 16.781 34.407 22.875 43.781 21.375 95.062 20.906 138.375-1.313a267.942 267.942 0 0 0 58.687-46.406c11.157-10.125 21.094-21.469 29.813-33.844 14.531-25.218 23.062-53.531 24.843-82.593 9-50.25 3.47-102-15.843-149.25-7.594-15.75-17.625-30.188-29.813-42.75a236.719 236.719 0 0 0-18.937-63.75c-6.75-14.532-14.907-28.407-21.188-43.313-2.531-6.094-4.781-12.281-7.593-18.188-2.72-6-6.47-11.53-11.063-16.218-4.969-4.594-10.875-8.063-17.344-10.031a71.82 71.82 0 0 0-19.875-3.375c-13.5-.657-27.093 1.03-40.406.562-10.781-.469-21.375-2.344-32.156-1.688-5.344.282-10.688 1.313-15.656 3.282A31.379 31.379 0 0 0 431 335.094m4.313-117.281c-5.063.375-9.844 2.53-13.5 6-3.657 3.468-6.375 7.875-7.875 12.656-2.532 9.75-3.188 19.969-1.782 30 .188 9.094 1.781 18.187 4.781 26.812 1.688 4.219 4.125 8.156 7.313 11.438 3.188 3.281 7.219 5.719 11.625 6.844a23.2 23.2 0 0 0 12.656-.47c4.031-1.312 7.781-3.562 10.781-6.562 4.407-4.5 7.594-10.031 9.188-16.031a64.942 64.942 0 0 0 2.156-18.563c0-7.78-1.219-15.562-3.562-23.062s-6.375-14.344-11.813-20.063c-2.625-2.718-5.625-5.062-9-6.75-3.469-1.593-7.219-2.437-10.969-2.25m89.063 0c-8.063 5.25-14.25 12.938-17.719 21.938-3.562 11.625-3 24 1.406 35.344a59.437 59.437 0 0 0 20.813 29.812 37.347 37.347 0 0 0 17.063 6.563c6.187.75 12.375-.281 17.906-3.094a35.218 35.218 0 0 0 14.906-16.219c3-6.937 4.688-14.344 4.875-21.844a73.847 73.847 0 0 0-3.563-28.218c-3.28-9.938-9.656-18.469-18.28-24.281-4.407-2.813-9.282-4.688-14.438-5.438a30.339 30.339 0 0 0-15.282 1.688 41.666 41.666 0 0 0-7.78 4.218",fill:"#FFF"})),T||(T=d.createElement("path",{d:"M542.469 241.625c-3 .188-5.813 1.125-8.344 2.719s-4.688 3.75-6.375 6.187a32.028 32.028 0 0 0-5.063 16.781c-.28 4.407.375 8.907 1.782 13.125s4.031 7.97 7.406 10.782a21.713 21.713 0 0 0 12.469 4.875c4.593.187 9.093-1.031 12.843-3.656 3-2.157 5.438-4.875 7.125-8.157 1.688-3.187 2.72-6.75 3.188-10.312.938-6.375-.188-12.938-3-18.656-2.906-5.813-7.875-10.22-13.875-12.563-2.625-1.031-5.344-1.406-8.156-1.313",fill:"#020204"})),z||(z=d.createElement("path",{d:"M435.313 217.906c-5.063.375-9.844 2.531-13.5 6-3.657 3.469-6.375 7.875-7.875 12.656-2.532 9.75-3.188 19.97-1.782 30 .188 9.094 1.781 18.188 4.781 26.813 1.688 4.313 4.125 8.156 7.313 11.438 3.188 3.28 7.219 5.718 11.625 6.843a23.2 23.2 0 0 0 12.656-.469c4.031-1.312 7.781-3.562 10.781-6.562 4.407-4.5 7.594-10.031 9.188-16.031a64.942 64.942 0 0 0 2.156-18.563c0-7.781-1.219-15.562-3.562-23.062s-6.375-14.344-11.813-20.063c-2.625-2.719-5.625-5.062-9-6.75-3.469-1.594-7.219-2.437-10.969-2.25",fill:"#FFF"})),M||(M=d.createElement("path",{d:"M423.219 259.625c-1.219 6.281-.938 12.844 1.031 18.938 1.5 4.03 3.75 7.687 6.75 10.78 1.875 2.063 4.031 3.844 6.563 5.063 2.53 1.313 5.343 1.688 8.156 1.031 2.531-.656 4.687-2.156 6.281-4.218 1.594-2.063 2.719-4.406 3.469-6.844 2.156-7.313 1.969-15.094-.375-22.406-1.5-5.344-4.406-10.219-8.531-13.875-1.97-1.688-4.407-3-6.938-3.656-2.625-.657-5.344-.47-7.875.656a13.685 13.685 0 0 0-6.094 6.094 26.075 26.075 0 0 0-2.531 8.343",fill:"#020204"})),O||(O=d.createElement("path",{d:"M411.313 338.469c.187.844.468 1.687.937 2.344a10.342 10.342 0 0 0 3.188 3.187c1.218.844 2.437 1.594 3.656 2.344 6.469 4.406 12.187 9.844 16.781 16.219C441.5 371.375 448.531 379.25 456.5 386c6.094 4.219 13.219 6.75 20.625 7.406 8.625.656 17.344-.375 25.688-3 7.687-2.25 15.093-5.437 22.03-9.656 11.907-9.563 24.657-18 38.157-25.031 3.188-1.125 6.375-1.969 9.375-3.375 3.094-1.313 5.719-3.563 7.313-6.563 1.03-3 1.687-6.187 1.78-9.375.47-3.375 1.595-6.656 2.157-10.031.75-3.375.469-6.844-.75-10.125a13.816 13.816 0 0 0-5.906-5.906c-2.532-1.219-5.344-1.969-8.157-2.063-5.718.188-11.343.75-16.875 1.688-7.5.656-15-.281-22.5 0-9.28.281-18.562 2.344-27.937 2.719-10.688.562-21.281-1.125-31.969-1.594-4.594-.281-9.281-.094-13.875.656-4.594.656-9 2.344-12.844 4.969-3.562 2.812-6.843 5.812-10.03 9a27.829 27.829 0 0 1-5.532 3.844c-2.063 1.03-4.219 1.593-6.563 1.5a10.766 10.766 0 0 0-3.468 0c-.656.28-1.313.656-1.781 1.125l-1.407 1.687c-.937 1.406-1.781 2.906-2.437 4.406",fill:"#D99A03"})),j||(j=d.createElement("path",{d:"M434.844 314.844c-3.75 2.25-7.406 4.687-11.063 7.219a14.568 14.568 0 0 0-4.781 4.78 10.16 10.16 0 0 0-.844 4.688 40.676 40.676 0 0 1 0 4.781c-.094 1.032-.469 2.157-.469 3.282 0 .562 0 1.125.188 1.594.188.562.375 1.03.75 1.406.469.469 1.125.844 1.875 1.031.656.188 1.406.281 2.156.469 3.281.937 6.281 2.719 8.719 5.062 2.531 2.25 4.781 4.875 7.5 7.031 7.5 5.625 16.594 8.532 25.875 8.438 9.281-.188 18.469-1.5 27.375-3.844 7.031-1.5 13.969-3.375 20.719-5.719 10.5-3.937 20.156-9.656 28.5-17.062a94.798 94.798 0 0 1 11.625-9.656c3.75-2.344 8.156-3.938 11.906-6.188.375-.187.656-.469 1.031-.656.282-.281.563-.563.75-.938a2.626 2.626 0 0 0 0-2.062c-.187-.656-.468-1.219-.843-1.688a12.797 12.797 0 0 0-1.594-1.593 26.443 26.443 0 0 0-14.813-5.156c-5.437-.375-10.593 0-15.843-1.032-4.875-1.031-9.657-2.437-14.344-4.125a103.68 103.68 0 0 0-15.282-3.656c-12.187-1.969-24.562-1.688-36.656.938-11.344 2.53-22.312 6.843-32.437 12.656",fill:"#604405"})),C||(C=d.createElement("path",{d:"M433.625 302.094c-5.438 3.656-10.313 8.156-14.531 13.219a31.347 31.347 0 0 0-5.719 9.656c-.844 2.812-1.406 5.719-1.875 8.625-.281 1.031-.469 2.156-.469 3.281 0 .563.094 1.125.281 1.594a3.53 3.53 0 0 0 .844 1.406c.656.656 1.5 1.031 2.438 1.219.844.187 1.781.187 2.719.281 4.125.656 7.968 2.344 11.343 4.781 3.375 2.344 6.563 5.063 10.031 7.313 7.875 4.687 16.875 7.219 26.063 7.406 9.188.188 18.281-.75 27.188-2.719a118.662 118.662 0 0 0 21-5.906 125.554 125.554 0 0 0 28.5-17.063c4.03-3 7.968-6.187 11.625-9.656 1.218-1.219 2.437-2.437 3.75-3.562a13.827 13.827 0 0 1 4.406-2.531c2.531-.657 5.156-.75 7.781-.094 1.875.469 3.844.656 5.813.656 1.03 0 1.968-.188 2.906-.469.937-.375 1.781-.937 2.343-1.687.844-1.031 1.22-2.25 1.22-3.563s-.376-2.531-1.032-3.656c-1.406-2.156-3.563-3.844-5.906-4.781-3.282-1.313-6.657-2.344-10.125-3a142.883 142.883 0 0 1-30.657-11.156c-4.875-2.438-9.468-5.063-14.343-7.594-4.875-2.719-9.938-5.063-15.188-6.75-12.094-3.281-24.937-2.719-36.656 1.687-13.125 4.594-24.844 12.563-33.844 23.156",fill:"#F5BD0C"})),V||(V=d.createElement("path",{d:"M494.656 287.188c.656 2.156 4.031 1.78 6 2.718 1.969.938 3.094 2.719 4.969 2.906 1.969.188 4.688-.656 4.969-2.437.375-2.438-3.188-3.938-5.438-4.781-3-1.406-6.375-1.5-9.375-.188-.656.281-1.312 1.125-1.125 1.781zm-32.25-1.125c-2.531-.844-6.656 3.562-5.437 5.906.375.656 1.5 1.406 2.25 1.031s2.156-2.906 3.375-3.75c.937-.75.75-2.906-.188-3.188zm0 0",fill:"#CD8907"})),H||(H=d.createElement("path",{d:"M864.219 809.938c-1.875 4.875-4.594 9.375-7.969 13.406-7.875 8.437-17.438 15.187-27.938 19.875-17.812 8.25-35.156 17.437-52.03 27.468a215.954 215.954 0 0 0-30.657 24.75c-7.781 8.157-16.125 15.657-24.938 22.688-9.187 6.75-19.78 11.344-31.03 13.125-13.782 1.781-27.75-.375-40.407-6.094-9.094-3.468-16.969-9.562-22.5-17.625-4.688-8.625-6.844-18.281-6.375-28.031a293.704 293.704 0 0 1 6.188-51.094c2.437-14.062 4.875-28.125 6.375-42.281 2.625-25.875 2.906-51.844.937-77.719a60.554 60.554 0 0 1 0-13.031c.563-8.813 7.969-15.563 16.875-15.469 4.031-.093 8.063.282 12 1.032 9.375 1.125 18.75 2.718 27.938 4.875 5.718 1.5 11.437 3.562 17.156 5.156 9.562 2.812 19.687 3.656 29.625 2.718 10.406-2.437 21-4.03 31.687-4.968 4.407.187 8.813.937 12.938 2.25 4.312 1.218 8.343 3.375 11.625 6.468 2.343 2.532 4.218 5.438 5.437 8.625 1.782 4.782 2.907 9.75 3.282 14.813.187 4.5.562 9 1.125 13.5 1.593 7.219 5.062 13.969 9.937 19.594 4.969 5.437 10.313 10.5 16.125 15a173.108 173.108 0 0 0 17.438 13.5c2.906 1.968 5.812 3.75 8.53 5.906 2.813 2.063 5.157 4.688 6.938 7.688 2.25 4.125 3 8.906 1.875 13.5",fill:"#F5BD0C"})),x||(x=d.createElement("path",{d:"M864.219 809.938c-1.875 4.875-4.594 9.375-7.969 13.406-7.875 8.437-17.438 15.187-27.938 19.875-17.812 8.25-35.156 17.437-52.03 27.468a215.954 215.954 0 0 0-30.657 24.75c-7.781 8.157-16.125 15.657-24.938 22.688-9.187 6.75-19.78 11.344-31.03 13.125-13.782 1.781-27.75-.375-40.407-6.094-9.094-3.468-16.969-9.562-22.5-17.625-4.688-8.625-6.844-18.281-6.375-28.031a293.704 293.704 0 0 1 6.188-51.094c2.437-14.062 4.875-28.125 6.375-42.281 2.625-25.875 2.906-51.844.937-77.719a60.554 60.554 0 0 1 0-13.031c.563-8.813 7.969-15.563 16.875-15.469 4.031-.093 8.063.282 12 1.032 9.375 1.125 18.75 2.718 27.938 4.875 5.718 1.5 11.437 3.562 17.156 5.156 9.562 2.812 19.687 3.656 29.625 2.718 10.406-2.437 21-4.03 31.687-4.968 4.407.187 8.813.937 12.938 2.25 4.312 1.218 8.343 3.375 11.625 6.468 2.343 2.532 4.218 5.438 5.437 8.625 1.782 4.782 2.907 9.75 3.282 14.813.187 4.5.562 9 1.125 13.5 1.593 7.219 5.062 13.969 9.937 19.594 4.969 5.437 10.313 10.5 16.125 15a173.108 173.108 0 0 0 17.438 13.5c2.906 1.968 5.812 3.75 8.53 5.906 2.813 2.063 5.157 4.688 6.938 7.688 2.25 4.125 3 8.906 1.875 13.5M275.188 666.03a26.145 26.145 0 0 1 14.437-1.312 35.242 35.242 0 0 1 13.5 5.718c7.781 5.907 14.531 13.22 19.875 21.375 13.219 18.188 25.875 36.75 37.406 56.063 9.375 15.656 17.906 31.781 28.688 46.5 7.031 9.563 15 18.469 22.125 28.031 7.406 9.375 13.031 20.063 16.5 31.407 4.125 15.093 2.437 31.125-4.594 45.093-5.063 9.75-12.656 17.907-21.938 23.532-9.375 5.625-20.156 8.437-31.125 8.156-17.25-2.344-33.937-7.594-49.312-15.563-32.719-13.031-68.25-17.156-102-27.281-10.406-3.094-20.531-6.844-31.031-9.656-4.688-1.125-9.281-2.532-13.781-4.407-4.407-1.875-8.25-5.062-10.782-9.093a20.743 20.743 0 0 1-2.719-10.782c.094-3.75.844-7.406 2.157-10.78 2.531-7.032 6.656-13.313 9.375-20.25a84.632 84.632 0 0 0 4.687-35.813c-.562-12.094-2.719-24.188-3.375-36.282a58.715 58.715 0 0 1 .563-16.218c1.406-10.688 9.75-19.219 20.531-20.813 4.969-.843 9.938-1.218 14.906-.937 4.969.281 10.031.281 15 0 4.969-.282 9.938-1.688 14.344-4.032 4.031-2.437 7.594-5.812 10.313-9.75a124.125 124.125 0 0 0 7.406-12.187c2.25-4.219 4.781-8.156 7.781-11.906 2.813-3.844 6.656-6.75 11.063-8.813",fill:"#F5BD0C"})),F||(F=d.createElement("path",{d:"M275.188 666.125a26.145 26.145 0 0 1 14.437-1.313 35.242 35.242 0 0 1 13.5 5.72c7.781 5.905 14.531 13.218 19.875 21.374 13.219 18.188 25.875 36.75 37.406 56.063 9.375 15.656 17.906 31.781 28.688 46.5 7.031 9.562 15 18.468 22.125 28.031 7.406 9.375 13.031 20.063 16.5 31.406 4.125 15.094 2.437 31.125-4.594 45.094-5.063 9.75-12.656 17.906-21.938 23.531-9.375 5.625-20.156 8.438-31.125 8.157-17.25-2.344-33.937-7.594-49.312-15.563-32.719-13.031-68.25-17.156-102-27.281-10.406-3.094-20.531-6.844-31.031-9.657-4.688-1.125-9.281-2.53-13.781-4.406-4.407-1.875-8.25-5.062-10.782-9.093a20.743 20.743 0 0 1-2.719-10.782c.094-3.75.844-7.406 2.157-10.781 2.531-7.031 6.656-13.313 9.375-20.25a84.632 84.632 0 0 0 4.687-35.813c-.562-12.093-2.719-24.093-3.375-36.28a58.715 58.715 0 0 1 .563-16.22c1.406-10.687 9.75-19.218 20.531-20.812 4.969-.844 9.938-1.219 14.906-.938 4.969.282 10.031.282 15 0 4.969-.28 9.938-1.687 14.344-4.03 4.031-2.438 7.594-5.813 10.313-9.75a124.125 124.125 0 0 0 7.406-12.188c2.25-4.219 4.781-8.157 7.781-11.907 2.813-3.843 6.656-6.843 11.063-8.812",fill:"#F5BD0C"})),B||(B=d.createElement("path",{d:"M282.406 674c4.125-1.594 8.719-1.875 13.031-.844s8.344 3 11.813 5.813c6.656 5.812 12.281 12.75 16.5 20.531 11.25 18.188 22.219 36.563 32.438 55.313a370.55 370.55 0 0 0 24.937 41.437c6.375 8.625 13.688 16.5 20.25 24.938 6.844 8.343 12 17.812 15.188 28.03 3.75 13.407 2.156 27.75-4.22 40.22-4.687 8.812-11.718 16.218-20.343 21.187a51.593 51.593 0 0 1-28.5 7.031 163.06 163.06 0 0 1-45.188-13.968c-28.5-10.407-59.53-11.72-88.78-19.875-10.5-2.813-20.72-6.657-31.313-9.282-4.688-1.031-9.375-2.343-13.875-4.031-4.5-1.688-8.438-4.875-11.063-8.906-1.687-3.188-2.531-6.75-2.344-10.313a33.95 33.95 0 0 1 2.25-10.5c2.532-6.656 6.563-12.75 9.094-19.406 3.563-10.313 4.781-21.188 3.656-32.063-.75-10.78-2.718-21.468-3.28-32.343-.376-4.782-.188-9.657.655-14.438.844-4.781 3.094-9.187 6.47-12.75 3.937-3.562 8.812-5.906 14.062-6.562 5.25-.657 10.5-.657 15.656 0 5.25.656 10.5.843 15.75.75 10.313 0 19.688-6 24.094-15.375a98.75 98.75 0 0 0 5.531-13.032c1.594-4.5 3.75-8.718 6.281-12.75 2.625-4.03 6.375-7.218 10.781-9.093",fill:"#F5BD0C"})))};var D;function P(){return P=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(e[c]=a[c])}return e},P.apply(this,arguments)}const L=e=>{let{title:t,titleId:a,...c}=e;return d.createElement("svg",P({className:"icon",viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg",width:200,height:200,"aria-labelledby":a},c),t?d.createElement("title",{id:a},t):null,D||(D=d.createElement("path",{d:"M878.3 721.7c-1.35 3.6-18.9 65.25-62.1 128.25-37.8 54.9-76.5 109.8-137.7 110.7-60.3.9-79.65-36-148.5-36s-90.45 35.1-147.6 36.9c-58.95 2.25-104.4-59.85-142.2-114.3C163.25 736.55 103.85 531.8 183.5 395c39.15-68.4 109.8-112.05 186.3-113.4 57.6-.9 112.95 39.15 148.05 39.15 36 0 102.6-48.6 172.8-41.4 29.25 1.35 111.6 12.15 164.25 89.1-4.05 2.7-98.1 58.5-97.2 171.45.9 136.35 119.25 181.35 120.6 181.8m-234-515.25c31.5-38.7 52.65-91.8 46.8-144.45-45 1.8-100.35 30.15-132.75 68.4-28.8 33.3-54.45 87.3-47.25 139.5 49.95 2.7 101.7-26.55 133.2-63.45",fill:"#fff"})))};var Z;function G(){return G=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(e[c]=a[c])}return e},G.apply(this,arguments)}const $=e=>{let{title:t,titleId:a,...c}=e;return d.createElement("svg",G({className:"icon",viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg",width:200,height:200,"aria-labelledby":a},c),t?d.createElement("title",{id:a},t):null,Z||(Z=d.createElement("path",{d:"M459.5 485.75V182.094l-314.906 67.5V485.75H459.5zm52.5 0h367.313V92.187L512 170.938V485.75zm-52.5 52.5H144.687v236.156l314.907 67.5V538.25zm52.5 0v314.906l367.313 78.75V538.25H512z",fill:"#00adef"})))};function R(){return d.createElement("div",{className:"TouchSocket-banner"},d.createElement("div",{className:"TouchSocket-banner-container"},d.createElement("div",{className:"TouchSocket-banner-item"},d.createElement("div",{className:"TouchSocket-banner-project"},"TouchSocket"," ",d.createElement("span",{style:{fontSize:14,fontWeight:"normal",color:"#8759ff"}})),d.createElement("div",{style:{color:"#82aaff",position:"relative",fontSize:14}},"\u4e00\u6b3e\u7b80\u5355\u6613\u7528\u7684\u57fa\u7840\u7f51\u7edc\u901a\u8baf\u7ec4\u4ef6\u5e93\u3002"),d.createElement("div",{className:"TouchSocket-banner-description"},"\u4e24\u5cb8\u733f\u58f0\u557c\u4e0d\u4f4f\uff0c\u8f7b\u821f\u5df2\u8fc7\u4e07\u91cd\u5c71\u3002"),d.createElement("ul",{className:"TouchSocket-banner-spec"},d.createElement("li",null," Apache-2.0 \u5bbd\u677e\u5f00\u6e90\u534f\u8bae\uff0c\u5546\u4e1a\u514d\u8d39\u6388\u6743"),d.createElement("li",null,"\u652f\u6301 .NET Framework 4.5\u53ca\u4ee5\u4e0a\uff0c .NET Core3.1\u53ca\u4ee5\u4e0a\uff0c.NET Standard2.0\u53ca\u4ee5\u4e0a"),d.createElement("li",null,"\u65e0\u4f9d\u8d56"),d.createElement("li",null,"\u6781\u901f\u4e0a\u624b\uff0c\u6781\u7b80\u4f7f\u7528")),d.createElement("div",{className:"TouchSocket-support-platform"},"\u53d7\u652f\u6301\u5e73\u53f0\uff1a"),d.createElement("div",{className:"TouchSocket-support-icons"},d.createElement("span",null,d.createElement($,{height:"39",width:"39"})),d.createElement("span",null,d.createElement(A,{height:"39",width:"39"})),d.createElement("span",null,d.createElement(p,{height:"39",width:"39"})),d.createElement("span",null,d.createElement(L,{height:"39",width:"39"})),d.createElement("span",null,d.createElement(v,{height:"39",width:"39"})),d.createElement("span",null,d.createElement(k,{height:"39",width:"39"}))),d.createElement("div",{className:"TouchSocket-get-start-btn"},d.createElement(r.Z,{className:"TouchSocket-get-start",to:(0,s.Z)("docs")},"\u5165\u95e8\u6307\u5357"))),d.createElement("div",{className:"TouchSocket-banner-item"},d.createElement(W,{style:{float:"right"}},d.createElement(U,{language:"cs",source:'\n// highlight-next-line\nTcpService service = new TcpService();\nservice.Connecting = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u6b63\u5728\u8fde\u63a5\nservice.Connected = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u6210\u529f\u8fde\u63a5\nservice.Disconnected = (client, e) => { };//\u6709\u5ba2\u6237\u7aef\u65ad\u5f00\u8fde\u63a5\nservice.Received = (client, byteBlock, requestInfo) =>\n{\n //\u4ece\u5ba2\u6237\u7aef\u6536\u5230\u4fe1\u606f\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n client.Logger.Info($"\u5df2\u4ece{client.ID}\u63a5\u6536\u5230\u4fe1\u606f\uff1a{mes}");\n};\n\nservice.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e\n .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .ConfigureContainer(a =>//\u5bb9\u5668\u7684\u914d\u7f6e\u987a\u5e8f\u5e94\u8be5\u5728\u6700\u524d\u9762\n {\n a.AddConsoleLogger();//\u6dfb\u52a0\u4e00\u4e2a\u63a7\u5236\u53f0\u65e5\u5fd7\u6ce8\u5165\uff08\u6ce8\u610f\uff1a\u5728maui\u4e2d\u63a7\u5236\u53f0\u65e5\u5fd7\u4e0d\u53ef\u7528\uff09\n })\n .ConfigurePlugins(a =>\n {\n //a.Add();//\u6b64\u5904\u53ef\u4ee5\u6dfb\u52a0\u63d2\u4ef6\n }))\n .Start();//\u542f\u52a8\n'})))))}function q(){const{colorMode:e,setLightTheme:t,setDarkTheme:a}=(0,i.I)(),c="dark"===e;return d.createElement("div",{className:"TouchSocket-content"},d.createElement("p",{className:"TouchSocket-small-title"+(c?" dark":"")},"\u5f00\u6e90\u514d\u8d39/\u5546\u4e1a\u514d\u8d39\u6388\u6743"),d.createElement("h1",{className:"TouchSocket-big-title"+(c?" dark":"")},"\u2b50\ufe0f Apache-2.0 \u5f00\u6e90\u534f\u8bae\uff0c\u4ee3\u7801\u5728 Gitee/Github \u5e73\u53f0\u6258\u7ba1 \u2b50\ufe0f"),d.createElement("div",{className:"TouchSocket-gitee-log"},d.createElement("div",{className:"TouchSocket-log-item",style:{border:"6px solid #723cff"}},d.createElement("div",{className:"TouchSocket-log-jiao"+(c?" dark":"")}),d.createElement("div",{className:"TouchSocket-log-number"},d.createElement("div",{style:{color:"#723cff"}},"1000 +"),d.createElement("span",{className:c?" dark":""},"Stars"))),d.createElement("div",{className:"TouchSocket-log-item",style:{border:"6px solid #3fbbfe"}},d.createElement("div",{className:"TouchSocket-log-jiao"+(c?" dark":"")}),d.createElement("div",{className:"TouchSocket-log-number"},d.createElement("div",{style:{color:"#3fbbfe"}},"400 +"),d.createElement("span",{className:c?" dark":""},"Forks"))),d.createElement("div",{className:"TouchSocket-log-item",style:{border:"6px solid #1fd898"}},d.createElement("div",{className:"TouchSocket-log-jiao"+(c?" dark":"")}),d.createElement("div",{className:"TouchSocket-log-number"},d.createElement("div",{style:{color:"#1fd898"}},"106,125"),d.createElement("span",{className:c?" dark":""},"Downloads")))))}function U(e){let{language:t,replace:a,section:c,source:l}=e;if(l=l.replace(/\/\/ <.*?\n/g,""),a)for(const[n,r]of Object.entries(a))l=l.replace(new RegExp(n,"gs"),r);return l=l.trim(),l.includes("\n")||(l+="\n"),d.createElement(h.Z.pre,null,d.createElement(h.Z.code,{children:l,className:`language-${t}`,mdxType:"code",originalType:"code",parentName:"pre"}))}function W(e){const{children:t,className:a,...c}=e;return d.createElement("div",(0,n.Z)({},c,{className:"system-window blue-accent preview-border "+a}),d.createElement("div",{className:"system-top-bar"},d.createElement("span",{className:"system-top-bar-circle",style:{backgroundColor:"#8759ff"}}),d.createElement("span",{className:"system-top-bar-circle",style:{backgroundColor:"#3fc4fe"}}),d.createElement("span",{className:"system-top-bar-circle",style:{backgroundColor:"#42ffac"}})),t)}const J=function(){const e=(0,o.Z)(),{siteConfig:t={}}=e;return d.useEffect((()=>{}),[]),d.createElement(m.Z,{title:`TouchSocket\u8bf4\u660e\u6587\u6863\u3002 ${t.title}`,description:"TouchSocket\u8bf4\u660e\u6587\u6863"},d.createElement(R,null),d.createElement(q,null))}}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/c8245f17.df41c7c6.js b/handbook/build/assets/js/c8245f17.df41c7c6.js new file mode 100644 index 000000000..cd1dd4cd4 --- /dev/null +++ b/handbook/build/assets/js/c8245f17.df41c7c6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7436],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),m=s(r),f=o,v=m["".concat(l,".").concat(f)]||m[f]||d[f]||i;return r?n.createElement(v,a(a({ref:t},u),{},{components:r})):n.createElement(v,a({ref:t},u))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,a[1]=c;for(var s=2;s<i;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},287:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const i={id:"remotemonitoring",title:"\u8fdc\u7a0b\u76d1\u6d4b\u3001\u63a7\u5236\u9879\u76ee"},a=void 0,c={unversionedId:"remotemonitoring",id:"remotemonitoring",title:"\u8fdc\u7a0b\u76d1\u6d4b\u3001\u63a7\u5236\u9879\u76ee",description:"\u5b9a\u5236\u65b9",source:"@site/docs/remotemonitoring.mdx",sourceDirName:".",slug:"/remotemonitoring",permalink:"/touchsocket/docs/remotemonitoring",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/remotemonitoring.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675263272,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"remotemonitoring",title:"\u8fdc\u7a0b\u76d1\u6d4b\u3001\u63a7\u5236\u9879\u76ee"},sidebar:"docs",previous:{title:"WPF\u754c\u9762\u3001\u6587\u4ef6\u4f20\u8f93\u9879\u76ee",permalink:"/touchsocket/docs/wpfuifiletransfer"},next:{title:"\u6587\u4ef6\u540c\u6b65\u7cfb\u7edf",permalink:"/touchsocket/docs/filesynchronization"}},l={},s=[{value:"\u5b9a\u5236\u65b9",id:"\u5b9a\u5236\u65b9",level:2},{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u6280\u672f\u70b9",id:"\u6280\u672f\u70b9",level:2},{value:"\u6548\u679c",id:"\u6548\u679c",level:2}],u={toc:s};function d(e){let{components:t,...i}=e;return(0,o.kt)("wrapper",(0,n.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u5b9a\u5236\u65b9"},"\u5b9a\u5236\u65b9"),(0,o.kt)("p",null,"\u7f51\u53cb "),(0,o.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,o.kt)("p",null,"\u5e94\u8be5\u7f51\u53cb\u8981\u6c42\uff0c\u57fa\u672c\u5b8c\u6210\u4e86\u9884\u5b9a\u7684\u6240\u6709\u529f\u80fd\uff0c\u5305\u62ec\u8fdc\u7a0b\u66f4\u65b0\u3001\u8fdc\u7a0b\u5c4f\u5e55\u76d1\u6d4b\u3001\u5c4f\u5e55\u64cd\u4f5c\u3001\u8fdc\u7a0b\u6587\u4ef6\u8d44\u6e90\u7ba1\u7406\u5668\u3001\u8fdc\u7a0b\u63a7\u5236\u53f0\u3001\u8fdc\u7a0b\u6ce8\u518c\u8868\u64cd\u4f5c\u3001\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c\uff08\u5220\u9664\u3001\u590d\u5236\u3001\u91cd\u547d\u540d\u3001\u538b\u7f29\uff09\u3001\u7b49\u7b49\u3002"),(0,o.kt)("h2",{id:"\u6280\u672f\u70b9"},"\u6280\u672f\u70b9"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"\u6574\u4f53\u754c\u9762\uff1a\u5e94\u5b9a\u5236\u65b9\u8981\u6c42\uff0c\u754c\u9762\u4f7f\u7528\u539f\u59cb\u63a7\u4ef6\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u5404\u79cd\u8fdc\u7a0b\u64cd\u4f5c\uff1a\u5747\u91c7\u7528\u7684\u662fRRQM\u901a\u4fe1\u6846\u67b6\u3002")),(0,o.kt)("h2",{id:"\u6548\u679c"},"\u6548\u679c"),(0,o.kt)("p",null,"\u3010\u5ba2\u6237\u7aef\u2014\u2014\u88ab\u63a7\u5236\u7aef\u3011"),(0,o.kt)("p",null,"\u5ba2\u6237\u7aef\u662f\u4e2awinform\u7684\u65e0\u754c\u9762\u7a0b\u5e8f\u3002"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"image.png",src:r(8840).Z,width:"317",height:"160"})),(0,o.kt)("p",null,"\u3010\u670d\u52a1\u5668\u2014\u2014\u7ba1\u7406\u7aef\u3011\n",(0,o.kt)("img",{alt:"1.gif",src:r(848).Z,width:"2002",height:"1196"}),"\n",(0,o.kt)("img",{alt:"2.gif",src:r(2081).Z,width:"2002",height:"1196"}),"\n",(0,o.kt)("img",{alt:"3.gif",src:r(8004).Z,width:"2002",height:"1196"}),"\n",(0,o.kt)("img",{alt:"4.gif",src:r(4695).Z,width:"2002",height:"1196"}),"\n",(0,o.kt)("img",{alt:"5.gif",src:r(8620).Z,width:"2002",height:"1196"})))}d.isMDXComponent=!0},8840:(e,t,r)=>{r.d(t,{Z:()=>n});const n="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAT0AAACgCAMAAABJykuGAAABrVBMVEUydnoAg/3/3QAwdHgydnh2dnZWVlZGhYf///8cHh79/f2rq6sgZWn4+PhBfYH7+/vy8vIMi0TV1dVGg4dEg4YAAABDgYQqbnIqcHIwdHYscHQucnYobHAeZGgkam3t7u0cQUM9e37f39/o6OjOzs50u0Ll5eU7eHswcHI4dnoqYmQiUFKPj48eYmgiZ2w2dHjLy8vR6f8GCwtWk8uTk5MNHRx0Vlb//8vl/////+WTVlYQi/00Y2U5bG8fMzESIyQuWFolR0lWdK9XVnR0r+X/5a8hJB//y5OvdFfLk1ZWVpPL//8qTU+v5f9ajjgyXmDlr3SUzP8NyLV0dHTP6OASLig4Tikrw4D82wEdk1Ioe5QZx6I+c3Zyt0JTgDTYuJMPf9XT0x0yWkQafLhWdJNUym+QpkJUhGh6eo2TdGJGZjBWb0ZknzyflXRvskB3mlBJbTD/5cuioqKOvrJ0dFbt2AsvPiXa2tqr0jeE0FZ0mct0k54Sx6uvy+Vqqj4jf2TPy6/l6ceLv/Grx8dCYS1AQEDLk3Salab/5eWrszISh0zly8uRx2YKcDZGzIUjxzBCAAAXwUlEQVR42uxcaU8byRZtmLJfp1HEIvWH9xQJ/Jih4gwSZjM4SEwSQCwRehBANhAJEGHJB4SyoGEZREJEtlHym1/tdW9124BNDEx84+CudnfhPn3uuUtX4nk/mfkN/21vbW26e7exsTEIAr8i835C9DraW5sEfIFfQ++y6P3J4FPoVQjez4hey58dynVrnlsOekz5atwrE71fLXo13bs8ei0Svbs1zy0PvQ4edBsrd92fDr0Ghd5d6bo19C5jRKHXWou55XEvA7hXQ68s7tV0r8a9a9W9Gnrlcq/muZXoXo17Ne5dC/fa22vcq3Gvpns17tV0r4ZejXv/NN27N9wTMusZvkduJiR0d3dzc3eX8q/3L3KjuEfaQmPDnpeu8EXSS+urdcJW15euYD66uVYo1Atb21x6tk9KnlBl3XvQH4bJTBCGfiYZhn88qJgo63XA1tOV0m6zUDDgHSw/+16fIjeDe/959KiNYXenxQ/8MGS/6dc7DL+2R48o/9plvdJE8W5IwbfqlT0X9QjdWqsvFPb21tb2DzaWnzFbq98lRb9eunq6p5y1Z7uJ/wrGPWZN2z1qd6XM69bwrVfCvF3OuoNn1g7YePMmcI8Bd3aWfN0kj5PoMfxeJ8/OykdvSbtsYOBbopWBV79vwdvg48KmV2xKWjXd03hh9PSoTG9bNegZ+FbLdt2tPal3G38p25Djwm6xKavJvZLolWcmXPh+o4av3Mzt+Vq9ihbLfy3zlwKvvrC3de353o9Az8bbwO/W7FsvM4vcrNd2sMztwIwLX4o57k3hHo943qV+eimJ3uyQ4N5Qt2LfKrn8XIQSWjBo7eWXl7+v1QPbij2vinXuj+Ael71Tn4MW+HVDin2rZXGPbFr06veXlxF49V+uP+ZeGD1Cz982sic55wcGvTot6PQyM/4i4FIIFjby3zWY4n2PxHmtibnXr3vcFQl/yQuS2zLRj26rkCcTZY5a4Bvw6sRxlJw/i9nm0xUA91jgyO8XsOsSe5K6OeSmcK9HMkG8PLBNimzLTZXtcdx8GzXqlgC3Ss5itnmVoWgmMCsUDpbze/WWfYVNgk+qdn8vjNjCt2Zm3xZ4vYG+Eyot4QB9QDV6HD72q22+TAQtLjSL2iZA9jhYhb18/qAgt2XGjESDKt7SqnGv38Guv9lYf9hv8lGSUrdXbXsEb8uiU4xspTHU7dtig3PvvFnQtphTomfF7iCfh4HjC/HgdIaC1dK94XAOzB0uNANbWLASTyAlPOSE7gigF/gIvQvNQmBs2SxY7FTg2IDopSPTVbXW+D28A47rb0b2TV9QCl+k4FBKf1XJllSkymXUA7WG1b34WdwJVUMUOq7IWvL5fTMU+TKxZ5gTr1z3YvuIzHrC1+awJgxe81dNFWJusXwjFgS2Q+9Scc9EjUYcNYitQ+NmcScUu3aB5xbWftvY+C2f37BxeBPcETNF1WoNBmBbOGwOewOh44MTaqXEyBagmXPr5c8um7HIWkOiR9I46EZmcanJfzwvmGRvbSOvbN8guuU5v11vX7XupbW0awIoZbkPyLe4aLBbnA/eKPLZcEjgjTaZmY0bKlWVrT3us6bWmJubS5Rtc/IPNLm75Dll2sW5x6843Rb2qO6e3wzBm+fv8hh0W1NOZgZJRG2lJjzW1Bpz/hUY/4cXgTD/h1kR9CiukuxWuj88g+hxj/3KwBM8JB7SpZSbl+odKcA+2d47HRI9FlVrzPm3xIpyjxrcQMGZ9si9np6kRe9N4/ziogav2cTGIuGSRHSLgpSlzkSNxK1HD5SByHXJo1DBJwBjyBnwmiO5nlI7Gy5TNh7r9yXQ31MJ3+3nXvHGyGPFvkUleQa8rzjXo05JqVlJEENJl+nMm1rj9nCvkZuLXhoRzu0VPWbsu8syFgWfBq/5hLc0vcjjFxNuIzUCn5uQ6FOh28O9JmaNxXSP4uvVSDL2DXfobNkmLhGdM2pHwA75KvlEsircW8nOxu9/O4rGr3bscQMPe9Fncy0tLbHoQdWjLqEe9IQ9fW6ldpJGObGtA2CoMMkLbJI4T8PXAXq5vzOZTMePQG8sOzIdvz+JYB14OPWU7+6b1uitfBrU3GtoaGkNouhRQyO3GSxix/0/wvAMdwlOcJUL0mVMRQ8pI5+t6z5eieEZ9MZeJoU9Gbw61DqUtX8cOdXbaPqZ5IuncDye7BU/ZzV6k1P687nOhqLcw1pl+rEydXnsdKgE83SybBO6FKo4UMsO3JUuz64CYsOE+d7J5HZf39urRG88GWPcV3MrnX3CdrJHautU0Co3wUkai14iFj3qYXmyIVKlfWx4fyEMFx6cfBXR9oTVpek4zKMlKXGVT57X9e+u++zPL10WvYGHCrZc5irRO2RasPIpY20ly9ALchMRUHslVf+eZ+y8JPcIKFEhCLaJJ4xdNbOIQtrELibFI+BexC2QSOgLnXp65XInUGBImdAQBGPZUUmx4w5o77K9gaFq73hyZG7ubTLJquYk4l6c7uGHCq4EUsU/LxZXm9iBFM9tqsXQzwwSWoAi6GGJcgQL2udin3H0gsnkSJ+xY4PetBM+GNECrYxj9oS353EPkyKarlnipGOuv7TjxvZ3UR/RcA9Hv9xHzoIX05HRpBZG5uuzQsKy9sixrLrYGXkUC+AfHdETQMejJ9oNjr1vGSype5YeJmNLYd+kiDhpSCiKuUXtMwzqNPlIac9lWIycgtSBBeAjFkIkpHDEvGra+nrAP9rq3EnKI130/NykihPcPpoAG4/ewMQh/yI4bBk8S8dcgir7uBWY1KlJQE8ZnYEDLc4EQStRfm5iLqPQi279XTnDAuPPcGRkbFII/aQEMyffXfRevUwetk4kD8X2hA3n8ejlJtgBLFjMRONJUd0DfIHpmnmUQLFzR/hDwBmuzlmMnZIjonviSjl+KLuV3olHCpiBhzK3UA7PQO2NoMeSYYZ0bif54pj7/qEhVRHP5QGWCeMrFZ2fyDA9fz73CKocIrEBjSlaLYseQeg6F7PX9gAp6odB7om6SbvZjL7hk3yMR6o+GBf4zEhWarxc7o0fG14DYgus4zKWGYbpuLwdQTCuhTi4gO65rWDQu6Pxi1Iibk1c9y/SA0QIJnA9yhgiLm5Edtz5VeGRddlRs21kMKJ7PCK/U0XM808ZHZsZ9476oO2IecZYOTyjWTnp0LNkzKUw5XN7d27RQEm0q4LDNoWSCIlI46OGJQX70pAavc4I4QRyuRj0PmdWOt+KgHw86L/fydpiIzcx9RRJ2NjLQ6EGo9x7mUI4tUmJfI+4KR8UQSRqyOdUkDZn2Ie3xJVELaNQDqkTNUydzr4uA+XQlqV4JCCbVd5cGj2h/ttv5m0XYmUnkeWkdAOruXe9PHKwTzPvsvzvkaxNLlTnpkjMM1C7mgJ1Y2QkJcRz9BLE4RgBJA5xaQQ9qf7WIX3fHQkdFAjC7E/rnnI3sT+XmR98n0E236iCRHw1PfnkPavPBszfUX8sO1o636OARpHFAV6RhXokTi4N/VDGTWwkNxPQIp4ruWeTOkUrLEGMYe/U5ZuPJAtVBq2r5iAIJmOzj3HnfhjdPX7P0IpH77w618n14JNZirQr8iQDhNoo/WAPED1GgZ47sz3v27yNX70Ika/e+O5IMCuhPJaBNsU/YucpHeSo8RxZkWsSFrSMWIGaYLZYaTzyYeVDUe6VqnNtrgf7xA4dwbIBEpdpoySHRNp8sEKB3OMalUiYlIXnGNt9fVnJETwSWZ4uP7nCv+hkEUFykH3Coml2akehF/DIqf+bvUC3i1UTNCJ7rxp4aPnfh8twT6laisQ+R4QDeAiJqCXcwIUHXPbpFh4JkCuL8IjG290xIw6Z8bzcjvooMDkPS+1mLPem/UizvYjj8ju4dfSh+1K659YMKbdNDOKr0zemqJLFywngwiW47NMpkhOwVdIO6sscczWTquKRljfbQQb1aEdHK4wDI4c2ZryTvQAdctwFCWMf5g3IF9c9ih8GEUAysE3wEwtcSsQsW5F748RSU1CkMeU8FRq/eAM6LmrMFDs9sBTNvT5tHHjZN3JuvhdTh0K9ikRfLI4pyzPLtRSIIE7zxqkFvTLQg/3Oc9GLem4wNjdd8hx+WCD+Z8OBl4mjwXN0j0DGgQ4fLDRSbmT13LwEp8lYKEmcgsqytwz0ZirsQwefy1kslDj/qRAKpcRdFBBRvrgmsm7vITY7Igqwvix64yPZZNF848JLrsqwkrUGagKniBfXm4uKo32jSM4i1R0Bq/uIV4HnjtuOc5XXEsTrHsVLP5GSeWhRQOyqzpjWvNPMw499YdZXnudej5WsNVBAhaxTFa2zLiDlLJ/y3IAKH6+RaCuGVBA1rmkdyznPNaKL4HFFERVHu3wqElAJfpxLYBkNuZm4LVa61iDuInhnubrn/BMNGrdSNPKPe0i0bjGJoO33k/sPfm+rjvGCMLHd+f/yrua3bVyJCygBV5uFt6gQvzrd3UbouqzffkKob5ZsX3QS7FN8knx+CIwgyMHvFizw8ocvSX1xhqQkx9S+ejNkFNmRbWX84ww5X/zPL8dTyzqXqLpWc+rr9Gi9+BocTZ7nDcOlnn62TQxDX758eRB08XBxFL01R6DhBQH0mMFECs2DyiIzeAYx7qXaFv7bNjEIXfz5vz//+OOntz+95f0Y0vrUgKW4EmSV9lWWH7oHlVp5DvS8oYnGn23S+8+fHx4Y4/gGJR8/MHrz5s2HhpZ36bFRa5gsolSeC9aqE4RPya88jnOMdzn/vJGue78Ty/RwwZj3Kd/kgCe8fPdNQ8u7OMtJ49egasQJjKoC8o2ojkoQ7lcwxdx4L35JT+QHfBxYr/glMq1Enpq9atWknqzJ6KJIVzo6AQmmdhx7njdoa/oHA+XoTXvhXg95agQv/BEICZoPAgcGKTMZp23Qa4GljMiBfezZzlOjmtA6KcGHQL3qEEfv8a2YfgLzNC/tC3sf7NeZhz4xRzHyEdVJJlvw8siUE5inGfJfO/bQcoHiODzdwhY5yUCYyikjVwXj1489qlnP1njSm/RwBm6FzKlN5vWIPZtaAwetUCDvCF7HISeZD+d7NrnXm861hD3q6GzJ2tAzeaJHlNTIQv2cB/Ys7q9BJbFGUJSYLkBKU2yFnBv2rM73CHJp+JK7tlCxki+tloQ4NOBs5J4t7FFgWVaTNiSXULWqJciP5ss69xywZ3O+p/E8OOp6Vx8Cjvj40rCn8TzU4VM15LAPo5KXKBrU6nzvq19rUDgeQfiUwaEh1+k5U53bSzUb7MD1YRYk0Tt5q2fIOc33LI5cH+hcbRCo6sMolS45P51rbb4H9ahkLCaqfwxGjUKlWzz58uZ7FGhSULqMANUr1ZxSovgKBfMCda4CMid2Y0Hil+vynj/gJ6wb09leGvaoAwPyBLktJJn65Mip85B7duuOUhiQxxEVd+KeFORYvsvLwh5Isa0zg1qYF1cRemgtQs2sCJNVUvdl+k+SeyguG2Ev1mGPYAN0I/a8JAiCy6rH83+G3CMARsWyoRV76hyQ5j41IyuSwI1KigN343npPEmS9NzlHijnQwD2Ygl48nk9U5E9HqRpnbsKorCMsNgsZhvGvCgI3OT/sc61rXNhpKyjHa4SEzWhuGUMlWnkMu6lXkGbBcPeMEyiWRA1ScCzkHs+yuChYORub2XaFtijjja+wKxzkyAaltybc+x5I4a+S4Y+73yxJyX8SPpT5t56ItNalnuV6KMFCKeN2BuWESxzjj1GaXR5ebkycu9M5B4OGyjlHl9abO936wxxz5Wn2QCCZuyV3ONNYI+dcO4Fq8FZr3Nl2OVbCFTY266zx6dtHG/3E8ZB3gvuyXUO5bpVTTOWRbJcbkS/nrmce94wubmJNo3Ym9rs9v0atYmlTsZ1cv162N/dx/E6y9YH9+lOHbkaa3PTyA1m7izv7HQjnkzDMEwHZ+5TUwLyBMDus3UcP623h6d99uQeHjn4smrkEorC61viWJbRzaKgeHEThUWYnueZmTdQammf0qd9yD0q6c8KfVzgrSfrePu4v70/uO5ucivYV8q9qYPCW0jhnTPP99JwXjTew2EZ5Xj+/lwHZ3NzQ1Q2OcTZPnbX2SHeTe7dA9cdWTlyqWZ912jfY/ybC9qwSXM4lylt1rnUEutoX/5cUMaikHu7bMdk3oFxb79nY/hwl91lss6VimX4pFXusbaJ3IW7WLjXYRgt3KLFrC1Nr5DL8J7ee8GeUsaCSQgBsMfscLhb8/ledu9us+w+vr3LsNaAaW6N8XvLxYw3xr35IpjNFgvRmQpZnfN8DwYhVzqXMeyRC77dfseH7h1fZTyV2Jsa8v2asMdG7oZTOJy7s+tNQcvIOF/O5R4ltgZuP2sNx8FBy8VsL9sf4tunw3aXTXaModGulnswcbL08TbGLdcB8eVaQyRrNHAPDFxy4rGndS4FUz3xZedrDYa8u/sDm+/tmd6NOQ9luQcSJ0kXv0ZaLDaKtUZ+7fCace+8dS6OPKsMKrePky1H3Xb3KJZrUOc6R+hcPnLDAmTcQlXGyJu5J+ReVTXyqL3+cNE2sJefRblHdXaWqWyR2u33xTpj0qBzaS6gmnVuUqwrmNzblLPkYRQYR6607wdxOu/1p+4k6PS6lx8FkXnQtsxXajnj6vmeOzWsUhp1bhJEYZqmuYVqmRYUdpB7wJBBjjzv1b5H0c1RUq1zC/ZBkux7KE+oTe4lQRBFAn9zN1hUZvpZi9yjqtpt2esPnfe6lx+himts2s2vIdda9ltjqLzljO+iGIUDj9vkBc3EMfE6zPeKT2jd6w/uJKjby8++fY/APYDa/LlTMA8jnXKFvDCJGPtumOpIN4lMYcNaA1T8UzLB2s973stPLapXy7243acGUdscS8DRF3DrCjsdVUm4RiNLiT0cye8by2UZdhJEe/n15deo4NceS0Bh1lCp25q5Fyar1UbYBNLkOrpmPbpezb22XCEYuoVLZOFzGao97+VHQSQ80fg1sEMS+dRQAFtrGp8nZsleeBOwURzwlgyabMswURg8luOtcREYp2EvP6tyjyrKXVjm44ZQAnfqSNs3y5OyLnHLHGvpclVSQ1QBVYOqHUOlF3UjQQdt+tazbbnOv5h2i6Fy5EFBu+dIVoveVtsy/mpBHCH+1ommBq88onqy7/lyTlqROtBEaKODbj41nF1fMc/rZlvOYUV0KtZXa+448N/xe8Qe3Bijmy2Xgo37xHk+3+uaPWpMacY6l8qR/OCjpeJ+YDqo/huFNux133DD7gYKTZVpXjcbS3Mqc8M6Vyk0RNCaDEwHJeGHF0M9zPdkS11pYm/2jGJZ6XSyLR+f3Vx77vAGlapxWzcFgKOK9pYrhKLm2820VC66V1fh6yN2VNmg0ie4eIKjaFw4HSA9xrFgHDU6YrA86W5jeQ72NCkiSGT4CgSAmJQtR/3FLUt54JQc4wSEGWx26xLIG2f5RKNpq4pq+nRhHyeN9Wff0yxbTdmRlbvAl2uD07a1xjOx56Ai+D4u90dAxUBJDoOMY0L7iWPR2EqanKKUmMKd+5B7oBIWxbeJsEjQ2hZvbf637Fn/bJrWc+DOUxczDTQz4wZnrd5a1aM/l/B9+vhGGVIruoGqi+GLymcauXE0lR/5/IYe2sVeUZMVN4eYvj50DX4Zscq8AYEfeXKzLPde2S5w5/WAPYtkGXvN7HuV/8i9+fqxNxqNvLyp/cg2GhHL3+57u3JvPB6/MrYx/nnV2sYjqzTu8pnHNLu1gN7raNzxOR3l//WwOKCOaai9SrrccHei45bf4ri61TG8VDx9xbD331LufXMy966u2FuK/v6q7vWh/kv9tyv5UtivroSfh/3r4og7opHmEnD56LP0kfAG9K3lQsE9NnJzuXcq81477yzTlYZJJ5Dt23snsPexwN7rU7H3r5reiS4/1ra817+rlpM/9IdDcRA/+cFEpquKt/CH1Z3UXffR7+AlSq/vkXPv00dbI/d72+SXRKsDP9L8AH4ouIpKrXyhb/vufry4eGsRez/aJmqVrN+ewJ6lUkCvnd9s09Qq2b67bzn2Pn0sJ8unYu9b2/S7VbJ+e4x7YqnxnRXs/WqNfrBIfbxn/sYXF/ame6//AiHKlpxBQH8GAAAAAElFTkSuQmCC"},848:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/remotemonitoring-2-5c74840e35ae767d7cf69f547a67de94.gif"},2081:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/remotemonitoring-3-a3933fd43dae5dbd36a20de2a4eab122.gif"},8004:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/remotemonitoring-4-6f88f3a5b775c025524a73109d71a925.gif"},4695:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/remotemonitoring-5-34a53f7476270e9d9624009686d1d365.gif"},8620:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/remotemonitoring-6-1cf6a6a157babffbaa8a15e2d8cf26a0.gif"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/c8d1f2bf.59006bc6.js b/handbook/build/assets/js/c8d1f2bf.59006bc6.js new file mode 100644 index 000000000..ffdc51728 --- /dev/null +++ b/handbook/build/assets/js/c8d1f2bf.59006bc6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8032],{3905:(e,n,o)=>{o.d(n,{Zo:()=>p,kt:()=>u});var t=o(7294);function g(e,n,o){return n in e?Object.defineProperty(e,n,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[n]=o,e}function r(e,n){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),o.push.apply(o,t)}return o}function c(e){for(var n=1;n<arguments.length;n++){var o=null!=arguments[n]?arguments[n]:{};n%2?r(Object(o),!0).forEach((function(n){g(e,n,o[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(o)):r(Object(o)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(o,n))}))}return e}function i(e,n){if(null==e)return{};var o,t,g=function(e,n){if(null==e)return{};var o,t,g={},r=Object.keys(e);for(t=0;t<r.length;t++)o=r[t],n.indexOf(o)>=0||(g[o]=e[o]);return g}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t<r.length;t++)o=r[t],n.indexOf(o)>=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(g[o]=e[o])}return g}var s=t.createContext({}),l=function(e){var n=t.useContext(s),o=n;return e&&(o="function"==typeof e?e(n):c(c({},n),e)),o},p=function(e){var n=l(e.components);return t.createElement(s.Provider,{value:n},e.children)},a={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},y=t.forwardRef((function(e,n){var o=e.components,g=e.mdxType,r=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),y=l(o),u=g,L=y["".concat(s,".").concat(u)]||y[u]||a[u]||r;return o?t.createElement(L,c(c({ref:n},p),{},{components:o})):t.createElement(L,c({ref:n},p))}));function u(e,n){var o=arguments,g=n&&n.mdxType;if("string"==typeof e||g){var r=o.length,c=new Array(r);c[0]=y;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i.mdxType="string"==typeof e?e:g,c[1]=i;for(var l=2;l<r;l++)c[l]=o[l];return t.createElement.apply(null,c)}return t.createElement.apply(null,o)}y.displayName="MDXCreateElement"},4139:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>s,contentTitle:()=>c,default:()=>a,frontMatter:()=>r,metadata:()=>i,toc:()=>l});var t=o(7462),g=(o(7294),o(3905));const r={id:"ioc",title:"\u4f9d\u8d56\u6ce8\u5165\u5bb9\u5668"},c=void 0,i={unversionedId:"ioc",id:"ioc",title:"\u4f9d\u8d56\u6ce8\u5165\u5bb9\u5668",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/ioc.mdx",sourceDirName:".",slug:"/ioc",permalink:"/touchsocket/docs/ioc",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/ioc.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"ioc",title:"\u4f9d\u8d56\u6ce8\u5165\u5bb9\u5668"},sidebar:"docs",previous:{title:"Json\u5e8f\u5217\u5316",permalink:"/touchsocket/docs/jsonserialize"},next:{title:"\u4f9d\u8d56\u5c5e\u6027",permalink:"/touchsocket/docs/dependencyproperty"}},s={},l=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9",id:"\u4e8c\u7279\u70b9",level:2},{value:"\u4e09\u3001\u6ce8\u5165\u65b9\u5f0f",id:"\u4e09\u6ce8\u5165\u65b9\u5f0f",level:2},{value:"3.1 \u6784\u9020\u51fd\u6570\u6ce8\u5165",id:"31-\u6784\u9020\u51fd\u6570\u6ce8\u5165",level:3},{value:"3.2 \u5c5e\u6027\u6ce8\u5165",id:"32-\u5c5e\u6027\u6ce8\u5165",level:3},{value:"3.2 \u65b9\u6cd5\u6ce8\u5165",id:"32-\u65b9\u6cd5\u6ce8\u5165",level:3},{value:"\u56db\u3001\u751f\u547d\u5468\u671f",id:"\u56db\u751f\u547d\u5468\u671f",level:2},{value:"\u6240\u6709\u6a21\u578b\u5b9a\u4e49",id:"\u6240\u6709\u6a21\u578b\u5b9a\u4e49",level:2}],p={toc:l};function a(e){let{components:n,...o}=e;return(0,g.kt)("wrapper",(0,t.Z)({},p,o,{components:n,mdxType:"MDXLayout"}),(0,g.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,g.kt)("p",null,"\u6240\u8c13\u4f9d\u8d56\u6ce8\u5165\uff0c\u662f\u6307\u7a0b\u5e8f\u8fd0\u884c\u8fc7\u7a0b\u4e2d\uff0c\u5982\u679c\u9700\u8981\u8c03\u7528\u53e6\u4e00\u4e2a\u5bf9\u8c61\u534f\u52a9\u65f6\uff0c\u65e0\u987b\u5728\u4ee3\u7801\u4e2d\u521b\u5efa\u88ab\u8c03\u7528\u8005\uff0c\u800c\u662f\u4f9d\u8d56\u4e8e\u5916\u90e8\u7684\u6ce8\u5165\u3002\u901a\u4fd7\u6765\u8bb2\uff0c\u5c31\u662f\u628a\u6709\u4f9d\u8d56\u5173\u7cfb\u7684\u7c7b\u653e\u5230\u5bb9\u5668\u4e2d\uff0c\u7136\u540e\u5728\u6211\u4eec\u9700\u8981\u8fd9\u4e9b\u7c7b\u65f6\uff0c\u5bb9\u5668\u81ea\u52a8\u89e3\u6790\u51fa\u8fd9\u4e9b\u7c7b\u7684\u5b9e\u4f8b\u3002\u4f9d\u8d56\u6ce8\u5165\u6700\u5927\u7684\u597d\u5904\u65f6\u5b9e\u73b0\u7c7b\u7684\u89e3\u8026\uff0c\u5229\u4e8e\u7a0b\u5e8f\u62d3\u5c55\u3001\u5355\u5143\u6d4b\u8bd5\u3001\u81ea\u52a8\u5316\u6a21\u62df\u6d4b\u8bd5\u7b49\u3002\u4f9d\u8d56\u6ce8\u5165\u7684\u82f1\u6587\u4e3a\uff1aDependency Injection\uff0c\u7b80\u79f0 DI\u3002\uff08\u8bf4\u660e\u6765\u81ea\u7f51\u7edc\uff09"),(0,g.kt)("p",null,"TouchSocket\u5185\u7f6e\u4e86",(0,g.kt)("strong",{parentName:"p"},(0,g.kt)("em",{parentName:"strong"},"Container")),"\u5bb9\u5668\u3002\u53ea\u9700\u8981\u5f15\u5165TouchSocket.Core\u5373\u53ef\u4f7f\u7528\u3002"),(0,g.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9"),(0,g.kt)("ul",null,(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301\u6784\u9020\u51fd\u6570\u3001\u5c5e\u6027\u3001\u65b9\u6cd5\u4e09\u79cd\u6ce8\u5165\u65b9\u5f0f\uff0c\u53ef\u4ee5\u9009\u62e9\u5176\u4e2d\u90e8\u5206\u751f\u6548\u3002"),(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301 Singleton\u3001Scoped\u3001Transient\u4e09\u79cd\u751f\u547d\u5468\u671f\u3002"),(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301\u5355\u63a5\u53e3\uff0c\u591a\u5b9e\u73b0\u6ce8\u5165\u3002"),(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301\u5f53\u83b7\u53d6\u7c7b\u578b\u662f\u53ef\u5b9e\u4f8b\u7c7b\u578b\u65f6\uff0c\u5373\u4f7f\u4e0d\u6ce8\u518c\uff0c\u4e5f\u80fd\u6210\u529f\u6784\u9020\u3002"),(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301\u9ed8\u8ba4\u53c2\u6570\u6ce8\u5165\u3002"),(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301\u6784\u5efa\u53c2\u6570\u6ce8\u5165\u3002"),(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301\u6807\u7b7e\u53c2\u6570\u6ce8\u5165\u3002"),(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301\u6cdb\u578b\u6ce8\u5165\u3002"),(0,g.kt)("li",{parentName:"ul"},"\u652f\u6301Object\u6ce8\u5165\u3002")),(0,g.kt)("h2",{id:"\u4e09\u6ce8\u5165\u65b9\u5f0f"},"\u4e09\u3001\u6ce8\u5165\u65b9\u5f0f"),(0,g.kt)("p",null,"\u5bf9\u4e8e\u4e00\u4e2a\u7c7b\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u4f1a\u652f\u6301\u6784\u9020\u51fd\u6570\u3001\u5c5e\u6027\u3001\u65b9\u6cd5\u4e09\u79cd\u6ce8\u5165\u65b9\u5f0f\u3002\u4f46\u662f\uff0c\u5f53\u660e\u786e\u77e5\u9053\u8be5\u7c7b\u578b\u4ec5\u4f1a\u4f7f\u7528\u5176\u4e2d\u90e8\u5206\u65b9\u5f0f\u6ce8\u5165\u65f6\uff0c\u53ef\u4ee5\u8bbe\u7f6e\u6ce8\u5165\u7c7b\u578b\uff0c\u4ee5\u6b64\u8282\u7ea6\u6027\u80fd\u3002"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp",metastring:"{4}","{4}":!0},"/// <summary>\n/// \u8ba9MyClass\u4ec5\u652f\u6301\u6784\u9020\u51fd\u6570\u548c\u5c5e\u6027\u6ce8\u5165\n/// </summary>\n[DependencyType(DependencyType.Constructor | DependencyType.Property)]\nclass MyClass\n{\n\n}\n")),(0,g.kt)("h3",{id:"31-\u6784\u9020\u51fd\u6570\u6ce8\u5165"},"3.1 \u6784\u9020\u51fd\u6570\u6ce8\u5165"),(0,g.kt)("p",null,"\u5176\u4e2dMyLog1\uff0cMyLog2\u867d\u7136\u6ca1\u6709\u6ce8\u518c\uff0c\u4f46\u662f\u56e0\u4e3a\u662f\u5b9e\u4f8b\uff0c\u6240\u4ee5\u4f9d\u7136\u53ef\u4ee5\u6210\u529f\u6784\u9020\u3002"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},"[Fact]\npublic void CtorShouldBeOk()\n{\n Container container = new Container();\n container.RegisterTransient<ILog, MyLog3>();\n\n var log3 = container.Resolve<ILog>() as MyLog3;\n\n Assert.NotNull(log3.MyLog1);\n Assert.NotNull(log3.MyLog2);\n}\n")),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyLog3 : ILog\n{\n public MyLog3(MyLog1 myLog1, MyLog2 myLog2)\n {\n this.MyLog1 = myLog1;\n this.MyLog2 = myLog2;\n }\n\n public MyLog1 MyLog1 { get; }\n public MyLog2 MyLog2 { get; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n")),(0,g.kt)("h3",{id:"32-\u5c5e\u6027\u6ce8\u5165"},"3.2 \u5c5e\u6027\u6ce8\u5165"),(0,g.kt)("p",null,"\u4f7f\u7528",(0,g.kt)("strong",{parentName:"p"},"DependencyParamterInject"),"\uff0c\u6216\u8005",(0,g.kt)("strong",{parentName:"p"},"DependencyInject"),"\u6807\u8bb0\u5c5e\u6027\uff0c\u5373\u53ef\u6ce8\u5165\u3002"),(0,g.kt)("p",null,"\u793a\u4f8b\u4e2d\u4f7f\u7528\u7684\u662f\u5355\u63a5\u53e3\u591a\u5b9e\u73b0\uff0c\u6240\u4ee5\u4f7f\u7528",(0,g.kt)("strong",{parentName:"p"},"DependencyParamterInject"),"\u6807\u8bb0\u3002"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},'[Fact]\npublic void PropertyShouldBeOk()\n{\n Container container = new Container();\n container.RegisterTransient<ILog, MyLog1>("MyLog1");\n container.RegisterTransient<ILog, MyLog2>("MyLog2");\n container.RegisterTransient<ILog, MyLog3>("MyLog3");\n container.RegisterTransient<ILog, MyLog5>();\n\n var log5 = container.Resolve<ILog>() as MyLog5;\n\n Assert.NotNull(log5.MyLog1);\n Assert.NotNull(log5.MyLog2);\n Assert.True(log5.MyLog1.GetType() == typeof(MyLog1));\n Assert.True(log5.MyLog2.GetType() == typeof(MyLog2));\n}\n\n')),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyLog5 : ILog\n{\n [DependencyParamterInject("MyLog1")]\n public ILog MyLog1 { get; set; }\n\n [DependencyParamterInject("MyLog2")]\n public ILog MyLog2 { get; set; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n')),(0,g.kt)("h3",{id:"32-\u65b9\u6cd5\u6ce8\u5165"},"3.2 \u65b9\u6cd5\u6ce8\u5165"),(0,g.kt)("p",null,"\u4f7f\u7528",(0,g.kt)("strong",{parentName:"p"},"DependencyInject"),"\u6807\u8bb0\u5c5e\u6027\uff0c\u5373\u53ef\u5bf9\u65b9\u6cd5\u6ce8\u5165\u3002"),(0,g.kt)("p",null,'\u540c\u65f6\uff0c\u793a\u4f8b\u4e2d\u6f14\u793a\u4e86\u9ed8\u8ba4\u53c2\u6570\u8bbe\u5b9a\u3002\u5728\u521d\u59cb\u5316MyLog6\u540e\uff0cA=10\uff0cB="TouchSocket"\u3002'),(0,g.kt)("p",null,"\u540c\u65f6\uff0c\u8fd8\u80fd\u5d4c\u5957MyLog1\u548cMyLog4\u7684\u540c\u4e00\u63a5\u53e3\u7684\u4e0d\u540c\u5b9e\u73b0\uff0c\u548c\u5b9e\u73b0\u7684\u9ed8\u8ba4\u53c2\u6570\u6784\u9020\u3002"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},'[Fact]\npublic void MethodShouldBeOk()\n{\n Container container = new Container();\n container.RegisterTransient<ILog, MyLog1>("MyLog1");\n container.RegisterTransient<ILog, MyLog2>("MyLog2");\n container.RegisterTransient<ILog, MyLog3>("MyLog3");\n container.RegisterTransient<ILog, MyLog4>("MyLog4");\n container.RegisterTransient<ILog, MyLog6>("MyLog5");\n container.RegisterTransient<ILog, MyLog6>();\n\n var log6 = container.Resolve<ILog>() as MyLog6;\n\n Assert.NotNull(log6.MyLog1);\n Assert.NotNull(log6.MyLog4);\n Assert.True(log6.MyLog1.GetType() == typeof(MyLog1));\n Assert.True(log6.MyLog4.GetType() == typeof(MyLog4));\n Assert.True(((MyLog4)log6.MyLog4).A == 20);\n Assert.True(((MyLog4)log6.MyLog4).B == "IOU");\n}\n')),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyLog6 : ILog\n{\n [DependencyInject(10, "TouchSocket")]\n public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)\n {\n this.A = a;\n this.B = b;\n this.MyLog1 = myLog1;\n this.MyLog4 = myLog4;\n }\n\n public int A { get; set; }\n public string B { get; set; }\n public ILog MyLog1 { get; set; }\n public ILog MyLog4 { get; set; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n')),(0,g.kt)("p",null,"Object\u6ce8\u5165"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},'[Fact]\npublic void ObjectSingletonShouldBeOk()\n{\n Container container = new Container();\n container.RegisterSingleton<ILog, MyLog1>();\n container.RegisterSingleton<ILog, MyLog10>("10");\n\n var log10 = container.Resolve<ILog>("10") as MyLog10;\n Assert.NotNull(log10);\n Assert.NotNull(log10.MyLog1);\n Assert.True(log10.MyLog1.GetType() == typeof(MyLog1));\n}\n')),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyLog10 : ILog\n{\n [DependencyParamterInject(typeof(ILog))]\n public object MyLog1 { get; set; }\n\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n")),(0,g.kt)("h2",{id:"\u56db\u751f\u547d\u5468\u671f"},"\u56db\u3001\u751f\u547d\u5468\u671f"),(0,g.kt)("p",null,"\u751f\u547d\u5468\u671f\u662f\u5bf9\u6ce8\u5165\u6784\u9020\u7684\u5b9e\u4f8b\u7684\u6709\u6548\u6027\u800c\u8a00\u7684\u3002TouchSocket\u652f\u6301\u4e09\u79cd\u751f\u547d\u5468\u671f\u3002"),(0,g.kt)("ul",null,(0,g.kt)("li",{parentName:"ul"},"Singleton\uff1a\u5355\u4f8b\u6ce8\u5165\uff0c\u5f53\u6ce8\u5165\uff0c\u5e76\u4e14\u5b9e\u4f8b\u5316\u4ee5\u540e\uff0c\u5168\u5c40\u552f\u4e00\u5b9e\u4f8b\u3002"),(0,g.kt)("li",{parentName:"ul"},"Transient\uff1a\u77ac\u65f6\u6ce8\u5165\uff0c\u6bcf\u6b21\u83b7\u53d6\u7684\u5b9e\u4f8b\u90fd\u662f\u65b0\u5b9e\u4f8b\u3002"),(0,g.kt)("li",{parentName:"ul"},"Scoped\uff1a\u533a\u57df\u5355\u4f8b\u6ce8\u5165\uff0c\u5f53\u5728\u4e00\u4e2aIScopedContainer\u65f6\uff0c\u5b9e\u4f8b\u552f\u4e00\u3002")),(0,g.kt)("p",null,"\u5bf9\u4e8e\u524d\u4e24\u79cd\uff0c\u719f\u6089IOC\u7684\u540c\u5b66\uff0c\u76f8\u4fe1\u90fd\u77e5\u9053\u5230\u3002\u90a3\u63a5\u4e0b\u6765\u5c31\u6f14\u793a\u4e00\u4e0bScoped\u3002"),(0,g.kt)("p",null,"\u5b9e\u9645\u4e0a\u4f7f\u7528Scoped\u65f6\uff0c\u5f97\u5148\u660e\u786e\u533a\u57df\uff0c\u4e5f\u5c31\u662f\u521b\u5efa\u4e00\u4e2aIScopedContainer\u7684\u533a\u57df\u5bb9\u5668\uff08\u7c7b\u4f3cAps.net\u7684IServiceProvider\uff09\u3002\u7136\u540e\u540e\u7eed\u5b9e\u4f8b\u4eceIScopedContainer\u83b7\u5f97\u5373\u53ef\u3002"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},"[Fact]\npublic void ScopedShouldBeOk()\n{\n Container container = new Container();\n container.RegisterScoped<ILog, MyLog1>();\n\n var log1 = container.Resolve<ILog>();\n var log2 = container.Resolve<ILog>();\n Assert.NotNull(log1);\n Assert.False(log1 == log2);\n\n IScopedContainer scopedContainer = container.Resolve<IScopedContainer>();\n log1 = scopedContainer.Resolve<ILog>();\n log2 = scopedContainer.Resolve<ILog>();\n Assert.NotNull(log1);\n Assert.True(log1 == log2);\n}\n")),(0,g.kt)("h2",{id:"\u6240\u6709\u6a21\u578b\u5b9a\u4e49"},"\u6240\u6709\u6a21\u578b\u5b9a\u4e49"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre",className:"language-csharp"},'public interface IGeneric<T1, T2>\n{\n}\n\npublic class Generic<T1, T2> : IGeneric<T1, T2>\n{\n\n}\n\n\n\npublic class MyLog1 : ILog\n{\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\npublic class MyLog2 : ILog\n{\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n\npublic class MyLog3 : ILog\n{\n public MyLog3(MyLog1 myLog1, MyLog2 myLog2)\n {\n this.MyLog1 = myLog1;\n this.MyLog2 = myLog2;\n }\n\n public MyLog1 MyLog1 { get; }\n public MyLog2 MyLog2 { get; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n\npublic class MyLog4 : ILog\n{\n [DependencyInject(10, "TouchSocket")]\n public MyLog4(int a, string b, MyLog1 myLog1, MyLog2 myLog2)\n {\n this.A = a;\n this.B = b;\n this.MyLog1 = myLog1;\n this.MyLog2 = myLog2;\n }\n\n public int A { get; }\n public string B { get; }\n public MyLog1 MyLog1 { get; }\n public MyLog2 MyLog2 { get; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n\npublic class MyLog5 : ILog\n{\n [DependencyParamterInject("MyLog1")]\n public ILog MyLog1 { get; set; }\n\n [DependencyParamterInject("MyLog2")]\n public ILog MyLog2 { get; set; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n\npublic class MyLog6 : ILog\n{\n [DependencyInject(10, "TouchSocket")]\n public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)\n {\n this.A = a;\n this.B = b;\n this.MyLog1 = myLog1;\n this.MyLog4 = myLog4;\n }\n\n public int A { get; set; }\n public string B { get; set; }\n public ILog MyLog1 { get; set; }\n public ILog MyLog4 { get; set; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n\npublic class MyLog7 : ILog\n{\n public MyLog7(IGeneric<ILog, MyLog2> generic)\n {\n this.Generic = generic;\n }\n\n public IGeneric<ILog, MyLog2> Generic { get; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n\n[DependencyType(DependencyType.Constructor)]\npublic class MyLog8 : ILog\n{\n [DependencyInject(10, "RRQM")]\n public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)\n {\n this.A = a;\n this.B = b;\n this.MyLog1 = myLog1;\n this.MyLog4 = myLog4;\n }\n\n public int A { get; set; }\n public string B { get; set; }\n public ILog MyLog1 { get; set; }\n public ILog MyLog4 { get; set; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n\n[DependencyType(DependencyType.Constructor | DependencyType.Method)]\npublic class MyLog9 : ILog\n{\n [DependencyInject(10, "RRQM")]\n public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)\n {\n this.A = a;\n this.B = b;\n this.MyLog1 = myLog1;\n this.MyLog4 = myLog4;\n }\n\n public int A { get; set; }\n public string B { get; set; }\n public ILog MyLog1 { get; set; }\n public ILog MyLog4 { get; set; }\n\n public void Debug(LogType logType, object source, string message, Exception exception)\n {\n\n }\n\n public void Debug(LogType logType, object source, string message)\n {\n\n }\n}\n')))}a.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/cbd4f89d.cc0b4777.js b/handbook/build/assets/js/cbd4f89d.cc0b4777.js new file mode 100644 index 000000000..8be5a4171 --- /dev/null +++ b/handbook/build/assets/js/cbd4f89d.cc0b4777.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6390],{3769:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/ce02ea51.3f2f2031.js b/handbook/build/assets/js/ce02ea51.3f2f2031.js new file mode 100644 index 000000000..ec735077e --- /dev/null +++ b/handbook/build/assets/js/ce02ea51.3f2f2031.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7790],{3905:(e,t,l)=>{l.d(t,{Zo:()=>p,kt:()=>m});var r=l(7294);function n(e,t,l){return t in e?Object.defineProperty(e,t,{value:l,enumerable:!0,configurable:!0,writable:!0}):e[t]=l,e}function a(e,t){var l=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),l.push.apply(l,r)}return l}function c(e){for(var t=1;t<arguments.length;t++){var l=null!=arguments[t]?arguments[t]:{};t%2?a(Object(l),!0).forEach((function(t){n(e,t,l[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(l)):a(Object(l)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(l,t))}))}return e}function o(e,t){if(null==e)return{};var l,r,n=function(e,t){if(null==e)return{};var l,r,n={},a=Object.keys(e);for(r=0;r<a.length;r++)l=a[r],t.indexOf(l)>=0||(n[l]=e[l]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)l=a[r],t.indexOf(l)>=0||Object.prototype.propertyIsEnumerable.call(e,l)&&(n[l]=e[l])}return n}var i=r.createContext({}),s=function(e){var t=r.useContext(i),l=t;return e&&(l="function"==typeof e?e(t):c(c({},t),e)),l},p=function(e){var t=s(e.components);return r.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var l=e.components,n=e.mdxType,a=e.originalType,i=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),d=s(l),m=n,h=d["".concat(i,".").concat(m)]||d[m]||u[m]||a;return l?r.createElement(h,c(c({ref:t},p),{},{components:l})):r.createElement(h,c({ref:t},p))}));function m(e,t){var l=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=l.length,c=new Array(a);c[0]=d;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o.mdxType="string"==typeof e?e:n,c[1]=o;for(var s=2;s<a;s++)c[s]=l[s];return r.createElement.apply(null,c)}return r.createElement.apply(null,l)}d.displayName="MDXCreateElement"},510:(e,t,l)=>{l.d(t,{Z:()=>_});var r=l(7294),n=l(7462);const a=(e,t,l)=>e?"string"==typeof e?e:e[t]||l:l,c={display:"block"},o=e=>{let{size:t,color:l,style:o,...i}=e;const s=o?{...c,...o}:c;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},i),r.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:a(l,0,"#333333")}))};o.defaultProps={size:18};const i=o,s={display:"block"},p=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...s,...c}:s;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:a(l,0,"#333333")}),r.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:a(l,1,"#333333")}))};p.defaultProps={size:18};const u=p,d={display:"block"},m=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...d,...c}:d;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:a(l,0,"#333333")}),r.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:a(l,1,"#333333")}),r.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:a(l,2,"#333333")}))};m.defaultProps={size:18};const h=m,g={display:"block"},f=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...g,...c}:g;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:a(l,0,"#333333")}))};f.defaultProps={size:18};const y=f,v={display:"block"},k=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...v,...c}:v;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:a(l,0,"#333333")}))};k.defaultProps={size:18};const b=k,z={display:"block"},E=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...z,...c}:z;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:a(l,0,"#333333")}),r.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:a(l,1,"#333333")}),r.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:a(l,2,"#333333")}))};E.defaultProps={size:18};const x=E,w={display:"block"},C=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...w,...c}:w;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:a(l,0,"#333333")}),r.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:a(l,1,"#333333")}))};C.defaultProps={size:18};const N=C,M={display:"block"},O=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...M,...c}:M;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:a(l,0,"#333333")}),r.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:a(l,1,"#333333")}))};O.defaultProps={size:18};const P=O,L={display:"block"},j=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...L,...c}:L;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:a(l,0,"#333333")}),r.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:a(l,1,"#333333")}))};j.defaultProps={size:18};const T=j,Z={display:"block"},B=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...Z,...c}:Z;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:a(l,0,"#333333")}))};B.defaultProps={size:18};const D=B,H={display:"block"},V=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...H,...c}:H;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:a(l,0,"#333333")}))};V.defaultProps={size:18};const S=V,A={display:"block"},R=e=>{let{size:t,color:l,style:c,...o}=e;const i=c?{...A,...c}:A;return r.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},o),r.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:a(l,0,"#333333")}))};R.defaultProps={size:18};const I=R,U=e=>{let{name:t,...l}=e;switch(t){case"youhua":return r.createElement(i,l);case"dayi":return r.createElement(u,l);case"shengji":return r.createElement(h,l);case"tiaozheng":return r.createElement(y,l);case"gengxin":return r.createElement(b,l);case"wendang":return r.createElement(x,l);case"shanchu":return r.createElement(N,l);case"bug":return r.createElement(P,l);case"xinzeng":return r.createElement(T,l);case"fuwu":return r.createElement(D,l);case"down":return r.createElement(S,l);case"up":return r.createElement(I,l)}return null},F="label_p8vM",X="icon_knQK";function _(e){const{children:t}=e,l={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return r.createElement("label",{className:F,title:t,style:{backgroundColor:l[t].bgColor}},r.createElement(U,{name:l[t].icon,color:"white",size:14,className:X})," ",t)}},1290:(e,t,l)=>{l.r(t),l.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>c,metadata:()=>i,toc:()=>p});var r=l(7462),n=(l(7294),l(3905)),a=l(510);const c={id:"remotefilecontrol",title:"\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c"},o=void 0,i={unversionedId:"remotefilecontrol",id:"remotefilecontrol",title:"\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c",description:"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248",source:"@site/docs/remotefilecontrol.mdx",sourceDirName:".",slug:"/remotefilecontrol",permalink:"/touchsocket/docs/remotefilecontrol",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/remotefilecontrol.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675745725,formattedLastUpdatedAt:"Feb 7, 2023",frontMatter:{id:"remotefilecontrol",title:"\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c"},sidebar:"docs",previous:{title:"\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93",permalink:"/touchsocket/docs/multithreadingfiletransfer"},next:{title:"Stream\u4f20\u8f93",permalink:"/touchsocket/docs/streamtransfer"}},s={},p=[{value:"\u4e00\u3001\u8bf4\u660e <Tag>\u4f01\u4e1a\u7248</Tag>",id:"\u4e00\u8bf4\u660e-\u4f01\u4e1a\u7248",level:2},{value:"\u4e8c\u3001\u652f\u6301\u7684\u64cd\u4f5c",id:"\u4e8c\u652f\u6301\u7684\u64cd\u4f5c",level:2},{value:"\u4e09\u3001\u4ee3\u7801\u793a\u4f8b",id:"\u4e09\u4ee3\u7801\u793a\u4f8b",level:2}],u={toc:p};function d(e){let{components:t,...l}=e;return(0,n.kt)("wrapper",(0,r.Z)({},u,l,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"\u4e00\u8bf4\u660e-\u4f01\u4e1a\u7248"},"\u4e00\u3001\u8bf4\u660e ",(0,n.kt)(a.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("p",null,"\u652f\u6301\u76f4\u63a5\u8bbf\u95ee\u8fdc\u7a0b\u6587\u4ef6\u3001\u6587\u4ef6\u5939\u7684\u5feb\u6377\u64cd\u4f5c\u3002"),(0,n.kt)("h2",{id:"\u4e8c\u652f\u6301\u7684\u64cd\u4f5c"},"\u4e8c\u3001\u652f\u6301\u7684\u64cd\u4f5c"),(0,n.kt)("p",null,"\u4ee5\u4e0b\u5185\u5bb9\uff0c\u6240\u6709TouchRpc\u5747\u652f\u6301\uff08\u5305\u62ec\u57fa\u4e8eudp\u534f\u8bae\u7684\uff09\u3002"),(0,n.kt)("table",null,(0,n.kt)("thead",{parentName:"table"},(0,n.kt)("tr",{parentName:"thead"},(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u64cd\u4f5c")),(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u6587\u4ef6")),(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u6587\u4ef6\u5939")))),(0,n.kt)("tbody",{parentName:"table"},(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"\u83b7\u53d6\u4fe1\u606f"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301\uff1a\u83b7\u53d6\u6587\u4ef6\u540d\u79f0\uff0c\u5927\u5c0f\uff0c\u4fee\u6539\u65f6\u95f4\u7b49\u3002"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301\uff1a\u83b7\u53d6\u6587\u4ef6\u5939\u540d\u79f0\uff0c\u5927\u5c0f\uff0c\u5b50\u6587\u4ef6\u5939\uff0c\u6587\u4ef6\u540d\u79f0\u3001\u4fee\u6539\u65f6\u95f4\u7b49\u3002")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"\u521b\u5efa"),(0,n.kt)("td",{parentName:"tr",align:null},"\u4e0d\u652f\u6301\u6587\u4ef6\u7684\u76f4\u63a5\u521b\u5efa\u3002"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"\u5220\u9664"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"\u590d\u5236"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},"\u79fb\u52a8"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301")))),(0,n.kt)("h2",{id:"\u4e09\u4ee3\u7801\u793a\u4f8b"},"\u4e09\u3001\u4ee3\u7801\u793a\u4f8b"),(0,n.kt)("p",null,"\u4ee5\u83b7\u53d6\u6587\u4ef6\u5939\u4fe1\u606f\u4e3a\u4f8b\uff1a"),(0,n.kt)("p",null,"client\u4e3aTouchRpc\u7684\u7ec8\u7aef\u3002\u53ef\u4ee5\u662f\u903b\u8f91\u5ba2\u6237\u7aef\uff0c\u4e5f\u53ef\u4ee5\u662f\u903b\u8f91\u670d\u52a1\u5668\u6240\u5305\u542b\u7684SocketClient"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},"//client\u5fc5\u9009\u5148\u5efa\u7acb\u8fde\u63a5\uff08udp\u534f\u8bae\u7684\u9664\u5916\uff09\n//Metadata\u53ef\u4ee5\u5411\u5bf9\u65b9\u4f20\u9012\u66f4\u591a\u7684\u6709\u7528\u4fe1\u606f\u3002\n//5000\u662f\u8d85\u65f6\u65f6\u95f4\uff0c\u5355\u4f4d\u6beb\u79d2\u3002\n//CancellationToken\u5305\u542b\u4e00\u4e2a\u53ef\u53d6\u6d88\u4ee4\u7bad\nRemoteDirectoryInfoResult rootDirectoryInfoResult = client.GetDirectoryInfo(dirPath,new Metadata(),5000,new CancellationToken());\n")),(0,n.kt)("p",null,"\u5176\u4f59\u64cd\u4f5c\u57fa\u672c\u4e00\u81f4\u3002"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/d22033f9.80f5a5bf.js b/handbook/build/assets/js/d22033f9.80f5a5bf.js new file mode 100644 index 000000000..9ba710f55 --- /dev/null +++ b/handbook/build/assets/js/d22033f9.80f5a5bf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[3371],{3905:(e,t,r)=>{r.d(t,{Zo:()=>m,kt:()=>s});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),c=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},m=function(e){var t=c(e.components);return n.createElement(p.Provider,{value:t},e.children)},k={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),u=c(r),s=a,d=u["".concat(p,".").concat(s)]||u[s]||k[s]||o;return r?n.createElement(d,l(l({ref:t},m),{},{components:r})):n.createElement(d,l({ref:t},m))}));function s(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,l=new Array(o);l[0]=u;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:a,l[1]=i;for(var c=2;c<o;c++)l[c]=r[c];return n.createElement.apply(null,l)}return n.createElement.apply(null,r)}u.displayName="MDXCreateElement"},3608:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>k,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var n=r(7462),a=(r(7294),r(3905));const o={id:"donate",title:"\u652f\u6301\u4f5c\u8005"},l=void 0,i={unversionedId:"donate",id:"donate",title:"\u652f\u6301\u4f5c\u8005",description:"\u8d5e\u52a9TouchSocket\u9879\u76ee",source:"@site/docs/donate.mdx",sourceDirName:".",slug:"/donate",permalink:"/touchsocket/docs/donate",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/donate.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"donate",title:"\u652f\u6301\u4f5c\u8005"},sidebar:"docs",previous:{title:"\u5386\u53f2\u66f4\u65b0",permalink:"/touchsocket/docs/upgrade"},next:{title:"\u4f01\u4e1a\u7248\u76f8\u5173",permalink:"/touchsocket/docs/enterprise"}},p={},c=[{value:"\u8d5e\u52a9TouchSocket\u9879\u76ee",id:"\u8d5e\u52a9touchsocket\u9879\u76ee",level:2},{value:"\u7231\u5fc3\u8d5e\u52a9\u540d\u5355\uff08\u4ee5\u4e0b\u6392\u540d\u53ea\u6309\u7167\u6253\u8d4f\u65f6\u95f4\u987a\u5e8f\uff09",id:"\u7231\u5fc3\u8d5e\u52a9\u540d\u5355\u4ee5\u4e0b\u6392\u540d\u53ea\u6309\u7167\u6253\u8d4f\u65f6\u95f4\u987a\u5e8f",level:3},{value:"\u4e00\u8d77\u559d\u9152\uff1f",id:"\u4e00\u8d77\u559d\u9152",level:3}],m={toc:c};function k(e){let{components:t,...o}=e;return(0,a.kt)("wrapper",(0,n.Z)({},m,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u8d5e\u52a9touchsocket\u9879\u76ee"},"\u8d5e\u52a9TouchSocket\u9879\u76ee"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"\u60a8\u7684\u652f\u6301\u5c31\u662f\u6211\u4e0d\u61c8\u52aa\u529b\u7684\u52a8\u529b\u3002")),(0,a.kt)("h3",{id:"\u7231\u5fc3\u8d5e\u52a9\u540d\u5355\u4ee5\u4e0b\u6392\u540d\u53ea\u6309\u7167\u6253\u8d4f\u65f6\u95f4\u987a\u5e8f"},"\u7231\u5fc3\u8d5e\u52a9\u540d\u5355\uff08\u4ee5\u4e0b\u6392\u540d\u53ea\u6309\u7167\u6253\u8d4f\u65f6\u95f4\u987a\u5e8f\uff09"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Bobo Joker\uff08200\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"UnitySir\uff0866\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"Coffee\uff08100\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"Ninety\uff0850\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u743c\uff08100\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"**\u5b89\uff085\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"**\u6587\uff08200+200\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"tonychen899\uff0850\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u5e73\uff0850\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u675c\uff08400+100\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u65bd*\u53cc\uff08666\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u7ae5\uff0820\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"Tom (88\uffe5)"),(0,a.kt)("li",{parentName:"ol"},"*\u5f3a\uff08200\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u6f6e\uff0810+20+1+2\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u661f\uff0820\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u8214\u72d7\u53cd\u54ac\u4e8b\u4ef6\uff0866\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u7f8e\u5c11\u5973\u9171\uff0830\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u6d41\u6c34\u6e38\u9c7c\uff089.99\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u534e\u4e3d\u8c22\u5e55\uff0833+20\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u9601\u4e3b\u60a6\u6f9c\u6b87\uff0850+50\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u70c8\u65e5\uff0820+20\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"Silent\uff0850\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u6708\u534e\u6563\uff0850\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u9ec4*\u5fb7\uff08PayPal\uff1a1000NT$\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u4e00\u5934\u5927\u72ee\u5b50\uff0820\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u848b*\u79cb\uff08188\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"**\u53d1\uff08100+100\xa5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u68a6\u60f3\u9065\u4e0d\u53ef\u53ca\uff08128+98\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u53ef\u7231\u53c8\u5584\u826f\u7684\u6211\uff08100\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u541b\uff086.6\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u4e8e\uff0830\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"J*n\uff08100\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"D*Y\uff0820\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u4eba\uff0850\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"*\u5149\uff0866\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"Estel(100\uffe5)"),(0,a.kt)("li",{parentName:"ol"},"1\uff08200\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"**\u9633\uff08100\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"chenqiang\uff086.6\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"Azure\uff0850\uffe5\uff09"),(0,a.kt)("li",{parentName:"ol"},"\u5e7f\u4e1c-\u5c0f\u767d\uff081.5\uffe5\uff09")),(0,a.kt)("h3",{id:"\u4e00\u8d77\u559d\u9152"},"\u4e00\u8d77\u559d\u9152\uff1f"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"\u6253\u8d4f\u652f\u4ed8.png",src:r(5197).Z,width:"850",height:"630"})))}k.isMDXComponent=!0},5197:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/donate-1-bc856a7a46e2b61db3ff9356d8210962.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/d5d2094c.734ef0f5.js b/handbook/build/assets/js/d5d2094c.734ef0f5.js new file mode 100644 index 000000000..3cf904333 --- /dev/null +++ b/handbook/build/assets/js/d5d2094c.734ef0f5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[904],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},l=Object.keys(e);for(o=0;o<l.length;o++)n=l[o],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(o=0;o<l.length;o++)n=l[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=o.createContext({}),s=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=s(e.components);return o.createElement(i.Provider,{value:t},e.children)},y={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(n),k=r,d=u["".concat(i,".").concat(k)]||u[k]||y[k]||l;return n?o.createElement(d,a(a({ref:t},p),{},{components:n})):o.createElement(d,a({ref:t},p))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,a=new Array(l);a[0]=u;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c.mdxType="string"==typeof e?e:r,a[1]=c;for(var s=2;s<l;s++)a[s]=n[s];return o.createElement.apply(null,a)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},1797:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>a,default:()=>y,frontMatter:()=>l,metadata:()=>c,toc:()=>s});var o=n(7462),r=(n(7294),n(3905));const l={id:"bytepool",title:"\u5185\u5b58\u6c60"},a=void 0,c={unversionedId:"bytepool",id:"bytepool",title:"\u5185\u5b58\u6c60",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/bytepool.mdx",sourceDirName:".",slug:"/bytepool",permalink:"/touchsocket/docs/bytepool",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/bytepool.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"bytepool",title:"\u5185\u5b58\u6c60"},sidebar:"docs",previous:{title:"\u5165\u95e8\u6307\u5357",permalink:"/touchsocket/docs/startguide"},next:{title:"\u63a7\u5236\u53f0\u884c\u4e3a",permalink:"/touchsocket/docs/consoleaction"}},i={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u529f\u80fd",id:"\u4e8c\u529f\u80fd",level:2},{value:"\u4e09\u3001\u521b\u5efa",id:"\u4e09\u521b\u5efa",level:2},{value:"\u56db\u3001\u4f7f\u7528",id:"\u56db\u4f7f\u7528",level:2},{value:"4.1 \u5199\u5165\u3001\u8bfb\u53d6\u6570\u636e\u5bf9\u8c61",id:"41-\u5199\u5165\u8bfb\u53d6\u6570\u636e\u5bf9\u8c61",level:3},{value:"4.2 \u591a\u7ebf\u7a0b\u540c\u6b65\u534f\u4f5c\uff08Hold\uff09",id:"42-\u591a\u7ebf\u7a0b\u540c\u6b65\u534f\u4f5chold",level:3}],p={toc:s};function y(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"\u5185\u5b58\u6c60\u662fTouchSocketCore\u7684\u6700\u91cd\u8981\u7684\u7ec4\u6210\u90e8\u5206\uff0c\u5728TouchSocket\u4ea7\u54c1\u4e2d\uff0cBytePool\u8d2f\u7a7f\u59cb\u7ec8\u3002\u6240\u4ee5\u719f\u6089\u4f7f\u7528BytePool\uff0c\u4e5f\u662f\u975e\u5e38\u91cd\u8981\u7684\u3002"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Nuget Package\uff1a"),(0,r.kt)("a",{parentName:"p",href:"https://www.nuget.org/packages/TouchSocket/"},"TouchSocket")),(0,r.kt)("h2",{id:"\u4e8c\u529f\u80fd"},"\u4e8c\u3001\u529f\u80fd"),(0,r.kt)("p",null,"\u5185\u5b58\u6c60\uff08BytePool\uff09\u7684\u6700\u5c0f\u5b9e\u73b0\u5355\u4f53\u662f\u5185\u5b58\u5757\uff08ByteBlock\uff09\uff0c\u5b83\u662f\u7ee7\u627f\u81eaStream\u7684\u7c7b\uff0c\u62e5\u6709\u548cMemoryStream\u4e00\u6837\u7684\u529f\u80fd\u548cRRQM\u7684\u589e\u5f3a\u529f\u80fd\u3002\u800c\u4e14\u62e5\u6709\u91ca\u653e\u56de\u6536\u80fd\u529b\uff0c\u6240\u4ee5\u5982\u679c\u6709MemoryStream\u7684\u4f7f\u7528\u9700\u6c42\u7684\u8bdd\uff0c\u5c31\u53ef\u4ee5\u5b8c\u5168\u8ba9ByteBlock\u66ff\u4ee3\u3002"),(0,r.kt)("h2",{id:"\u4e09\u521b\u5efa"},"\u4e09\u3001\u521b\u5efa"),(0,r.kt)("p",null,"BytePool\u662f\u9759\u6001\u7c7b\uff0c\u65e0\u9700\u521b\u5efa\uff0c\u76f4\u63a5\u4f7f\u7528\u5373\u53ef\u3002ByteBlock\u53ef\u901a\u8fc7BytePool\u521b\u5efa\uff0c\u4e5f\u53ef\u4ee5\u76f4\u63a5new\u5bf9\u8c61\uff0c\u8fd9\u4e24\u8005\u5b9e\u9645\u64cd\u4f5c\u4e00\u81f4\u3002\n",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("em",{parentName:"strong"},"\u6ce8\u610f\uff1a\u521b\u5efa\u7684ByteBlock\u5fc5\u987b\u91ca\u653e\uff08Dispose\uff09\uff0c\u867d\u7136\u4e0d\u4f1a\u5185\u5b58\u6cc4\u9732\uff0c\u4f46\u662f\u4f1a\u5f71\u54cd\u6027\u80fd\u3002"))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"ByteBlock byteBlock1 = new ByteBlock(byteSize:1024*1024,equalSize:false);\nbyteBlock1.Dispose();\nByteBlock byteBlock2 = BytePool.GetByteBlock(byteSize:1024*1024,equalSize:false);\nbyteBlock2.Dispose();\nusing (ByteBlock byteBlock3=new ByteBlock())\n{\n}\n")),(0,r.kt)("h2",{id:"\u56db\u4f7f\u7528"},"\u56db\u3001\u4f7f\u7528"),(0,r.kt)("p",null,"\u57fa\u7840\u4f7f\u7528\u548cMemoryStream\u4e00\u81f4\uff0c\u4e0b\u9762\u4ec5\u4ecb\u7ecd\u7279\u5b9a\u4f7f\u7528\u3002"),(0,r.kt)("h3",{id:"41-\u5199\u5165\u8bfb\u53d6\u6570\u636e\u5bf9\u8c61"},"4.1 \u5199\u5165\u3001\u8bfb\u53d6\u6570\u636e\u5bf9\u8c61"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'using (ByteBlock byteBlock = new ByteBlock())\n{\n byteBlock.Write(byte.MaxValue);\n byteBlock.Write(int.MaxValue);\n byteBlock.Write(long.MaxValue);\n byteBlock.Write("RRQM");\n byteBlock.WriteObject(new Person(), SerializationType.Json);\n byteBlock.WriteBytesPackage(new byte[1024]);\n byteBlock.Pos = 0;//\u8bfb\u53d6\u65f6\uff0c\u5148\u5c06\u6e38\u6807\u79fb\u52a8\u5230\u521d\u59cb\u5199\u5165\u7684\u4f4d\u7f6e\uff0c\u7136\u540e\u6309\u5199\u5165\u987a\u5e8f\uff0c\u4f9d\u6b21\u8bfb\u53d6\n byte ByteValue = byteBlock.ReadByte();\n int IntValue = byteBlock.ReadInt32();\n long LongValue = byteBlock.ReadInt64();\n string StringValue = byteBlock.ReadString();\n Person ObjectValue = byteBlock.ReadObject<Person>(SerializationType.Json);\n byte[] BytesValue = byteBlock.ReadBytesPackage();\n}\n')),(0,r.kt)("h3",{id:"42-\u591a\u7ebf\u7a0b\u540c\u6b65\u534f\u4f5chold"},"4.2 \u591a\u7ebf\u7a0b\u540c\u6b65\u534f\u4f5c\uff08Hold\uff09"),(0,r.kt)("p",null,"\u5728\u591a\u7ebf\u7a0b\u5f02\u6b65\u65f6\uff0c\u8bbe\u8ba1\u67b6\u6784\u5e94\u5f53\u9075\u5b88\u8c01\uff08Thread\uff09\u521b\u5efa\u7684ByteBlock\uff0c\u7531\u8c01\u91ca\u653e\uff0c\u8fd9\u6837\u5c31\u80fd\u5f88\u597d\u7684\u907f\u514d\u672a\u91ca\u653e\u7684\u60c5\u51b5\u53d1\u751f\u3002\u5b9e\u9645\u4e0aRRQMSocket\u4e2d\uff0c\u5c31\u662f\u79c9\u627f\u8fd9\u6837\u7684\u8bbe\u8ba1\uff0c\u4efb\u4f55\u975e\u7528\u6237\u521b\u5efa\u7684ByteBlock\uff0c\u90fd\u4f1a\u7531\u521b\u5efa\u7684\u7ebf\u7a0b\u6700\u540e\u91ca\u653e\u3002\u4f46\u662f\u5728\u4f7f\u7528\u4e2d\uff0c\u7ecf\u5e38\u51fa\u73b0\u5f02\u6b65\u591a\u7ebf\u7a0b\u7684\u64cd\u4f5c\u3002\n\u4ee5RRQMSocket\u7684TcpClient\u4e3a\u4f8b\u3002\u5982\u679c\u76f4\u63a5\u5728\u6536\u5230\u6570\u636e\u65f6\uff0c\u4f7f\u7528Task\u5f02\u6b65\uff0c\u5219\u5fc5\u5b9a\u4f1a\u53d1\u751f\u5173\u4e8eByteBlock\u7684\u5404\u79cd\u5404\u6837\u7684\u5f02\u5e38\u3002\n",(0,r.kt)("strong",{parentName:"p"},"\u539f\u56e0\u975e\u5e38\u7b80\u5355\uff0cbyteBlock\u5bf9\u8c61\u5728\u5230\u8fbeHandleReceivedData\u65f6\uff0c\u89e6\u53d1Task\u5f02\u6b65\uff0c\u6b64\u65f6\u89e6\u53d1\u7ebf\u7a0b\u4f1a\u7acb\u5373\u8fd4\u56de\uff0c\u5e76\u91ca\u653ebyteBlock\uff0c\u800cTask\u5f02\u6b65\u7ebf\u7a0b\u4f1a\u6ede\u540e\uff0c\u7136\u540e\u8bd5\u56fe\u4ece\u5df2\u91ca\u653e\u7684byteBlock\u4e2d\u83b7\u53d6\u6570\u636e\uff0c\u6240\u4ee5\uff0c\u5fc5\u5b9a\u53d1\u751f\u5f02\u5e38\u3002")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyTClient : TcpClient\n{\n protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)\n {\n Task.Run(()=> \n {\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n Console.WriteLine($"\u5df2\u63a5\u6536\u5230\u4fe1\u606f\uff1a{mes}");\n });\n }\n}\n')),(0,r.kt)("p",null,"\u89e3\u51b3\u65b9\u6cd5\u4e5f\u975e\u5e38\u7b80\u5355\uff0c\u53ea\u9700\u8981\u5728\u5f02\u6b65\u524d\u9501\u5b9a\uff0c\u7136\u540e\u4f7f\u7528\u5b8c\u6210\u540e\u53d6\u6d88\u9501\u5b9a\uff0c\u4e14\u4e0d\u7528\u518d\u8c03\u7528Dispose\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyTClient : TcpClient\n{\n protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)\n {\n byteBlock.SetHolding(true);//\u5f02\u6b65\u524d\u9501\u5b9a\n Task.Run(()=> \n {\n string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);\n byteBlock.SetHolding(false);//\u4f7f\u7528\u5b8c\u6210\u540e\u53d6\u6d88\u9501\u5b9a\uff0c\u4e14\u4e0d\u7528\u518d\u8c03\u7528Dispose\n Console.WriteLine($"\u5df2\u63a5\u6536\u5230\u4fe1\u606f\uff1a{mes}");\n });\n }\n}\n')))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/d6520aa6.ca22c63f.js b/handbook/build/assets/js/d6520aa6.ca22c63f.js new file mode 100644 index 000000000..07937ba93 --- /dev/null +++ b/handbook/build/assets/js/d6520aa6.ca22c63f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6050],{3905:(e,t,r)=>{r.d(t,{Zo:()=>l,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?c(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):c(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},c=Object.keys(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,c=e.originalType,p=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),d=s(r),m=o,f=d["".concat(p,".").concat(m)]||d[m]||u[m]||c;return r?n.createElement(f,a(a({ref:t},l),{},{components:r})):n.createElement(f,a({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=r.length,a=new Array(c);a[0]=d;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:o,a[1]=i;for(var s=2;s<c;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},5833:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>u,frontMatter:()=>c,metadata:()=>i,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const c={id:"jsonrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},a=void 0,i={unversionedId:"jsonrpcdescription",id:"jsonrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/jsonrpcdescription.mdx",sourceDirName:".",slug:"/jsonrpcdescription",permalink:"/touchsocket/docs/jsonrpcdescription",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/jsonrpcdescription.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"jsonrpcdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},sidebar:"docs",previous:{title:"\u53d1\u73b0\u3001\u8c03\u7528\u670d\u52a1",permalink:"/touchsocket/docs/callwebapi"},next:{title:"\u5b9a\u4e49\u3001\u53d1\u5e03\u3001\u542f\u52a8\u670d\u52a1",permalink:"/touchsocket/docs/jsonrpcservice"}},p={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u7279\u70b9\uff1a",id:"\u4e8c\u7279\u70b9",level:2}],l={toc:s};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,o.kt)("p",null,"JsonRpc\u662f",(0,o.kt)("strong",{parentName:"p"},"\u901a\u7528"),"\u7684RPC\u89c4\u8303\uff0c\u4e0e",(0,o.kt)("strong",{parentName:"p"},"\u7f16\u7a0b\u8bed\u8a00\u65e0\u5173\u3001\u64cd\u4f5c\u7cfb\u7edf\u65e0\u5173"),"\u3002\u8be6\u7ec6\u8bf4\u660e\u8bf7\u53c2\u9605",(0,o.kt)("a",{parentName:"p",href:"https://www.jsonrpc.org/specification"},"JsonRpc 2.0 \u5b98\u65b9\u6587\u6863"),"\uff0c\u5728TouchSocket\u4e2d\u5c01\u88c5\u4e86",(0,o.kt)("strong",{parentName:"p"},"\u524d\u540e\u7aef"),"\uff0c\u4f7f\u5176\u4f7f\u7528\u66f4\u52a0\u65b9\u4fbf\u3001\u9ad8\u6548\u3002"),(0,o.kt)("p",null,"\u76ee\u524d\u652f\u6301Tcp\u3001Http\u3001Websocket\u4e09\u79cd\u534f\u8bae\u8c03\u7528\u3002"),(0,o.kt)("a",{name:"C6IwW"}),(0,o.kt)("h2",{id:"\u4e8c\u7279\u70b9"},"\u4e8c\u3001\u7279\u70b9\uff1a"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"\u5f02\u5e38\u53cd\u9988")," \u3002"),(0,o.kt)("li",{parentName:"ul"},"\u63d2\u4ef6\u652f\u6301\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301\u81ea\u5b9a\u4e49\u7c7b\u578b\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301\u7c7b\u578b\u5d4c\u5957\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u652f\u6301js\u3001Android\u7b49\u8c03\u7528\u3002")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/d6be6cb7.b3757292.js b/handbook/build/assets/js/d6be6cb7.b3757292.js new file mode 100644 index 000000000..05124bb1c --- /dev/null +++ b/handbook/build/assets/js/d6be6cb7.b3757292.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1705],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var c=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);t&&(c=c.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,c)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,c,r=function(e,t){if(null==e)return{};var n,c,r={},l=Object.keys(e);for(c=0;c<l.length;c++)n=l[c],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(c=0;c<l.length;c++)n=l[c],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=c.createContext({}),s=function(e){var t=c.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return c.createElement(i.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return c.createElement(c.Fragment,{},t)}},u=c.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=a(e,["components","mdxType","originalType","parentName"]),u=s(n),h=r,v=u["".concat(i,".").concat(h)]||u[h]||d[h]||l;return n?c.createElement(v,o(o({ref:t},p),{},{components:n})):c.createElement(v,o({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=u;var a={};for(var i in t)hasOwnProperty.call(t,i)&&(a[i]=t[i]);a.originalType=e,a.mdxType="string"==typeof e?e:r,o[1]=a;for(var s=2;s<l;s++)o[s]=n[s];return c.createElement.apply(null,o)}return c.createElement.apply(null,n)}u.displayName="MDXCreateElement"},510:(e,t,n)=>{n.d(t,{Z:()=>X});var c=n(7294),r=n(7462);const l=(e,t,n)=>e?"string"==typeof e?e:e[t]||n:n,o={display:"block"},a=e=>{let{size:t,color:n,style:a,...i}=e;const s=a?{...o,...a}:o;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},i),c.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:l(n,0,"#333333")}))};a.defaultProps={size:18};const i=a,s={display:"block"},p=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...s,...o}:s;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:l(n,0,"#333333")}),c.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:l(n,1,"#333333")}))};p.defaultProps={size:18};const d=p,u={display:"block"},h=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...u,...o}:u;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:l(n,0,"#333333")}),c.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:l(n,1,"#333333")}),c.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:l(n,2,"#333333")}))};h.defaultProps={size:18};const v=h,g={display:"block"},m=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...g,...o}:g;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:l(n,0,"#333333")}))};m.defaultProps={size:18};const f=m,y={display:"block"},C=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...y,...o}:y;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:l(n,0,"#333333")}))};C.defaultProps={size:18};const k=C,b={display:"block"},E=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...b,...o}:b;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:l(n,0,"#333333")}),c.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:l(n,1,"#333333")}),c.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:l(n,2,"#333333")}))};E.defaultProps={size:18};const x=E,z={display:"block"},w=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...z,...o}:z;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:l(n,0,"#333333")}),c.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:l(n,1,"#333333")}))};w.defaultProps={size:18};const T=w,M={display:"block"},P=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...M,...o}:M;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:l(n,0,"#333333")}),c.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:l(n,1,"#333333")}))};P.defaultProps={size:18};const O=P,N={display:"block"},S=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...N,...o}:N;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:l(n,0,"#333333")}),c.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:l(n,1,"#333333")}))};S.defaultProps={size:18};const A=S,L={display:"block"},B=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...L,...o}:L;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:l(n,0,"#333333")}))};B.defaultProps={size:18};const I=B,j={display:"block"},H=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...j,...o}:j;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:l(n,0,"#333333")}))};H.defaultProps={size:18};const Z=H,R={display:"block"},D=e=>{let{size:t,color:n,style:o,...a}=e;const i=o?{...R,...o}:R;return c.createElement("svg",(0,r.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),c.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:l(n,0,"#333333")}))};D.defaultProps={size:18};const V=D,q=e=>{let{name:t,...n}=e;switch(t){case"youhua":return c.createElement(i,n);case"dayi":return c.createElement(d,n);case"shengji":return c.createElement(v,n);case"tiaozheng":return c.createElement(f,n);case"gengxin":return c.createElement(k,n);case"wendang":return c.createElement(x,n);case"shanchu":return c.createElement(T,n);case"bug":return c.createElement(O,n);case"xinzeng":return c.createElement(A,n);case"fuwu":return c.createElement(I,n);case"down":return c.createElement(Z,n);case"up":return c.createElement(V,n)}return null},U="label_p8vM",F="icon_knQK";function X(e){const{children:t}=e,n={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return c.createElement("label",{className:U,title:t,style:{backgroundColor:n[t].bgColor}},c.createElement(q,{name:n[t].icon,color:"white",size:14,className:F})," ",t)}},6643:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var c=n(7462),r=(n(7294),n(3905)),l=n(510);const o={id:"natservice",title:"Tcp\u7aef\u53e3\u8f6c\u53d1"},a=void 0,i={unversionedId:"natservice",id:"natservice",title:"Tcp\u7aef\u53e3\u8f6c\u53d1",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/natservice.mdx",sourceDirName:".",slug:"/natservice",permalink:"/touchsocket/docs/natservice",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/natservice.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675527977,formattedLastUpdatedAt:"Feb 4, 2023",frontMatter:{id:"natservice",title:"Tcp\u7aef\u53e3\u8f6c\u53d1"},sidebar:"docs",previous:{title:"\u540c\u6b65\u8bf7\u6c42",permalink:"/touchsocket/docs/waitingclient"},next:{title:"\u670d\u52a1\u5668\u91cd\u7f6eID",permalink:"/touchsocket/docs/resetid"}},s={},p=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u5e38\u89c1\u4f7f\u7528\u573a\u666f",id:"\u4e8c\u5e38\u89c1\u4f7f\u7528\u573a\u666f",level:2},{value:"\u4e09\u3001\u521b\u5efaNATService",id:"\u4e09\u521b\u5efanatservice",level:2},{value:"\u56db\u3001\u8f6c\u53d1\u65ad\u7ebf\u91cd\u8fde <Tag>\u4f01\u4e1a\u7248</Tag>",id:"\u56db\u8f6c\u53d1\u65ad\u7ebf\u91cd\u8fde-\u4f01\u4e1a\u7248",level:2}],d={toc:p};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,c.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"NATService\u662f\u5177\u6709\u8f6c\u53d1\u529f\u80fd\u7684TCP\u670d\u52a1\u5668\u3002\u4ed6\u7684\u804c\u80fd\u662f\u5c06\u6536\u5230\u7684TCP\u6570\u636e\u8f6c\u53d1\u5230\u591a\u4e2a\u76ee\u6807\u670d\u52a1\u5668\u3002\u4e5f\u80fd\u5c06\u591a\u4e2a\u76ee\u6807\u670d\u52a1\u5668\u7684\u6570\u636e\u8f6c\u53d1\u5230\u8fde\u63a5\u5ba2\u6237\u7aef\u3002"),(0,r.kt)("h2",{id:"\u4e8c\u5e38\u89c1\u4f7f\u7528\u573a\u666f"},"\u4e8c\u3001\u5e38\u89c1\u4f7f\u7528\u573a\u666f"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"\u8c03\u8bd5\u573a\u666f\uff1a"),"\u5728\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u60f3\u8981\u8c03\u8bd5\u5ba2\u6237\u7aef\uff0c\u8981\u4e48\u4e2d\u65ad\u670d\u52a1\u5668\uff0c\u8981\u4e48\u5c31\u5c06\u5b9e\u9645\u6570\u636e\u8f6c\u53d1\u5230NAT\uff0c\u7136\u540e\u5728\u4e0d\u5f71\u54cd\u5b9e\u9645\u573a\u666f\u7684\u60c5\u51b5\u4e0b\u8fdb\u884c\u8c03\u8bd5\u3002"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"\u5185\u7f51\u7a7f\u900f\u573a\u666f\uff1a"),"\u4e00\u822ctcp\u90fd\u4f1a\u4f7f\u7528\u8f6c\u53d1\u5f0f\u7684\u5185\u7f51\u7a7f\u900f\u3002")),(0,r.kt)("h2",{id:"\u4e09\u521b\u5efanatservice"},"\u4e09\u3001\u521b\u5efaNATService"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'static void Main(string[] args)\n{\n MyNATService service = new MyNATService();\n var config = new TouchSocketConfig();\n config.SetListenIPHosts(new IPHost[] { new IPHost(7788) });\n\n service.Setup(config);\n service.Start();\n\n Console.WriteLine("\u8f6c\u53d1\u670d\u52a1\u5668\u5df2\u542f\u52a8\u3002\u5df2\u5c067788\u7aef\u53e3\u8f6c\u53d1\u5230127.0.0.1:7789\u4e0e127.0.0.1:7790\u5730\u5740");\n}\n')),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"NATService\u652f\u6301\u5ba2\u6237\u7aef\u9002\u914d\u5668\u548cSsl\u3002\u4e5f\u652f\u6301\u8f6c\u53d1\u9002\u914d\u5668\u548cSsl\u3002")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},' class MyNATService : NATService\n {\n protected override void OnConnected(NATSocketClient socketClient, RRQMEventArgs e)\n {\n base.OnConnected(socketClient, e);\n\n try\n {\n //\u6b64\u5904\u6a21\u62df\u7684\u662f\u53ea\u8981\u8fde\u63a5\u5230NAT\u670d\u52a1\u5668\uff0c\u5c31\u8f6c\u53d1\u3002\n //\u5b9e\u9645\u4e0a\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u968f\u65f6\u8c03\u7528\u3002\n socketClient.AddTargetClient(new TouchSocketConfig().SetRemoteIPHost("127.0.0.1:7789"));\n socketClient.AddTargetClient(new TouchSocketConfig().SetRemoteIPHost("127.0.0.1:7790"));\n }\n catch (Exception ex)\n {\n socketClient.Logger.Exception(ex);\n }\n }\n\n protected override void OnTargetClientDisconnected(NATSocketClient socketClient, ITcpClient tcpClient, ClientDisconnectedEventArgs e)\n {\n socketClient.Logger.Message($"{socketClient.IP}:{socketClient.Port}\u7684\u8f6c\u53d1\u5ba2\u6237\u7aef{tcpClient.IP}:{tcpClient.Port}\u5df2\u7ecf\u65ad\u5f00\u8fde\u63a5\u3002");\n base.OnTargetClientDisconnected(socketClient, tcpClient, e);\n }\n\n protected override byte[] OnNATReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)\n {\n //\u670d\u52a1\u5668\u6536\u5230\u7684\u6570\u636e\n return base.OnNATReceived(socketClient, byteBlock, requestInfo);\n }\n\n protected override byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ByteBlock byteBlock, IRequestInfo requestInfo)\n {\n //\u8fde\u63a5\u7684\u5ba2\u6237\u7aef\u6536\u5230\u7684\u6570\u636e\n return base.OnTargetClientReceived(socketClient, tcpClient, byteBlock, requestInfo);\n }\n }\n\n\n')),(0,r.kt)("h2",{id:"\u56db\u8f6c\u53d1\u65ad\u7ebf\u91cd\u8fde-\u4f01\u4e1a\u7248"},"\u56db\u3001\u8f6c\u53d1\u65ad\u7ebf\u91cd\u8fde ",(0,r.kt)(l.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'try\n{\n //\u6b64\u5904\u6a21\u62df\u7684\u662f\u53ea\u8981\u8fde\u63a5\u5230NAT\u670d\u52a1\u5668\uff0c\u5c31\u8f6c\u53d1\u3002\n //\u5b9e\u9645\u4e0a\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u968f\u65f6\u8c03\u7528\u3002\n socketClient.AddTargetClient(new TouchSocketConfig()\n .SetRemoteIPHost("127.0.0.1:7789")\n .ConfigurePlugins(a=> \n {\n //\u5728\u4f01\u4e1a\u7248\u4e2d\uff0c\u4f7f\u7528\u4ee5\u4e0b\u4efb\u610f\u65b9\u5f0f\uff0c\u53ef\u5b9e\u73b0\u8f6c\u53d1\u5ba2\u6237\u7aef\u7684\u65ad\u7ebf\u91cd\u8fde\u3002\n a.Add<PollingKeepAlivePlugin<TcpClient>>()\n .SetTick(1000);//\u6bcf\u79d2\u68c0\u67e5\n //a.UseReconnection();\n }));\n}\ncatch (Exception ex)\n{\n socketClient.Logger.Exception(ex);\n}\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/da3959dc.f28eac04.js b/handbook/build/assets/js/da3959dc.f28eac04.js new file mode 100644 index 000000000..5472d5a01 --- /dev/null +++ b/handbook/build/assets/js/da3959dc.f28eac04.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1793],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var r=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){l(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,r,l=function(e,t){if(null==e)return{};var n,r,l={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var i=r.createContext({}),s=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,l=e.mdxType,o=e.originalType,i=e.parentName,p=a(e,["components","mdxType","originalType","parentName"]),h=s(n),d=l,f=h["".concat(i,".").concat(d)]||h[d]||u[d]||o;return n?r.createElement(f,c(c({ref:t},p),{},{components:n})):r.createElement(f,c({ref:t},p))}));function d(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=n.length,c=new Array(o);c[0]=h;var a={};for(var i in t)hasOwnProperty.call(t,i)&&(a[i]=t[i]);a.originalType=e,a.mdxType="string"==typeof e?e:l,c[1]=a;for(var s=2;s<o;s++)c[s]=n[s];return r.createElement.apply(null,c)}return r.createElement.apply(null,n)}h.displayName="MDXCreateElement"},510:(e,t,n)=>{n.d(t,{Z:()=>U});var r=n(7294),l=n(7462);const o=(e,t,n)=>e?"string"==typeof e?e:e[t]||n:n,c={display:"block"},a=e=>{let{size:t,color:n,style:a,...i}=e;const s=a?{...c,...a}:c;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:s},i),r.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:o(n,0,"#333333")}))};a.defaultProps={size:18};const i=a,s={display:"block"},p=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...s,...c}:s;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:o(n,0,"#333333")}),r.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:o(n,1,"#333333")}))};p.defaultProps={size:18};const u=p,h={display:"block"},d=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...h,...c}:h;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:o(n,0,"#333333")}),r.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:o(n,1,"#333333")}),r.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:o(n,2,"#333333")}))};d.defaultProps={size:18};const f=d,g={display:"block"},m=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...g,...c}:g;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:o(n,0,"#333333")}))};m.defaultProps={size:18};const y=m,v={display:"block"},C=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...v,...c}:v;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:o(n,0,"#333333")}))};C.defaultProps={size:18};const k=C,b={display:"block"},w=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...b,...c}:b;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:o(n,0,"#333333")}),r.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:o(n,1,"#333333")}),r.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:o(n,2,"#333333")}))};w.defaultProps={size:18};const z=w,x={display:"block"},E=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...x,...c}:x;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:o(n,0,"#333333")}),r.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:o(n,1,"#333333")}))};E.defaultProps={size:18};const T=E,M={display:"block"},O=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...M,...c}:M;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:o(n,0,"#333333")}),r.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:o(n,1,"#333333")}))};O.defaultProps={size:18};const P=O,S={display:"block"},F=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...S,...c}:S;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:o(n,0,"#333333")}),r.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:o(n,1,"#333333")}))};F.defaultProps={size:18};const R=F,L={display:"block"},I=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...L,...c}:L;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:o(n,0,"#333333")}))};I.defaultProps={size:18};const N=I,A={display:"block"},j=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...A,...c}:A;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:o(n,0,"#333333")}))};j.defaultProps={size:18};const B=j,Z={display:"block"},H=e=>{let{size:t,color:n,style:c,...a}=e;const i=c?{...Z,...c}:Z;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},a),r.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:o(n,0,"#333333")}))};H.defaultProps={size:18};const V=H,D=e=>{let{name:t,...n}=e;switch(t){case"youhua":return r.createElement(i,n);case"dayi":return r.createElement(u,n);case"shengji":return r.createElement(f,n);case"tiaozheng":return r.createElement(y,n);case"gengxin":return r.createElement(k,n);case"wendang":return r.createElement(z,n);case"shanchu":return r.createElement(T,n);case"bug":return r.createElement(P,n);case"xinzeng":return r.createElement(R,n);case"fuwu":return r.createElement(N,n);case"down":return r.createElement(B,n);case"up":return r.createElement(V,n)}return null},_="label_p8vM",G="icon_knQK";function U(e){const{children:t}=e,n={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return r.createElement("label",{className:_,title:t,style:{backgroundColor:n[t].bgColor}},r.createElement(D,{name:n[t].icon,color:"white",size:14,className:G})," ",t)}},1184:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>h,frontMatter:()=>c,metadata:()=>i,toc:()=>p});var r=n(7462),l=(n(7294),n(3905)),o=n(510);const c={id:"multithreadingfiletransfer",title:"\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93"},a=void 0,i={unversionedId:"multithreadingfiletransfer",id:"multithreadingfiletransfer",title:"\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93",description:"\u4e00\u3001\u8bf4\u660e \u4f01\u4e1a\u7248",source:"@site/docs/multithreadingfiletransfer.mdx",sourceDirName:".",slug:"/multithreadingfiletransfer",permalink:"/touchsocket/docs/multithreadingfiletransfer",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/multithreadingfiletransfer.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675745725,formattedLastUpdatedAt:"Feb 7, 2023",frontMatter:{id:"multithreadingfiletransfer",title:"\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93"},sidebar:"docs",previous:{title:"\u5c0f\u6587\u4ef6\u4f20\u8f93",permalink:"/touchsocket/docs/smallfiletransfer"},next:{title:"\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c",permalink:"/touchsocket/docs/remotefilecontrol"}},s={},p=[{value:"\u4e00\u3001\u8bf4\u660e <Tag>\u4f01\u4e1a\u7248</Tag>",id:"\u4e00\u8bf4\u660e-\u4f01\u4e1a\u7248",level:2},{value:"\u4e8c\u3001\u4f7f\u7528",id:"\u4e8c\u4f7f\u7528",level:2},{value:"\u4e09\u3001\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6",id:"\u4e09\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6",level:2}],u={toc:p};function h(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"\u4e00\u8bf4\u660e-\u4f01\u4e1a\u7248"},"\u4e00\u3001\u8bf4\u660e ",(0,l.kt)(o.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,l.kt)("p",null,"\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93\uff0c\u987e\u540d\u601d\u4e49\uff0c\u5c31\u662f\u591a\u4e2a\u8fde\u63a5\u94fe\u8def\uff0c\u5171\u540c\u4f20\u8f93\u4e00\u4e2a\u6587\u4ef6\u3002"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"\u591a\u7ebf\u7a0b\u4f20\u8f93\u7684\u4f18\u70b9\u662f\u4ec0\u4e48\uff1f\u548c"),(0,l.kt)("a",{parentName:"p",href:"/touchsocket/docs/transferfile"},(0,l.kt)("strong",{parentName:"a"},"\u5e38\u89c4\u6587\u4ef6\u4f20\u8f93")),(0,l.kt)("strong",{parentName:"p"},"\u76f8\u6bd4\uff0c\u573a\u666f\u6709\u54ea\u4e9b\u4e0d\u540c\uff1f")),(0,l.kt)("p",null,"\u9996\u5148\uff0c",(0,l.kt)("a",{parentName:"p",href:"/touchsocket/docs/transferfile"},"\u5e38\u89c4\u6587\u4ef6\u4f20\u8f93"),"\u662f\u57fa\u4e8e\u5355\u4e2a\u8fde\u63a5\u94fe\u8def\u7684\uff0c\u6240\u4ee5\uff0c\u5355\u4e2a\u8fde\u63a5\u7684\u4f20\u8f93\u901f\u7387\u4e0a\u9650\uff0c\u5c31\u662f\u5e38\u89c4\u4f20\u8f93\u7684\u4e0a\u9650\u3002\u4e00\u822c\u6765\u8bf4\uff0c\u5c40\u57df\u7f51\u5f53\u4e2d\uff0c\u5355\u4e2a\u8fde\u63a5\u5373\u53ef\u5360\u6ee1\u6240\u6709\u5e26\u5bbd\uff0c\u6240\u4ee5\u8fd9\u65f6\u5019\u591a\u7ebf\u7a0b\u4f20\u8f93\u548c\u5e38\u89c4\u4f20\u8f93\u5e76\u65e0\u5dee\u522b\u3002\u4f46\u662f\uff0c\u5728\u4e91\u670d\u52a1\u5668\uff0c\u6216\u8005\u5728\u6709\u6d41\u91cf\u5747\u8861\u7b97\u6cd5\u7684\u7f51\u7edc\u4e2d\uff0c\u6bcf\u4e2a\u8fde\u63a5\u7684\u6700\u5927\u901f\u7387\u4e0d\u662f\u5e26\u5bbd\u7684\u6700\u5927\u901f\u7387\uff0c\u90a3\u4e48\u8fd9\u65f6\u5019\uff0c\u4e24\u4e2a\u5dee\u8ddd\u662f\u6bd4\u8f83\u5927\u7684\u3002"),(0,l.kt)("p",null,"\u4f8b\u5982\uff0c\u6211\u81ea\u5df1\u79df\u7684\u4e00\u4e2a\u5355\u6838\u4e91\u670d\u52a1\u5668\uff0c\u5b83\u7684\u5355\u4e2a\u8fde\u63a5\u901f\u7387\u53ea\u67091Mb\uff0c\u4f46\u662f\u5f39\u6027\u5e26\u5bbd\u5374\u670910Mb\u3002\u5b8f\u89c2\u8868\u8c61\u5c31\u662f\uff0c\u4e00\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5\u65f6\uff0c\u53ef\u4ee5\u75281Mb\u5e26\u5bbd\uff0c\u4e24\u4e2a\u5ba2\u6237\u7aef\u8fde\u63a5\u65f6\uff0c\u5c31\u53ef\u4ee5\u75282Mb\u3002\u90a3\u4e48\u8fd9\u65f6\u5019\uff0c\u591a\u7ebf\u7a0b\u4f20\u8f93\u5c31\u663e\u5f97\u683c\u5916\u91cd\u8981\u4e86\u3002"),(0,l.kt)("p",null,"\u5176\u6b21\uff0c\u591a\u7ebf\u7a0b\u4f20\u8f93\u662f\u65e0\u72b6\u6001\u7684\uff0c\u6240\u4ee5\u5bf9\u4e8e\u65ad\u7ebf\u91cd\u8fde\uff0c\u6362\u7f51\u91cd\u8fde\u7b49\u64cd\u4f5c\uff0c\u662f\u5b8c\u5168\u65e0\u611f\u7684\u3002"),(0,l.kt)("h2",{id:"\u4e8c\u4f7f\u7528"},"\u4e8c\u3001\u4f7f\u7528"),(0,l.kt)("p",null,"\u56e0\u4e3a\u662f\u591a\u94fe\u8def\u4f20\u8f93\uff0c\u6240\u4ee5\uff0c\u5c31\u5fc5\u987b\u5efa\u7acb\u591a\u4e2a\u5ba2\u6237\u7aef\u7684\u8fde\u63a5\u5230\u670d\u52a1\u5668\u3002\u8fd9\u91cc\u4f7f\u7528\u5df2\u7ecf\u5c01\u88c5\u597d\u7684\u901a\u4fe1\u6a21\u578bClientFactory\u3002"),(0,l.kt)("p",null,"ClientFactory\u7684\u901a\u4fe1\u6a21\u578b\u4f7f\u7528\u7684\u662f\u4e00\u4e2a\u4e3b\u901a\u4fe1\u7aef+\u591a\u4e2a\u4f20\u8f93\u5ba2\u6237\u7aef\u3002"),(0,l.kt)("p",null,"\u5bf9\u4e8e\u5ba2\u6237\u7aef\u7684\u914d\u7f6e\uff0c\u8bf7\u8be6\u7ec6\u53c2\u8003",(0,l.kt)("a",{parentName:"p",href:"/touchsocket/docs/createtouchrpcclient"},"\u521b\u5efaTouchRpc\u5ba2\u6237\u7aef")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'private TcpTouchRpcClientFactory CreateClientFactory()\n{\n TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory()\n {\n MinCount = 5,\n MaxCount = 10,\n OnGetMainConfig = () =>//\u914d\u7f6e\u4e3b\u901a\u4fe1\n {\n return new TouchSocketConfig()\n .SetRemoteIPHost("tcp://127.0.0.1:7789");\n },\n OnGetTransferConfig = () => //\u914d\u7f6e\u8f85\u52a9\u901a\u4fe1\n {\n return new TouchSocketConfig()\n .SetRemoteIPHost("tcp://127.0.0.1:7789");\n }\n };\n\n return clientFactory;\n}\n')),(0,l.kt)("p",null,"\u3010\u62c9\u53d6\u6587\u4ef6\u3011"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClientFactory clientFactory = CreateClientFactory();\nvar resultCon = clientFactory.CheckStatus();//\u68c0\u9a8c\u4e3b\u901a\u4fe1\u5668\u8fde\u63a5\u72b6\u6001\u3002\u9ed8\u8ba4\u5982\u679c\u6ca1\u6709\u8fde\u63a5\uff0c\u5219\u4f1a\u5efa\u7acb\u3002\nif (resultCon.IsSuccess())\n{\n var fileOperator = new MultithreadingFileOperator()\n {\n ResourcePath = path,//\u8bf7\u6c42\u8d44\u6e90\u8def\u5f84\n SavePath = savePath,//\u672c\u5730\u4fdd\u5b58\u8def\u5f84\n };\n //\u6b64\u5904\u76f8\u5f53\u4e8eTimer\uff0c\u6bcf\u79d2\u83b7\u53d6\u4f20\u8f93\u7684\u901f\u5ea6\u548c\u8fdb\u5ea6\n LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) => \n {\n if (fileOperator.IsEnd)\n {\n loop.SafeDispose();\n }\n\n Console.WriteLine($"\u901f\u5ea6\uff1a{fileOperator.Speed()}\uff0c\u8fdb\u5ea6:{fileOperator.Progress}");\n });\n _=loopAction.RunAsync();\n\n Result result= await clientFactory.PullFileAsync(fileOperator);\n if (result.IsSuccess())\n {\n MessageBox.Show(result.ToString());\n }\n}\nelse\n{\n MessageBox.Show(resultCon.ToString());\n}\n\n')),(0,l.kt)("p",null,"\u3010\u63a8\u9001\u6587\u4ef6\u3011"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClientFactory clientFactory = CreateClientFactory();\nvar resultCon = clientFactory.CheckStatus();//\u68c0\u9a8c\u4e3b\u901a\u4fe1\u5668\u8fde\u63a5\u72b6\u6001\u3002\u9ed8\u8ba4\u5982\u679c\u6ca1\u6709\u8fde\u63a5\uff0c\u5219\u4f1a\u5efa\u7acb\u3002\nif (resultCon.IsSuccess())\n{\n var fileOperator = new MultithreadingFileOperator()\n {\n ResourcePath = path,\n SavePath = savePath,\n };\n \n //\u6b64\u5904\u76f8\u5f53\u4e8eTimer\uff0c\u6bcf\u79d2\u83b7\u53d6\u4f20\u8f93\u7684\u901f\u5ea6\u548c\u8fdb\u5ea6\n LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) => \n {\n if (fileOperator.IsEnd)\n {\n loop.SafeDispose();\n }\n\n Console.WriteLine($"\u901f\u5ea6\uff1a{fileOperator.Speed()}\uff0c\u8fdb\u5ea6:{fileOperator.Progress}");\n });\n _=loopAction.RunAsync();\n\n Result result=await clientFactory.PushFileAsync(fileOperator);\n if (result.IsSuccess())\n {\n MessageBox.Show(result.ToString());\n }\n}\nelse\n{\n MessageBox.Show(resultCon.ToString());\n}\n')),(0,l.kt)("h2",{id:"\u4e09\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6"},"\u4e09\u3001\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6"),(0,l.kt)("p",null,"\u8be5\u529f\u80fd\u4e5f\u652f\u6301\u5ba2\u6237\u7aef\u4e4b\u95f4\u4e92\u76f8\u4f20\u8f93\u3002\u4f7f\u7528\u65b9\u6cd5\u57fa\u672c\u4e00\u81f4\uff0c\u9700\u8981\u989d\u5916\u6307\u5b9a\u76ee\u6807Id\uff0c\u4ee5\u53ca",(0,l.kt)("strong",{parentName:"p"},"\u83b7\u53d6\u4f20\u8f93\u7684Id\u96c6\u5408"),"\u5373\u53ef\u3002"),(0,l.kt)("p",null,"\u591a\u7ebf\u7a0b\u7684\u5ba2\u6237\u7aef\u4e4b\u95f4\u4f20\u8f93\u6587\u4ef6\uff0c\u4e0d\u50cf\u5176\u4ed6\u64cd\u4f5c\u7c7b\u578b\u90a3\u4e48\u7b80\u5355\u3002\u56e0\u4e3a\u9664\u4e86\u9700\u8981\u6307\u5b9a\u76ee\u7684Id\u5916\uff0c\u8fd8\u9700\u8981\u6307\u5b9a\u83b7\u53d6\u76ee\u6807Id\u7684\uff0c\u4f20\u8f93\u5ba2\u6237\u7aef\u7684Id\u96c6\u5408\uff0c\u4e0d\u7136\uff0c\u83b7\u53d6\u6570\u636e\u7684\u65f6\u5019\uff0c\u4ecd\u7136\u4f1a\u662f\u5355\u7ebf\u7a0b\u5de5\u4f5c\u7684\u3002"),(0,l.kt)("p",null,"\u6b64\u5916\uff0c",(0,l.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u4e5f\u9700\u8981\u540c\u610f\u8def\u7531"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},"internal class MyTouchRpcPlugin : TouchRpcPluginBase\n{\n protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)\n {\n if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile)\n {\n e.IsPermitOperation = true;\n }\n base.OnRouting(client, e);\n }\n}\n")),(0,l.kt)("p",null,"\u3010\u83b7\u53d6\u76ee\u6807\u4f20\u8f93\u5ba2\u6237\u7aef\u7684Id\u96c6\u5408\u3011\n\u5728TcpTouchRpcClientFactory\u5c5e\u6027\u4e2d\uff0c\u6709\u4e2aOnFindTransferIds\u3002\u901a\u8fc7\u5b9e\u73b0\u8be5\u5c5e\u6027\uff0c\u4f7f\u5176\u80fd\u591f\u83b7\u53d6\u5230\u5bf9\u5e94\u5ba2\u6237\u7aef\u7684\u4f20\u8f93\u5ba2\u6237\u7aefId\u96c6\u5408\uff08\u4e0b\u5217\u4ee3\u7801\u4e3a\u6a21\u62df\u503c\uff0c\u8981\u5177\u4f53\u5b9e\u73b0\u8be5\u529f\u80fd\uff0c\u8fd8\u5f97\u81ea\u884c\u5b9e\u73b0\uff09\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory()\n{\n MinCount = 5,\n MaxCount = 10,\n OnGetMainConfig = () =>//\u914d\u7f6e\u4e3b\u901a\u4fe1\n {\n return new TouchSocketConfig()\n .SetRemoteIPHost("tcp://127.0.0.1:7789")\n .SetVerifyToken("FileService");\n },\n OnGetTransferConfig = () => //\u914d\u7f6e\u8f85\u52a9\u901a\u4fe1\n {\n return new TouchSocketConfig()\n .SetRemoteIPHost("tcp://127.0.0.1:7789")\n .SetVerifyToken("FileService");\n }\n ,\n OnFindTransferIds = (client,targetId) => \n {\n //\u6b64\u5904\u7684\u64cd\u4f5c\u4e0d\u552f\u4e00\uff0c\u53ef\u80fd\u9700\u8981rpc\u5b9e\u73b0\u3002\n //\u5176\u76ee\u7684\u6bd4\u8f83\u7b80\u5355\uff0c\u5c31\u662f\u83b7\u53d6\u5230targetId\u5bf9\u5e94\u7684\u4e3b\u5ba2\u6237\u7aef\u7684\u6240\u6709\u4f20\u8f93\u5ba2\u6237\u7aef\u7684Id\u96c6\u5408\u3002\n //\u8fd9\u6837\u5c31\u5b9e\u73b0\u4e86\u591a\u4e2a\u5ba2\u6237\u7aef\u5411\u591a\u4e2a\u5ba2\u6237\u7aef\u4f20\u8f93\u6587\u4ef6\u7684\u76ee\u7684\u3002\n\n return new string[] { targetId};//\u6b64\u5904\u4e3a\u6a21\u62df\u7ed3\u679c\u3002\n }\n};\n')))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/df41208d.a4876b14.js b/handbook/build/assets/js/df41208d.a4876b14.js new file mode 100644 index 000000000..1040c9945 --- /dev/null +++ b/handbook/build/assets/js/df41208d.a4876b14.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8102],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>g});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)t=i[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)t=i[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var c=r.createContext({}),s=function(e){var n=r.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=s(e.components);return r.createElement(c.Provider,{value:n},e.children)},u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},d=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(t),g=a,y=d["".concat(c,".").concat(g)]||d[g]||u[g]||i;return t?r.createElement(y,o(o({ref:n},p),{},{components:t})):r.createElement(y,o({ref:n},p))}));function g(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=d;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=t[s];return r.createElement.apply(null,o)}return r.createElement.apply(null,t)}d.displayName="MDXCreateElement"},439:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=t(7462),a=(t(7294),t(3905));const i={id:"heartbeat",title:"\u5fc3\u8df3\u8bbe\u8ba1"},o=void 0,l={unversionedId:"heartbeat",id:"heartbeat",title:"\u5fc3\u8df3\u8bbe\u8ba1",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/heartbeat.mdx",sourceDirName:".",slug:"/heartbeat",permalink:"/touchsocket/docs/heartbeat",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/heartbeat.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675609832,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"heartbeat",title:"\u5fc3\u8df3\u8bbe\u8ba1"},sidebar:"docs",previous:{title:"\u547d\u4ee4\u884c\u6267\u884c\u63d2\u4ef6",permalink:"/touchsocket/docs/tcpcommandlineplugin"},next:{title:"\u5176\u4ed6\u573a\u666f\u5e94\u7528",permalink:"/touchsocket/docs/tcpother"}},c={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"1.1 \u4e3a\u4ec0\u4e48\u8981\u8bbe\u7f6e\u5fc3\u8df3\uff1f",id:"11-\u4e3a\u4ec0\u4e48\u8981\u8bbe\u7f6e\u5fc3\u8df3",level:3},{value:"\u4e8c\u3001\u8bbe\u8ba1\u6570\u636e\u683c\u5f0f",id:"\u4e8c\u8bbe\u8ba1\u6570\u636e\u683c\u5f0f",level:2},{value:"2.1 \u89e3\u6790\u6570\u636e\u683c\u5f0f",id:"21-\u89e3\u6790\u6570\u636e\u683c\u5f0f",level:3},{value:"\u4e09\u3001\u521b\u5efa\u6269\u5c55\u7c7b",id:"\u4e09\u521b\u5efa\u6269\u5c55\u7c7b",level:2},{value:"\u56db\u3001\u521b\u5efa\u5fc3\u8df3\u63d2\u4ef6\u7c7b",id:"\u56db\u521b\u5efa\u5fc3\u8df3\u63d2\u4ef6\u7c7b",level:2},{value:"\u4e94\u3001\u6d4b\u8bd5\u3001\u542f\u52a8",id:"\u4e94\u6d4b\u8bd5\u542f\u52a8",level:2}],p={toc:s};function u(e){let{components:n,...t}=e;return(0,a.kt)("wrapper",(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,a.kt)("h3",{id:"11-\u4e3a\u4ec0\u4e48\u8981\u8bbe\u7f6e\u5fc3\u8df3"},"1.1 \u4e3a\u4ec0\u4e48\u8981\u8bbe\u7f6e\u5fc3\u8df3\uff1f"),(0,a.kt)("p",null,"\u5fc3\u8df3\u673a\u5236\u4e00\u822c\u662f",(0,a.kt)("strong",{parentName:"p"},"\u5ba2\u6237\u7aef"),"\u5411",(0,a.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668"),"\u5b9a\u65f6\u53d1\u9001\u4e00\u4e2a\u7279\u5b9a\u7684\u6570\u636e\u5305\uff0c\u8ba9\u670d\u52a1\u5668\u77e5\u9053\u81ea\u5df1\u8fd8\u5728\u7ebf\uff0c\u4ee5\u786e\u4fdd\u8fde\u63a5\u7684\u6709\u6548\u6027\u7684\u673a\u5236\u3002 \u7f51\u7edc\u4e2d\u7684\u63a5\u6536\u548c\u53d1\u9001\u6570\u636e\u90fd\u662f\u4f7f\u7528\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u7684 SOCKET \u8fdb\u884c\u5b9e\u73b0\u3002 \u4f46\u662f\u5982\u679c\u6b64 \u5957\u63a5\u5b57 \u5df2\u7ecf\u65ad\u5f00\uff0c\u90a3\u53d1\u9001\u6570\u636e\u548c\u63a5\u6536\u6570\u636e\u7684\u65f6\u5019\u5c31\u4e00\u5b9a\u4f1a\u6709\u95ee\u9898\u3002 \u53ef\u662f\u5982\u4f55\u5224\u65ad\u8fd9\u4e2a\u5957\u63a5\u5b57\u662f\u5426\u8fd8\u53ef\u4ee5\u4f7f\u7528\u5462\uff1f \u8fd9\u4e2a\u5c31\u9700\u8981\u5728\u7cfb\u7edf\u4e2d\u521b\u5efa\u5fc3\u8df3\u673a\u5236\u3002 "),(0,a.kt)("p",null,"\u5176\u5b9eTCP\u4e2d\u5df2\u7ecf\u4e3a\u6211\u4eec\u5b9e\u73b0\u4e86\u4e00\u4e2a",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/createtcpclient#setkeepalivevalue"},"\u5185\u7f6e\u5fc3\u8df3\u673a\u5236\uff08SetKeepAliveValue\uff09"),"\u3002\u4f46\u662f\u8be5\u673a\u5236\u53d7\u9650\u4e8e\u64cd\u4f5c\u7cfb\u7edf\uff0c\u800c\u4e14\u5f88\u5bb9\u6613\u8bef\u62a5\u3002\u6240\u4ee5\u5f88\u5c11\u88ab\u5927\u5bb6\u4f7f\u7528\u3002"),(0,a.kt)("p",null,"\u5927\u5bb6\u4f7f\u7528\u6700\u591a\u7684\uff0c\u5c31\u662f\u81ea\u5df1\u8bbe\u8ba1\u6570\u636e\u5305\uff0c\u7136\u540e\u9884\u7559\u5fc3\u8df3\u683c\u5f0f\uff0c\u5f53\u5bf9\u65b9\u6536\u5230\u5fc3\u8df3\u5305\u65f6\uff0c\u76f4\u63a5\u8fd4\u56de\u54cd\u5e94\u5305\u5373\u53ef\u3002"),(0,a.kt)("p",null,"\u90a3\u4e48\uff0c\u6309\u8fd9\u4e2a\u601d\u8def\uff0c\u8ba9\u6211\u4eec\u4f7f\u7528\u4f18\u96c5\u7684\u5b9e\u73b0\u5427\u3002"),(0,a.kt)("h2",{id:"\u4e8c\u8bbe\u8ba1\u6570\u636e\u683c\u5f0f"},"\u4e8c\u3001\u8bbe\u8ba1\u6570\u636e\u683c\u5f0f"),(0,a.kt)("p",null,"\u4f7f\u7528\u5fc3\u8df3\u4e4b\u524d\uff0c\u5fc5\u987b\u8981\u660e\u786e\u6570\u636e\u683c\u5f0f\uff0c\u7edd\u5bf9\u4e0d\u80fd\u6df7\u6dc6\u4e1a\u52a1\u6570\u636e\u3002\u4e00\u822c\u5728\u9002\u914dPlc\u7b49\u73b0\u6210\u6a21\u5757\u65f6\uff0c\u4ed6\u4eec\u662f\u6709\u56fa\u5b9a\u7684\u6570\u636e\u683c\u5f0f\uff0c\u8fd9\u65f6\u5019\u4f60\u53ef\u4ee5\u53c2\u9605",(0,a.kt)("a",{parentName:"p",href:"/touchsocket/docs/adapterdemodescription"},"\u6570\u636e\u5904\u7406\u9002\u914d\u5668"),"\uff0c\u5feb\u901f\u7684\u89e3\u6790\u6570\u636e\u3002"),(0,a.kt)("p",null,"\u4f46\u662f\u5728\u672c\u6587\u4e2d\uff0c\u5e76\u6ca1\u6709\u89c4\u5b9a\u7684\u683c\u5f0f\uff0c\u6240\u4ee5\u6211\u4eec\u9700\u8981\u5148\u8bbe\u8ba1\u4e00\u79cd\u7b80\u5355\u9ad8\u6548\u7684\u6570\u636e\u683c\u5f0f\u3002"),(0,a.kt)("p",null,"\u5982\u4e0b\uff1a"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},(0,a.kt)("strong",{parentName:"th"},"\u6570\u636e\u957f\u5ea6")),(0,a.kt)("th",{parentName:"tr",align:null},(0,a.kt)("strong",{parentName:"th"},"\u6570\u636e\u7c7b\u578b")),(0,a.kt)("th",{parentName:"tr",align:null},(0,a.kt)("strong",{parentName:"th"},"\u8f7d\u8377\u6570\u636e")))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"2\u5b57\u8282\uff08Ushort\uff09"),(0,a.kt)("td",{parentName:"tr",align:null},"1\u5b57\u8282\uff08Byte\uff09"),(0,a.kt)("td",{parentName:"tr",align:null},"n\u5b57\u8282\uff08<65535\uff09")))),(0,a.kt)("h3",{id:"21-\u89e3\u6790\u6570\u636e\u683c\u5f0f"},"2.1 \u89e3\u6790\u6570\u636e\u683c\u5f0f"),(0,a.kt)("p",null,"\u4e0b\u5217\u4ee3\u7801\u4e3b\u8981\u5b9e\u73b0\u5bf9\u4e0a\u8ff0\u6570\u636e\u683c\u5f0f\u7684\u89e3\u6790"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'internal class MyFixedHeaderDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyRequestInfo>\n{\n public override int HeaderLength => 3;\n\n public override bool CanSendRequestInfo => false;\n\n protected override MyRequestInfo GetInstance()\n {\n return new MyRequestInfo();\n }\n\n protected override void PreviewSend(IRequestInfo requestInfo)\n {\n throw new NotImplementedException();\n }\n}\n\ninternal class MyRequestInfo : IFixedHeaderRequestInfo\n{\n public DataType DataType { get; set; }\n public byte[] Data { get; set; }\n\n public int BodyLength { get; private set; }\n\n public bool OnParsingBody(byte[] body)\n {\n if (body.Length == this.BodyLength)\n {\n this.Data = body;\n return true;\n }\n return false;\n }\n\n public bool OnParsingHeader(byte[] header)\n {\n if (header.Length == 3)\n {\n this.BodyLength = TouchSocketBitConverter.Default.ToUInt16(header, 0) - 1;\n this.DataType = (DataType)header[2];\n return true;\n }\n return false;\n }\n\n public void Package(ByteBlock byteBlock)\n {\n byteBlock.Write((ushort)((this.Data == null ? 0 : this.Data.Length) + 1));\n byteBlock.Write((byte)this.DataType);\n if (Data != null)\n {\n byteBlock.Write(Data);\n }\n }\n\n public byte[] PackageAsBytes()\n {\n using ByteBlock byteBlock = new ByteBlock();\n this.Package(byteBlock);\n return byteBlock.ToArray();\n }\n\n public override string ToString()\n {\n return $"\u6570\u636e\u7c7b\u578b={this.DataType}\uff0c\u6570\u636e={(this.Data == null ? "null" : Encoding.UTF8.GetString(this.Data))}";\n }\n}\n\ninternal enum DataType : byte\n{\n Ping,\n Pong,\n Data\n}\n')),(0,a.kt)("h2",{id:"\u4e09\u521b\u5efa\u6269\u5c55\u7c7b"},"\u4e09\u3001\u521b\u5efa\u6269\u5c55\u7c7b"),(0,a.kt)("p",null,"\u4e0b\u5217\u4ee3\u7801\u53ef\u9009\uff0c\u4e3b\u8981\u5b9e\u73b0\u5bf9Client\u589e\u52a0Ping\u7684\u6269\u5c55\u65b9\u6cd5\u3002\u65b9\u4fbf\u8c03\u7528\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'/// <summary>\n/// \u4e00\u4e2a\u5fc3\u8df3\u8ba1\u6570\u5668\u6269\u5c55\u3002\n/// </summary>\ninternal static class DependencyExtensions\n{\n public static readonly DependencyProperty<Timer> HeartbeatTimerProperty =\n DependencyProperty<Timer>.Register("HeartbeatTimer", typeof(DependencyExtensions), null);\n\n public static bool Ping<TClient>(this TClient client) where TClient : ITcpClientBase\n {\n try\n {\n client.Send(new MyRequestInfo() { DataType = DataType.Ping }.PackageAsBytes());\n return true;\n }\n catch (Exception ex)\n {\n client.Logger.Exception(ex);\n }\n\n return false;\n }\n\n public static bool Pong<TClient>(this TClient client) where TClient : ITcpClientBase\n {\n try\n {\n client.Send(new MyRequestInfo() { DataType = DataType.Pong }.PackageAsBytes());\n return true;\n }\n catch (Exception ex)\n {\n client.Logger.Exception(ex);\n }\n\n return false;\n }\n}\n')),(0,a.kt)("h2",{id:"\u56db\u521b\u5efa\u5fc3\u8df3\u63d2\u4ef6\u7c7b"},"\u56db\u3001\u521b\u5efa\u5fc3\u8df3\u63d2\u4ef6\u7c7b"),(0,a.kt)("p",null,"\u4e0b\u5217\u4ee3\u7801\u4e3b\u8981\u5b9e\u73b0\u5fc3\u8df3\u63d2\u4ef6\u7684\u529f\u80fd\u3002\u9ed8\u8ba4\u6bcf\u4e94\u79d2\u81ea\u52a8\u89e6\u53d1\u4e00\u6b21\u3002\u4e14\u63a5\u6536\u65b9\u6536\u5230Ping\u540e\uff0c\u76f4\u63a5\u4f1a\u56de\u590dPong\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"internal class HeartbeatAndReceivePlugin : TcpPluginBase\n{\n private readonly int m_timeTick;\n private readonly ILog logger;\n\n [DependencyInject(1000 * 5)]\n public HeartbeatAndReceivePlugin(int timeTick, ILog logger)\n {\n this.m_timeTick = timeTick;\n this.logger = logger;\n }\n\n protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e)\n {\n if (client is ISocketClient)\n {\n return;//\u6b64\u5904\u53ef\u5224\u65ad\uff0c\u5982\u679c\u4e3a\u670d\u52a1\u5668\uff0c\u5219\u4e0d\u7528\u4f7f\u7528\u5fc3\u8df3\u3002\n }\n\n if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer)\n {\n timer.Dispose();\n }\n\n client.SetValue(DependencyExtensions.HeartbeatTimerProperty, new Timer((o) =>\n {\n client.Ping();\n }, null, 0, m_timeTick));\n\n base.OnConnected(client, e);\n }\n\n protected override void OnDisconnected(ITcpClientBase client, ClientDisconnectedEventArgs e)\n {\n base.OnDisconnected(client, e);\n if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer)\n {\n timer.Dispose();\n client.SetValue(DependencyExtensions.HeartbeatTimerProperty, null);\n }\n }\n\n protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e)\n {\n if (e.RequestInfo is MyRequestInfo myRequest)\n {\n this.logger.Info(myRequest.ToString());\n if (myRequest.DataType == DataType.Ping)\n {\n client.Pong();\n }\n }\n base.OnReceivedData(client, e);\n }\n}\n")),(0,a.kt)("h2",{id:"\u4e94\u6d4b\u8bd5\u542f\u52a8"},"\u4e94\u3001\u6d4b\u8bd5\u3001\u542f\u52a8"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'/// <summary>\n/// \u793a\u4f8b\u5fc3\u8df3\u3002\n/// \u535a\u5ba2\u5730\u5740<see href="https://blog.csdn.net/qq_40374647/article/details/125598921"/>\n/// </summary>\n/// <param name="args"></param>\nprivate static void Main(string[] args)\n{\n ConsoleAction consoleAction = new ConsoleAction();\n\n //\u670d\u52a1\u5668\n TcpService service = new TcpService();\n service.Setup(new TouchSocketConfig()//\u8f7d\u5165\u914d\u7f6e\n .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//\u540c\u65f6\u76d1\u542c\u4e24\u4e2a\u5730\u5740\n .UsePlugin()\n .SetDataHandlingAdapter(()=>new MyFixedHeaderDataHandlingAdapter())\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n })\n .ConfigurePlugins(a =>\n {\n a.Add<HeartbeatAndReceivePlugin>();\n }))\n .Start();//\u542f\u52a8\n service.Logger.Info("\u670d\u52a1\u5668\u6210\u529f\u542f\u52a8");\n\n //\u5ba2\u6237\u7aef\n TcpClient tcpClient = new TcpClient();\n tcpClient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost(new IPHost("127.0.0.1:7789"))\n .UsePlugin()\n .SetDataHandlingAdapter(() => new MyFixedHeaderDataHandlingAdapter())\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n })\n .ConfigurePlugins(a =>\n {\n a.Add<HeartbeatAndReceivePlugin>();\n }));\n tcpClient.Connect();\n tcpClient.Logger.Info("\u5ba2\u6237\u7aef\u6210\u529f\u8fde\u63a5");\n\n consoleAction.OnException += ConsoleAction_OnException;\n consoleAction.Add("1", "\u53d1\u9001\u5fc3\u8df3", () =>\n {\n tcpClient.Ping();\n });\n consoleAction.Add("2", "\u53d1\u9001\u6570\u636e", () =>\n {\n tcpClient.Send(new MyRequestInfo()\n {\n DataType = DataType.Data,\n Data = Encoding.UTF8.GetBytes(Console.ReadLine())\n }\n .PackageAsBytes());\n });\n consoleAction.ShowAll();\n while (true)\n {\n consoleAction.Run(Console.ReadLine());\n }\n}\n\nprivate static void ConsoleAction_OnException(Exception obj)\n{\n Console.WriteLine(obj);\n}\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/dfe172e5.3113feba.js b/handbook/build/assets/js/dfe172e5.3113feba.js new file mode 100644 index 000000000..034cebac1 --- /dev/null +++ b/handbook/build/assets/js/dfe172e5.3113feba.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[7016],{3905:(e,n,t)=>{t.d(n,{Zo:()=>s,kt:()=>m});var c=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);n&&(c=c.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,c)}return t}function p(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function a(e,n){if(null==e)return{};var t,c,r=function(e,n){if(null==e)return{};var t,c,r={},o=Object.keys(e);for(c=0;c<o.length;c++)t=o[c],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(c=0;c<o.length;c++)t=o[c],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=c.createContext({}),i=function(e){var n=c.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):p(p({},n),e)),t},s=function(e){var n=i(e.components);return c.createElement(l.Provider,{value:n},e.children)},u={inlineCode:"code",wrapper:function(e){var n=e.children;return c.createElement(c.Fragment,{},n)}},k=c.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,s=a(e,["components","mdxType","originalType","parentName"]),k=i(t),m=r,R=k["".concat(l,".").concat(m)]||k[m]||u[m]||o;return t?c.createElement(R,p(p({ref:n},s),{},{components:t})):c.createElement(R,p({ref:n},s))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,p=new Array(o);p[0]=k;var a={};for(var l in n)hasOwnProperty.call(n,l)&&(a[l]=n[l]);a.originalType=e,a.mdxType="string"==typeof e?e:r,p[1]=a;for(var i=2;i<o;i++)p[i]=t[i];return c.createElement.apply(null,p)}return c.createElement.apply(null,t)}k.displayName="MDXCreateElement"},9011:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>p,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>i});var c=t(7462),r=(t(7294),t(3905));const o={id:"createandcallrpc",title:"\u521b\u5efarpc\u670d\u52a1"},p=void 0,a={unversionedId:"createandcallrpc",id:"createandcallrpc",title:"\u521b\u5efarpc\u670d\u52a1",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/createandcallrpc.mdx",sourceDirName:".",slug:"/createandcallrpc",permalink:"/touchsocket/docs/createandcallrpc",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/createandcallrpc.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675660193,formattedLastUpdatedAt:"Feb 6, 2023",frontMatter:{id:"createandcallrpc",title:"\u521b\u5efarpc\u670d\u52a1"},sidebar:"docs",previous:{title:"\u57fa\u7840\u529f\u80fd",permalink:"/touchsocket/docs/touchrpcbase"},next:{title:"Rpc\u5927\u6570\u636e\u6d41\u5f0f\u4f20\u8f93",permalink:"/touchsocket/docs/rpcstream"}},l={},i=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u5b9a\u4e49\u670d\u52a1",id:"\u4e8c\u5b9a\u4e49\u670d\u52a1",level:2},{value:"\u4e09\u3001\u542f\u52a8Rpc\u670d\u52a1\u5668",id:"\u4e09\u542f\u52a8rpc\u670d\u52a1\u5668",level:2},{value:"\u56db\u3001\u8c03\u7528Rpc",id:"\u56db\u8c03\u7528rpc",level:2},{value:"4.1 \u76f4\u63a5\u8c03\u7528",id:"41-\u76f4\u63a5\u8c03\u7528",level:3},{value:"4.2\u3001\u4ee3\u7406\u8c03\u7528",id:"42\u4ee3\u7406\u8c03\u7528",level:2},{value:"\u4e94\u3001\u53cd\u5411Rpc",id:"\u4e94\u53cd\u5411rpc",level:2},{value:"5.1 \u5b9a\u4e49\u3001\u53d1\u5e03\u53cd\u5411RPC\u670d\u52a1",id:"51-\u5b9a\u4e49\u53d1\u5e03\u53cd\u5411rpc\u670d\u52a1",level:3},{value:"5.2 \u8c03\u7528\u53cd\u5411RPC",id:"52-\u8c03\u7528\u53cd\u5411rpc",level:3},{value:"5.2.1 \u901a\u8fc7\u670d\u52a1\u5668\u76f4\u63a5\u83b7\u53d6",id:"521-\u901a\u8fc7\u670d\u52a1\u5668\u76f4\u63a5\u83b7\u53d6",level:3},{value:"5.2.2 \u901a\u8fc7\u8c03\u7528\u4e0a\u4e0b\u6587\u83b7\u53d6",id:"522-\u901a\u8fc7\u8c03\u7528\u4e0a\u4e0b\u6587\u83b7\u53d6",level:4},{value:"\u516d\u3001\u5ba2\u6237\u7aef\u4e92Call RPC",id:"\u516d\u5ba2\u6237\u7aef\u4e92call-rpc",level:2},{value:"6.1 \u4e92Call RPC",id:"61-\u4e92call-rpc",level:3}],s={toc:i};function u(e){let{components:n,...t}=e;return(0,r.kt)("wrapper",(0,c.Z)({},s,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,r.kt)("p",null,"RPC\uff08Remote Procedure Call\uff09\u8fdc\u7a0b\u8fc7\u7a0b\u8c03\u7528\u534f\u8bae\uff0c\u4e00\u79cd\u901a\u8fc7\u7f51\u7edc\u4ece\u8fdc\u7a0b\u8ba1\u7b97\u673a\u4e0a\u8bf7\u6c42\u670d\u52a1\uff0c\u800c\u4e0d\u9700\u8981\u4e86\u89e3\u5e95\u5c42\u7f51\u7edc\u6280\u672f\u7684\u534f\u8bae\u3002RPC\u5b83\u5047\u5b9a\u67d0\u4e9b\u534f\u8bae\u7684\u5b58\u5728\uff0c\u4f8b\u5982TPC/UDP\u7b49\uff0c\u4e3a\u901a\u4fe1\u7a0b\u5e8f\u4e4b\u95f4\u643a\u5e26\u4fe1\u606f\u6570\u636e\u3002\u5728OSI\u7f51\u7edc\u4e03\u5c42\u6a21\u578b\u4e2d\uff0cRPC\u8de8\u8d8a\u4e86\u4f20\u8f93\u5c42\u548c\u5e94\u7528\u5c42\uff0cRPC\u4f7f\u5f97\u5f00\u53d1\uff0c\u5305\u62ec\u7f51\u7edc\u5206\u5e03\u5f0f\u591a\u7a0b\u5e8f\u5728\u5185\u7684\u5e94\u7528\u7a0b\u5e8f\u66f4\u52a0\u5bb9\u6613\u3002"),(0,r.kt)("p",null,"\u8fc7\u7a0b\u662f\u4ec0\u4e48\uff1f \u8fc7\u7a0b\u5c31\u662f\u4e1a\u52a1\u5904\u7406\u3001\u8ba1\u7b97\u4efb\u52a1\uff0c\u66f4\u76f4\u767d\u7684\u8bf4\uff0c\u5c31\u662f\u7a0b\u5e8f\uff0c\u5c31\u662f\u60f3\u8c03\u7528\u672c\u5730\u65b9\u6cd5\u4e00\u6837\u8c03\u7528\u8fdc\u7a0b\u7684\u8fc7\u7a0b\u3002"),(0,r.kt)("p",null,"TouchRpc\u652f\u6301\u670d\u52a1\u5668\u4e0e\u5ba2\u6237\u7aef\u4e92\u76f8\u8c03\u7528\uff0c\u4e5f\u652f\u6301\u5ba2\u6237\u7aef\u4e4b\u95f4\u76f8\u4e92\u8c03\u7528\u3002"),(0,r.kt)("h2",{id:"\u4e8c\u5b9a\u4e49\u670d\u52a1"},"\u4e8c\u3001\u5b9a\u4e49\u670d\u52a1"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"\u5728",(0,r.kt)("strong",{parentName:"li"},"\u88ab\u8c03\u7528"),"\u7aef\u4e2d\u65b0\u5efa\u4e00\u4e2a\u7c7b\u540d\u4e3a",(0,r.kt)("strong",{parentName:"li"},"MyRpcServer"),"\u3002"),(0,r.kt)("li",{parentName:"ol"},"\u7ee7\u627f\u4e8eRpcServer\u7c7b\u3001\u6216\u5b9e\u73b0IRpcServer\u3002\u4ea6\u6216\u8005\u5c06\u670d\u52a1\u5668\u58f0\u660e\u4e3a",(0,r.kt)("strong",{parentName:"li"},"\u77ac\u65f6\u751f\u547d"),"\u7684\u670d\u52a1\uff0c\u7ee7\u627fTransientRpcServer\u3001\u6216ITransientRpcServer\u3002"),(0,r.kt)("li",{parentName:"ol"},"\u5728\u8be5\u7c7b\u4e2d\u5199",(0,r.kt)("strong",{parentName:"li"},"\u516c\u5171\u65b9\u6cd5"),"\uff0c\u5e76\u7528",(0,r.kt)("strong",{parentName:"li"},"TouchRpc"),"\u5c5e\u6027\u6807\u7b7e\u6807\u8bb0\u3002")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyRpcServer : RpcServer\n{\n [Description("\u767b\u5f55")]//\u670d\u52a1\u63cf\u8ff0\uff0c\u5728\u751f\u6210\u4ee3\u7406\u65f6\uff0c\u4f1a\u53d8\u6210\u6ce8\u91ca\u3002\n [TouchRpc("Login")]//\u670d\u52a1\u6ce8\u518c\u7684\u51fd\u6570\u952e\uff0c\u6b64\u5904\u4e3a\u663e\u5f0f\u6307\u5b9a\u3002\u9ed8\u8ba4\u4e0d\u4f20\u53c2\u7684\u65f6\u5019\uff0c\u4e3a\u8be5\u51fd\u6570\u7c7b\u5168\u540d+\u65b9\u6cd5\u540d\u7684\u5168\u5c0f\u5199\u3002\n public bool Login(string account,string password)\n {\n if (account=="123"&&password=="abc")\n {\n return true;\n }\n\n return false;\n }\n}\n')),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'public class MyRpcServer : TransientRpcServer\n{\n [Description("\u767b\u5f55")]//\u670d\u52a1\u63cf\u8ff0\uff0c\u5728\u751f\u6210\u4ee3\u7406\u65f6\uff0c\u4f1a\u53d8\u6210\u6ce8\u91ca\u3002\n [TouchRpc("Login")]//\u670d\u52a1\u6ce8\u518c\u7684\u51fd\u6570\u952e\uff0c\u6b64\u5904\u4e3a\u663e\u5f0f\u6307\u5b9a\u3002\u9ed8\u8ba4\u4e0d\u4f20\u53c2\u7684\u65f6\u5019\uff0c\u4e3a\u8be5\u51fd\u6570\u7c7b\u5168\u540d+\u65b9\u6cd5\u540d\u7684\u5168\u5c0f\u5199\u3002\n public bool Login(string account,string password)\n {\n if (account=="123"&&password=="abc")\n {\n return true;\n }\n\n return false;\n }\n}\n')),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("strong",{parentName:"p"},"\u77ac\u65f6\u751f\u547d"),"\u7684\u670d\u52a1\uff0c\u6700\u5927\u7684\u7279\u70b9\u5c31\u662f\uff0c\u6bcf\u4e2a\u8bf7\u6c42\uff0c\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u670d\u52a1\u7c7b\u5bf9\u8c61\u3002\u7136\u540e\u53ef\u4ee5\u901a\u8fc7",(0,r.kt)("strong",{parentName:"p"},"this.CallContext"),"\u76f4\u63a5\u8bbf\u95ee\u5f53\u524d\u7684\u8c03\u7528\u4e0a\u4e0b\u6587\u3002")),(0,r.kt)("h2",{id:"\u4e09\u542f\u52a8rpc\u670d\u52a1\u5668"},"\u4e09\u3001\u542f\u52a8Rpc\u670d\u52a1\u5668"),(0,r.kt)("p",null,"\u4ee5\u4e0b\u4ec5\u793a\u4f8b\u57fa\u4e8eTcp\u534f\u8baeTouchRpc\u3002\u5176\u4ed6\u534f\u8bae\u7684\u670d\u52a1\u5668\u8bf7\u770b",(0,r.kt)("a",{parentName:"p",href:"/touchsocket/docs/createtouchrpcservice"},"\u521b\u5efaTouchRpc\u670d\u52a1\u5668")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'var service =new TcpTouchRpcService();\nTouchSocketConfig config= new TouchSocketConfig()//\u914d\u7f6e\n .SetListenIPHosts(new IPHost[] { new IPHost(7789) })\n .ConfigureRpcStore(a=> \n {\n a.RegisterServer<MyRpcServer>();//\u6ce8\u518c\u670d\u52a1\n })\n .SetVerifyToken("TouchRpc");\n\nservice.Setup(config)\n .Start();\n\nservice.Logger.Info($"{service.GetType().Name}\u5df2\u542f\u52a8");\n')),(0,r.kt)("h2",{id:"\u56db\u8c03\u7528rpc"},"\u56db\u3001\u8c03\u7528Rpc"),(0,r.kt)("h3",{id:"41-\u76f4\u63a5\u8c03\u7528"},"4.1 \u76f4\u63a5\u8c03\u7528"),(0,r.kt)("p",null,"\u76f4\u63a5\u8c03\u7528\uff0c\u5219\u662f\u4e0d\u4f7f\u7528",(0,r.kt)("strong",{parentName:"p"},"\u4efb\u4f55\u4ee3\u7406"),"\uff0c\u4f7f\u7528",(0,r.kt)("strong",{parentName:"p"},"\u5b57\u7b26\u4e32"),"\u548c",(0,r.kt)("strong",{parentName:"p"},"\u53c2\u6570"),"\u76f4\u63a5Call Rpc\uff0c\u4f7f\u7528\u6bd4\u8f83\u7b80\u5355\u3002"),(0,r.kt)("p",null,"\u4e0b\u5217\u4ee5TcpTouchRpcClient\u4e3a\u4f8b\uff0c\u5176\u4ed6\u5ba2\u6237\u7aef\u4e00\u6a21\u4e00\u6837\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClient client = new TcpTouchRpcClient();\nclient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("127.0.0.1:7789")\n .SetVerifyToken("TouchRpc"));\nclient.Connect();\n\n//\u76f4\u63a5\u8c03\u7528\u65f6\uff0c\u7b2c\u4e00\u4e2a\u53c2\u6570\u4e3a\u8c03\u7528\u952e\n//\u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e3a\u8c03\u7528\u914d\u7f6e\u53c2\u6570\uff0c\u53ef\u8bbe\u7f6e\u8c03\u7528\u8d85\u65f6\u65f6\u95f4\uff0c\u53d6\u6d88\u8c03\u7528\u7b49\u529f\u80fd\u3002\u793a\u4f8b\u4e2d\u4f7f\u7528\u7684\u9884\u8bbe\uff0c\u5b9e\u9645\u4e0a\u53ef\u4ee5\u81ea\u884cnew InvokeOption();\n//\u540e\u7eed\u53c2\u6570\u4e3a\u8c03\u7528\u53c2\u6570\u3002\n//\u6cdb\u578b\u4e3a\u8fd4\u56de\u503c\u7c7b\u578b\u3002\nbool result = client.Invoke<bool>("Login", InvokeOption.WaitInvoke, 123, "abc");\n')),(0,r.kt)("h2",{id:"42\u4ee3\u7406\u8c03\u7528"},"4.2\u3001\u4ee3\u7406\u8c03\u7528"),(0,r.kt)("p",null,"\u4ee3\u7406\u8c03\u7528\u7684\u4fbf\u6377\u5728\u4e8e\uff0c\u5ba2\u6237\u7aef\u4e0d\u7528\u518d\u77e5\u9053\u54ea\u4e9b\u670d\u52a1\u53ef\u8c03\uff0c\u4e5f\u4e0d\u7528\u518d\u7ea0\u7ed3\u8c03\u7528\u7684\u53c2\u6570\u7c7b\u578b\u6b63\u4e0d\u6b63\u786e\uff0c\u56e0\u4e3a\u8fd9\u4e9b\uff0c\u4ee3\u7406\u5de5\u5177\u90fd\u4f1a\u66ff\u4f60\u505a\u597d\u3002"),(0,r.kt)("p",null,"\u8be6\u7ec6\u6b65\u9aa4\uff1a"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"/touchsocket/docs/generateproxy"},"\u751f\u6210\u4ee3\u7406\u6587\u4ef6")),(0,r.kt)("li",{parentName:"ol"},"\u5c06\u751f\u6210\u7684cs\u6587\u4ef6\u6dfb\u52a0\u5230\u8c03\u7528\u7aef\u4e00\u8d77\u7f16\u8bd1\u3002")),(0,r.kt)("admonition",{title:"\u5907\u6ce8",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"\u4ee5\u4e0a\u793a\u4f8b\uff0c\u4f1a\u751f\u6210\u4e0b\u5217\u4ee3\u7406\u4ee3\u7801\u3002")),(0,r.kt)("p",null,"\u3010\u751f\u6210\u7684\u4ee3\u7406\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'using TouchSocket.Rpc;\nusing System.Threading.Tasks;\nnamespace RpcProxy\n{\n public interface IMyRpcServer : IRemoteServer\n {\n ///<summary>\n ///\u767b\u5f55\n ///</summary>\n /// <exception cref="System.TimeoutException">\u8c03\u7528\u8d85\u65f6</exception>\n /// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc\u8c03\u7528\u5f02\u5e38</exception>\n /// <exception cref="System.Exception">\u5176\u4ed6\u5f02\u5e38</exception>\n System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default);\n ///<summary>\n ///\u767b\u5f55\n ///</summary>\n /// <exception cref="System.TimeoutException">\u8c03\u7528\u8d85\u65f6</exception>\n /// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc\u8c03\u7528\u5f02\u5e38</exception>\n /// <exception cref="System.Exception">\u5176\u4ed6\u5f02\u5e38</exception>\n Task<System.Boolean> LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default);\n\n }\n public class MyRpcServer : IMyRpcServer\n {\n public MyRpcServer(IRpcClient client)\n {\n this.Client = client;\n }\n public IRpcClient Client { get; private set; }\n ///<summary>\n ///\u767b\u5f55\n ///</summary>\n /// <exception cref="System.TimeoutException">\u8c03\u7528\u8d85\u65f6</exception>\n /// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc\u8c03\u7528\u5f02\u5e38</exception>\n /// <exception cref="System.Exception">\u5176\u4ed6\u5f02\u5e38</exception>\n public System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default)\n {\n if (Client == null)\n {\n throw new RpcException("IRpcClient\u4e3a\u7a7a\uff0c\u8bf7\u5148\u521d\u59cb\u5316\u6216\u8005\u8fdb\u884c\u8d4b\u503c");\n }\n if (Client.TryCanInvoke?.Invoke(Client) == false)\n {\n throw new RpcException("Rpc\u65e0\u6cd5\u6267\u884c\u3002");\n }\n object[] parameters = new object[] { account, password };\n System.Boolean returnData = Client.Invoke<System.Boolean>("Login", invokeOption, parameters);\n return returnData;\n }\n ///<summary>\n ///\u767b\u5f55\n ///</summary>\n public Task<System.Boolean> LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default)\n {\n if (Client == null)\n {\n throw new RpcException("IRpcClient\u4e3a\u7a7a\uff0c\u8bf7\u5148\u521d\u59cb\u5316\u6216\u8005\u8fdb\u884c\u8d4b\u503c");\n }\n if (Client.TryCanInvoke?.Invoke(Client) == false)\n {\n throw new RpcException("Rpc\u65e0\u6cd5\u6267\u884c\u3002");\n }\n object[] parameters = new object[] { account, password };\n return Client.InvokeAsync<System.Boolean>("Login", invokeOption, parameters);\n }\n }\n public static class MyRpcServerExtensions\n {\n ///<summary>\n ///\u767b\u5f55\n ///</summary>\n /// <exception cref="System.TimeoutException">\u8c03\u7528\u8d85\u65f6</exception>\n /// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc\u8c03\u7528\u5f02\u5e38</exception>\n /// <exception cref="System.Exception">\u5176\u4ed6\u5f02\u5e38</exception>\n public static System.Boolean Login<TClient>(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient :\n TouchSocket.Rpc.IRpcClient\n {\n if (client.TryCanInvoke?.Invoke(client) == false)\n {\n throw new RpcException("Rpc\u65e0\u6cd5\u6267\u884c\u3002");\n }\n object[] parameters = new object[] { account, password };\n System.Boolean returnData = client.Invoke<System.Boolean>("Login", invokeOption, parameters);\n return returnData;\n }\n ///<summary>\n ///\u767b\u5f55\n ///</summary>\n public static Task<System.Boolean> LoginAsync<TClient>(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient :\n TouchSocket.Rpc.IRpcClient\n {\n if (client.TryCanInvoke?.Invoke(client) == false)\n {\n throw new RpcException("Rpc\u65e0\u6cd5\u6267\u884c\u3002");\n }\n object[] parameters = new object[] { account, password };\n return client.InvokeAsync<System.Boolean>("Login", invokeOption, parameters);\n }\n }\n}\n\n')),(0,r.kt)("p",null,"\u4f7f\u7528\u4ee3\u7406\u6269\u5c55\u76f4\u63a5\u8c03\u7528\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClient client = new TcpTouchRpcClient();\nclient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("127.0.0.1:7789")\n .SetVerifyToken("TouchRpc"));\nclient.Connect();\n\nbool result = client.Login(123, "abc");//Login\u662f\u6269\u5c55\u65b9\u6cd5\u3002\u53ef\u80fd\u9700\u8981\u989d\u5916\u6dfb\u52a0\u547d\u540d\u7a7a\u95f4\u3002\n')),(0,r.kt)("h2",{id:"\u4e94\u53cd\u5411rpc"},"\u4e94\u3001\u53cd\u5411Rpc"),(0,r.kt)("p",null,"\u4e00\u822c\u7684rpc\u670d\u52a1\u90fd\u662f\u5ba2\u6237\u7aef\u53d1\u8d77\uff0c\u670d\u52a1\u5668\u54cd\u5e94\u3002\u4f46\u662f\u6709\u65f6\u5019\u4e5f\u9700\u8981\u670d\u52a1\u5668\u4e3b\u52a8\u8c03\u7528\u5ba2\u6237\u7aef\uff0c\u6240\u4ee5\u9700\u8981\u53cd\u5411rpc\u3002"),(0,r.kt)("h3",{id:"51-\u5b9a\u4e49\u53d1\u5e03\u53cd\u5411rpc\u670d\u52a1"},"5.1 \u5b9a\u4e49\u3001\u53d1\u5e03\u53cd\u5411RPC\u670d\u52a1"),(0,r.kt)("p",null,"\u5b9e\u9645\u4e0a\uff0c\u6240\u6709\u7684Rpc\u5ba2\u6237\u7aef\uff08",(0,r.kt)("strong",{parentName:"p"},"TcpTouchRpcClient"),"\u3001",(0,r.kt)("strong",{parentName:"p"},"UdpTouchRpc"),"\uff08\u4e0d\u533a\u5206\u5ba2\u6237\u7aef\uff09\u3001",(0,r.kt)("strong",{parentName:"p"},"HttpTouchRpcClient"),"\u3001",(0,r.kt)("strong",{parentName:"p"},"WSTouchRpcClient"),"\uff09\u4e5f\u5b9e\u73b0\u4e86",(0,r.kt)("strong",{parentName:"p"},"IRpcParser"),"\u63a5\u53e3\uff0c\u8fd9\u610f\u5473\u7740\u53cd\u5411RPC\u5176\u5b9e",(0,r.kt)("strong",{parentName:"p"},"\u4e5f\u662fRPC"),"\uff0c\u6240\u4ee5\uff0c\u6240\u6709\u64cd\u4f5c\u4e00\u6a21\u4e00\u6837\u3002\u56e0\u4e3a\u5f53\u5ba2\u6237\u7aef\u548c\u670d\u52a1\u5668\u5efa\u7acb\u8fde\u63a5\u4ee5\u540e\uff0c\u5c31\u4e0d\u518d\u533a\u5206\u8c01\u662f\u5ba2\u6237\u7aef\uff0c\u8c01\u662f\u670d\u52a1\u5668\u4e86\u3002\u53ea\u5173\u5fc3\uff0c",(0,r.kt)("strong",{parentName:"p"},"\u8c01\u80fd\u63d0\u4f9b\u670d\u52a1\uff0c\u8c01\u5728\u8c03\u7528\u670d\u52a1"),"\u3002"),(0,r.kt)("p",null,"\u4e0b\u5217\u5c31\u4ee5\u7b80\u5355\u7684\u793a\u4f8b\u4e0b\uff0c\u7531\u5ba2\u6237\u7aef\u58f0\u660e\u670d\u52a1\uff0c\u670d\u52a1\u5668\u8c03\u7528\u670d\u52a1\u3002"),(0,r.kt)("p",null,"\u5177\u4f53\u6b65\u9aa4\uff1a"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"\u5728",(0,r.kt)("strong",{parentName:"li"},"\u5ba2\u6237\u7aef\u9879\u76ee"),"\u4e2d\u5b9a\u4e49\u670d\u52a1"),(0,r.kt)("li",{parentName:"ol"},"\u7528",(0,r.kt)("strong",{parentName:"li"},"TouchRpc"),"\u6807\u8bb0")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'public class ReverseCallbackServer : RpcServer\n{\n [TouchRpc]\n public string SayHello(string name)\n {\n return $"{name},hi";\n }\n}\n')),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"\u3010\u5ba2\u6237\u7aef\u53d1\u5e03\u670d\u52a1\u3011"),"\n\u53d1\u5e03\u670d\u52a1\uff0c\u5b9e\u9645\u4e0a\u662f\u8ba9TcpTouchRpcClient\u4e5f\u62e5\u6709\u63d0\u4f9bRPC\u7684\u80fd\u529b\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'TcpTouchRpcClient client = new TcpTouchRpcClient();\nclient.Setup(new TouchSocketConfig()\n .SetRemoteIPHost("127.0.0.1:7789")\n .ConfigureContainer(a =>\n {\n a.AddConsoleLogger();\n a.AddFileLogger();\n })\n .ConfigureRpcStore(a =>\n {\n a.RegisterServer<ReverseCallbackServer>();\n })\n .SetVerifyToken("TouchRpc"));\nclient.Connect();\n')),(0,r.kt)("h3",{id:"52-\u8c03\u7528\u53cd\u5411rpc"},"5.2 \u8c03\u7528\u53cd\u5411RPC"),(0,r.kt)("p",null,"\u670d\u52a1\u5668\u56de\u8c03\u5ba2\u6237\u7aef\uff0c\u6700\u7ec8\u5fc5\u987b\u901a\u8fc7",(0,r.kt)("strong",{parentName:"p"},"\u670d\u52a1\u5668\u8f85\u52a9\u7c7b\u5ba2\u6237\u7aef"),"\uff08ISocketClient\u7684\u6d3e\u751f\u7c7b\uff09\uff0c\u4ee5TcpTouchRpcService\u4e3a\u4f8b\uff0c\u5176\u8f85\u52a9\u5ba2\u6237\u7aef\u4e3aTcpTouchRpcSocketClient\u3002"),(0,r.kt)("p",null,"\u56e0\u4e3a\uff0cTcpTouchRpcSocketClient\u5df2\u5b9e\u73b0IRpcClient\u63a5\u53e3\uff0c\u610f\u5473\u7740\uff0c\u53cd\u5411RPC\u4e5f\u53ef\u4ee5\u4f7f\u7528\u4ee3\u7406\u8c03\u7528\u3002\u6240\u6709\u7528\u6cd5\u548cRPC\u4e00\u81f4\u3002"),(0,r.kt)("p",null,"\u4e0b\u5217\u793a\u4f8b\u4ee5TcpTouchRpcSocketClient\u4e3a\u4f8b\uff0c\u5176\u4f59\u4e00\u81f4\u3002"),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"\u53cd\u5411RPC\u4e5f\u53ef\u4ee5\u4f7f\u7528\u4ee3\u7406\u8c03\u7528\u3002\u6240\u6709\u7528\u6cd5\u548cRPC\u4e00\u81f4\u3002")),(0,r.kt)("h3",{id:"521-\u901a\u8fc7\u670d\u52a1\u5668\u76f4\u63a5\u83b7\u53d6"},"5.2.1 \u901a\u8fc7\u670d\u52a1\u5668\u76f4\u63a5\u83b7\u53d6"),(0,r.kt)("p",null,"\u53ef\u4ee5\u83b7\u53d6\u6240\u6709\u7ec8\u7aef\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'foreach (var item in tcpTouchRpcService.GetClients())\n{\n client.Logger.Info(item.Invoke<string>("ReverseRpcConsoleApp.ReverseCallbackServer.SayHello".ToLower(), InvokeOption.WaitInvoke, "\u5f20\u4e09"));\n}\n')),(0,r.kt)("p",null,"\u4e5f\u53ef\u4ee5\u5148\u7b5b\u9009ID\uff0c\u7136\u540e\u518d\u8c03\u7528\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},'string id = tcpTouchRpcService.GetIDs().FirstOrDefault(a => a.Equals("\u7279\u5b9aid"));\nif (tcpTouchRpcService.TryGetSocketClient(id, out var rpcSocketClient))\n{\n rpcSocketClient.Invoke<string>("ReverseRpcConsoleApp.ReverseCallbackServer.SayHello".ToLower(), InvokeOption.WaitInvoke, "\u5f20\u4e09");\n}\n')),(0,r.kt)("h4",{id:"522-\u901a\u8fc7\u8c03\u7528\u4e0a\u4e0b\u6587\u83b7\u53d6"},"5.2.2 \u901a\u8fc7\u8c03\u7528\u4e0a\u4e0b\u6587\u83b7\u53d6"),(0,r.kt)("p",null,"\u5177\u4f53\u6b65\u9aa4"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"\u8bbe\u7f6e\u8c03\u7528\u4e0a\u4e0b\u6587"),(0,r.kt)("li",{parentName:"ol"},"\u4e0a\u4e0b\u6587\u7684Caller\uff0c\u5373\u4e3a\u670d\u52a1\u5668\u8f85\u52a9\u7c7b\u7ec8\u7aef\uff0c\u8fdb\u884c\u5f3a\u8f6c\u5373\u53ef\u3002")),(0,r.kt)("h2",{id:"\u516d\u5ba2\u6237\u7aef\u4e92call-rpc"},"\u516d\u3001\u5ba2\u6237\u7aef\u4e92Call RPC"),(0,r.kt)("p",null,"\u9664\u4e86\u6b63\u5411RPC\uff0c\u53cd\u5411RPC\uff0cTouchRpc\u8fd8\u652f\u6301",(0,r.kt)("strong",{parentName:"p"},"\u5ba2\u6237\u7aef"),"\u4e4b\u95f4\u4e92Call RPC\u3002\u670d\u52a1\u7684\u5b9a\u4e49\u4e0eRpc\u4e00\u6837\u3002"),(0,r.kt)("h3",{id:"61-\u4e92call-rpc"},"6.1 \u4e92Call RPC"),(0,r.kt)("p",null,"\u5ba2\u6237\u7aefA\u8c03\u7528\u5ba2\u6237\u7aefB\u7684\u65b9\u6cd5\uff0c\u9700\u8981\u77e5\u9053\u5bf9\u65b9\u7684",(0,r.kt)("strong",{parentName:"p"},"ID"),"\u3002\u548c",(0,r.kt)("strong",{parentName:"p"},"\u65b9\u6cd5\u540d"),"\u3002\u7136\u540e\u4f7f\u7528\u4e0b\u5217\u51fd\u6570\u8c03\u7528\u5373\u53ef\u3002"),(0,r.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"\u4e92Call RPC\u4e5f\u652f\u6301\u8c03\u7528\u4e0a\u4e0b\u6587\u3002")),(0,r.kt)("admonition",{title:"\u670d\u52a1\u5668\u6ce8\u610f",type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"\u5ba2\u6237\u7aef\u4e92Call\u7684\u65f6\u5019\uff0c\u6bcf\u4e2a\u8bf7\u6c42\uff0c\u90fd\u9700\u8981\u670d\u52a1\u540c\u610f\u8def\u7531\uff0c\u624d\u53ef\u4ee5\u88ab\u8f6c\u53d1\u3002\u6240\u4ee5\u670d\u52a1\u5668\u9700\u8981\u505a\u4e00\u4e9b\u5141\u8bb8\u64cd\u4f5c\u3002")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"internal class MyTouchRpcPlugin : TouchRpcPluginBase\n{\n protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)\n {\n if (e.RouterType== RouteType.Rpc)\n {\n e.IsPermitOperation = true;\n }\n base.OnRouting(client, e);\n }\n}\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/e5d5df95.1d148f38.js b/handbook/build/assets/js/e5d5df95.1d148f38.js new file mode 100644 index 000000000..34e92e311 --- /dev/null +++ b/handbook/build/assets/js/e5d5df95.1d148f38.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[4649],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),d=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},s=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=d(r),f=a,m=s["".concat(l,".").concat(f)]||s[f]||u[f]||o;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=s;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:a,i[1]=c;for(var d=2;d<o;d++)i[d]=r[d];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}s.displayName="MDXCreateElement"},8865:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const o={id:"dataforwarding",title:"\u6570\u636e\u8f6c\u53d1\u9879\u76ee"},i=void 0,c={unversionedId:"dataforwarding",id:"dataforwarding",title:"\u6570\u636e\u8f6c\u53d1\u9879\u76ee",description:"\u5b9a\u5236\u65b9",source:"@site/docs/dataforwarding.mdx",sourceDirName:".",slug:"/dataforwarding",permalink:"/touchsocket/docs/dataforwarding",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/dataforwarding.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675265724,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"dataforwarding",title:"\u6570\u636e\u8f6c\u53d1\u9879\u76ee"},sidebar:"docs",previous:{title:"\u6587\u4ef6\u540c\u6b65\u7cfb\u7edf",permalink:"/touchsocket/docs/filesynchronization"},next:{title:"Web\u6570\u636e\u8f6c\u53d1Winform\u9879\u76ee",permalink:"/touchsocket/docs/webdataforwarding"}},l={},d=[{value:"\u5b9a\u5236\u65b9",id:"\u5b9a\u5236\u65b9",level:2},{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u6280\u672f\u70b9",id:"\u6280\u672f\u70b9",level:2},{value:"\u6548\u679c",id:"\u6548\u679c",level:2}],p={toc:d};function u(e){let{components:t,...o}=e;return(0,a.kt)("wrapper",(0,n.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u5b9a\u5236\u65b9"},"\u5b9a\u5236\u65b9"),(0,a.kt)("p",null,"\u9091*\u7269\u8054\u6709\u9650\u516c\u53f8"),(0,a.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,a.kt)("p",null,"\u5e94\u8be5\u516c\u53f8\u8981\u6c42\uff0c\u5f00\u53d1\u4e00\u4e2a\u80fd\u591f\u8f6c\u53d1\u6570\u636e\u7684\u670d\u52a1\u5668\u3002\u6309\u7167\u4e00\u5b9a\u89c4\u5219\uff0c\u8bbe\u8ba1\u8f6c\u53d1\u89c4\u5219\u3002"),(0,a.kt)("h2",{id:"\u6280\u672f\u70b9"},"\u6280\u672f\u70b9"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"\u7f51\u7edc\u7f16\u7a0b")),(0,a.kt)("h2",{id:"\u6548\u679c"},"\u6548\u679c"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"image.png",src:r(508).Z,width:"1978",height:"1189"})))}u.isMDXComponent=!0},508:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/dataforwarding-1-700ae9bd774c6299f265e8106362a702.png"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/e782541c.36f93477.js b/handbook/build/assets/js/e782541c.36f93477.js new file mode 100644 index 000000000..bb549286c --- /dev/null +++ b/handbook/build/assets/js/e782541c.36f93477.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[2934],{3905:(t,n,a)=>{a.d(n,{Zo:()=>m,kt:()=>N});var e=a(7294);function l(t,n,a){return n in t?Object.defineProperty(t,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[n]=a,t}function r(t,n){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var e=Object.getOwnPropertySymbols(t);n&&(e=e.filter((function(n){return Object.getOwnPropertyDescriptor(t,n).enumerable}))),a.push.apply(a,e)}return a}function p(t){for(var n=1;n<arguments.length;n++){var a=null!=arguments[n]?arguments[n]:{};n%2?r(Object(a),!0).forEach((function(n){l(t,n,a[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(n){Object.defineProperty(t,n,Object.getOwnPropertyDescriptor(a,n))}))}return t}function i(t,n){if(null==t)return{};var a,e,l=function(t,n){if(null==t)return{};var a,e,l={},r=Object.keys(t);for(e=0;e<r.length;e++)a=r[e],n.indexOf(a)>=0||(l[a]=t[a]);return l}(t,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(e=0;e<r.length;e++)a=r[e],n.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(l[a]=t[a])}return l}var d=e.createContext({}),u=function(t){var n=e.useContext(d),a=n;return t&&(a="function"==typeof t?t(n):p(p({},n),t)),a},m=function(t){var n=u(t.components);return e.createElement(d.Provider,{value:n},t.children)},k={inlineCode:"code",wrapper:function(t){var n=t.children;return e.createElement(e.Fragment,{},n)}},g=e.forwardRef((function(t,n){var a=t.components,l=t.mdxType,r=t.originalType,d=t.parentName,m=i(t,["components","mdxType","originalType","parentName"]),g=u(a),N=l,o=g["".concat(d,".").concat(N)]||g[N]||k[N]||r;return a?e.createElement(o,p(p({ref:n},m),{},{components:a})):e.createElement(o,p({ref:n},m))}));function N(t,n){var a=arguments,l=n&&n.mdxType;if("string"==typeof t||l){var r=a.length,p=new Array(r);p[0]=g;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=t,i.mdxType="string"==typeof t?t:l,p[1]=i;for(var u=2;u<r;u++)p[u]=a[u];return e.createElement.apply(null,p)}return e.createElement.apply(null,a)}g.displayName="MDXCreateElement"},774:(t,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>p,default:()=>k,frontMatter:()=>r,metadata:()=>i,toc:()=>u});var e=a(7462),l=(a(7294),a(3905));const r={id:"udptransmitbigdata",title:"\u4f20\u8f93\u5927\u4e8e64K\u7684\u6570\u636e"},p=void 0,i={unversionedId:"udptransmitbigdata",id:"udptransmitbigdata",title:"\u4f20\u8f93\u5927\u4e8e64K\u7684\u6570\u636e",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/udptransmitbigdata.mdx",sourceDirName:".",slug:"/udptransmitbigdata",permalink:"/touchsocket/docs/udptransmitbigdata",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/udptransmitbigdata.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675572697,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"udptransmitbigdata",title:"\u4f20\u8f93\u5927\u4e8e64K\u7684\u6570\u636e"},sidebar:"docs",previous:{title:"\u521b\u5efaUdpSession",permalink:"/touchsocket/docs/createudpsession"},next:{title:"\u7ec4\u64ad\u3001\u5e7f\u64ad",permalink:"/touchsocket/docs/udpbroadcast"}},d={},u=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001\u4f7f\u7528",id:"\u4e8c\u4f7f\u7528",level:2},{value:"\u4e09\u3001\u539f\u7406",id:"\u4e09\u539f\u7406",level:2},{value:"3.1 \u6570\u636e\u683c\u5f0f",id:"31-\u6570\u636e\u683c\u5f0f",level:3}],m={toc:u};function k(t){let{components:n,...a}=t;return(0,l.kt)("wrapper",(0,e.Z)({},m,a,{components:n,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,l.kt)("p",null,"UDP\u7531\u4e8e\u81ea\u8eab\u9650\u5236\uff0c\u6bcf\u6b21\u53d1\u9001\u7684\u6570\u636e\u5305\u6700\u5927\u7ea664K\uff0c\u4f46\u662f\u5728\u5c40\u57df\u7f51\u5185\uff0c\u6709\u65f6\u5019\u5e0c\u671b\u4f20\u8f93\u66f4\u5927\u7684\u6570\u636e\u3002\u6240\u4ee5\u5fc5\u987b\u6709\u7b56\u7565\u53d1\u9001\u3002"),(0,l.kt)("p",null,"TouchSocket\u53ef\u901a\u8fc7\u7b80\u5355\u8bbe\u7f6e\uff0c\u5b9e\u73b0\u8be5\u529f\u80fd\u3002"),(0,l.kt)("h2",{id:"\u4e8c\u4f7f\u7528"},"\u4e8c\u3001\u4f7f\u7528"),(0,l.kt)("p",null,"\u53ea\u9700\u8981\u5728\u914d\u7f6e\u4e2d\uff0c\u8bbe\u7f6e\u5176\u9002\u914d\u5668\u4e3a",(0,l.kt)("strong",{parentName:"p"},"UdpPackageAdapter"),"\u7c7b\u578b\u5373\u53ef\uff08\u9ed8\u8ba4\u4e3a",(0,l.kt)("strong",{parentName:"p"},"NormalUdpDataHandlingAdapter"),"\uff09\u3002\u540c\u65f6\u53ef\u4ee5\u6839\u636e\u4f20\u8f93\u6570\u636e\u7684\u5927\u5c0f\uff0c\u4fee\u6539\u76f8\u5173\u5c5e\u6027\uff0c\u5982\uff1a",(0,l.kt)("strong",{parentName:"p"},"MTU"),"\uff0c",(0,l.kt)("strong",{parentName:"p"},"Timeout"),"\u7b49\u3002"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-csharp"},'UdpSession udpSession = new UdpSession();\nudpSession.Received += (endpoint, byteBlock, requestInfo) =>\n{\n\n};\n\nudpSession.Setup(new TouchSocketConfig()\n .SetBindIPHost(new IPHost($"127.0.0.1:7789"))\n .SetUdpDataHandlingAdapter(()=> new UdpPackageAdapter()));//\u52a0\u8f7d\u914d\u7f6e\nudpSession.Start();//\u542f\u52a8\n')),(0,l.kt)("admonition",{title:"\u6ce8\u610f",type:"caution"},(0,l.kt)("p",{parentName:"admonition"},(0,l.kt)("strong",{parentName:"p"},"\u6b64\u6a21\u5f0f\u4e0b\uff0c\u53d1\u9001\u7aef\u4e0e\u63a5\u6536\u7aef\u5747\u5fc5\u987b\u4e3aTouchSocket\uff08\u6216\u5b9e\u73b0\u76f8\u540c\u7b97\u6cd5\uff09\uff0c\u4e14\u4e3a\u76f8\u540c\u8bbe\u7f6e\u3002"))),(0,l.kt)("h2",{id:"\u4e09\u539f\u7406"},"\u4e09\u3001\u539f\u7406"),(0,l.kt)("p",null,"\u5728\u53d1\u9001\u65f6\uff0c\u4f1a\u5c06\u8981\u53d1\u9001\u7684\u6570\u636e\u5206\u5272\u6210MTU\u957f\u5ea6\u7684\u6570\u636e\u3002\u7136\u540e\u4e3a\u5176\u7f16\u53f7\uff0c\u7136\u540e\u53d1\u9001\uff0c\u6700\u540e\u7531\u63a5\u6536\u65b9\u91cd\u7ec4\u3002"),(0,l.kt)("h3",{id:"31-\u6570\u636e\u683c\u5f0f"},"3.1 \u6570\u636e\u683c\u5f0f"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"ID\uff1a\u7531\u96ea\u82b1\u7b97\u6cd5\u751f\u6210\uff0c\u5728\u5e76\u53d1\u8bf7\u6c42\u65f61\u6beb\u79d2\u4e2d\u6709400w\u5206\u4e4b\u4e00\u7684\u6982\u7387\u53d1\u751fID\u91cd\u590d\u3002\u4f46\u57fa\u672c\u53ef\u4ee5\u5ffd\u7565\u4e0d\u8ba1\u3002")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Bit"),(0,l.kt)("th",{parentName:"tr",align:null},"\u8bf4\u660e"),(0,l.kt)("th",{parentName:"tr",align:null},"7"),(0,l.kt)("th",{parentName:"tr",align:null},"6"),(0,l.kt)("th",{parentName:"tr",align:null},"5"),(0,l.kt)("th",{parentName:"tr",align:null},"4"),(0,l.kt)("th",{parentName:"tr",align:null},"3"),(0,l.kt)("th",{parentName:"tr",align:null},"2"),(0,l.kt)("th",{parentName:"tr",align:null},"1"),(0,l.kt)("th",{parentName:"tr",align:null},"0"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"\u534f\u8bae\u540d"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte1"),(0,l.kt)("td",{parentName:"tr",align:null},"PackageID\u4e3along\u7c7b\u578b\uff0c\u5360\u75288\u5b57\u8282\uff0c\u6807\u8bc6\u6570\u636e\u5305\u552f\u4e00\u6027\u3002"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte2"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte3"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte4"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte5"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte6"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte7"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte8"),(0,l.kt)("td",{parentName:"tr",align:null},"SN\u4e3aUshort\u53602\u5b57\u8282\uff0c\u6807\u8bc6\u5e27\u5e8f"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte9"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte10"),(0,l.kt)("td",{parentName:"tr",align:null},"flag\uff0c\u53601\u5b57\u8282\uff0c\u6700\u9ad8\u4f4d\u6807\u8bc6\u662f\u5426\u4e3a\u7ed3\u675f\uff0c\u5176\u4ed6\u4f4d\u4fdd\u7559\u3002"),(0,l.kt)("td",{parentName:"tr",align:null},"1"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte\uff1f"),(0,l.kt)("td",{parentName:"tr",align:null},"\u6709\u6548\u8f7d\u8377\u6570\u636e"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte^2"),(0,l.kt)("td",{parentName:"tr",align:null},"\u5f53\u4e0d\u4e3a\u7ec8\u7ed3\u5e27\u65f6\uff0c\u6b64\u5904\u4ecd\u7136\u4e3a\u8f7d\u8377\u6570\u636e\u3002\u5f53\u662f\u7ec8\u7ed3\u5e27\u65f6\uff0c\u5012\u6570\u4e24\u4e2a\u5b57\u8282\u4e3aCrc16\u6821\u9a8c\u3002"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"byte^1"),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null}),(0,l.kt)("td",{parentName:"tr",align:null})))))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/e7e0ef60.a120f8c2.js b/handbook/build/assets/js/e7e0ef60.a120f8c2.js new file mode 100644 index 000000000..87c932b52 --- /dev/null +++ b/handbook/build/assets/js/e7e0ef60.a120f8c2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[6746],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},p=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},l={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=u(r),f=a,y=d["".concat(s,".").concat(f)]||d[f]||l[f]||o;return r?n.createElement(y,c(c({ref:t},p),{},{components:r})):n.createElement(y,c({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:a,c[1]=i;for(var u=2;u<o;u++)c[u]=r[u];return n.createElement.apply(null,c)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},5869:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>c,default:()=>l,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var n=r(7462),a=(r(7294),r(3905));const o={id:"datasecurity",title:"\u6570\u636e\u52a0\u5bc6"},c=void 0,i={unversionedId:"datasecurity",id:"datasecurity",title:"\u6570\u636e\u52a0\u5bc6",description:"\u4e00\u30013DES",source:"@site/docs/datasecurity.mdx",sourceDirName:".",slug:"/datasecurity",permalink:"/touchsocket/docs/datasecurity",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/datasecurity.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675229490,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"datasecurity",title:"\u6570\u636e\u52a0\u5bc6"},sidebar:"docs",previous:{title:"\u5927\u5c0f\u7aef\u8f6c\u6362\u5668",permalink:"/touchsocket/docs/touchsocketbitconverter"},next:{title:"\u65e5\u5fd7\u8bb0\u5f55\u5668",permalink:"/touchsocket/docs/ilog"}},s={},u=[{value:"\u4e00\u30013DES",id:"\u4e003des",level:2}],p={toc:u};function l(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u4e003des"},"\u4e00\u30013DES"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Nuget Package\uff1a"),(0,a.kt)("a",{parentName:"p",href:"https://www.nuget.org/packages/TouchSocket/"},"TouchSocket"),"\n\u3010\u52a0\u5bc6\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'var dataLocked = DataSecurity.EncryptDES(data, "12345678");//\u52a0\u5bc6\u53e3\u4ee4\uff0c\u957f\u5ea6\u4e3a8\u3002\n')),(0,a.kt)("p",null,"\u3010\u89e3\u5bc6\u3011"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'var newData = DataSecurity.DecryptDES(dataLocked, "12345678");//\u89e3\u5bc6\u53e3\u4ee4\uff0c\u548c\u52a0\u5bc6\u4e00\u81f4\u3002\n')))}l.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/eafaca75.9c10e3ec.js b/handbook/build/assets/js/eafaca75.9c10e3ec.js new file mode 100644 index 000000000..3062b329c --- /dev/null +++ b/handbook/build/assets/js/eafaca75.9c10e3ec.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1569],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>u});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function s(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?l(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):l(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function o(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)t=l[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)t=l[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),i=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},c=function(e){var n=i(e.components);return r.createElement(d.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},y=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,l=e.originalType,d=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),y=i(t),u=a,A=y["".concat(d,".").concat(u)]||y[u]||p[u]||l;return t?r.createElement(A,s(s({ref:n},c),{},{components:t})):r.createElement(A,s({ref:n},c))}));function u(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,s=new Array(l);s[0]=y;var o={};for(var d in n)hasOwnProperty.call(n,d)&&(o[d]=n[d]);o.originalType=e,o.mdxType="string"==typeof e?e:a,s[1]=o;for(var i=2;i<l;i++)s[i]=t[i];return r.createElement.apply(null,s)}return r.createElement.apply(null,t)}y.displayName="MDXCreateElement"},5786:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>s,default:()=>p,frontMatter:()=>l,metadata:()=>o,toc:()=>i});var r=t(7462),a=(t(7294),t(3905));const l={id:"datahandleadapter",title:"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668"},s=void 0,o={unversionedId:"datahandleadapter",id:"datahandleadapter",title:"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668",description:"\u8bf4\u660e",source:"@site/docs/datahandleadapter.mdx",sourceDirName:".",slug:"/datahandleadapter",permalink:"/touchsocket/docs/datahandleadapter",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/datahandleadapter.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675577572,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"datahandleadapter",title:"\u539f\u59cb\u81ea\u5b9a\u4e49\u9002\u914d\u5668"},sidebar:"docs",previous:{title:"\u7ec8\u6b62\u56e0\u5b50\u5206\u5272\u6570\u636e\u5904\u7406\u9002\u914d\u5668",permalink:"/touchsocket/docs/terminatorpackageadapter"},next:{title:"\u7528\u6237\u81ea\u5b9a\u4e49\u9002\u914d\u5668",permalink:"/touchsocket/docs/customdatahandlingadapter"}},d={},i=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u539f\u59cbDataHandlingAdapter",id:"\u539f\u59cbdatahandlingadapter",level:2},{value:"\u5b9e\u73b0",id:"\u5b9e\u73b0",level:2},{value:"\u4f7f\u7528\u81ea\u5b9a\u4e49\u9002\u914d\u5668",id:"\u4f7f\u7528\u81ea\u5b9a\u4e49\u9002\u914d\u5668",level:2},{value:"\u5c01\u88c5\u51fd\u6570\u53ca\u5206\u7247\u53d1\u9001\u610f\u4e49",id:"\u5c01\u88c5\u51fd\u6570\u53ca\u5206\u7247\u53d1\u9001\u610f\u4e49",level:2}],c={toc:i};function p(e){let{components:n,...l}=e;return(0,a.kt)("wrapper",(0,r.Z)({},c,l,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"\u81ea\u5b9a\u4e49\u9002\u914d\u5668\u53ef\u4ece\u4e24\u4e2a\u65b9\u9762\u5165\u624b\u3002")),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u5219\u662f\u76f4\u63a5\u4eceDataHandlingAdapter\u7ee7\u627f\uff0c\u6b64\u65f6\u53ef\u4ee5\u63a5\u89e6\u5230\u6700\u539f\u59cb\u7684TCP\u6570\u636e\uff0c\u53ef\u4ee5\u81ea\u5b9a\u5b9e\u73b0\u6570\u636e\u7684\u7ee7\u7eed\u6295\u9012\u65b9\u5f0f\u3002\u4f46\u4e00\u822c\u5b9e\u73b0\u7b97\u6cd5\u6bd4\u8f83\u56f0\u96be\uff0c\u56e0\u4e3a\u6240\u8003\u8651\u7684\u60c5\u51b5\u6bd4\u8f83\u591a\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u5219\u662f\u4eceCustomDataHandlingAdapter\uff08\u7528\u6237\u5feb\u6377\u81ea\u5b9a\u4e49\u9002\u914d\u5668\uff09\u7ee7\u627f\uff0c\u6b64\u65f6\u6570\u636e\u7684\u6295\u9012\u5fc5\u987b\u901a\u8fc7IRequestInfo\uff0cByteBlock\u5c06\u4e3anull\u3002\u6240\u9700\u8003\u8651\u7684\u60c5\u51b5\u6bd4\u8f83\u5355\u4e00\uff0c\u5bf9\u4e8e\u6570\u636e\u7684\u5904\u7406\u4e5f\u6bd4\u8f83\u7b80\u5355\u3002 ",(0,a.kt)("a",{name:"TwJUE"}))),(0,a.kt)("h2",{id:"\u539f\u59cbdatahandlingadapter"},"\u539f\u59cbDataHandlingAdapter"),(0,a.kt)("p",null,"\u81ea\u5df1\u5b9e\u73b0\u9002\u914d\u5668\uff0c\u7136\u540e\u4f7f\u5176\u5de5\u4f5c\u3002\u4f8b\u5982\uff1a\u5047\u8bbe\u5982\u4e0b\u6570\u636e\u683c\u5f0f\uff0c\u7b2c\u4e00\u4e2a\u5b57\u8282\u8868\u793a\u6574\u4e2a\u6570\u636e\u957f\u5ea6\uff08\u5305\u62ec\u6570\u636e\u7c7b\u578b\u548c\u6307\u4ee4\u7c7b\u578b\uff09\uff0c\u7b2c\u4e8c\u5b57\u8282\u8868\u793a\u6570\u636e\u7c7b\u578b\uff0c\u7b2c\u4e09\u5b57\u8282\u8868\u793a\u6307\u4ee4\u7c7b\u578b\uff0c\u540e\u7eed\u5b57\u8282\u8868\u793a\u5176\u4ed6\u6570\u636e\u3002"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"\u5176\u6b21\uff0c\u5e0c\u671b\u5728\u53d1\u9001\u65f6\uff0c\u53ea\u4f20\u5165\u6570\u636e\u7c7b\u578b\uff0c\u6307\u4ee4\u7c7b\u578b\u548c\u5176\u4ed6\u6570\u636e\uff0c\u800c\u6570\u636e\u957f\u5ea6\u5219\u7531\u9002\u914d\u5668\u81ea\u884c\u5c01\u88c5\u3002\u6700\u540e\uff0c\u5e0c\u671b\u5728\u63a5\u6536\u7aef\u6bcf\u6b21\u80fd\u63a5\u6536\u5230\u4e00\u4e2a\u5b8c\u6574\u7684\u6570\u636e\u3002")),(0,a.kt)("img",{src:t(3718).Z}),(0,a.kt)("h2",{id:"\u5b9e\u73b0"},"\u5b9e\u73b0"),(0,a.kt)("p",null,"\u9996\u5148\uff0c\u521b\u5efa\u7c7b\uff0c\u7ee7\u627f\u81ea",(0,a.kt)("inlineCode",{parentName:"p"},"DataHandlingAdapter"),"\uff0c\u7136\u540e\u5b9e\u73b0\u5bf9\u5e94\u5c5e\u6027\uff0c\u53ca\u65b9\u6cd5\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyDataHandleAdapter : DataHandlingAdapter\n{\n public override bool CanSplicingSend => false;\n\n public override bool CanSendRequestInfo => false;\n\n protected override void PreviewReceived(ByteBlock byteBlock)\n {\n \n }\n\n protected override void PreviewSend(byte[] buffer, int offset, int length)\n {\n \n }\n\n protected override void PreviewSend(IRequestInfo requestInfo)\n {\n \n }\n\n protected override void PreviewSend(IList<ArraySegment<byte>> transferBytes)\n {\n \n }\n\n protected override void Reset()\n {\n \n }\n}\n")),(0,a.kt)("p",null,"\u3010\u5c01\u88c5\u53d1\u9001\u6570\u636e\u957f\u5ea6\u3011\n\u5c01\u88c5\u53d1\u9001\u6570\u636e\u65f6\uff0c\u6bd4\u8f83\u7b80\u5355\uff0c\u793a\u4f8b\u5982\u4e0b\uff1a"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'protected override void PreviewSend(byte[] buffer, int offset, int length)\n{\n int dataLen = length - offset;//\u5148\u83b7\u53d6\u9700\u8981\u53d1\u9001\u7684\u5b9e\u9645\u6570\u636e\u957f\u5ea6\n if (dataLen > byte.MaxValue)//\u8d85\u957f\u5224\u65ad\n {\n throw new OverlengthException("\u53d1\u9001\u6570\u636e\u592a\u957f\u3002");\n }\n\n //\u4ece\u5185\u5b58\u6c60\u7533\u8bf7\u5185\u5b58\u5757\uff0c\u56e0\u4e3a\u6b64\u5904\u6570\u636e\u7edd\u4e0d\u8d85\u8fc7255\uff0c\u6240\u4ee5\u907f\u514d\u5185\u5b58\u6c60\u788e\u7247\u5316\uff0c\u6bcf\u6b21\u7533\u8bf764K\n //ByteBlock byteBlock = new ByteBlock(dataLen+1);//\u5b9e\u9645\u5199\u6cd5\u3002\n using (ByteBlock byteBlock = new ByteBlock(64 * 1024))\n {\n byteBlock.Write((byte)dataLen);//\u5148\u5199\u957f\u5ea6\n byteBlock.Write(buffer, offset, length);//\u518d\u5199\u6570\u636e\n this.GoSend(byteBlock.Buffer, 0, byteBlock.Len);\n }\n}\n')),(0,a.kt)("p",null,"\u3010\u89e3\u6790\u63a5\u6536\u6570\u636e\u3011\n\u4ece\u539f\u751f\u9002\u914d\u5668\u89e3\u5c01\u6570\u636e\uff0c\u9700\u8981\u8003\u8651\u7684\u60c5\u51b5\u6bd4\u8f83\u591a\u3002\u5728\u672c\u793a\u4f8b\u4e2d\uff0c\u9700\u8981\u8003\u8651\u4ee5\u4e0b\u60c5\u51b5\uff1a"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"\u4e00\u6b21\u521a\u597d\u63a5\u6536\u4e00\u4e2a\u6570\u636e\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u4e00\u6b21\u521a\u597d\u63a5\u6536\u4e86\u591a\u4e2a\u6570\u636e\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u4e00\u6b21\u63a5\u6536\u4e86\u591a\u4e2a\u6570\u636e\uff0c\u4f46\u6700\u540e\u4e00\u4e2a\u6570\u636e\u4e0d\u5b8c\u6574\u3002"),(0,a.kt)("li",{parentName:"ol"},"\u4e00\u6b21\u672a\u63a5\u6536\u5b8c\u4e00\u4e2a\u6570\u636e\u3002")),(0,a.kt)("p",null,"\u7efc\u4e0a\uff0c\u60c5\u51b5\u6bd4\u8f83\u590d\u6742\uff0c\u6240\u4ee5\u5c31\u5fc5\u987b\u81ea\u5df1\u505a\u63a5\u6536\u6570\u636e\u7684\u7f13\u5b58\u5bb9\u5668\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'/// <summary>\n/// \u4e34\u65f6\u5305\uff0c\u6b64\u5305\u4ec5\u5f53\u524d\u5b9e\u4f8b\u50a8\u5b58\n/// </summary>\nprivate ByteBlock tempByteBlock;\n\n/// <summary>\n/// \u5305\u5269\u4f59\u957f\u5ea6\n/// </summary>\nprivate byte surPlusLength;\nprotected override void PreviewReceived(ByteBlock byteBlock)\n{\n byte[] buffer = byteBlock.Buffer;\n int r = byteBlock.Len;\n if (this.tempByteBlock == null)//\u5982\u679c\u6ca1\u6709\u4e34\u65f6\u5305\uff0c\u5219\u76f4\u63a5\u5206\u5305\u3002\n {\n SplitPackage(buffer, 0, r);\n }\n else\n {\n if (surPlusLength == r)//\u63a5\u6536\u957f\u5ea6\u6b63\u597d\u7b49\u4e8e\u5269\u4f59\u957f\u5ea6\uff0c\u7ec4\u5408\u5b8c\u6570\u636e\u4ee5\u540e\u76f4\u63a5\u5904\u7406\u6570\u636e\u3002\n {\n this.tempByteBlock.Write(buffer, 0, surPlusLength);\n PreviewHandle(this.tempByteBlock);\n this.tempByteBlock = null;\n surPlusLength = 0;\n }\n else if (surPlusLength < r)//\u63a5\u6536\u957f\u5ea6\u5927\u4e8e\u5269\u4f59\u957f\u5ea6\uff0c\u5148\u7ec4\u5408\u5305\uff0c\u7136\u540e\u5904\u7406\u5305\uff0c\u7136\u540e\u5c06\u5269\u4e0b\u7684\u5206\u5305\u3002\n {\n this.tempByteBlock.Write(buffer, 0, surPlusLength);\n PreviewHandle(this.tempByteBlock);\n this.tempByteBlock = null;\n SplitPackage(buffer, surPlusLength, r);\n }\n else//\u63a5\u6536\u957f\u5ea6\u5c0f\u4e8e\u5269\u4f59\u957f\u5ea6\uff0c\u65e0\u6cd5\u5904\u7406\u5305\uff0c\u6240\u4ee5\u5fc5\u987b\u5148\u7ec4\u5408\u5305\uff0c\u7136\u540e\u7b49\u4e0b\u6b21\u63a5\u6536\u3002\n {\n this.tempByteBlock.Write(buffer, 0, r);\n surPlusLength -= (byte)r;\n }\n }\n}\n/// <summary>\n/// \u5206\u89e3\u5305\n/// </summary>\n/// <param name="dataBuffer"></param>\n/// <param name="index"></param>\n/// <param name="r"></param>\nprivate void SplitPackage(byte[] dataBuffer, int index, int r)\n{\n while (index < r)\n {\n byte length = dataBuffer[index];\n int recedSurPlusLength = r - index - 1;\n if (recedSurPlusLength >= length)\n {\n ByteBlock byteBlock = new ByteBlock(length);\n byteBlock.Write(dataBuffer, index + 1, length);\n PreviewHandle(byteBlock);\n surPlusLength = 0;\n }\n else//\u534a\u5305\n {\n this.tempByteBlock = new ByteBlock(length);\n surPlusLength = (byte)(length - recedSurPlusLength);\n this.tempByteBlock.Write(dataBuffer, index + 1, recedSurPlusLength);\n }\n index += length + 1;\n }\n}\n/// <summary>\n/// \u5904\u7406\u6570\u636e\n/// </summary>\n/// <param name="byteBlock"></param>\nprivate void PreviewHandle(ByteBlock byteBlock)\n{\n try\n {\n this.GoReceived(byteBlock, null);\n }\n finally\n {\n byteBlock.Dispose();//\u5728\u6846\u67b6\u91cc\u9762\u5c06\u5185\u5b58\u5757\u91ca\u653e\n }\n}\n')),(0,a.kt)("h2",{id:"\u4f7f\u7528\u81ea\u5b9a\u4e49\u9002\u914d\u5668"},"\u4f7f\u7528\u81ea\u5b9a\u4e49\u9002\u914d\u5668"),(0,a.kt)("p",null,"\u81ea\u5b9a\u4e49\u9002\u914d\u5668\u7684\u4f7f\u7528\u548c\u9884\u8bbe\u7684\u9002\u914d\u5668\u4e00\u6837\u3002\u4e0d\u8fc7\u5728\u8be5\u6848\u4f8b\u4e2d\uff0c\u53d1\u9001\u6570\u636e\u65f6\uff0c\u5e94\u5f53\u4f20\u5165\u4e09\u4e2a\u6709\u6548\u503c\uff0c\u5206\u522b\u4e3a",(0,a.kt)("strong",{parentName:"p"},"\u6570\u636e\u7c7b\u578b"),"\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u6307\u4ee4\u7c7b\u578b"),"\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u5176\u4ed6\u6570\u636e"),"\u3002 ",(0,a.kt)("a",{name:"V3gQW"})),(0,a.kt)("h2",{id:"\u5c01\u88c5\u51fd\u6570\u53ca\u5206\u7247\u53d1\u9001\u610f\u4e49"},"\u5c01\u88c5\u51fd\u6570\u53ca\u5206\u7247\u53d1\u9001\u610f\u4e49"),(0,a.kt)("p",null,"\u5728\u4e0a\u8ff0\u6848\u4f8b\u4e2d\uff0c\u53d1\u9001\u6570\u636e\u65f6\u5e94\u5f53\u4f20\u5165",(0,a.kt)("strong",{parentName:"p"},"\u6570\u636e\u7c7b\u578b"),"\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u6307\u4ee4\u7c7b\u578b"),"\uff0c",(0,a.kt)("strong",{parentName:"p"},"\u5176\u4ed6\u6570\u636e"),"\u4e09\u4e2a\u6709\u6548\u503c\uff0c\u800c\u5728RRQM\u4e2d\uff0c\u53d1\u9001\u51fd\u6570\u4ec5\u6709Send\uff08\u548c\u91cd\u8f7d\uff09\uff0c\u8fd9\u65e0\u7591\u9700\u8981\u6211\u4eec\u81ea\u5df1\u5c01\u88c5",(0,a.kt)("inlineCode",{parentName:"p"},"\u5176\u4ed6\u65b9\u6cd5"),"\u3002\n",(0,a.kt)("strong",{parentName:"p"},(0,a.kt)("em",{parentName:"strong"},"\u5047\u8bbe\u4ee5\u4e0b\u60c5\u51b5\u9700\u8981\u5b9e\u73b0\uff1a"))),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"\u6570\u636e\u7c7b\u578b\u6709\u4e24\u79cd\uff0c\u5206\u522b\u4e3aUp\uff081\uff09\uff0cDown\uff080\uff09\u3002\u6307\u4ee4\u7c7b\u578b\u6709\u4e24\u79cd\uff0c\u5206\u522b\u4e3aGo\uff081\uff09\u3001Hold\uff080\uff09\u3002\u6570\u636e\u7c7b\u578b\u548c\u6307\u4ee4\u7c7b\u578b\u53ef\u4ee5\u4efb\u610f\u7ec4\u5408\uff0c\u4e14\u5747\u53ef\u643a\u5e26\u5176\u4ed6\u6570\u636e\u3002")),(0,a.kt)("p",null,"\u9762\u5bf9\u4e0a\u8ff0\u60c5\u51b5\uff0c\u6211\u4eec\u53ef\u4ee5\u5c01\u88c5\u4ee5\u4e0b\u51fd\u6570\u4f7f\u7528\uff1a"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MySocketClient : SimpleSocketClient\n{\n public void Up_Go_Send(byte[] data)\n {\n ByteBlock byteBlock = new ByteBlock(this.BufferLength);//\u5185\u5b58\u6c60\u5b9e\u73b0\uff0c\u53ef\u4ee5\u76f4\u63a5new byte[].\n byteBlock.Write((byte)1);\n byteBlock.Write((byte)1);\n byteBlock.Write(data);\n try\n {\n this.Send(byteBlock);\n }\n finally\n {\n byteBlock.Dispose();\n }\n }\n public void Down_Go_Send(byte[] data)\n {\n ByteBlock byteBlock = new ByteBlock(this.BufferLength);//\u5185\u5b58\u6c60\u5b9e\u73b0\uff0c\u53ef\u4ee5\u76f4\u63a5new byte[].\n byteBlock.Write((byte)0);\n byteBlock.Write((byte)1);\n byteBlock.Write(data);\n try\n {\n this.Send(byteBlock);\n }\n finally\n {\n byteBlock.Dispose();\n }\n }\n public void Up_Hold_Send(byte[] data)\n {\n ByteBlock byteBlock = new ByteBlock(this.BufferLength);//\u5185\u5b58\u6c60\u5b9e\u73b0\uff0c\u53ef\u4ee5\u76f4\u63a5new byte[].\n byteBlock.Write((byte)1);\n byteBlock.Write((byte)0);\n byteBlock.Write(data);\n try\n {\n this.Send(byteBlock);\n }\n finally\n {\n byteBlock.Dispose();\n }\n }\n public void Down_Hold_Send(byte[] data)\n {\n ByteBlock byteBlock = new ByteBlock(this.BufferLength);//\u5185\u5b58\u6c60\u5b9e\u73b0\uff0c\u53ef\u4ee5\u76f4\u63a5new byte[].\n byteBlock.Write((byte)0);\n byteBlock.Write((byte)0);\n byteBlock.Write(data);\n try\n {\n this.Send(byteBlock);\n }\n finally\n {\n byteBlock.Dispose();\n }\n }\n}\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},(0,a.kt)("em",{parentName:"strong"},"\u4e3a\u4ec0\u4e48\u8981\u5206\u7247\u53d1\u9001\uff1f\uff1f"))),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"\u5728\u793a\u4f8b\u4ee3\u7801\u4e2d\u4e0d\u96be\u770b\u51fa\uff0c\u5c01\u88c5\u7684\u51fd\u6570\u5c06",(0,a.kt)("strong",{parentName:"p"},"\u53d1\u9001\u6570\u636e"),"\u8fdb\u884c\u4e86",(0,a.kt)("strong",{parentName:"p"},"Write"),"\u64cd\u4f5c\uff08\u76f8\u5f53\u4e8eCopy\uff09\uff0c\u8fd9\u65e0\u7591\u662f\u6d88\u8017\u6027\u80fd\u7684\u3002\u53ea\u662f\u5728\u8be5\u6848\u4f8b\u4e2d\uff0c\u590d\u5236\u7684\u6570\u636e\u6700\u5927\u4e3a255\uff0c\u611f\u89c9\u4f18\u5316\u6548\u679c\u751a\u5fae\uff0c\u5018\u82e5\u6211\u4eec\u9700\u8981\u53d1\u9001\u7684\u6570\u636e\u662f1Mb\uff0c\u90a3\u5c31\u76f8\u5f53\u4e8e\u5728\u5c01\u88c5\u6570\u636e\u65f6\uff0c\u56e0\u4e3a",(0,a.kt)("strong",{parentName:"p"},"\u524d\u4e24\u4e2a\u5b57\u8282"),"\u7684\u5b58\u5728\u800c\u590d\u52361Mb\u7684\u6570\u636e\uff08\u51a4\u6b7b\u4e86\uff09\uff0c\u7136\u540e\u5728\u9002\u914d\u5668\u4e2d\u8fd8\u9700\u8981\u56e0\u4e3a",(0,a.kt)("strong",{parentName:"p"},"\u6570\u636e\u5305\u5934"),"\uff0c\u518d\u590d\u5236\u4e00\u6b21\u3002")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},(0,a.kt)("em",{parentName:"strong"},"\u4f18\u5316\u3002\u3002\u3002")),"\n\u6240\u4ee5\u6211\u4eec\u5728\u5c01\u88c5\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528\u5206\u7247\u53d1\u9001\uff0c\u4f46\u662f\u540c\u65f6\u4e5f\u9700\u8981\u9002\u914d\u5668\u652f\u6301\u3002\u4e0d\u7136\u5185\u90e8\u4f1a\u51fa\u9519\u3002"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'protected override void PreviewSend(IList<ArraySegment<byte>> transferBytes)\n{\n int dataLen = 0;\n foreach (var item in transferBytes)\n {\n dataLen += item.Count;\n }\n if (dataLen > byte.MaxValue)//\u8d85\u957f\u5224\u65ad\n {\n throw new OverlengthException("\u53d1\u9001\u6570\u636e\u592a\u957f\u3002");\n }\n\n //\u4ece\u5185\u5b58\u6c60\u7533\u8bf7\u5185\u5b58\u5757\uff0c\u56e0\u4e3a\u6b64\u5904\u6570\u636e\u7edd\u4e0d\u8d85\u8fc7255\uff0c\u6240\u4ee5\u907f\u514d\u5185\u5b58\u6c60\u788e\u7247\u5316\uff0c\u6bcf\u6b21\u7533\u8bf764K\n //ByteBlock byteBlock = new ByteBlock(dataLen+1);//\u5b9e\u9645\u5199\u6cd5\u3002\n\n using (ByteBlock byteBlock = new ByteBlock(64 * 1024))\n {\n byteBlock.Write((byte)dataLen);//\u5148\u5199\u957f\u5ea6\n foreach (var item in transferBytes)\n {\n byteBlock.Write(item.Array, item.Offset, item.Count);//\u4f9d\u6b21\u5199\u5165\n }\n this.GoSend(byteBlock.Buffer, 0, byteBlock.Len);\n }\n}\n')),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},(0,a.kt)("em",{parentName:"strong"},"\u91cd\u65b0\u5c01\u88c5\u51fd\u6570\u3002\u3002\u3002"))),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public void Up_Go_SplicingSend(byte[] data)\n{\n List<TransferByte> transferBytes = new List<TransferByte>();\n transferBytes.Add(new TransferByte(new byte[] { 1}));\n transferBytes.Add(new TransferByte(new byte[] { 1}));\n transferBytes.Add(new TransferByte(data));\n this.Send(transferBytes);\n}\npublic void Down_Go_SplicingSend(byte[] data)\n{\n List<TransferByte> transferBytes = new List<TransferByte>();\n transferBytes.Add(new TransferByte(new byte[] { 0 }));\n transferBytes.Add(new TransferByte(new byte[] { 1 }));\n transferBytes.Add(new TransferByte(data));\n this.Send(transferBytes);\n}\npublic void Up_Hold_SplicingSend(byte[] data)\n{\n List<TransferByte> transferBytes = new List<TransferByte>();\n transferBytes.Add(new TransferByte(new byte[] { 1 }));\n transferBytes.Add(new TransferByte(new byte[] { 0 }));\n transferBytes.Add(new TransferByte(data));\n this.Send(transferBytes);\n}\npublic void Down_Hold_SplicingSend(byte[] data)\n{\n List<TransferByte> transferBytes = new List<TransferByte>();\n transferBytes.Add(new TransferByte(new byte[] { 0 }));\n transferBytes.Add(new TransferByte(new byte[] { 0 }));\n transferBytes.Add(new TransferByte(data));\n this.Send(transferBytes);\n}\n")))}p.isMDXComponent=!0},3718:(e,n,t)=>{t.d(n,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA7MAAAEECAMAAADNkJO5AAAAzFBMVEX////v7+7n5+fc3NyZ2ev/fib29PS15xwAAADtHCT9/fynp6fFxcXV1dW4/f+enp76+PgHC2aRkZHOzs67u7ug5vja4ufbkTqysrJ/f3/u8jmIiIj//9/k///8qcb5cjH73//+/7zvX6y377H7p1X/8ZzP+f//znfd6e3zu//x//+86HLW6iT/3Zj/iniEhIS72+8EUqPC8+H0Nm3/lZ3993Lb/v9mFwC3ZgD7v9//jzH/2LT/qyb3SiQnCiCRZjrtHFBYkcNmt//JkWZqAa6EAAAQQ0lEQVR42uydC1viOB9HS7koUbEO4u66yE1uIrIdUXeNl3Xe/f7f6U3SizrqSDOgzXDO6FCQOM/TX07+SVodzwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgJWyCQCfBs4C4CwA4CwA4CzAWjlbtcQ0LmXGNCsvjnn/BsAvBc4C4CzOAuAszgLgLADO4iwAzuIsAM4C4CzOAuAszgLgLADO4iwAzuIsAM4C4CzOAuAszgLgLADO4iwAzuIsAM7iLOAszgLgLM4C4CzOAs7iLADO4iwAzuIs4CzOAuAszgLgbLm/V5M4Czhr4+xor/YTzqrWFs7e/Lu5V6POAs5aOGvssXbWtM7srGq1ibOAszbOxvZYOhu3zuasvPnbfA1nAWczO5vaY+Vs2jpjnT2739wr/YazgLPZnU3tsXI2bZ3V2b1SuYyzgLM2zu6VqlVrZ0d76q/3nZVPPh/BWcBZ233j335mDypjnZUvnE1txlnA2Rw6S50FnMVZyMp/f3y7av53v3n/NeRk4Oz7zkqc/Wz+2dzrRnv+9//jbODsK87K8osdKJz9XGe//n3/rbjzr75Qx+nA2R/UWfnS2UefcfYDnY1dVQcUWpxlPeuEs5GqZ/eb3zgdOLuAsxJnP3s9G02J1ar2K6cDZ793Vr4+PcbZT13PDnEWZ39YZyVz45zV2Sucxdn358Zv3bsY3wmFsx9ZZ3EWZ9mDYm4Mv6yz8omzEmc/d258j7M4+/rP9VBnmRvjrGN1Vr65GYWzOIuzrv2uVImznzY3xlmcXWjfWFJnqbM462ydlTgLOJs3ZyX/jwDgrKt1Vj47eDZbxlnA2Rw5K8s/XsxSZwFn+T+2AHDWxtn3K6zEWcDZvNdZSZ0FnHVvbvzd7ynHWcDZXF3rkaxnAWcdvdYjXy+5OAs4y74xAM4uy9mXNx/jLOBs7uuspM4CzuZ1D0q+uw2Fs4Czuayz8q2Ki7OAs9xTAYCzP3Pv4mveSpwFnOV3ywDg7FJ+Fo89KMBZJ+usxFnAWXeclW/Ki7OAs3n+fVCSOgs4+56zAPAp4CwAzgIAzgIAzgKsi7NLQOg/C+LpD5uBxQMAAAAAAAAAgF+TapVzQOrgVHjW8ZH7OqYOeQjPMj67hvQVt1MHh9Oza0lfwVlwylk6C87CUtKr4iypg1PhVT8qd/qK46mDw+lVf8JZOgvOgiPO0llwFpYTnkV8OLuOqYPD6dm1pK/gLDjlLJ0FZ2FZ4VletMHZ9Uod8pFe+rD63OkrbqcOzjubtSUDPM7CMiZJVjc62DtLZ3E3dcjLgGthkV3uOOt26uC8s1lbMsDjLCw1veqHOEtncTd1yE942S2yyh1nHU8dHE7PriUDPM6CU87SWXAWlhBe9eUxzpI65H7AzWiRXe4463bq4LyzWVsywOMsLG+SlNEie2fpLO6mDvkacLPv/2bOHWfdTh2cdzZrSwZ4nIVlTpIyWWTvLJ3F3dQhbwNuBovscsdZt1MH553N2pIBHmfBQWfpLDgLS1vYeJYXbXB2TVKH/A24C6dnlzvOup06OO9s1pYM8DgLS58kLbotZO8sncXd1CGPA+6CFtnljrNupw7OO5u1JQM8zsLyJ0kLWmTvLJ3F3dQhnwPu4vu/mXPHWbdTB+edzdqSAR5nYSmzpFduJrTZAF7QWTqLu6lDfsL7/ofjFr3QmjF3nHU8dXA4PbuWDPA4C045S2fBWVhefDbLWZxds9QhVxFmXVva5I6zrqcOzqeXtSUDPM6CW87SWXAWcBZwlvRwltQBZ+ksOAs4CzhLejhL6oCzdBacBZwFnCU9nCV1zgnO0llwFnAWcBZwltSJAWfpLDgLOAs4CzhL6sSAs3QWnAWcBZwFnAViwFmcxVnAWcBZwFkgBpzFWZwFnAWcBZwFYiA9nMVZwFnAWcBZIAbSw1mcBZwFnAWcBWIgPZzFWcBZwFnAWSAG0sNZUoccpfcMnCV1+IWdzdoSZ3EWHHSWzoKzgLOAs2sbn4ezpA7kjrMADPAAAAAAAAAAAAAAAABribhpNedB/2TU08/OeqIdXXY58UT7RL8UfUF/7aHD6QLIgbT963m/5fVPIme9tjFT+1o+Eepg7uun6SXUHmcM4JOVNSq2jI/t6sP8aZ0Vo2pL6DcphZXLIhI7Jqh5B1eFWqVhnjS8cclQ8yqloTceeiIcqkNNo9BQb03aDVre6NrzmrIc1e3bi+j1kex4/Y7XVQ+jsuZi1GrOSGilNKdD/TA9j54eHnNKXJBWzO56Qb8XdOcVkdZZI+r1XVJVyw9JnW09tvRr4bjhFWra6iDUmioOap5XaEzGQxE2JuqbhFeVhlAf4dFTZ7WS19HT21Y//p6jC68vuuXrwPO6M2+k3oazK6U7vVLOmo8rkTh7uRFzesQZyutIe3c9H/Vm80D56g16YtbRq9q4uCb6ll+pswVTQ8NQF9IDfRTVWW2u8A6GUSdQrqpCrD7GSZ29VbqOjK+DC11tlbD9i2jw8HSdjXoTzn4Eg9Pm9FxV2kHsp7hUzsbHA5zNLe1Oc97sTWadUUvZqufH1XienGKEbUdHTxmrUqpqahBembnxMDLvoJTSiI/D53VWFVODngR3tLkDdXhbTmnFxzj7AXNjXWEPTWE9Ng+nqbMTTk9uY5vr4jbqtU+ad9Ve86GjKq4QgQjUejYurMGs88qk+qA2HjfG4VGgJsHCOKuPTHFVsjailuHkuzrrnT1Or2/VodDSmkWtmhbfls0X9WvU2ZVzGM+Cj/Wi1ixlmRu7UWdNVRVNtajV+8bdudmUeugIvW/cnQdG64eztOQ+VtlhEB4NjwrDSqjdLMV7UHqOfKRWuXr7SamqhRVmjpzW2fLszJTRmXg6csjyTM+N9VK35d1ea2c9gbMrHq9Ppxvnyt1zpavehkrmxspd5sb55Ww+ad4pO81VnJveWa9/olaWevWq1rPBzdwsL3uBrsbNu9azpgdDtXKtNMY1octqONRVNdmfMhNlXWD1pwhLjeQrUik50N9H+9iPZ8OJmv1IY+2r+uyW5QUBrQ5xudGcjqfH09PjeAP5MHJWr2thwZO4UzA9vf7jdxUretbp6/LlJ7VK+DuRLPWs/2hX19lR9USqQjvotVuzqM5qZ/vzjnG539N7VerFp0scs1ZtTJSvE32tR4RRoR0+Xc9Gm1U14T0pqWo9O3gUtWlq7LWusynRjrLejxL0iRUyPdeqdk+F8nQQO3t4msyNN44DTtH7BLtGPP+vVMRifFTfenxX5Yt+tfCHOqWVPwtJt97ZNw/F/YzDRFvf3jSaT7SZ7epFbyLNrRQdNVuOLs6OqtfzrpkWd5/dUxGEV2pJqx50CQ3CQNVb5Vi0E1UpxXNhP9U30V1oZ5M663VluTNoJ51j1I8Lrt6EMhJTZ1fKYMPE1Z0OL49VQJcbp1fmQC9uBQPmQs7WTZ0tJLVS1Hei6ultPXNW35pU2FXntLKrS65fPCj6O9vF5MEv1isZzY32mMSzyvZeaGrGW2pUSjW/caTqrN8oJNd6KiW9mVyK10PC1FnxRp1VE+DEy5E66qbT5PS6D6yszib1VKj58bnQVfZYTYsra3BvhSjubxf9yJLC9u/qWNeNSrFe3yn6UR2s+NvBK2XQ39/a2o7fsr+7u1Xc2lXs73xRx7tf9Mv1P+vmloUv28+cFcIv/O776q+DYtGr/7+d822RIgfCeFdKS8gfE5Lckrb1hYhynMNFFn1xcN//c11V0j3TepyrB4os9YAz0jvdy+70L89TlZptraHPnp9C2fjROfrxP/bvT95ZS0ympd/unjz/8Ac8HzXunQRmofTDdc/2bLR/P/3r5LOD1Y+zB/VxZ/jpn8NiZ1hWo/2BeiH7OTID9Va6xHaw+uLN5fH3jSmurtbgxSLLGqvn/zMy4LJz0YUwTJGPzQQbzyf2GrAw5HIqMIIUPT+B2YxoWF2dztvxdB4fI2/W1qphQv1wROvaIutGiz+5CBzjF3b46D5GcXjq9cn+y7Q1dv0Kenl5dm9fvJfsc3n/St6TT29eXu5HB/k6W/EoXbZ1MyrPZtkB22gMtcZkOS+3JmJlh4WME74Ts7BFGveuGYwPGrewQFrCut/6xu53vHE3YIPhJaLymjBOuBoqQor8bY1RHlTf7rTDTt8+u79IGcsm+/by6vLomYXuByWBq0xw0w5rE5+dzgqhcXrcYKbiG7MpO6HSkCXCtgNZyMZ47f3iqGYBEYrHOzCIHgjBZK5ZeU1Arlz7KQQXD0BAZEDvRdU3taDYaF9f7j+x3b6+zH3Zy5tj1OIRMxvW3S2dsYzXLcHuzC4YE3sqV7T4GbOFLZLyVkPJbMMHepYvc7q2wI9c8vboPObY5IsWi7yEVl+LufnsEjYphgvGbvRuVH1TD+rd9Fqh015kdhE5Iz96n7U+nyrNEgzZo1rd3RIiMrNgJTzfmLXSVYrRMq91sfwSNlWufU2rYQor41g9CflmBfbqnUWSL0osFrO++WwJIUldWdegd6Pq/9zKR3v/sVdXycfTj4iucW4FOvssuCI+yyG5nJgVAgVF9su7Zdlw8VykenBbvWrgWCRS+zjAnXwixtBgAU9EcPhsar0WZLIVWZXqQWY/W6uwxRakDj357GR2Eee8zkbQZhcUi5YH6GlujsJ6G2OaS14Uc92kN1ymoVuHufTCrMfY7qbPWsgdrWFoXVdkVaqvB4oQv4wSENCBvfksY8TMWg619eSzDhYjrSfPRur2HlTCL7u+IwEL8dbm+SLMkGVTB9ZFelszircMHGyS75u2jVWqByQtplnYXtu1VnrGR99YmlSchEn6S56uzKbgF1MM+YDU9hZUKnWdCodJlzbScJJoPMvZWMcclB2FLu2jGlKHWL4+KrEq1UMyZR/OX9EeU06U/bWeTTkyxKPuTIi3HpTMF/qcS9m6m7RT9N7ZKVcmfcKubc4bajNV42qYWXAubs61uEUXJ8vJuJxddK4Gp++KSvXfIizidSlmMUSzWytaqmPfJ7V+J+l2YGnCrfqlgvTZgC/kjQS3ccBNn6XZd7IBS5iX5igts4sGEsD4x4+yGrSNy9wxPkWY9V1Rqb4WjgsCmdi5kkw1GCCo3Un1asCYkvvIsHt/F08dK2jFJD4nTCyxZ5hReDA7Tbrc2swt4N6In58RSLHZFIKsF/zNuws275vDRplVqb4mG2LuaxzNn1Rz3tZcZSd2FKZ5jkiU3S/NeuoyW47GW18namF1SSYgEyUiStNnbZ5h29LWLFe++watMJvcZsaklFzYS8GbjoJamVWpHqIWDO0z8HaB7xkdJCPJdlrwYLvnIYyjnjV9rATswU5Gl0sbR4kNmYO02dP2dYSqterlEwpBmVWpfpbaYcNZfNbGLqiGuDY7K95hu9iNX49P25m8d5zYi+s+QKXMqlQ/rTY+5pX3jtOwbB+Po2mgmyCVcO1dmcNnycMcPvv+Py+jUql+bBbXX4FKpVKpVCqVSqVSqVQqlUqlUqlUKpVKpVL9qvoHFd+Yldt1J+4AAAAASUVORK5CYII="}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/eb7c3b1b.0dba8683.js b/handbook/build/assets/js/eb7c3b1b.0dba8683.js new file mode 100644 index 000000000..d0b577b4c --- /dev/null +++ b/handbook/build/assets/js/eb7c3b1b.0dba8683.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[8610],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>k});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?c(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):c(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},c=Object.keys(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(n=0;n<c.length;n++)r=c[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,c=e.originalType,l=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),d=p(r),k=o,m=d["".concat(l,".").concat(k)]||d[k]||u[k]||c;return r?n.createElement(m,a(a({ref:t},s),{},{components:r})):n.createElement(m,a({ref:t},s))}));function k(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var c=r.length,a=new Array(c);a[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,a[1]=i;for(var p=2;p<c;p++)a[p]=r[p];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},9130:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>c,metadata:()=>i,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const c={id:"websocketdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},a=void 0,i={unversionedId:"websocketdescription",id:"websocketdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd",description:"\u4ea7\u54c1\u4ecb\u7ecd",source:"@site/docs/websocketdescription.mdx",sourceDirName:".",slug:"/websocketdescription",permalink:"/touchsocket/docs/websocketdescription",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/websocketdescription.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675238151,formattedLastUpdatedAt:"Feb 1, 2023",frontMatter:{id:"websocketdescription",title:"\u4ea7\u54c1\u53ca\u67b6\u6784\u4ecb\u7ecd"},sidebar:"docs",previous:{title:"\u6587\u4ef6\u4f20\u8f93",permalink:"/touchsocket/docs/httpfiletransfer"},next:{title:"\u521b\u5efaWebSocket\u670d\u52a1\u5668",permalink:"/touchsocket/docs/createwebsocketservice"}},l={},p=[{value:"\u4ea7\u54c1\u4ecb\u7ecd",id:"\u4ea7\u54c1\u4ecb\u7ecd",level:2},{value:"\u4ea7\u54c1\u7279\u70b9",id:"\u4ea7\u54c1\u7279\u70b9",level:2},{value:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f",id:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f",level:2},{value:"\u670d\u52a1\u5668\u67b6\u6784",id:"\u670d\u52a1\u5668\u67b6\u6784",level:2}],s={toc:p};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u4ea7\u54c1\u4ecb\u7ecd"},"\u4ea7\u54c1\u4ecb\u7ecd"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"WebSocket\u662f\u4e00\u79cd\u5728\u5355\u4e2aTCP\u8fde\u63a5\u4e0a\u8fdb\u884c\u5168\u53cc\u5de5\u901a\u4fe1\u7684\u534f\u8bae\u3002WebSocket\u901a\u4fe1\u534f\u8bae\u4e8e2011\u5e74\u88abIETF\u5b9a\u4e3a\u6807\u51c6RFC 6455\uff0c\u5e76\u7531RFC7936\u8865\u5145\u89c4\u8303\u3002WebSocket API\u4e5f\u88abW3C\u5b9a\u4e3a\u6807\u51c6\u3002WebSocket\u4f7f\u5f97\u5ba2\u6237\u7aef\u548c\u670d\u52a1\u5668\u4e4b\u95f4\u7684\u6570\u636e\u4ea4\u6362\u53d8\u5f97\u66f4\u52a0\u7b80\u5355\uff0c\u5141\u8bb8\u670d\u52a1\u7aef\u4e3b\u52a8\u5411\u5ba2\u6237\u7aef\u63a8\u9001\u6570\u636e\u3002\u5728WebSocket API\u4e2d\uff0c\u6d4f\u89c8\u5668\u548c\u670d\u52a1\u5668\u53ea\u9700\u8981\u5b8c\u6210\u4e00\u6b21\u63e1\u624b\uff0c\u4e24\u8005\u4e4b\u95f4\u5c31\u76f4\u63a5\u53ef\u4ee5\u521b\u5efa\u6301\u4e45\u6027\u7684\u8fde\u63a5\uff0c\u5e76\u8fdb\u884c\u53cc\u5411\u6570\u636e\u4f20\u8f93\u3002 ",(0,o.kt)("a",{name:"Sdw1r"}))),(0,o.kt)("h2",{id:"\u4ea7\u54c1\u7279\u70b9"},"\u4ea7\u54c1\u7279\u70b9"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"\u7b80\u5355\u6613\u7528\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u591a\u7ebf\u7a0b\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u5185\u5b58\u6c60"),(0,o.kt)("li",{parentName:"ul"},"\u9ad8\u6027\u80fd"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"\u591a\u79cd\u6570\u636e\u63a5\u6536\u6a21\u5f0f"),"\uff08IOCP\uff0cBIO\uff0cSelect\uff09\u3002"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"\u591a\u5730\u5740\u76d1\u542c"),"\uff08\u53ef\u4ee5\u4e00\u6b21\u6027\u76d1\u542c\u591a\u4e2aIP\u53ca\u7aef\u53e3\uff09 ",(0,o.kt)("a",{name:"h6l2a"}))),(0,o.kt)("h2",{id:"\u4ea7\u54c1\u5e94\u7528\u573a\u666f"},"\u4ea7\u54c1\u5e94\u7528\u573a\u666f"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"WebSocket\u57fa\u7840\u4f7f\u7528\u573a\u666f\uff1a\u53ef\u8de8\u5e73\u53f0\u3001\u8de8\u8bed\u8a00\u4f7f\u7528\u3002"),(0,o.kt)("li",{parentName:"ul"},"\u81ea\u5b9a\u4e49\u534f\u8bae\u89e3\u6790\u573a\u666f\uff1a\u53ef\u89e3\u6790\u4efb\u610f\u6570\u636e\u683c\u5f0f\u7684WebSocket\u6570\u636e\u62a5\u6587\u3002")),(0,o.kt)("h2",{id:"\u670d\u52a1\u5668\u67b6\u6784"},"\u670d\u52a1\u5668\u67b6\u6784"),(0,o.kt)("p",null,"\u670d\u52a1\u5668\u8fd0\u884c\u6302\u8f7d\u5728HttpService\u4e0a\uff0c\u6240\u4ee5\u67b6\u6784\u548cHttpService\u4e00\u81f4\u3002"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/f05a39b7.7ba7a087.js b/handbook/build/assets/js/f05a39b7.7ba7a087.js new file mode 100644 index 000000000..47c69bb0e --- /dev/null +++ b/handbook/build/assets/js/f05a39b7.7ba7a087.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[1822],{3905:(e,t,l)=>{l.d(t,{Zo:()=>s,kt:()=>d});var a=l(7294);function n(e,t,l){return t in e?Object.defineProperty(e,t,{value:l,enumerable:!0,configurable:!0,writable:!0}):e[t]=l,e}function r(e,t){var l=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),l.push.apply(l,a)}return l}function o(e){for(var t=1;t<arguments.length;t++){var l=null!=arguments[t]?arguments[t]:{};t%2?r(Object(l),!0).forEach((function(t){n(e,t,l[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(l)):r(Object(l)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(l,t))}))}return e}function c(e,t){if(null==e)return{};var l,a,n=function(e,t){if(null==e)return{};var l,a,n={},r=Object.keys(e);for(a=0;a<r.length;a++)l=r[a],t.indexOf(l)>=0||(n[l]=e[l]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)l=r[a],t.indexOf(l)>=0||Object.prototype.propertyIsEnumerable.call(e,l)&&(n[l]=e[l])}return n}var i=a.createContext({}),p=function(e){var t=a.useContext(i),l=t;return e&&(l="function"==typeof e?e(t):o(o({},t),e)),l},s=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var l=e.components,n=e.mdxType,r=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),k=p(l),d=n,m=k["".concat(i,".").concat(d)]||k[d]||u[d]||r;return l?a.createElement(m,o(o({ref:t},s),{},{components:l})):a.createElement(m,o({ref:t},s))}));function d(e,t){var l=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=l.length,o=new Array(r);o[0]=k;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c.mdxType="string"==typeof e?e:n,o[1]=c;for(var p=2;p<r;p++)o[p]=l[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,l)}k.displayName="MDXCreateElement"},510:(e,t,l)=>{l.d(t,{Z:()=>Q});var a=l(7294),n=l(7462);const r=(e,t,l)=>e?"string"==typeof e?e:e[t]||l:l,o={display:"block"},c=e=>{let{size:t,color:l,style:c,...i}=e;const p=c?{...o,...c}:o;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:p},i),a.createElement("path",{d:"M856.4 292.8c-63.3-63.6-126.6-127.1-190.2-190.3-15.3-15.2-32.7-16.1-48.1-0.8-64.3 63.6-128.1 127.6-191.8 191.9-14 14.2-16.3 31.6-1.7 46 14.8 14.7 31.5 10.6 46.1-2.7 5.1-4.6 9.8-9.7 14.7-14.7 39.2-39.7 78.5-79.5 122.8-124.4 0 170 3 332.2-1.1 494-2.4 96.4-91.2 174.6-187.4 176.6-110.6 2.3-198.6-84.4-199-197.4-0.6-136.3-0.2-272.6-0.1-408.9 0-21.8-7.9-37.4-31.2-39.9-18.9-2-33.2 13.2-33.1 37.5 0 145.8-3.4 291.7 2.4 437.2 6 152.1 160.4 263.5 309.5 230.5C591.8 900 672.8 797.2 673.6 664.6c0.8-144 0.2-288.1 0.2-432.1v-33.3c11.2 10.2 17.6 15.4 23.3 21.3 38.5 38.4 76.7 77 115.3 115.2 14.8 14.6 32.2 19.2 47.8 2.9 13.8-14.8 10.3-31.7-3.8-45.8z",fill:r(l,0,"#333333")}))};c.defaultProps={size:18};const i=c,p={display:"block"},s=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...p,...o}:p;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M143.872 768a51.2 51.2 0 0 1-15.36-2.56 51.2 51.2 0 0 1-35.328-51.2V283.136a148.992 148.992 0 0 1 141.824-153.6h450.56a148.992 148.992 0 0 1 141.824 153.6V512a148.992 148.992 0 0 1-141.824 153.6H244.224l-60.928 80.896a51.2 51.2 0 0 1-39.424 21.504zM235.008 180.224a97.792 97.792 0 0 0-90.624 102.4v430.592L218.624 614.4h466.944a97.792 97.792 0 0 0 90.624-102.4V283.136a97.792 97.792 0 0 0-90.624-102.4z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M880.128 875.52a51.2 51.2 0 0 1-39.424-20.48l-60.928-80.896h-243.2a25.6 25.6 0 0 1 0-51.2h268.8l76.288 102.4v-295.936a25.6 25.6 0 0 1 25.6-25.6 25.6 25.6 0 0 1 25.6 25.6v293.888a51.2 51.2 0 0 1-51.2 51.2z",fill:r(l,1,"#333333")}))};s.defaultProps={size:18};const u=s,k={display:"block"},d=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...k,...o}:k;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M223.425605 449.2744l161.632237 0 0 253.65714c0 16.954137 13.745049 30.699186 30.699186 30.699186 16.95516 0 30.699186-13.745049 30.699186-30.699186l0-284.356326c0-16.95516-13.744026-30.699186-30.699186-30.699186L291.035446 387.876028l217.23665-248.51605L733.039255 387.580293 607.104031 387.580293c-16.954137 0-30.699186 13.745049-30.699186 30.699186l0 284.652062c0 16.954137 13.745049 30.699186 30.699186 30.699186s30.699186-13.745049 30.699186-30.699186L637.803217 448.978664l164.448376 0c12.140505 0 23.140023-7.154957 28.063149-18.251689 4.922103-11.097756 2.841721-24.053835-5.307889-33.05279L530.62315 72.570829c-5.881964-6.495948-14.273075-10.134825-23.024389-10.091846-8.763594 0.076748-17.076934 3.895727-22.844288 10.494005L200.312188 398.371056c-7.92653 9.067516-9.818623 21.931498-4.839215 32.896224S211.383338 449.2744 223.425605 449.2744z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M222.354204 829.113381l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186s-13.745049-30.699186-30.699186-30.699186L222.354204 767.715009c-16.954137 0-30.699186 13.745049-30.699186 30.699186S205.400067 829.113381 222.354204 829.113381z",fill:r(l,1,"#333333")}),a.createElement("path",{d:"M804.086381 896.729361 222.354204 896.729361c-16.954137 0-30.699186 13.745049-30.699186 30.699186s13.745049 30.699186 30.699186 30.699186l581.732178 0c16.954137 0 30.699186-13.745049 30.699186-30.699186S821.041542 896.729361 804.086381 896.729361z",fill:r(l,2,"#333333")}))};d.defaultProps={size:18};const m=d,h={display:"block"},g=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...h,...o}:h;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M380.15463648 874.54223633c0 18.12744166-14.83154297 32.95898463-32.95898463 32.95898463s-32.95898463-14.83154297-32.95898462-32.95898463V228.9152832L172.71078883 370.86962865a33.04467773 33.04467773 0 0 1-46.60400416 0 33.04467773 33.04467773 0 0 1 0-46.6040034l197.55615234-198.14941406A32.76782227 32.76782227 0 0 1 347.0967749 116.52514674c0.03295924 0 0.06591772-0.03295924 0.09887695-0.03295924 1.54907201 0 2.90039088 0.69213867 4.41650366 0.88989258 2.66967773 0.39550781 5.40527318 0.59326172 7.94311548 1.61499049 12.03002904 4.94384766 20.59936549 16.71020508 20.59936549 30.45410156v725.0910642z m320.15698192 23.34155248a32.85351537 32.85351537 0 0 1-23.43383789 9.59106445c-0.03295924 0-0.06591772 0.03295924-0.09887696 0.03295924-1.54907201 0-2.90039088-0.69213867-4.41650365-0.92285182-2.70263697-0.36254857-5.40527318-0.56030248-7.94311549-1.61498972-12.03002904-4.91088842-20.59936549-16.67724584-20.59936473-30.42114309V149.45776367c0-18.12744166 14.83154297-32.95898463 32.95898387-32.95898463s32.95898463 14.83154297 32.95898463 32.95898463v645.60058619l141.52587916-141.92138697c12.81445313-12.82104467 33.81591797-12.82104467 46.63037109 0 12.78808619 12.81445313 12.78808619 33.77636719 0 46.60400416L700.3116184 897.88378881z",fill:r(l,0,"#333333")}))};g.defaultProps={size:18};const N=g,v={display:"block"},y=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...v,...o}:v;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1172 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M870.0416 250.4704a38.4 38.4 0 0 0-8.96 53.5552c13.056 18.2784 24.4224 37.8368 33.7408 58.112a38.4512 38.4512 0 0 0 50.944 18.8928 38.4512 38.4512 0 0 0 18.8416-50.944 436.0192 436.0192 0 0 0-40.96-70.6048 38.3488 38.3488 0 0 0-53.6064-9.0112zM181.4528 566.016a35.9936 35.9936 0 0 0 25.5488-10.5984L351.7952 410.624a36.096 36.096 0 1 0-51.0976-51.0976L217.6 442.5728C250.0096 278.1184 395.264 153.6 569.1392 153.6c50.7904 0 99.8912 10.3936 145.92 30.9248a38.4 38.4 0 1 0 31.232-70.0928 431.36 431.36 0 0 0-177.152-37.632c-214.6816 0-393.1136 156.416-428.4416 361.216L62.1568 359.4752a36.1984 36.1984 0 0 0-51.0976 51.0976l144.8448 144.7936a36.0448 36.0448 0 0 0 25.5488 10.6496zM978.5344 463.104a36.1984 36.1984 0 0 0-51.0976 0l-144.8448 144.7936a36.096 36.096 0 1 0 51.0976 51.0976l88.6272-88.576C894.3104 740.2496 746.8032 870.4 569.1392 870.4a357.7856 357.7856 0 0 1-325.2736-207.7184 38.4 38.4 0 1 0-69.7344 32.3072 434.3808 434.3808 0 0 0 394.9568 252.2112c215.1936 0 393.984-157.184 428.6464-362.7008l74.496 74.496a35.9936 35.9936 0 0 0 51.0976 0 36.096 36.096 0 0 0 0-51.0976l-144.7936-144.7936z",fill:r(l,0,"#333333")}))};y.defaultProps={size:18};const f=y,b={display:"block"},E=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...b,...o}:b;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M302 332a30 30 0 1 1 0-60h420a30 30 0 0 1 0 60H302zM302 542a30 30 0 0 1 0-60h420a30 30 0 0 1 0 60H302zM302 752a30 30 0 0 1 0-60h120a30 30 0 0 1 0 60H302z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M789.47 784.1a30 30 0 0 1 39.36 45.3l-144.24 125.25a30 30 0 0 1-19.68 7.35H214.85C163.4 962 122 919.46 122 867.38V156.62C122 104.54 163.4 62 214.85 62h594.3C860.6 62 902 104.54 902 156.62v529.05a30 30 0 1 1-60 0V156.62C842 137.3 827.09 122 809.15 122H214.85C196.91 122 182 137.3 182 156.62v710.76C182 886.7 196.91 902 214.85 902h438.84l135.78-117.9z",fill:r(l,1,"#333333")}),a.createElement("path",{d:"M692 931.19a30 30 0 1 1-60 0v-174.6C632 704.57 673.4 662 724.85 662h147.78a30 30 0 0 1 0 60h-147.78c-17.94 0-32.85 15.3-32.85 34.62v174.6z",fill:r(l,2,"#333333")}))};E.defaultProps={size:18};const x=E,C={display:"block"},z=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...C,...o}:C;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z",fill:r(l,1,"#333333")}))};z.defaultProps={size:18};const w=z,T={display:"block"},D=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...T,...o}:T;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 34.8-28.2 63-63 63H232c-34.8 0-63-28.2-63-63 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5 0.2 13 0.7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7 6 17.2 13.6 33.6 22.7 49 24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2c41.5-24.3 76.2-59 100.5-100.5 9.1-15.5 16.7-31.9 22.7-49C812.1 793.1 836 831.8 836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7 0.4-6.4 0.7-12.8 0.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3-20.1 11.8-42 20-64.9 24.3V484c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v396.5c-22.9-4.3-44.8-12.5-64.9-24.3-30.3-17.7-55.6-43-73.3-73.3C317.7 752 308 716.8 308 680V412h408v268z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1-17.2-31.5-42.5-56.8-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9-31.5 17.2-56.8 42.5-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z",fill:r(l,1,"#333333")}))};D.defaultProps={size:18};const P=D,M={display:"block"},S=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...M,...o}:M;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M512 71.68c-242.688 0-440.32 197.632-440.32 440.32s197.632 440.32 440.32 440.32 440.32-197.632 440.32-440.32-197.632-440.32-440.32-440.32z m0 819.2c-208.896 0-378.88-169.984-378.88-378.88s169.984-378.88 378.88-378.88 378.88 169.984 378.88 378.88-169.984 378.88-378.88 378.88z",fill:r(l,0,"#333333")}),a.createElement("path",{d:"M542.72 261.12H481.28v220.16H261.12v61.44h220.16v220.16h61.44v-220.16h220.16V481.28h-220.16z",fill:r(l,1,"#333333")}))};S.defaultProps={size:18};const B=S,L={display:"block"},O=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...L,...o}:L;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M384 896h-64v-70.4c0-15.2-10.4-28-24.8-31.2C159.2 768 64 644.8 64 496v-32h64v32c0 118.4 73.6 215.2 179.2 236 44.8 8.8 76.8 48 76.8 94.4v69.6zM704 896h-64v-70.4c0-45.6 32-85.6 76.8-94.4C822.4 711.2 896 614.4 896 496v-32h64v32c0 148.8-95.2 272-231.2 298.4-14.4 3.2-24.8 16-24.8 31.2v70.4zM512.8 640l-41.6-37.6c-147.2-133.6-244-208-244-316.8 0-88 68.8-156.8 156.8-156.8 49.6 0 97.6 23.2 128.8 60C544 152 592 128.8 641.6 128.8c88 0 156.8 68.8 156.8 156.8 0 108-96.8 183.2-244 316.8L512.8 640z",fill:r(l,0,"#333333")}))};O.defaultProps={size:18};const Z=O,A={display:"block"},j=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...A,...o}:A;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M942.4615936 284.62787926c-14.30911886-14.12709945-37.31996786-14.05468217-51.48229632 0.21920654L517.97142983 661.27810333 139.75544149 286.45003606c-14.30911886-14.16232846-37.31996786-14.05468217-51.51948344 0.21920654-14.16232846 14.30911886-14.05468217 37.35519687 0.21920654 51.51948345l401.99014627 398.34974663c0.61847666 0.61847666 1.41897273 0.76526706 2.03940637 1.34655658 0.14483342 0.14483342 0.18201941 0.32685283 0.32685283 0.47364324 7.09877874 7.02636259 16.38375538 10.55911595 25.63154489 10.55911595 9.35739278 0 18.75001458-3.60516949 25.85075143-10.77636551l398.34974663-401.99014628C956.84312974 321.8382427 956.73548345 298.7921647 942.4615936 284.62787926z",fill:r(l,0,"#333333")}))};j.defaultProps={size:18};const H=j,V={display:"block"},F=e=>{let{size:t,color:l,style:o,...c}=e;const i=o?{...V,...o}:V;return a.createElement("svg",(0,n.Z)({viewBox:"0 0 1024 1024",width:t+"px",height:t+"px",style:i},c),a.createElement("path",{d:"M81.5384064 739.37212074c14.30911886 14.12709945 37.31996786 14.05468217 51.48229632-0.21920654L506.02857017 362.72189667 884.24455851 737.54996394c14.30911886 14.16232846 37.31996786 14.05468217 51.51948344-0.21920654 14.16232846-14.30911886 14.05468217-37.35519687-0.21920654-51.51948345l-401.99014627-398.34974663c-0.61847666-0.61847666-1.41897273-0.76526706-2.03940637-1.34655658-0.14483342-0.14483342-0.18201941-0.32685283-0.32685282-0.47364324-7.09877874-7.02636259-16.38375538-10.55911595-25.6315449-10.55911595-9.35739278 0-18.75001458 3.60516949-25.85075143 10.77636551l-398.34974663 401.99014628C67.15687026 702.1617573 67.26451655 725.2078353 81.5384064 739.37212074z",fill:r(l,0,"#333333")}))};F.defaultProps={size:18};const I=F,R=e=>{let{name:t,...l}=e;switch(t){case"youhua":return a.createElement(i,l);case"dayi":return a.createElement(u,l);case"shengji":return a.createElement(m,l);case"tiaozheng":return a.createElement(N,l);case"gengxin":return a.createElement(f,l);case"wendang":return a.createElement(x,l);case"shanchu":return a.createElement(w,l);case"bug":return a.createElement(P,l);case"xinzeng":return a.createElement(B,l);case"fuwu":return a.createElement(Z,l);case"down":return a.createElement(H,l);case"up":return a.createElement(I,l)}return null},U="label_p8vM",q="icon_knQK";function Q(e){const{children:t}=e,l={"\u65b0\u589e":{icon:"xinzeng",bgColor:"#39b54a"},"\u4fee\u590d":{icon:"bug",bgColor:"#9c26b0"},"\u6587\u6863":{icon:"wendang",bgColor:"rgb(79, 147, 255)"},"\u66f4\u65b0":{icon:"gengxin",bgColor:"#0081ff"},"\u8c03\u6574":{icon:"tiaozheng",bgColor:"#333"},"\u5347\u7ea7":{icon:"shengji",bgColor:"#e03997"},"\u79fb\u9664":{icon:"shanchu",bgColor:"#666"},"\u7b54\u7591":{icon:"dayi",bgColor:"#bbb"},"\u4f18\u5316":{icon:"youhua",bgColor:"#38e550"},"\u63a8\u8350":{bgColor:"#38e550"},"\u4f01\u4e1a\u7248":{bgColor:"#23AAF2"}};return a.createElement("label",{className:U,title:t,style:{backgroundColor:l[t].bgColor}},a.createElement(R,{name:l[t].icon,color:"white",size:14,className:q})," ",t)}},3968:(e,t,l)=>{l.r(t),l.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>k,frontMatter:()=>o,metadata:()=>i,toc:()=>s});var a=l(7462),n=(l(7294),l(3905)),r=l(510);const o={id:"enterprise",title:"\u4f01\u4e1a\u7248\u76f8\u5173"},c=void 0,i={unversionedId:"enterprise",id:"enterprise",title:"\u4f01\u4e1a\u7248\u76f8\u5173",description:"\u4e00\u3001\u8bf4\u660e",source:"@site/docs/enterprise.mdx",sourceDirName:".",slug:"/enterprise",permalink:"/touchsocket/docs/enterprise",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/enterprise.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675745725,formattedLastUpdatedAt:"Feb 7, 2023",frontMatter:{id:"enterprise",title:"\u4f01\u4e1a\u7248\u76f8\u5173"},sidebar:"docs",previous:{title:"\u652f\u6301\u4f5c\u8005",permalink:"/touchsocket/docs/donate"},next:{title:"\u5546\u4e1a\u5408\u4f5c",permalink:"/touchsocket/docs/cooperation"}},p={},s=[{value:"\u4e00\u3001\u8bf4\u660e",id:"\u4e00\u8bf4\u660e",level:2},{value:"\u4e8c\u3001TouchSocket\u4e0eTouchSocketPro",id:"\u4e8ctouchsocket\u4e0etouchsocketpro",level:2},{value:"2.1 Tcp\u7ec4\u4ef6",id:"21-tcp\u7ec4\u4ef6",level:3},{value:"2.2 NAT\u7ec4\u4ef6",id:"22-nat\u7ec4\u4ef6",level:3},{value:"2.3 UDP\u7ec4\u4ef6",id:"23-udp\u7ec4\u4ef6",level:3},{value:"2.4 JsonRpc",id:"24-jsonrpc",level:3},{value:"2.5 WebApi",id:"25-webapi",level:3},{value:"2.6 XmlRpc",id:"26-xmlrpc",level:3},{value:"2.7 TouchRpc\uff08tcp\u3001udp\u3001http\u3001websocket\uff09",id:"27-touchrpctcpudphttpwebsocket",level:3},{value:"2.8 Http\u7ec4\u4ef6",id:"28-http\u7ec4\u4ef6",level:3},{value:"WebSocket",id:"websocket",level:3},{value:"\u4e09\u3001\u80fd\u63d0\u4f9b\u7684\u4e2a\u6027\u670d\u52a1",id:"\u4e09\u80fd\u63d0\u4f9b\u7684\u4e2a\u6027\u670d\u52a1",level:2},{value:"3.1 \u6570\u636e\u5904\u7406\u9002\u914d\u5668\u7684\u91cd\u5199",id:"31-\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u7684\u91cd\u5199",level:3},{value:"3.2 \u589e\u52a0\u6216\u9650\u5236\u67d0\u4e2a\u529f\u80fd",id:"32-\u589e\u52a0\u6216\u9650\u5236\u67d0\u4e2a\u529f\u80fd",level:3},{value:"\u56db\u3001TouchSocketPro",id:"\u56dbtouchsocketpro",level:2},{value:"4.1 \u4e2a\u4eba\u72ec\u7acb\u6388\u6743",id:"41-\u4e2a\u4eba\u72ec\u7acb\u6388\u6743",level:3},{value:"4.2 \u4e2a\u4eba\u4f01\u4e1a\u6388\u6743",id:"42-\u4e2a\u4eba\u4f01\u4e1a\u6388\u6743",level:3},{value:"4.3 \u4f01\u4e1a\u6388\u6743",id:"43-\u4f01\u4e1a\u6388\u6743",level:3},{value:"\u4e94\u3001\u5bc6\u94a5\u4f7f\u7528",id:"\u4e94\u5bc6\u94a5\u4f7f\u7528",level:2},{value:"\u516d\u3001\u9650\u65f6\u6d4b\u8bd5",id:"\u516d\u9650\u65f6\u6d4b\u8bd5",level:2},{value:"\u4e03\u3001\u8d2d\u4e70\u901a\u9053",id:"\u4e03\u8d2d\u4e70\u901a\u9053",level:2}],u={toc:s};function k(e){let{components:t,...o}=e;return(0,n.kt)("wrapper",(0,a.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"\u4e00\u8bf4\u660e"},"\u4e00\u3001\u8bf4\u660e"),(0,n.kt)("p",null,"TouchSocketPro\u662fTouchSocket\u7cfb\u7684\u52a0\u5f3a\u7248\u672c\u3002\u5176\u57fa\u7840\u529f\u80fd\u5b8c\u5168\u5305\u542bTouchSocket\uff0c\u9664\u6b64\u4e4b\u5916\uff0c\u8fd8\u6709\u4e00\u4e9b\u9644\u52a0\u529f\u80fd\uff0c\u8fd9\u9700\u8981",(0,n.kt)("strong",{parentName:"p"},"\u4ed8\u8d39\u8d2d\u4e70\u5bc6\u94a5"),"\uff0c\u7136\u540e\u624d\u80fd\u4f7f\u7528\u3002\u5177\u4f53\u8be6\u7ec6\u533a\u522b",(0,n.kt)("strong",{parentName:"p"},"\u5982\u4e0b\u8868\u683c"),"\u6240\u793a\u3002"),(0,n.kt)("p",null,"\u540c\u65f6TouchSocketPro\u8fd8\u63d0\u4f9b",(0,n.kt)("strong",{parentName:"p"},"\u4f01\u4e1a\u5b9a\u5236\u670d\u52a1"),"\u53ca\u5fc5\u8981\u7684",(0,n.kt)("strong",{parentName:"p"},"\u8fdc\u7a0b\u534f\u52a9"),"\uff0c\u5177\u4f53\u6536\u8d39\u53ef\u4ee5\u54a8\u8be2\u4f5c\u8005\u82e5\u6c5d\u68cb\u8317\uff0c\u8054\u7cfb\u65b9\u5f0f\uff1aQQ\uff1a505554090\u3002"),(0,n.kt)("h2",{id:"\u4e8ctouchsocket\u4e0etouchsocketpro"},"\u4e8c\u3001TouchSocket\u4e0eTouchSocketPro"),(0,n.kt)("h3",{id:"21-tcp\u7ec4\u4ef6"},"2.1 Tcp\u7ec4\u4ef6"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/reconnection#%E4%B8%89%E4%BD%BF%E7%94%A8pollingkeepalive%E6%8F%92%E4%BB%B6-%E4%BC%81%E4%B8%9A%E7%89%88"},"\u8f6e\u8be2\u5f0f\u65ad\u7ebf\u91cd\u8fde")," ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/tlvdatahandlingadapter"},"TLV\u9002\u914d\u5668")," ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},"\u5176\u4f59\u529f\u80fd")),(0,n.kt)("h3",{id:"22-nat\u7ec4\u4ef6"},"2.2 NAT\u7ec4\u4ef6"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/natservice#%E5%9B%9B%E8%BD%AC%E5%8F%91%E6%96%AD%E7%BA%BF%E9%87%8D%E8%BF%9E-%E4%BC%81%E4%B8%9A%E7%89%88"},"\u8f6c\u53d1\u5ba2\u6237\u7aef\u91cd\u8fde")," ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},"\u5176\u4f59\u529f\u80fd")),(0,n.kt)("h3",{id:"23-udp\u7ec4\u4ef6"},"2.3 UDP\u7ec4\u4ef6"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u6240\u6709\u529f\u80fd")),(0,n.kt)("h3",{id:"24-jsonrpc"},"2.4 JsonRpc"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u81ea\u5b9a\u4e49\u89e3\u6790 ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},"\u5176\u4f59\u529f\u80fd")),(0,n.kt)("h3",{id:"25-webapi"},"2.5 WebApi"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u6240\u6709\u529f\u80fd")),(0,n.kt)("h3",{id:"26-xmlrpc"},"2.6 XmlRpc"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u6240\u6709\u529f\u80fd")),(0,n.kt)("h3",{id:"27-touchrpctcpudphttpwebsocket"},"2.7 TouchRpc\uff08tcp\u3001udp\u3001http\u3001websocket\uff09"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/remotefilecontrol"},"\u8fdc\u7a0b\u6587\u4ef6\u64cd\u4f5c")," ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/remotestreamaccess"},"\u8fdc\u7a0b\u6d41\u8bbf\u95ee")," ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},"\u6587\u4ef6\u4f20\u8f93\u529f\u80fd"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/multithreadingfiletransfer"},"\u591a\u7ebf\u7a0b\u6587\u4ef6\u4f20\u8f93")," ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/touchsocket/docs/smallfiletransfer"},"\u5c0f\u6587\u4ef6\u4f20\u8f93")),(0,n.kt)("li",{parentName:"ul"},"\u6587\u4ef6\u4f20\u8f93\u9650\u901f ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.yuque.com/rrqm/touchsocket/ipt4zr"},"EventBus\u529f\u80fd")," ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")),(0,n.kt)("li",{parentName:"ul"},"Redis")),(0,n.kt)("h3",{id:"28-http\u7ec4\u4ef6"},"2.8 Http\u7ec4\u4ef6"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u8d85\u5927\u6587\u4ef6\u4f20\u8f93"),(0,n.kt)("li",{parentName:"ul"},"\u591a\u901a\u9053\u6587\u4ef6\u7eed\u4f20"),(0,n.kt)("li",{parentName:"ul"},"\u9759\u6001\u7f51\u9875\u5c55\u793a"),(0,n.kt)("li",{parentName:"ul"},"\u6587\u4ef6\u4f20\u8f93\u9650\u901f")),(0,n.kt)("h3",{id:"websocket"},"WebSocket"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u5168\u90e8\u529f\u80fd")),(0,n.kt)("admonition",{title:"\u63d0\u793a",type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"\u4e0a\u8ff0\u7684\u529f\u80fd\u4e2d\uff0c\u6240\u6709\u5e26\u6709 ",(0,n.kt)(r.Z,{mdxType:"Tag"},"\u4f01\u4e1a\u7248")," \u7684\u6807\u8bc6\uff0c\u5747\u4e3a",(0,n.kt)("inlineCode",{parentName:"p"},"TouchSocketPro"),"\u5305\u542b\u7684\u5185\u5bb9\u3002\u5176\u4f59\u529f\u80fd",(0,n.kt)("inlineCode",{parentName:"p"},"TouchSocket"),"\u4e5f\u5747\u652f\u6301\u3002")),(0,n.kt)("h2",{id:"\u4e09\u80fd\u63d0\u4f9b\u7684\u4e2a\u6027\u670d\u52a1"},"\u4e09\u3001\u80fd\u63d0\u4f9b\u7684\u4e2a\u6027\u670d\u52a1"),(0,n.kt)("h3",{id:"31-\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u7684\u91cd\u5199"},"3.1 \u6570\u636e\u5904\u7406\u9002\u914d\u5668\u7684\u91cd\u5199"),(0,n.kt)("p",null,"\u5728TouchSocketPro\u4e2d\uff0c\u53ef\u4ee5\u901a\u8fc7\u9002\u914d\u5668\u5bf9\u6570\u636e\u8fdb\u884c\u9884\u5904\u7406\u548c\u5bf9\u8c61\u89e3\u6790\uff0c\u76ee\u524dTouchSocketPro\u62e5\u6709\u7684\u9002\u914d\u5668\u4ec5\u6709",(0,n.kt)("inlineCode",{parentName:"p"},"\u56fa\u5b9a\u5305\u5934"),"\u3001",(0,n.kt)("inlineCode",{parentName:"p"},"\u56fa\u5b9a\u957f\u5ea6"),"\u3001",(0,n.kt)("inlineCode",{parentName:"p"},"\u7ec8\u6b62\u5206\u5272"),"\u3001",(0,n.kt)("inlineCode",{parentName:"p"},"Json\u5b57\u7b26\u4e32\u89e3\u6790"),"\u3001",(0,n.kt)("inlineCode",{parentName:"p"},"Http\u5bf9\u8c61\u89e3\u6790"),"\u4e94\u79cd\u9002\u914d\u5668\u3002\u4f46\u662f\u5f80\u5f80\u8fd9\u4e9b\u9002\u914d\u5668\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\uff0c\u4f8b\u5982\uff1a\u4e32\u53e3\u4fe1\u53f7\u3001AGV\u6570\u636e\u683c\u5f0f\u7b49\u3002\u90a3\u4e48\u6211\u4eec\u53ef\u4ee5\u4e3a\u60a8\u63d0\u4f9b\u89e3\u6790\u6570\u636e\u683c\u5f0f\uff08\u5bf9\u8c61\uff09\u7684\u670d\u52a1\u3002"),(0,n.kt)("h3",{id:"32-\u589e\u52a0\u6216\u9650\u5236\u67d0\u4e2a\u529f\u80fd"},"3.2 \u589e\u52a0\u6216\u9650\u5236\u67d0\u4e2a\u529f\u80fd"),(0,n.kt)("p",null,"\u7a0b\u5e8f\u5e93\u4e3a\u7684\u662f\u80fd\u63d0\u4f9b\u57fa\u7840\u670d\u52a1\uff0c\u6240\u4ee5\u67d0\u4e2a\u529f\u80fd\u7684\u51fa\u73b0\uff0c\u5747\u662f\u4e3a\u4e86\u5177\u5907\u66f4\u597d\u7684\u666e\u9002\u6027\uff0c\u4f46\u662f\u6709\u65f6\u5019\u4e5f\u4f1a\u4e0e\u60a8\u7684\u9700\u6c42\u80cc\u9053\u800c\u9a70\uff0c\u90a3\u4e48\u6211\u4eec\u4e5f\u53ef\u4ee5\u4e3a\u60a8\u5b9a\u5236\u67d0\u4e2a\u529f\u80fd\uff08\u6216\u7981\u7528\u67d0\u4e2a\u529f\u80fd\uff09\u3002"),(0,n.kt)("h2",{id:"\u56dbtouchsocketpro"},"\u56db\u3001TouchSocketPro"),(0,n.kt)("table",null,(0,n.kt)("thead",{parentName:"table"},(0,n.kt)("tr",{parentName:"thead"},(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u7c7b\u578b")),(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u4e2a\u4eba\u72ec\u7acb\u6388\u6743")),(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u4e2a\u4eba\u4f01\u4e1a\u6388\u6743")),(0,n.kt)("th",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"th"},"\u4f01\u4e1a\u6388\u6743")))),(0,n.kt)("tbody",{parentName:"table"},(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u529f\u80fd")),(0,n.kt)("td",{parentName:"tr",align:null},"\u5168\u90e8\u529f\u80fd"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5168\u90e8\u529f\u80fd"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5168\u90e8\u529f\u80fd")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u4f7f\u7528\u671f\u9650")),(0,n.kt)("td",{parentName:"tr",align:null},"\u6c38\u4e45"),(0,n.kt)("td",{parentName:"tr",align:null},"\u6c38\u4e45"),(0,n.kt)("td",{parentName:"tr",align:null},"\u6c38\u4e45")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u6388\u6743\u5f52\u5c5e")),(0,n.kt)("td",{parentName:"tr",align:null},"\u4e2a\u4eba"),(0,n.kt)("td",{parentName:"tr",align:null},"\u4e2a\u4eba"),(0,n.kt)("td",{parentName:"tr",align:null},"\u4f01\u4e1a")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u534f\u52a9\u670d\u52a1")),(0,n.kt)("td",{parentName:"tr",align:null},"\u65e0"),(0,n.kt)("td",{parentName:"tr",align:null},"\u65e0"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5168\u90e8\u73b0\u6709\u529f\u80fd\u534f\u52a9")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u4e2a\u6027\u5316\u529f\u80fd\u6269\u5c55")),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u6fc0\u6d3b\u65b9\u5f0f")),(0,n.kt)("td",{parentName:"tr",align:null},"\u5bc6\u94a5\u6fc0\u6d3b"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5bc6\u94a5\u6fc0\u6d3b"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5bc6\u94a5\u6fc0\u6d3b\u548c\u6e90\u7801\u5f15\u7528")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u540e\u7eed\u5347\u7ea7")),(0,n.kt)("td",{parentName:"tr",align:null},"Nuget\u5347\u7ea7"),(0,n.kt)("td",{parentName:"tr",align:null},"Nuget\u5347\u7ea7"),(0,n.kt)("td",{parentName:"tr",align:null},"Nuget\u5347\u7ea7\u6216\u968f\u65f6\u7d22\u8981\u6700\u65b0\u6e90\u7801")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u6e90\u4ee3\u7801\u5f00\u653e")),(0,n.kt)("td",{parentName:"tr",align:null},"\u4e0d\u5f00\u653e"),(0,n.kt)("td",{parentName:"tr",align:null},"\u4e0d\u5f00\u653e"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5f00\u653e")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u7528\u4e8e\u76c8\u5229")),(0,n.kt)("td",{parentName:"tr",align:null},"\u5141\u8bb8"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5141\u8bb8"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5141\u8bb8")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u4e2a\u6027\u5316\u529f\u80fd\u6269\u5c55")),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301"),(0,n.kt)("td",{parentName:"tr",align:null},"\u652f\u6301")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u5f00\u5177\u53d1\u7968")),(0,n.kt)("td",{parentName:"tr",align:null},"\u539f\u5219\u4e0a\u4e0d\u5f00\u5177"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5f00\u5177"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5f00\u5177")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u8d60\u54c1")),(0,n.kt)("td",{parentName:"tr",align:null},"\u9001\u60a81\u675f\u73ab\u7470"),(0,n.kt)("td",{parentName:"tr",align:null},"\u9001\u60a82\u675f\u73ab\u7470"),(0,n.kt)("td",{parentName:"tr",align:null},"\u9001\u60a83\u675f\u73ab\u7470\uff0c\u548c\u4e00\u4e2a\u81ea\u5b9a\u4e49\u9002\u914d\u5668\uff0c\u6216\u590d\u6742\u5ea6\u76f8\u540c\u7684\u4e2a\u6027\u5316\u670d\u52a1\u3002")),(0,n.kt)("tr",{parentName:"tbody"},(0,n.kt)("td",{parentName:"tr",align:null},(0,n.kt)("strong",{parentName:"td"},"\u4ef7\u683c")),(0,n.kt)("td",{parentName:"tr",align:null},"298\uffe5"),(0,n.kt)("td",{parentName:"tr",align:null},"\u5df2\u505c\u552e"),(0,n.kt)("td",{parentName:"tr",align:null},"998\uffe5")))),(0,n.kt)("h3",{id:"41-\u4e2a\u4eba\u72ec\u7acb\u6388\u6743"},"4.1 \u4e2a\u4eba\u72ec\u7acb\u6388\u6743"),(0,n.kt)("p",null,"\u6388\u6743\u5f52\u5c5e\u4e8e\u8d2d\u4e70\u8005\u4e2a\u4eba\u6240\u6709\uff0c\u89c4\u5b9a\u8d2d\u4e70\u8005\u53ef\u5c06\u6240\u8d2d\u4ea7\u54c1\u53ea\u80fd\u5e94\u7528\u4e8e\u6240\u5c5e\u4e2a\u4eba\u7684\u4efb\u4f55\u8f6f\u4ef6\uff08\u4ea7\u54c1\uff09\u4e0a\uff0c\u53ef\u4ee5\u4ee5\u6b64\u76c8\u5229\uff0c\u4f46\u5fc5\u987b\u9075\u5b88",(0,n.kt)("a",{parentName:"p",href:"/touchsocket/docs/#qLp3q"},"\u4e2a\u4eba\u4f7f\u7528\u534f\u8bae"),"\u3002"),(0,n.kt)("h3",{id:"42-\u4e2a\u4eba\u4f01\u4e1a\u6388\u6743"},"4.2 \u4e2a\u4eba\u4f01\u4e1a\u6388\u6743"),(0,n.kt)("p",null,"\u6388\u6743\u5f52\u5c5e\u4e8e\u8d2d\u4e70\u8005\u4e2a\u4eba\u6240\u6709\uff0c\u89c4\u5b9a\u8d2d\u4e70\u8005\u53ef\u5c06\u6240\u8d2d\u4ea7\u54c1\u5e94\u7528\u4e8e\u8d2d\u4e70\u8005\u670d\u52a1\uff08\u5de5\u4f5c\uff09\u7684\u4f01\u4e1a\u7684\u4efb\u4f55\u8f6f\u4ef6\uff08\u4ea7\u54c1\uff09\u4e0a\uff0c\u4f46\u6388\u6743\u671f\u9650\u4e0e\u8d2d\u4e70\u8005\u670d\u52a1\uff08\u5de5\u4f5c\uff09\u671f\u9650\u4e00\u81f4\uff0c\u4e00\u65e6\u8d2d\u4e70\u8005\u79bb\u804c\uff08\u6216\u4e0d\u518d\u670d\u52a1\u4e8e\u4f01\u4e1a\uff09\uff0c\u6388\u6743\u5c06\u572830\u4e2a\u5de5\u4f5c\u65e5\u540e\u5931\u6548\u3002\u540c\u65f6\uff0c\u8d2d\u4e70\u8005\u5728\u5c06\u6240\u8d2d\u4ea7\u54c1\u5e94\u7528\u4e8e\u4f01\u4e1a\u65f6\uff0c\u6709\u5fc5\u8981\u544a\u77e5\u4e49\u52a1\uff0c\u5728\u79bb\u804c\uff08\u6216\u4e0d\u518d\u670d\u52a1\u4e8e\u4f01\u4e1a\uff09\u65f6\uff0c\u4e5f\u5e94\u5f53\u518d\u6b21\u544a\u77e5\u4f01\u4e1a\u8be6\u60c5\u3002"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"\uff08\u4e2a\u4eba\u4f01\u4e1a\u7248\u57282023.1.1\u65e5\u540e\u4e0d\u518d\u552e\u5356\u3002\u5df2\u552e\u5356\u7684\u4e2a\u4eba\u4f01\u4e1a\u7248\u539f\u59cb\u529f\u80fd\u4e0d\u53d8\u3002\u6216\u8005\u8054\u7cfb\u4f5c\u8005\uff0c\u53ef\u514d\u8d39\u5347\u7ea7\u81f3\u4f01\u4e1a\u7248\uff09")),(0,n.kt)("h3",{id:"43-\u4f01\u4e1a\u6388\u6743"},"4.3 \u4f01\u4e1a\u6388\u6743"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"\u5f53\u6388\u6743\u5f52\u5c5e\u4e8e\u4f01\u4e1a\u6240\u6709\u65f6\uff0c\u6c38\u4e45\u6388\u6743\u3002\u4e14\u4ec5\u4f01\u4e1a\u4eab\u6709\u6388\u6743\uff0c\u6240\u6709\u804c\u5458\u5747\u65e0\u6388\u6743\u3002"),(0,n.kt)("li",{parentName:"ul"},"\u5f53\u6388\u6743\u5f52\u5c5e\u4e2a\u4eba\u6240\u6709\u65f6\uff0c\u6c38\u4e45\u6388\u6743\u3002\u4e14\u4fdd\u7559\u4e00\u6b21\u4f01\u4e1a\u51a0\u540d\u6743\u76ca\uff0c\u73b0\u6709\u6388\u6743\u81ea\u52a8\u964d\u4e3a\u201c",(0,n.kt)("strong",{parentName:"li"},"\u4e2a\u4eba\u4f01\u4e1a\u6388\u6743"),"\u201d\u6761\u6b3e\u3002\u3002")),(0,n.kt)("h2",{id:"\u4e94\u5bc6\u94a5\u4f7f\u7528"},"\u4e94\u3001\u5bc6\u94a5\u4f7f\u7528"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"\u9996\u5148\u8bf7\u786e\u4fdd\u6240\u6709\u7684\u9879\u76ee\u5b8c\u5168\u5378\u8f7d\u5220\u9664TouchSocket\uff0c\u5e76\u4e14\u5728\u9700\u8981\u7684\u9879\u76ee\u4e2d\u5b89\u88c5\u4e86TouchSocketPro\u3002")),(0,n.kt)("p",null,"\u5f53\u8d2d\u4e70\u5bc6\u94a5\u540e\uff0c\u60a8\u4f1a\u83b7\u5f97\u7c7b\u4f3c\u201cD1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1\u201d\u8fd9\u6837\u7684\u5bc6\u94a5\u3002\u7136\u540e\u5728\u7a0b\u5e8f",(0,n.kt)("strong",{parentName:"p"},"\u521d\u59cb\u5316"),"(\u4f8b\u5982Main\u51fd\u6570)\u65f6\u3002\u4f7f\u7528\u4ee5\u4e0b\u4ee3\u7801\u5373\u53ef\u3002"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},' Enterprise.Default.LicenceKey = "\u5bc6\u94a5";\n')),(0,n.kt)("p",null,"AspNetCore\u4e2d\u4f7f\u7528\u65f6\uff0c\u5efa\u8bae\u81ea\u5b9a\u4e49\u670d\u52a1\u6ce8\u5165\u7684\u65b9\u5f0f\u5b9e\u73b0\u3002\u6b65\u9aa4\u5982\u4e0b\uff1a"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"\u65b0\u5efa\u9879\u76ee\uff0c\u5f15\u7528",(0,n.kt)("inlineCode",{parentName:"li"},"Microsoft.Extensions.DependencyInjection"),"\u548c",(0,n.kt)("inlineCode",{parentName:"li"},"TouchSocketPro.AspNetCore"),"\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u65b0\u5efa\u9759\u6001\u7c7b",(0,n.kt)("strong",{parentName:"li"},"ServiceCollectionExtension"),"\uff0c\u521b\u5efaIServiceCollection\u7684\u6269\u5c55\u65b9\u6cd5\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u5728IServiceCollection\u7684\u6269\u5c55\u65b9\u6cd5\u4e2d\uff0c\u6ce8\u5165\u5bc6\u94a5\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u5728AspNetCore\u5f15\u7528\u65b0\u5efa\u7684\u9879\u76ee\u3002"),(0,n.kt)("li",{parentName:"ol"},"\u5728\u670d\u52a1\u4e2d\u6ce8\u5165\u3002")),(0,n.kt)("p",null,"\u90e8\u5206\u4ee3\u7801\u793a\u4f8b\u5982\u4e0b\uff1a"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},'public static class ServiceCollectionExtension\n{\n public static void AddLicence(this IServiceCollection service)\n {\n Enterprise.Default.LicenceKey = "D1D1D1D1D1D1D1";\n }\n}\n')),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},"public void ConfigureServices(IServiceCollection services)\n{\n services.AddLicence();\n}\n\n")),(0,n.kt)("h2",{id:"\u516d\u9650\u65f6\u6d4b\u8bd5"},"\u516d\u3001\u9650\u65f6\u6d4b\u8bd5"),(0,n.kt)("p",null,"\u4e3a\u65b9\u4fbf\u5927\u5bb6\u6d4b\u8bd5\uff0cTouchSocketPro\u63d0\u4f9b",(0,n.kt)("strong",{parentName:"p"},"\u9650\u65f61\u5c0f\u65f6"),"\u7684\u6d4b\u8bd5\u529f\u80fd\uff0c\u5f53\u65f6\u95f4\u7ed3\u675f\u65f6\u4f01\u4e1a\u7248\u529f\u80fd\u5173\u95ed\uff0c",(0,n.kt)("strong",{parentName:"p"},"\u91cd\u542f\u8fdb\u7a0b"),"\u5373\u53ef\u518d\u6b21\u8bd5\u75281\u5c0f\u65f6\uff0c\u4ee5\u6b64\u5f80\u590d\u3002"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"\u8c03\u7528ForTest\u65f6\uff0c\u4f1a\u629b\u51fa\u53ef\u63a7\u5f02\u5e38\u3002\u5982\u679c\u575a\u6301\u4f7f\u7528\u4f01\u4e1a\u7248\uff0c\u4f7f\u7528Try\u62e6\u622a\u5373\u53ef\u3002")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-csharp"},"try\n{\n Enterprise.ForTest();\n}\ncatch (Exception ex)\n{\n Console.WriteLine(ex.Message);\n}\n")),(0,n.kt)("h2",{id:"\u4e03\u8d2d\u4e70\u901a\u9053"},"\u4e03\u3001\u8d2d\u4e70\u901a\u9053"),(0,n.kt)("p",null,"\u8d2d\u4e70\u53ef\u901a\u8fc7\u4ee5\u4e0b\u65b9\u5f0f\u3002",(0,n.kt)("strong",{parentName:"p"},"\u8d2d\u4e70\u524d\u8bf7\u5148\u8054\u7cfb\u4f5c\u8005\u82e5\u6c5d\u68cb\u8317"),"\u3002\u8054\u7cfbQQ\uff1a505554090\u3002"),(0,n.kt)("p",null,"\u626b\u63cf\u4e0b\u5217\u5fae\u4fe1\u7801\uff0c\u6216\u8005\u70b9\u51fb",(0,n.kt)("a",{parentName:"p",href:"https://item.taobao.com/item.htm?spm=a2126o.success.result.1.382c4831HDDIvA&id=691874706840"},"\u6dd8\u5b9d\u94fe\u63a5"),"\u3002"),(0,n.kt)("img",{src:l(745).Z,width:"500"}))}k.isMDXComponent=!0},745:(e,t,l)=>{l.d(t,{Z:()=>a});const a=l.p+"assets/images/enterprise-1-b2ffe369f19088bca3f0671679bad11d.jpg"}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/fce76f89.87ef30ad.js b/handbook/build/assets/js/fce76f89.87ef30ad.js new file mode 100644 index 000000000..41e42d945 --- /dev/null +++ b/handbook/build/assets/js/fce76f89.87ef30ad.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[138],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>g});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},l=Object.keys(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),c=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(p.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},s=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),s=c(n),g=r,k=s["".concat(p,".").concat(g)]||s[g]||u[g]||l;return n?a.createElement(k,o(o({ref:t},d),{},{components:n})):a.createElement(k,o({ref:t},d))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=s;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i.mdxType="string"==typeof e?e:r,o[1]=i;for(var c=2;c<l;c++)o[c]=n[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}s.displayName="MDXCreateElement"},770:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>l,metadata:()=>i,toc:()=>c});var a=n(7462),r=(n(7294),n(3905));const l={id:"adapterdescription",title:"\u4ecb\u7ecd\u53ca\u4f7f\u7528"},o=void 0,i={unversionedId:"adapterdescription",id:"adapterdescription",title:"\u4ecb\u7ecd\u53ca\u4f7f\u7528",description:"\u8bf4\u660e",source:"@site/docs/adapterdescription.mdx",sourceDirName:".",slug:"/adapterdescription",permalink:"/touchsocket/docs/adapterdescription",draft:!1,editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/docs/adapterdescription.mdx",tags:[],version:"current",lastUpdatedBy:"\u82e5\u6c5d\u68cb\u8317",lastUpdatedAt:1675566039,formattedLastUpdatedAt:"Feb 5, 2023",frontMatter:{id:"adapterdescription",title:"\u4ecb\u7ecd\u53ca\u4f7f\u7528"},sidebar:"docs",previous:{title:"\u7ec4\u64ad\u3001\u5e7f\u64ad",permalink:"/touchsocket/docs/udpbroadcast"},next:{title:"a.\u6b63\u5e38\u6570\u636e\u5904\u7406\u9002\u914d\u5668",permalink:"/touchsocket/docs/normaldatahandlingadapter"}},p={},c=[{value:"\u8bf4\u660e",id:"\u8bf4\u660e",level:2},{value:"\u8bbe\u8ba1\u67b6\u6784",id:"\u8bbe\u8ba1\u67b6\u6784",level:2},{value:"\u5de5\u4f5c\u903b\u8f91",id:"\u5de5\u4f5c\u903b\u8f91",level:3},{value:"\u6570\u636e\u903b\u8f91",id:"\u6570\u636e\u903b\u8f91",level:3},{value:"\u8bbe\u8ba1\u89e3\u91ca",id:"\u8bbe\u8ba1\u89e3\u91ca",level:3},{value:"\u4e09\u3001TCP\u4f7f\u7528",id:"\u4e09tcp\u4f7f\u7528",level:2},{value:"3.1 \u5728Config\u914d\u7f6e\u4e2d\u4f7f\u7528",id:"31-\u5728config\u914d\u7f6e\u4e2d\u4f7f\u7528",level:3},{value:"3.2 \u8ba2\u9605Connecting\u76f8\u5173\u4e8b\u4ef6",id:"32-\u8ba2\u9605connecting\u76f8\u5173\u4e8b\u4ef6",level:3},{value:"3.3 \u4f7f\u7528\u63d2\u4ef6\uff0c\u4ee3\u66ffConnecting\u76f8\u5173\u4e8b\u4ef6\u5b9e\u73b0",id:"33-\u4f7f\u7528\u63d2\u4ef6\u4ee3\u66ffconnecting\u76f8\u5173\u4e8b\u4ef6\u5b9e\u73b0",level:3},{value:"3.4 \u4efb\u610f\u65f6\u523b\u8bbe\u7f6e",id:"34-\u4efb\u610f\u65f6\u523b\u8bbe\u7f6e",level:3},{value:"\u56db\u3001UDP\u4f7f\u7528\u63d2\u4ef6",id:"\u56dbudp\u4f7f\u7528\u63d2\u4ef6",level:2},{value:"\u4e94\u3001\u9650\u5236\u4f7f\u7528",id:"\u4e94\u9650\u5236\u4f7f\u7528",level:2},{value:"\u516d\u3001\u7f13\u5b58\u8d85\u65f6\uff08\u4ec5Tcp\u9002\u914d\u5668\uff09",id:"\u516d\u7f13\u5b58\u8d85\u65f6\u4ec5tcp\u9002\u914d\u5668",level:2}],d={toc:c};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"\u8bf4\u660e"},"\u8bf4\u660e"),(0,r.kt)("p",null,"\u5728TouchSocket\u4e2d\uff0c\u9002\u914d\u5668\u8d2f\u7a7f\u59cb\u7ec8\uff0c\u5176\u4f5c\u7528\u5b9e\u9645\u4e0a\u6709\u4e24\u4e2a\uff0c\u5206\u522b\u4e3a\uff1a"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"\u5bf9\u53d1\u9001\u548c\u63a5\u6536\u7684\u6570\u636e\u8fdb\u884c\u9884\u5148\u7684\u5c01\u88c5\u548c\u89e3\u5c01\uff0c\u4ee5\u8fbe\u5230\u89e3\u6790\u6570\u636e\u7684\u4f5c\u7528\uff08\u53ef\u4ee5\u7b80\u5355\u7406\u89e3\u4e3a\u5904\u7406\u9ecf\u3001\u5206\u5305\uff09\u3002"),(0,r.kt)("li",{parentName:"ul"},"\u5c06\u7279\u6b8a\u6570\u636e\u89e3\u6790\u4e3a\u53ef\u4ee5\u4f20\u9012\u7684\u6570\u636e\u7ed3\u6784\uff0c\u4ee5\u8fbe\u5230\u89e3\u6790\u6570\u636e\u7684\u76ee\u7684\u3002")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"\u5f88\u660e\u663e\uff0c\u5927\u5bb6\u770b\u5230\u4e86\uff0c\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u7684\u4f5c\u7528\u7528\u4e00\u53e5\u8bdd\u8bf4\uff0c\u5c31\u662f\u89e3\u6790\u6570\u636e\u7528\u7684\u3002")),(0,r.kt)("h2",{id:"\u8bbe\u8ba1\u67b6\u6784"},"\u8bbe\u8ba1\u67b6\u6784"),(0,r.kt)("h3",{id:"\u5de5\u4f5c\u903b\u8f91"},"\u5de5\u4f5c\u903b\u8f91"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://images.gitee.com/uploads/images/2022/0125/192152_18f6c642_8553710.png#crop=0&crop=0&crop=1&crop=1&id=y6Ob5&originHeight=1487&originWidth=3450&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=",alt:null})),(0,r.kt)("h3",{id:"\u6570\u636e\u903b\u8f91"},"\u6570\u636e\u903b\u8f91"),(0,r.kt)("p",null,"TouchSocket\u7684\u9002\u914d\u5668\uff0c\u5728\u521d\u59cb\u9636\u6bb5\uff08\u539f\u59cbTCP\uff09\uff0c\u4f1a\u6536\u5230\u4e00\u4e2aByteBlock\u6570\u636e\uff0c\u7136\u540e\u7ecf\u8fc7\u9002\u914d\u5668\u5904\u7406\u4ee5\u540e\uff0c\u53ef\u9009\u62e9\u4e24\u4e2a\u53c2\u6570\uff08ByteBlock\u548cIRequestInfo\uff09\u7684",(0,r.kt)("strong",{parentName:"p"},"\u4efb\u610f\u7ec4\u5408"),"\u6295\u9012\u6570\u636e\u3002"),(0,r.kt)("p",null,"\u4f8b\u5982\uff1a",(0,r.kt)("strong",{parentName:"p"},"FixedHeaderPackageAdapter"),"\uff0c\u4ec5\u6295\u9012ByteBlock\u6570\u636e\uff0c\u5c4a\u65f6IRequestInfo\u5c06\u4e3anull\u3002\u800c\u5982\u679c\u662f\u7ee7\u627f\u7684",(0,r.kt)("strong",{parentName:"p"},"CustomDataHandlingAdapter"),"\uff0c\u5219\u4ec5\u6295\u9012IRequestInfo\uff0cByteBlock\u5c06\u4e3anull\u3002"),(0,r.kt)("h3",{id:"\u8bbe\u8ba1\u89e3\u91ca"},"\u8bbe\u8ba1\u89e3\u91ca"),(0,r.kt)("p",null,"\u5927\u5bb6\u6709\u65f6\u5019\u53ef\u80fd\u4f1a\u8ff7\u60d1\uff0c\u4e3a\u4ec0\u4e48TouchSocket\u8981\u8bbe\u8ba1\u4e24\u4e2a\u53c2\u6570\u6295\u9012\uff0c\u800c\u4e0d\u50cf\u5176\u4ed6\u7684\u90a3\u6837\u7684\uff0c\u5728\u4f1a\u8bdd\u91cc\u9762\uff0c\u628a\u9002\u914d\u5668\u76f4\u63a5\u6cdb\u578b\u89c4\u8303\u4e86\uff0c\u76f4\u63a5\u629b\u51fa\u5bf9\u5e94\u7684\u7c7b\u578b\u3002\u8fd9\u662f\u56e0\u4e3a\u6cdb\u578b\u7ea6\u675f\u592a\u5927\uff0c\u4e0d\u591f\u7075\u6d3b\u3002\u4f8b\u5982\uff1a"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"\u7b2c\u4e00\uff0c\u4e0d\u80fd\u968f\u65f6\u5207\u6362\u9002\u914d\u5668\uff0c\u4f8b\u5982\u9002\u914dwebSocket\uff0c\u5728\u63e1\u624b\u9636\u6bb5\uff0c\u8981\u89e3\u6790http\u6570\u636e\uff0c\u6240\u4ee5\uff0c\u6b64\u65f6\u5e94\u8be5\u9009\u62e9http\u6570\u636e\u5904\u7406\u9002\u914d\uff0c\u800c\u5b8c\u6210\u63e1\u624b\u4ee5\u540e\uff0c\u5c31\u8981\u89e3\u6790ws\u6570\u636e\u683c\u5f0f\u4e86\uff0c\u6240\u4ee5\u6b64\u65f6\u5e94\u8be5\u5207\u6362\u9002\u914d\u5668\u4e3aws\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u3002"),(0,r.kt)("li",{parentName:"ul"},"\u7b2c\u4e8c\uff0c\u4e24\u4e2a\u53c2\u6570\u80fd\u63d0\u9ad8\u6027\u80fd\u3002\u4f8b\u5982HTTP\u6570\u636e\u5904\u7406\u9002\u914d\u5668\uff0c\u5728\u9ad8\u6027\u80fd\u5de5\u4f5c\u6a21\u5f0f\u4e0b\uff0c\u7531IRequestInfo\u6295\u9012\u8bf7\u6c42\u5934\uff0c\u7531ByteBlock\u6295\u9012Body\uff0c\u8fd9\u6837Body\u662f\u4ece\u5185\u5b58\u6c60\u83b7\u5f97\uff0c\u5c31\u4e0d\u5b58\u5728\u5185\u5b58\u6d88\u8017\u4e86\u3002")),(0,r.kt)("h2",{id:"\u4e09tcp\u4f7f\u7528"},"\u4e09\u3001TCP\u4f7f\u7528"),(0,r.kt)("p",null,"\u5728TCP\u7cfb\u4e2d\u4f7f\u7528\u6570\u636e\u5904\u7406\u9002\u914d\u5668\u662f\u975e\u5e38\u7b80\u5355\u7684\u4e00\u4e2a\u8fc7\u7a0b\u3002\u800c\u4e14\u4e3a\u4e86\u4e0d\u540c\u573a\u666f\uff0cTouchSocket\u652f\u6301\u591a\u79cd\u65b9\u5f0f\u7684\u9002\u914d\u5668\u4f7f\u7528\u3002\u670d\u52a1\u5668\u548c\u5ba2\u6237\u7aef\u4f7f\u7528\u4e00\u81f4"),(0,r.kt)("h3",{id:"31-\u5728config\u914d\u7f6e\u4e2d\u4f7f\u7528"},"3.1 \u5728Config\u914d\u7f6e\u4e2d\u4f7f\u7528"),(0,r.kt)("p",null,"\u5728Config\u914d\u7f6e\u4f7f\u7528\u65f6\uff0c\u76f8\u5f53\u4e8e\u521d\u59cb\u5316\u8d4b\u503c\u3002\u6bd4\u8f83\u5355\u4e00\uff0c\u4f46\u662f\u5f88\u53ef\u9760\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},".SetDataHandlingAdapter(()=> { return new MyCustomBetweenAndDataHandlingAdapter(); })\n")),(0,r.kt)("h3",{id:"32-\u8ba2\u9605connecting\u76f8\u5173\u4e8b\u4ef6"},"3.2 \u8ba2\u9605Connecting\u76f8\u5173\u4e8b\u4ef6"),(0,r.kt)("p",null,"\u53ea\u9700\u8981\u5728",(0,r.kt)("inlineCode",{parentName:"p"},"OnConnecting"),"\u65b9\u6cd5\uff08\u6216",(0,r.kt)("inlineCode",{parentName:"p"},"Connecting"),"\u4e8b\u4ef6\uff09\u4e2d\u5bf9\u65b0\u8fde\u63a5\u7684Client\uff0c\u8c03\u7528SetDataHandlingAdapter\u8fdb\u884c\u8d4b\u503c\u5373\u53ef\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MyTcpService : TcpService<MySocketClient>\n{\n protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e)\n {\n socketClient.SetDataHandlingAdapter(new NormalDataHandlingAdapter());//\u76f4\u63a5\u5bf9\u6570\u636e\u5904\u7406\u5668\u8d4b\u503c\uff0c\u7acb\u5373\u751f\u6548\n base.OnConnecting(socketClient, e);\n }\n}\n")),(0,r.kt)("h3",{id:"33-\u4f7f\u7528\u63d2\u4ef6\u4ee3\u66ffconnecting\u76f8\u5173\u4e8b\u4ef6\u5b9e\u73b0"},"3.3 \u4f7f\u7528\u63d2\u4ef6\uff0c\u4ee3\u66ffConnecting\u76f8\u5173\u4e8b\u4ef6\u5b9e\u73b0"),(0,r.kt)("p",null,"\u4f7f\u7528\u63d2\u4ef6\u5b9e\u73b0\u8be5\u529f\u80fd\uff0c\u5b9e\u9645\u4e0a\u548c\u6b65\u9aa42\u4e00\u6837\uff0c\u4f46\u662f\u56e0\u4e3a\u662f\u57fa\u4e8e\u63d2\u4ef6\uff0c\u6240\u4ee5\u66f4\u597d\u4e8e\u7ba1\u7406\u3002"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"class MyPlugin : TcpPluginBase\n{\n protected override void OnConnecting(ITcpClientBase client, ClientOperationEventArgs e)\n {\n client.SetDataHandlingAdapter(new NormalDataHandlingAdapter());\n base.OnConnecting(client, e);\n }\n}\n")),(0,r.kt)("h3",{id:"34-\u4efb\u610f\u65f6\u523b\u8bbe\u7f6e"},"3.4 \u4efb\u610f\u65f6\u523b\u8bbe\u7f6e"),(0,r.kt)("p",null,"\u5b9e\u9645\u4e0a\uff0c\u5927\u5bb6\u53ef\u4ee5\u4ece\u6b65\u9aa42\u30013\u4e2d\u770b\u51fa\u6765\uff0c\u9002\u914d\u5668\u662f\u53ef\u4ee5\u88ab\u968f\u610f\u8d4b\u503c\u7684\uff0c\u8fd9\u4e5f\u5c31\u8bf4\u660e\uff0c\u9002\u914d\u5668\u662f\u53ef\u4ee5\u968f\u65f6\u88ab\u66ff\u6362\u7684\u3002\u90a3\u4e48\u4e5f\u5c31\u53ef\u4ee5\u88ab\u968f\u65f6\u8d4b\u503c\u4e86\u3002"),(0,r.kt)("h2",{id:"\u56dbudp\u4f7f\u7528\u63d2\u4ef6"},"\u56db\u3001UDP\u4f7f\u7528\u63d2\u4ef6"),(0,r.kt)("p",null,"Udp\u4f7f\u7528\u7684\u63d2\u4ef6\uff0c\u53ea\u80fd\u4eceConfig\u914d\u7f6e\u3002\n\u3010",(0,r.kt)("strong",{parentName:"p"},"UdpSession"),"\u3011"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"}," m_udpSession.Setup(new TouchSocketConfig()\n .SetBindIPHost(new IPHost(this.textBox2.Text))\n .SetUdpDataHandlingAdapter(()=> \n {\n return new NormalUdpDataHandlingAdapter();\n })\n .ConfigureContainer(a =>\n {\n a.SetSingletonLogger(new LoggerGroup(new EasyLogger(this.ShowMsg), new FileLogger()));\n }))\n .Start();\n")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("em",{parentName:"strong"},"\u6ce8\u610f\uff1a"),"\u540c\u4e00\u4e2a\u9002\u914d\u5668\u5b9e\u4f8b\uff0c\u53ea\u53ef\u88ab\u8d4b\u503c\u4e00\u6b21\uff0c\u4e0d\u7136\u4f1a\u5f02\u5e38\u3002",(0,r.kt)("em",{parentName:"strong"},"\u5982\u679c\u5728\u6784\u9020\u51fd\u6570\uff08\u6216\u5176\u4ed6\u4e00\u6b21\u6027\u51fd\u6570\uff09\u4e2d\u8bbe\u7f6e\u9002\u914d\u5668\u7684\u8bdd\uff0c\u5728\u91cd\u8fde\u65f6\uff0c\u6700\u597d\u91cd\u65b0\u8bbe\u7f6e\u9002\u914d\u5668\uff0c\u56e0\u4e3a\u6846\u67b6\u5728Disconnected\u65f6\u4f1a\u7f6e\u7a7a\u9002\u914d\u5668\uff0c\u540c\u65f6\u5728Connecting\u6267\u884c\u5b8c\u540e\u4f1a\u68c0\u6d4b\u9002\u914d\u5668\uff0c\u5982\u679c\u6ca1\u6709\u518d\u6b21\u8bbe\u7f6e\u9002\u914d\u5668\u7684\u8bdd\uff0c\u4f1a\u9009\u62e9\u9ed8\u8ba4\u9002\u914d\u5668\uff08TcpClient\u4f1a\u9009\u62e9\u666e\u901a\u9002\u914d\u5668\uff0cProtocol\u53ca\u6d3e\u751f\u4f1a\u9009\u62e9\u56fa\u5b9a\u5305\u5934\u9002\u914d\u5668\uff09\u3002"))),(0,r.kt)("h2",{id:"\u4e94\u9650\u5236\u4f7f\u7528"},"\u4e94\u3001\u9650\u5236\u4f7f\u7528"),(0,r.kt)("p",null,"\u9650\u5236\u4f7f\u7528\u7684\u573a\u666f\u5e94\u7528\u4e8e\u81ea\u5b9a\u4e49\u5c01\u88c5\u3002\u4f8b\u5982\uff1a\u81ea\u5df1\u5c01\u88c5\u4e00\u4e2a\u670d\u52a1\u5668\uff0c\u7136\u540e\u9002\u914d\u5668\u4ec5",(0,r.kt)("strong",{parentName:"p"},"\u7279\u5b9a\u4f7f\u7528"),"\uff0c\u4e0d\u5141\u8bb8\u5916\u90e8\u968f\u610f\u8d4b\u503c\uff0c\u90a3\u4e48\u53ef\u4ee5\u5982\u4e0b\u5b9e\u73b0\uff1a"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"},"public class MySocketClient : SocketClient\n{\n /// <summary>\n /// <inheritdoc/>\n /// </summary>\n public override sealed bool CanSetDataHandlingAdapter => false;//\u4e0d\u5141\u8bb8\u968f\u610f\u8d4b\u503c\n \n private void InternalSetAdapter(DataHandlingAdapter adapter)\n {\n this.SetAdapter(adapter);//\u4ec5\u7ee7\u627f\u5185\u90e8\u8d4b\u503c\n }\n}\n")),(0,r.kt)("h2",{id:"\u516d\u7f13\u5b58\u8d85\u65f6\u4ec5tcp\u9002\u914d\u5668"},"\u516d\u3001\u7f13\u5b58\u8d85\u65f6\uff08\u4ec5Tcp\u9002\u914d\u5668\uff09"),(0,r.kt)("p",null,"\u5f53\u9002\u914d\u5668\u5728\u5de5\u4f5c\u65f6\uff0c\u5982\u679c\u4e00\u4e2a\u6570\u636e\u5305\u5728\u8bbe\u7f6e\u7684\u5468\u671f\u5185\uff08\u9ed8\u8ba41000ms\uff09\u6ca1\u6709\u5b8c\u6210\u63a5\u6536\uff0c\u5219\u4f1a\u6e05\u7a7a\u6240\u6709\u7f13\u5b58\u6570\u636e\uff0c\u7136\u540e\u91cd\u65b0\u63a5\u6536\u3002\n\u8fd9\u79cd\u8bbe\u8ba1\u662f\u4e3a\u4e86\u5e94\u5bf9\uff0c\u5f53\u63a5\u6536\u6570\u636e\u65f6\uff0c\u5982\u679c\u53d1\u9001\u65b9\u53d1\u9001\u4e86\u5f02\u5e38\u6570\u636e\uff08\u4e5f\u6709\u53ef\u80fd\u5728\u79fb\u52a8\u7f51\u65f6\uff0c\u7531\u8fd0\u8425\u5546\u53d1\u9001\u7684\u65e0\u6548\u5305\uff09\u800c\u5bfc\u81f4\u6574\u4e2a\u63a5\u6536\u961f\u5217\u6570\u636e\u65e0\u6548\u7684\u95ee\u9898\u3002\n\u73b0\u5728\u52a0\u5165\u7f13\u5b58\u8d85\u65f6\u8bbe\u7f6e\uff0c\u5219\u5982\u679c\u53d1\u9001\u4e0a\u8ff0\u60c5\u51b5\uff0c\u4e5f\u4f1a\u5728\u4e00\u4e2a\u5468\u671f\u540e\uff0c\u5feb\u901f\u6062\u590d\u63a5\u6536\u3002"),(0,r.kt)("p",null,"\u76f8\u5173\u5c5e\u6027\u8bbe\u7f6e\uff1a"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"CacheTimeoutEnable\uff1a\u662f\u5426\u542f\u7528\u7f13\u5b58\u8d85\u65f6\u3002"),(0,r.kt)("li",{parentName:"ul"},"CacheTimeout\uff1a\u7f13\u5b58\u8d85\u65f6\u65f6\u95f4"),(0,r.kt)("li",{parentName:"ul"},"UpdateCacheTimeWhenRev\uff1a\u662f\u5426\u6bcf\u6b21\u63a5\u6536\u5c31\u66f4\u65b0\u7f13\u5b58\u65f6\u95f4\u3002\u9ed8\u8ba4true\uff0c\u610f\u5473\u7740\u53ea\u8981\u6709\u6570\u636e\u63a5\u6536\uff0c\u5219\u7f13\u5b58\u6c38\u8fdc\u4e0d\u4f1a\u8fc7\u671f\u3002\u5f53\u4e3afalse\u65f6\uff0c\u5219\u6bcf\u4e2a\u7f13\u5b58\u5305\uff0c\u5fc5\u987b\u5728\u8bbe\u7f6e\u7684\u5468\u671f\u5185\u5b8c\u6210\u63a5\u6536\u3002")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/handbook/build/assets/js/main.175592cd.js b/handbook/build/assets/js/main.175592cd.js new file mode 100644 index 000000000..96152f799 --- /dev/null +++ b/handbook/build/assets/js/main.175592cd.js @@ -0,0 +1,2 @@ +/*! For license information please see main.175592cd.js.LICENSE.txt */ +(self.webpackChunktouchsocket=self.webpackChunktouchsocket||[]).push([[179],{723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),o=n(7462),a=n(8356),i=n.n(a),s=n(6887);const c={"01fa1a8d":[()=>n.e(9035).then(n.bind(n,3914)),"@site/docs/terminatorpackageadapter.mdx",3914],"04ff01fb":[()=>Promise.all([n.e(532),n.e(1586)]).then(n.bind(n,4748)),"@site/docs/createtcpservice.mdx",4748],"0654e75d":[()=>n.e(7987).then(n.t.bind(n,5745,19)),"D:\\OpenCode\\TouchSocket\\handbook\\.docusaurus\\docusaurus-plugin-content-pages\\default\\plugin-route-context-module-100.json",5745],"078d73b8":[()=>n.e(4018).then(n.bind(n,7430)),"@site/docs/pipelinedatahandlingadapter.mdx",7430],"09a85799":[()=>n.e(9541).then(n.bind(n,7475)),"@site/docs/tcpcommandlineplugin.mdx",7475],"0a7a9b32":[()=>n.e(7162).then(n.bind(n,2878)),"@site/docs/rpcoption.mdx",2878],"0afce4d0":[()=>n.e(2996).then(n.bind(n,4898)),"@site/docs/customdatahandlingadapter.mdx",4898],"0b8ef44c":[()=>n.e(9750).then(n.bind(n,3819)),"@site/docs/xmlrpcdescription.mdx",3819],"0c2b5d1a":[()=>n.e(9925).then(n.bind(n,4348)),"@site/docs/othercore.mdx",4348],"0fc86718":[()=>n.e(2903).then(n.bind(n,8690)),"@site/docs/consoleaction.mdx",8690],"11f9f480":[()=>n.e(2671).then(n.bind(n,7116)),"@site/docs/wscommandlineplugin.mdx",7116],"11fc8f46":[()=>n.e(1317).then(n.bind(n,6854)),"@site/docs/tcpother.mdx",6854],"13b149a4":[()=>n.e(9911).then(n.bind(n,3565)),"@site/docs/appmessenger.mdx",3565],"17443a98":[()=>n.e(1965).then(n.bind(n,2702)),"@site/docs/transferfile.mdx",2702],"177fd31f":[()=>n.e(8300).then(n.bind(n,291)),"@site/docs/webapiservice.mdx",291],17896441:[()=>Promise.all([n.e(532),n.e(9523),n.e(7918)]).then(n.bind(n,2839)),"@theme/DocItem",2839],"19a46420":[()=>Promise.all([n.e(532),n.e(5725)]).then(n.bind(n,598)),"@site/docs/generateproxy.mdx",598],"1a4e3797":[()=>Promise.all([n.e(532),n.e(7920)]).then(n.bind(n,2027)),"@theme/SearchPage",2027],"1be78505":[()=>Promise.all([n.e(532),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"1c9cad99":[()=>n.e(1285).then(n.bind(n,3230)),"@site/docs/dataadaptertester.mdx",3230],"1ec5dc39":[()=>n.e(7462).then(n.bind(n,5160)),"@site/docs/createtouchrpcservice.mdx",5160],"223951e7":[()=>n.e(631).then(n.bind(n,7183)),"@site/docs/eventbus.mdx",7183],"28d8f037":[()=>n.e(505).then(n.bind(n,4519)),"@site/docs/adapterdemodescription.mdx",4519],"2c06b999":[()=>n.e(5983).then(n.bind(n,5389)),"@site/docs/createudpsession.mdx",5389],"3030335d":[()=>n.e(2289).then(n.bind(n,9574)),"@site/docs/fixedheaderpackageadapter.mdx",9574],"320af078":[()=>n.e(6373).then(n.bind(n,3312)),"@site/docs/udpdatahandlingadapter.mdx",3312],"329302c4":[()=>n.e(230).then(n.t.bind(n,2776,19)),"D:\\OpenCode\\TouchSocket\\handbook\\.docusaurus\\@easyops-cn\\docusaurus-search-local\\default\\plugin-route-context-module-100.json",2776],"355b4941":[()=>n.e(5683).then(n.bind(n,2214)),"@site/docs/createhttpservice.mdx",2214],"389c2360":[()=>n.e(1687).then(n.bind(n,4873)),"@site/docs/stategridtransmission.mdx",4873],"3ab343cc":[()=>n.e(5873).then(n.bind(n,2855)),"@site/docs/createwebsocketservice.mdx",2855],"3b5f8c2c":[()=>n.e(9171).then(n.bind(n,6807)),"@site/docs/rpcallcontext.mdx",6807],41627674:[()=>n.e(2894).then(n.bind(n,5959)),"@site/docs/createhttpclient.mdx",5959],"41b30073":[()=>n.e(1868).then(n.bind(n,961)),"@site/docs/wsjsonrpc.mdx",961],"430053de":[()=>n.e(803).then(n.bind(n,1714)),"@site/docs/callwebapi.mdx",1714],"47f1b9ba":[()=>n.e(4929).then(n.bind(n,8104)),"@site/docs/httpstaticpageplugin.mdx",8104],"4c79e569":[()=>Promise.all([n.e(532),n.e(8707)]).then(n.bind(n,7271)),"@site/docs/upgrade.mdx",7271],"4d13c877":[()=>n.e(9030).then(n.bind(n,551)),"@site/docs/customfixedheaderdatahandlingadapter.mdx",551],"4e9c6747":[()=>n.e(1168).then(n.bind(n,2673)),"@site/docs/serializationselector.mdx",2673],"4ecf139e":[()=>n.e(5215).then(n.bind(n,7506)),"@site/docs/webdataforwarding.mdx",7506],"5137840a":[()=>n.e(8494).then(n.bind(n,4178)),"@site/docs/description.mdx",4178],"53cff02b":[()=>n.e(9311).then(n.bind(n,7148)),"@site/docs/createwebsocketclient.mdx",7148],"578e6f54":[()=>n.e(2375).then(n.bind(n,2467)),"@site/docs/streamtransfer.mdx",2467],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"6bf8fe32":[()=>Promise.all([n.e(532),n.e(8808)]).then(n.bind(n,7507)),"@site/docs/tlvdatahandlingadapter.mdx",7507],"763782ab":[()=>n.e(1969).then(n.bind(n,3094)),"@site/docs/ilog.mdx",3094],"7a6724ae":[()=>n.e(4456).then(n.bind(n,8759)),"@site/docs/calljsonrpc.mdx",8759],"7b93349f":[()=>n.e(6171).then(n.bind(n,5705)),"@site/docs/dependencyproperty.mdx",5705],"7c171c7d":[()=>n.e(2373).then(n.bind(n,4738)),"@site/docs/callxmlrpc.mdx",4738],"8154dd80":[()=>n.e(908).then(n.bind(n,4071)),"@site/docs/wpfuifiletransfer.mdx",4071],"88be757d":[()=>n.e(1302).then(n.bind(n,9522)),"@site/docs/fpsgame.mdx",9522],"8973b48c":[()=>n.e(3635).then(n.bind(n,753)),"@site/docs/pluginsmanager.mdx",753],"8aa4b8ad":[()=>n.e(1877).then(n.bind(n,2436)),"@site/docs/startguide.mdx",2436],"8c4cc064":[()=>n.e(3214).then(n.bind(n,4046)),"@site/docs/resetid.mdx",4046],"8e1e2f35":[()=>n.e(9198).then(n.bind(n,3286)),"@site/docs/bigfixedheadercustomdatahandlingadapter.mdx",3286],"8e5f0e39":[()=>n.e(9954).then(n.bind(n,4393)),"@site/docs/httpfiletransfer.mdx",4393],"9106ea79":[()=>n.e(9769).then(n.bind(n,9882)),"@site/docs/createtouchrpcclient.mdx",9882],"915634cf":[()=>Promise.all([n.e(532),n.e(2022)]).then(n.bind(n,2859)),"@site/docs/reconnection.mdx",2859],"91a311b4":[()=>n.e(4850).then(n.bind(n,2105)),"@site/docs/jsonserialize.mdx",2105],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],"94601e7d":[()=>n.e(7278).then(n.bind(n,5623)),"@site/docs/smallfiletransfer.mdx",5623],"94e3a799":[()=>n.e(7453).then(n.bind(n,3475)),"@site/docs/rpcstream.mdx",3475],"965c04d6":[()=>n.e(6505).then(n.bind(n,646)),"@site/docs/jsonrpcservice.mdx",646],"9a8bd036":[()=>n.e(2416).then(n.bind(n,920)),"@site/docs/customunfixedheaderdatahandlingadapter.mdx",920],"9bfb9f12":[()=>n.e(5264).then(n.bind(n,9817)),"@site/docs/fastbinaryformatter.mdx",9817],"9e2cc891":[()=>n.e(1895).then(n.bind(n,7688)),"@site/docs/udpbroadcast.mdx",7688],a14859b4:[()=>n.e(9660).then(n.bind(n,7409)),"@site/docs/xmlrpcservice.mdx",7409],a2c90a25:[()=>n.e(8719).then(n.bind(n,8610)),"@site/docs/touchrpcbase.mdx",8610],a46d2111:[()=>n.e(8835).then(n.bind(n,9170)),"@site/docs/touchrpcdescription.mdx",9170],a81d4448:[()=>n.e(6191).then(n.bind(n,1413)),"@site/docs/createtcpclient.mdx",1413],a82e3754:[()=>n.e(1592).then(n.bind(n,6435)),"@site/docs/webapidescription.mdx",6435],aa2c2bac:[()=>n.e(8411).then(n.bind(n,6244)),"@site/docs/touchsocketbitconverter.mdx",6244],aa4c723b:[()=>n.e(6487).then(n.bind(n,5009)),"@site/docs/normaldatahandlingadapter.mdx",5009],adf44bc8:[()=>n.e(9253).then(n.bind(n,7157)),"@site/docs/filepool.mdx",7157],b0d79caf:[()=>n.e(1971).then(n.bind(n,4734)),"@site/docs/engineertoolbox.mdx",4734],b1f68223:[()=>n.e(3285).then(n.bind(n,3387)),"@site/docs/custombetweenanddatahandlingadapter.mdx",3387],b4d3dab5:[()=>n.e(4724).then(n.bind(n,3245)),"@site/docs/cooperation.mdx",3245],b7e03a75:[()=>n.e(3503).then(n.bind(n,8744)),"@site/docs/waitingclient.mdx",8744],b806365f:[()=>Promise.all([n.e(532),n.e(1601)]).then(n.bind(n,4359)),"@site/docs/remotestreamaccess.mdx",4359],b992e8b3:[()=>n.e(6128).then(n.bind(n,8496)),"@site/docs/ipackage.mdx",8496],ba9c7ecd:[()=>n.e(487).then(n.bind(n,6923)),"@site/docs/fixedsizepackageadapter.mdx",6923],babdfbe3:[()=>n.e(3420).then(n.bind(n,2257)),"@site/docs/independentusedatahandlingadapter.mdx",2257],bc87ecb9:[()=>n.e(7586).then(n.bind(n,7112)),"@site/docs/rpcactionfilter.mdx",7112],bcf858d2:[()=>n.e(7986).then(n.bind(n,9620)),"@site/docs/filesynchronization.mdx",9620],c4f5d8e4:[()=>Promise.all([n.e(532),n.e(9523),n.e(4195)]).then(n.bind(n,6959)),"@site/src/pages/index.js",6959],c8245f17:[()=>n.e(7436).then(n.bind(n,287)),"@site/docs/remotemonitoring.mdx",287],c8d1f2bf:[()=>n.e(8032).then(n.bind(n,4139)),"@site/docs/ioc.mdx",4139],cbd4f89d:[()=>n.e(6390).then(n.t.bind(n,3769,19)),"D:\\OpenCode\\TouchSocket\\handbook\\.docusaurus\\docusaurus-plugin-content-docs\\default\\plugin-route-context-module-100.json",3769],ce02ea51:[()=>Promise.all([n.e(532),n.e(7790)]).then(n.bind(n,1290)),"@site/docs/remotefilecontrol.mdx",1290],d22033f9:[()=>n.e(3371).then(n.bind(n,3608)),"@site/docs/donate.mdx",3608],d5d2094c:[()=>n.e(904).then(n.bind(n,1797)),"@site/docs/bytepool.mdx",1797],d6520aa6:[()=>n.e(6050).then(n.bind(n,5833)),"@site/docs/jsonrpcdescription.mdx",5833],d6be6cb7:[()=>Promise.all([n.e(532),n.e(1705)]).then(n.bind(n,6643)),"@site/docs/natservice.mdx",6643],da3959dc:[()=>Promise.all([n.e(532),n.e(1793)]).then(n.bind(n,1184)),"@site/docs/multithreadingfiletransfer.mdx",1184],df41208d:[()=>n.e(8102).then(n.bind(n,439)),"@site/docs/heartbeat.mdx",439],dfe172e5:[()=>n.e(7016).then(n.bind(n,9011)),"@site/docs/createandcallrpc.mdx",9011],e5d5df95:[()=>n.e(4649).then(n.bind(n,8865)),"@site/docs/dataforwarding.mdx",8865],e782541c:[()=>n.e(2934).then(n.bind(n,774)),"@site/docs/udptransmitbigdata.mdx",774],e7e0ef60:[()=>n.e(6746).then(n.bind(n,5869)),"@site/docs/datasecurity.mdx",5869],eafaca75:[()=>n.e(1569).then(n.bind(n,5786)),"@site/docs/datahandleadapter.mdx",5786],eb7c3b1b:[()=>n.e(8610).then(n.bind(n,9130)),"@site/docs/websocketdescription.mdx",9130],f05a39b7:[()=>Promise.all([n.e(532),n.e(1822)]).then(n.bind(n,3968)),"@site/docs/enterprise.mdx",3968],fce76f89:[()=>n.e(138).then(n.bind(n,770)),"@site/docs/adapterdescription.mdx",770]};function l(e){let{error:t,retry:n,pastDelay:o}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):o?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var u=n(9670),d=n(226);function p(e,t){if("*"===e)return i()({loading:l,loader:()=>n.e(4972).then(n.bind(n,4972)),modules:["@theme/NotFound"],webpack:()=>[4972],render(e,t){const n=e.default;return r.createElement(d.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const a=s[`${e}-${t}`],p={},f=[],h=[],m=(0,u.Z)(a);return Object.entries(m).forEach((e=>{let[t,n]=e;const r=c[n];r&&(p[t]=r[0],f.push(r[1]),h.push(r[2]))})),i().Map({loading:l,loader:p,modules:f,webpack:()=>h,render(t,n){const i=JSON.parse(JSON.stringify(a));Object.entries(t).forEach((t=>{let[n,r]=t;const o=r.default;if(!o)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof o&&"function"!=typeof o||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{o[e]=r[e]}));let a=i;const s=n.split(".");s.slice(0,-1).forEach((e=>{a=a[e]})),a[s[s.length-1]]=o}));const s=i.__comp;delete i.__comp;const c=i.__context;return delete i.__context,r.createElement(d.z,{value:c},r.createElement(s,(0,o.Z)({},i,n)))}})}const f=[{path:"/touchsocket/search",component:p("/touchsocket/search","f08"),exact:!0},{path:"/touchsocket/docs",component:p("/touchsocket/docs","8f3"),routes:[{path:"/touchsocket/docs/",component:p("/touchsocket/docs/","cb6"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/adapterdemodescription",component:p("/touchsocket/docs/adapterdemodescription","a95"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/adapterdescription",component:p("/touchsocket/docs/adapterdescription","b0b"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/appmessenger",component:p("/touchsocket/docs/appmessenger","66c"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter",component:p("/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","6bb"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/bytepool",component:p("/touchsocket/docs/bytepool","ef6"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/calljsonrpc",component:p("/touchsocket/docs/calljsonrpc","fd9"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/callwebapi",component:p("/touchsocket/docs/callwebapi","a42"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/callxmlrpc",component:p("/touchsocket/docs/callxmlrpc","56e"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/consoleaction",component:p("/touchsocket/docs/consoleaction","920"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/cooperation",component:p("/touchsocket/docs/cooperation","cab"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createandcallrpc",component:p("/touchsocket/docs/createandcallrpc","de5"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createhttpclient",component:p("/touchsocket/docs/createhttpclient","11e"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createhttpservice",component:p("/touchsocket/docs/createhttpservice","d76"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createtcpclient",component:p("/touchsocket/docs/createtcpclient","b72"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createtcpservice",component:p("/touchsocket/docs/createtcpservice","aad"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createtouchrpcclient",component:p("/touchsocket/docs/createtouchrpcclient","c57"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createtouchrpcservice",component:p("/touchsocket/docs/createtouchrpcservice","23d"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createudpsession",component:p("/touchsocket/docs/createudpsession","539"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createwebsocketclient",component:p("/touchsocket/docs/createwebsocketclient","58c"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/createwebsocketservice",component:p("/touchsocket/docs/createwebsocketservice","2f1"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/custombetweenanddatahandlingadapter",component:p("/touchsocket/docs/custombetweenanddatahandlingadapter","f13"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/customdatahandlingadapter",component:p("/touchsocket/docs/customdatahandlingadapter","23d"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/customfixedheaderdatahandlingadapter",component:p("/touchsocket/docs/customfixedheaderdatahandlingadapter","6c6"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/customunfixedheaderdatahandlingadapter",component:p("/touchsocket/docs/customunfixedheaderdatahandlingadapter","ce0"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/dataadaptertester",component:p("/touchsocket/docs/dataadaptertester","18e"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/dataforwarding",component:p("/touchsocket/docs/dataforwarding","2ec"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/datahandleadapter",component:p("/touchsocket/docs/datahandleadapter","c50"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/datasecurity",component:p("/touchsocket/docs/datasecurity","c18"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/dependencyproperty",component:p("/touchsocket/docs/dependencyproperty","02c"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/donate",component:p("/touchsocket/docs/donate","bf4"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/engineertoolbox",component:p("/touchsocket/docs/engineertoolbox","11e"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/enterprise",component:p("/touchsocket/docs/enterprise","dc8"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/eventbus",component:p("/touchsocket/docs/eventbus","926"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/fastbinaryformatter",component:p("/touchsocket/docs/fastbinaryformatter","0dc"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/filepool",component:p("/touchsocket/docs/filepool","ca8"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/filesynchronization",component:p("/touchsocket/docs/filesynchronization","4f8"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/fixedheaderpackageadapter",component:p("/touchsocket/docs/fixedheaderpackageadapter","e86"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/fixedsizepackageadapter",component:p("/touchsocket/docs/fixedsizepackageadapter","e8a"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/fpsgame",component:p("/touchsocket/docs/fpsgame","a6d"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/generateproxy",component:p("/touchsocket/docs/generateproxy","b1d"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/heartbeat",component:p("/touchsocket/docs/heartbeat","01b"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/httpfiletransfer",component:p("/touchsocket/docs/httpfiletransfer","af0"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/httpstaticpageplugin",component:p("/touchsocket/docs/httpstaticpageplugin","82c"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/ilog",component:p("/touchsocket/docs/ilog","2f1"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/independentusedatahandlingadapter",component:p("/touchsocket/docs/independentusedatahandlingadapter","a22"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/ioc",component:p("/touchsocket/docs/ioc","0b7"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/ipackage",component:p("/touchsocket/docs/ipackage","5da"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/jsonrpcdescription",component:p("/touchsocket/docs/jsonrpcdescription","83f"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/jsonrpcservice",component:p("/touchsocket/docs/jsonrpcservice","06e"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/jsonserialize",component:p("/touchsocket/docs/jsonserialize","995"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/multithreadingfiletransfer",component:p("/touchsocket/docs/multithreadingfiletransfer","b72"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/natservice",component:p("/touchsocket/docs/natservice","405"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/normaldatahandlingadapter",component:p("/touchsocket/docs/normaldatahandlingadapter","9cc"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/othercore",component:p("/touchsocket/docs/othercore","943"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/pipelinedatahandlingadapter",component:p("/touchsocket/docs/pipelinedatahandlingadapter","e0b"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/pluginsmanager",component:p("/touchsocket/docs/pluginsmanager","8e0"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/reconnection",component:p("/touchsocket/docs/reconnection","35a"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/remotefilecontrol",component:p("/touchsocket/docs/remotefilecontrol","79b"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/remotemonitoring",component:p("/touchsocket/docs/remotemonitoring","ddf"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/remotestreamaccess",component:p("/touchsocket/docs/remotestreamaccess","e07"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/resetid",component:p("/touchsocket/docs/resetid","256"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/rpcactionfilter",component:p("/touchsocket/docs/rpcactionfilter","dd3"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/rpcallcontext",component:p("/touchsocket/docs/rpcallcontext","f79"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/rpcoption",component:p("/touchsocket/docs/rpcoption","93c"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/rpcstream",component:p("/touchsocket/docs/rpcstream","4f6"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/serializationselector",component:p("/touchsocket/docs/serializationselector","152"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/smallfiletransfer",component:p("/touchsocket/docs/smallfiletransfer","37f"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/startguide",component:p("/touchsocket/docs/startguide","ea6"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/stategridtransmission",component:p("/touchsocket/docs/stategridtransmission","37e"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/streamtransfer",component:p("/touchsocket/docs/streamtransfer","5dc"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/tcpcommandlineplugin",component:p("/touchsocket/docs/tcpcommandlineplugin","1db"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/tcpother",component:p("/touchsocket/docs/tcpother","0fb"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/terminatorpackageadapter",component:p("/touchsocket/docs/terminatorpackageadapter","4ab"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/tlvdatahandlingadapter",component:p("/touchsocket/docs/tlvdatahandlingadapter","116"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/touchrpcbase",component:p("/touchsocket/docs/touchrpcbase","7a5"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/touchrpcdescription",component:p("/touchsocket/docs/touchrpcdescription","bcb"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/touchsocketbitconverter",component:p("/touchsocket/docs/touchsocketbitconverter","063"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/transferfile",component:p("/touchsocket/docs/transferfile","88a"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/udpbroadcast",component:p("/touchsocket/docs/udpbroadcast","3b5"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/udpdatahandlingadapter",component:p("/touchsocket/docs/udpdatahandlingadapter","05f"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/udptransmitbigdata",component:p("/touchsocket/docs/udptransmitbigdata","3b2"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/upgrade",component:p("/touchsocket/docs/upgrade","8ca"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/waitingclient",component:p("/touchsocket/docs/waitingclient","631"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/webapidescription",component:p("/touchsocket/docs/webapidescription","f37"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/webapiservice",component:p("/touchsocket/docs/webapiservice","136"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/webdataforwarding",component:p("/touchsocket/docs/webdataforwarding","1bb"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/websocketdescription",component:p("/touchsocket/docs/websocketdescription","0d3"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/wpfuifiletransfer",component:p("/touchsocket/docs/wpfuifiletransfer","ce5"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/wscommandlineplugin",component:p("/touchsocket/docs/wscommandlineplugin","8e5"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/wsjsonrpc",component:p("/touchsocket/docs/wsjsonrpc","b21"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/xmlrpcdescription",component:p("/touchsocket/docs/xmlrpcdescription","4c9"),exact:!0,sidebar:"docs"},{path:"/touchsocket/docs/xmlrpcservice",component:p("/touchsocket/docs/xmlrpcservice","b6f"),exact:!0,sidebar:"docs"}]},{path:"/touchsocket/",component:p("/touchsocket/","c0a"),exact:!0},{path:"*",component:p("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>o,t:()=>a});var r=n(7294);const o=r.createContext(!1);function a(e){let{children:t}=e;const[n,a]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{a(!0)}),[]),r.createElement(o.Provider,{value:n},t)}},9383:(e,t,n)=>{"use strict";var r=n(7294),o=n(3935),a=n(3727),i=n(405),s=n(412);const c=[n(2497),n(3310),n(8320),n(2295),n(4811)];var l=n(723),u=n(6775),d=n(8790);function p(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var f=n(7462),h=n(5742),m=n(2263),g=n(4996),b=n(6668),v=n(1944),y=n(4711),k=n(9727),E=n(3320),w=n(197);function x(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,m.Z)(),n=(0,y.l)();return r.createElement(h.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:o}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:o})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function S(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,m.Z)(),o=function(){const{siteConfig:{url:e}}=(0,m.Z)(),{pathname:t}=(0,u.TH)();return e+(0,g.Z)(t)}(),a=t?`${n}${t}`:o;return r.createElement(h.Z,null,r.createElement("meta",{property:"og:url",content:a}),r.createElement("link",{rel:"canonical",href:a}))}function _(){const{i18n:{currentLocale:e}}=(0,m.Z)(),{metadata:t,image:n}=(0,b.L)();return r.createElement(r.Fragment,null,r.createElement(h.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:k.h})),n&&r.createElement(v.d,{image:n}),r.createElement(S,null),r.createElement(x,null),r.createElement(w.Z,{tag:E.HX,locale:e}),r.createElement(h.Z,null,t.map(((e,t)=>r.createElement("meta",(0,f.Z)({key:t},e))))))}const T=new Map;function C(e){if(T.has(e.pathname))return{...e,pathname:T.get(e.pathname)};if((0,d.f)(l.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return T.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return T.set(e.pathname,t),{...e,pathname:t}}var L=n(8934),N=n(8940);function I(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const o=c.map((t=>{var r;const o=(null==(r=t.default)?void 0:r[e])??t[e];return null==o?void 0:o(...n)}));return()=>o.forEach((e=>null==e?void 0:e()))}const O=function(e){let{children:t,location:n,previousLocation:o}=e;return(0,r.useLayoutEffect)((()=>{o!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,o=t.hash===n.hash,a=t.search===n.search;if(r&&o&&!a)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);null==t||t.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:o}),I("onRouteDidUpdate",{previousLocation:o,location:n}))}),[o,n]),t};function A(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(l.Z,e))).flat();return Promise.all(t.map((e=>null==e.route.component.preload?void 0:e.route.component.preload())))}class R extends r.Component{constructor(e){super(e),this.previousLocation=void 0,this.routeUpdateCleanupCb=void 0,this.previousLocation=null,this.routeUpdateCleanupCb=s.Z.canUseDOM?I("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=I("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),A(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(O,{previousLocation:this.previousLocation,location:t},r.createElement(u.AW,{location:t,render:()=>e}))}}const P=R,D="docusaurus-base-url-issue-banner-container",M="docusaurus-base-url-issue-banner-suggestion-container",F="__DOCUSAURUS_INSERT_BASEURL_BANNER";function z(e){return`\nwindow['${F}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${F}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${D}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="docusaurus-base-url-issue-banner" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseurl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${M}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n var suggestionContainer = document.getElementById('${M}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function B(){const{siteConfig:{baseUrl:e}}=(0,m.Z)();return(0,r.useLayoutEffect)((()=>{window[F]=!1}),[]),r.createElement(r.Fragment,null,!s.Z.canUseDOM&&r.createElement(h.Z,null,r.createElement("script",null,z(e))),r.createElement("div",{id:D}))}function U(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,m.Z)(),{pathname:n}=(0,u.TH)();return t&&n===e?r.createElement(B,null):null}function j(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:o,localeConfigs:a}}=(0,m.Z)(),i=(0,g.Z)(e),{htmlLang:s,direction:c}=a[o];return r.createElement(h.Z,null,r.createElement("html",{lang:s,dir:c}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:i}))}var $=n(4763);function H(){const e=(0,d.H)(l.Z),t=(0,u.TH)();return r.createElement($.Z,null,r.createElement(N.M,null,r.createElement(L.t,null,r.createElement(p,null,r.createElement(j,null),r.createElement(_,null),r.createElement(U,null),r.createElement(P,{location:C(t)},e)))))}var Z=n(6887);const V=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{var r;if("undefined"==typeof document)return void n();const o=document.createElement("link");o.setAttribute("rel","prefetch"),o.setAttribute("href",e),o.onload=()=>t(),o.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??(null==(r=document.getElementsByName("script")[0])?void 0:r.parentNode);null==a||a.appendChild(o)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var Q=n(9670);const W=new Set,G=new Set,q=()=>{var e,t;return(null==(e=navigator.connection)?void 0:e.effectiveType.includes("2g"))||(null==(t=navigator.connection)?void 0:t.saveData)},Y={prefetch(e){if(!(e=>!q()&&!G.has(e)&&!W.has(e))(e))return!1;W.add(e);const t=(0,d.f)(l.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(Z).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,Q.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?V(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!q()&&!G.has(e))(e)&&(G.add(e),A(e))},K=Object.freeze(Y);if(s.Z.canUseDOM){window.docusaurus=K;const e=o.hydrate;A(window.location.pathname).then((()=>{e(r.createElement(i.B6,null,r.createElement(a.VK,null,r.createElement(H,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>u,M:()=>d});var r=n(7294),o=n(6809);const a=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/touchsocket/docs","versions":[{"name":"current","label":"Next","isLast":true,"path":"/touchsocket/docs","mainDocId":"description","docs":[{"id":"adapterdemodescription","path":"/touchsocket/docs/adapterdemodescription","sidebar":"docs"},{"id":"adapterdescription","path":"/touchsocket/docs/adapterdescription","sidebar":"docs"},{"id":"appmessenger","path":"/touchsocket/docs/appmessenger","sidebar":"docs"},{"id":"bigfixedheadercustomdatahandlingadapter","path":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","sidebar":"docs"},{"id":"bytepool","path":"/touchsocket/docs/bytepool","sidebar":"docs"},{"id":"calljsonrpc","path":"/touchsocket/docs/calljsonrpc","sidebar":"docs"},{"id":"callwebapi","path":"/touchsocket/docs/callwebapi","sidebar":"docs"},{"id":"callxmlrpc","path":"/touchsocket/docs/callxmlrpc","sidebar":"docs"},{"id":"consoleaction","path":"/touchsocket/docs/consoleaction","sidebar":"docs"},{"id":"cooperation","path":"/touchsocket/docs/cooperation","sidebar":"docs"},{"id":"createandcallrpc","path":"/touchsocket/docs/createandcallrpc","sidebar":"docs"},{"id":"createhttpclient","path":"/touchsocket/docs/createhttpclient","sidebar":"docs"},{"id":"createhttpservice","path":"/touchsocket/docs/createhttpservice","sidebar":"docs"},{"id":"createtcpclient","path":"/touchsocket/docs/createtcpclient","sidebar":"docs"},{"id":"createtcpservice","path":"/touchsocket/docs/createtcpservice","sidebar":"docs"},{"id":"createtouchrpcclient","path":"/touchsocket/docs/createtouchrpcclient","sidebar":"docs"},{"id":"createtouchrpcservice","path":"/touchsocket/docs/createtouchrpcservice","sidebar":"docs"},{"id":"createudpsession","path":"/touchsocket/docs/createudpsession","sidebar":"docs"},{"id":"createwebsocketclient","path":"/touchsocket/docs/createwebsocketclient","sidebar":"docs"},{"id":"createwebsocketservice","path":"/touchsocket/docs/createwebsocketservice","sidebar":"docs"},{"id":"custombetweenanddatahandlingadapter","path":"/touchsocket/docs/custombetweenanddatahandlingadapter","sidebar":"docs"},{"id":"customdatahandlingadapter","path":"/touchsocket/docs/customdatahandlingadapter","sidebar":"docs"},{"id":"customfixedheaderdatahandlingadapter","path":"/touchsocket/docs/customfixedheaderdatahandlingadapter","sidebar":"docs"},{"id":"customunfixedheaderdatahandlingadapter","path":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","sidebar":"docs"},{"id":"dataadaptertester","path":"/touchsocket/docs/dataadaptertester","sidebar":"docs"},{"id":"dataforwarding","path":"/touchsocket/docs/dataforwarding","sidebar":"docs"},{"id":"datahandleadapter","path":"/touchsocket/docs/datahandleadapter","sidebar":"docs"},{"id":"datasecurity","path":"/touchsocket/docs/datasecurity","sidebar":"docs"},{"id":"dependencyproperty","path":"/touchsocket/docs/dependencyproperty","sidebar":"docs"},{"id":"description","path":"/touchsocket/docs/","sidebar":"docs"},{"id":"donate","path":"/touchsocket/docs/donate","sidebar":"docs"},{"id":"engineertoolbox","path":"/touchsocket/docs/engineertoolbox","sidebar":"docs"},{"id":"enterprise","path":"/touchsocket/docs/enterprise","sidebar":"docs"},{"id":"eventbus","path":"/touchsocket/docs/eventbus","sidebar":"docs"},{"id":"fastbinaryformatter","path":"/touchsocket/docs/fastbinaryformatter","sidebar":"docs"},{"id":"filepool","path":"/touchsocket/docs/filepool","sidebar":"docs"},{"id":"filesynchronization","path":"/touchsocket/docs/filesynchronization","sidebar":"docs"},{"id":"fixedheaderpackageadapter","path":"/touchsocket/docs/fixedheaderpackageadapter","sidebar":"docs"},{"id":"fixedsizepackageadapter","path":"/touchsocket/docs/fixedsizepackageadapter","sidebar":"docs"},{"id":"fpsgame","path":"/touchsocket/docs/fpsgame","sidebar":"docs"},{"id":"generateproxy","path":"/touchsocket/docs/generateproxy","sidebar":"docs"},{"id":"heartbeat","path":"/touchsocket/docs/heartbeat","sidebar":"docs"},{"id":"httpfiletransfer","path":"/touchsocket/docs/httpfiletransfer","sidebar":"docs"},{"id":"httpstaticpageplugin","path":"/touchsocket/docs/httpstaticpageplugin","sidebar":"docs"},{"id":"ilog","path":"/touchsocket/docs/ilog","sidebar":"docs"},{"id":"independentusedatahandlingadapter","path":"/touchsocket/docs/independentusedatahandlingadapter","sidebar":"docs"},{"id":"ioc","path":"/touchsocket/docs/ioc","sidebar":"docs"},{"id":"ipackage","path":"/touchsocket/docs/ipackage","sidebar":"docs"},{"id":"jsonrpcdescription","path":"/touchsocket/docs/jsonrpcdescription","sidebar":"docs"},{"id":"jsonrpcservice","path":"/touchsocket/docs/jsonrpcservice","sidebar":"docs"},{"id":"jsonserialize","path":"/touchsocket/docs/jsonserialize","sidebar":"docs"},{"id":"multithreadingfiletransfer","path":"/touchsocket/docs/multithreadingfiletransfer","sidebar":"docs"},{"id":"natservice","path":"/touchsocket/docs/natservice","sidebar":"docs"},{"id":"normaldatahandlingadapter","path":"/touchsocket/docs/normaldatahandlingadapter","sidebar":"docs"},{"id":"othercore","path":"/touchsocket/docs/othercore","sidebar":"docs"},{"id":"pipelinedatahandlingadapter","path":"/touchsocket/docs/pipelinedatahandlingadapter","sidebar":"docs"},{"id":"pluginsmanager","path":"/touchsocket/docs/pluginsmanager","sidebar":"docs"},{"id":"reconnection","path":"/touchsocket/docs/reconnection","sidebar":"docs"},{"id":"remotefilecontrol","path":"/touchsocket/docs/remotefilecontrol","sidebar":"docs"},{"id":"remotemonitoring","path":"/touchsocket/docs/remotemonitoring","sidebar":"docs"},{"id":"remotestreamaccess","path":"/touchsocket/docs/remotestreamaccess","sidebar":"docs"},{"id":"resetid","path":"/touchsocket/docs/resetid","sidebar":"docs"},{"id":"rpcactionfilter","path":"/touchsocket/docs/rpcactionfilter","sidebar":"docs"},{"id":"rpcallcontext","path":"/touchsocket/docs/rpcallcontext","sidebar":"docs"},{"id":"rpcoption","path":"/touchsocket/docs/rpcoption","sidebar":"docs"},{"id":"rpcstream","path":"/touchsocket/docs/rpcstream","sidebar":"docs"},{"id":"serializationselector","path":"/touchsocket/docs/serializationselector","sidebar":"docs"},{"id":"smallfiletransfer","path":"/touchsocket/docs/smallfiletransfer","sidebar":"docs"},{"id":"startguide","path":"/touchsocket/docs/startguide","sidebar":"docs"},{"id":"stategridtransmission","path":"/touchsocket/docs/stategridtransmission","sidebar":"docs"},{"id":"streamtransfer","path":"/touchsocket/docs/streamtransfer","sidebar":"docs"},{"id":"tcpcommandlineplugin","path":"/touchsocket/docs/tcpcommandlineplugin","sidebar":"docs"},{"id":"tcpother","path":"/touchsocket/docs/tcpother","sidebar":"docs"},{"id":"terminatorpackageadapter","path":"/touchsocket/docs/terminatorpackageadapter","sidebar":"docs"},{"id":"tlvdatahandlingadapter","path":"/touchsocket/docs/tlvdatahandlingadapter","sidebar":"docs"},{"id":"touchrpcbase","path":"/touchsocket/docs/touchrpcbase","sidebar":"docs"},{"id":"touchrpcdescription","path":"/touchsocket/docs/touchrpcdescription","sidebar":"docs"},{"id":"touchsocketbitconverter","path":"/touchsocket/docs/touchsocketbitconverter","sidebar":"docs"},{"id":"transferfile","path":"/touchsocket/docs/transferfile","sidebar":"docs"},{"id":"udpbroadcast","path":"/touchsocket/docs/udpbroadcast","sidebar":"docs"},{"id":"udpdatahandlingadapter","path":"/touchsocket/docs/udpdatahandlingadapter","sidebar":"docs"},{"id":"udptransmitbigdata","path":"/touchsocket/docs/udptransmitbigdata","sidebar":"docs"},{"id":"upgrade","path":"/touchsocket/docs/upgrade","sidebar":"docs"},{"id":"waitingclient","path":"/touchsocket/docs/waitingclient","sidebar":"docs"},{"id":"webapidescription","path":"/touchsocket/docs/webapidescription","sidebar":"docs"},{"id":"webapiservice","path":"/touchsocket/docs/webapiservice","sidebar":"docs"},{"id":"webdataforwarding","path":"/touchsocket/docs/webdataforwarding","sidebar":"docs"},{"id":"websocketdescription","path":"/touchsocket/docs/websocketdescription","sidebar":"docs"},{"id":"wpfuifiletransfer","path":"/touchsocket/docs/wpfuifiletransfer","sidebar":"docs"},{"id":"wscommandlineplugin","path":"/touchsocket/docs/wscommandlineplugin","sidebar":"docs"},{"id":"wsjsonrpc","path":"/touchsocket/docs/wsjsonrpc","sidebar":"docs"},{"id":"xmlrpcdescription","path":"/touchsocket/docs/xmlrpcdescription","sidebar":"docs"},{"id":"xmlrpcservice","path":"/touchsocket/docs/xmlrpcservice","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/touchsocket/docs/","label":"01\u3001\u8bf4\u660e\uff08\u4f7f\u7528\u524d\u5fc5\u8981\u9605\u8bfb\uff09"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var s=n(7529);const c=JSON.parse('{"docusaurusVersion":"2.3.1","siteVersion":"v1.2","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.3.1"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.3.1"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.3.1"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.3.1"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.3.1"},"docusaurus-plugin-image-zoom":{"type":"package","name":"docusaurus-plugin-image-zoom","version":"0.1.1"},"@easyops-cn/docusaurus-search-local":{"type":"package","name":"@easyops-cn/docusaurus-search-local","version":"0.33.5"}}}'),l={siteConfig:o.default,siteMetadata:c,globalData:a,i18n:i,codeTranslations:s},u=r.createContext(l);function d(e){let{children:t}=e;return r.createElement(u.Provider,{value:l},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var r=n(7294),o=n(412),a=n(5742),i=n(3929);function s(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",height:"50vh",width:"100%",fontSize:"20px"}},r.createElement("h1",null,"This page crashed."),r.createElement("p",null,t.message),r.createElement("button",{type:"button",onClick:n},"Try again"))}function c(e){let{error:t,tryAgain:n}=e;return r.createElement(u,{fallback:()=>r.createElement(s,{error:t,tryAgain:n})},r.createElement(a.Z,null,r.createElement("title",null,"Page Error")),r.createElement(i.Z,null,r.createElement(s,{error:t,tryAgain:n})))}const l=e=>r.createElement(c,e);class u extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){o.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??l)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,o={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(7294),o=n(405);function a(e){return r.createElement(o.ql,e)}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7462),o=n(7294),a=n(3727),i=n(8780),s=n(2263),c=n(3919),l=n(412);const u=o.createContext({collectLink:()=>{}});var d=n(4996);function p(e,t){var n;let{isNavLink:p,to:f,href:h,activeClassName:m,isActive:g,"data-noBrokenLinkCheck":b,autoAddBaseUrl:v=!0,...y}=e;const{siteConfig:{trailingSlash:k,baseUrl:E}}=(0,s.Z)(),{withBaseUrl:w}=(0,d.C)(),x=(0,o.useContext)(u),S=(0,o.useRef)(null);(0,o.useImperativeHandle)(t,(()=>S.current));const _=f||h;const T=(0,c.Z)(_),C=null==_?void 0:_.replace("pathname://","");let L=void 0!==C?(N=C,v&&(e=>e.startsWith("/"))(N)?w(N):N):void 0;var N;L&&T&&(L=(0,i.applyTrailingSlash)(L,{trailingSlash:k,baseUrl:E}));const I=(0,o.useRef)(!1),O=p?a.OL:a.rU,A=l.Z.canUseIntersectionObserver,R=(0,o.useRef)(),P=()=>{I.current||null==L||(window.docusaurus.preload(L),I.current=!0)};(0,o.useEffect)((()=>(!A&&T&&null!=L&&window.docusaurus.prefetch(L),()=>{A&&R.current&&R.current.disconnect()})),[R,L,A,T]);const D=(null==(n=L)?void 0:n.startsWith("#"))??!1,M=!L||!T||D;return M||b||x.collectLink(L),M?o.createElement("a",(0,r.Z)({ref:S,href:L},_&&!T&&{target:"_blank",rel:"noopener noreferrer"},y)):o.createElement(O,(0,r.Z)({},y,{onMouseEnter:P,onTouchStart:P,innerRef:e=>{S.current=e,A&&e&&T&&(R.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(R.current.unobserve(e),R.current.disconnect(),null!=L&&window.docusaurus.prefetch(L))}))})),R.current.observe(e))},to:L},p&&{isActive:g,activeClassName:m}))}const f=o.forwardRef(p)},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c,I:()=>s});var r=n(7294);function o(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=null==t?void 0:t[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var a=n(7529);function i(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return a[t??n]??n??t}function s(e,t){let{message:n,id:r}=e;return o(i({message:n,id:r}),t)}function c(e){let{children:t,id:n,values:a}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const s=i({message:t,id:n});return r.createElement(r.Fragment,null,o(s,a))}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function o(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>o,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>i,Z:()=>s});var r=n(7294),o=n(2263),a=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,o.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:o=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,a.b)(n))return n;if(o)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const s=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+s:s}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function s(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(7294),o=n(8940);function a(){return(0,r.useContext)(o._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(7294),o=n(8934);function a(){return(0,r.useContext)(o._)}},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>r});function r(e){const t={};return function e(n,r){Object.entries(n).forEach((n=>{let[o,a]=n;const i=r?`${r}.${o}`:o;var s;"object"==typeof(s=a)&&s&&Object.keys(s).length>0?e(a,i):t[i]=a}))}(e),t}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>o,z:()=>a});var r=n(7294);const o=r.createContext(null);function a(e){let{children:t,value:n}=e;const a=r.useContext(o),i=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...null==n?void 0:n.data};return{plugin:t.plugin,data:r}}({parent:a,value:n})),[a,n]);return r.createElement(o.Provider,{value:i},t)}},143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>m,gA:()=>p,_r:()=>u,Jo:()=>g,zh:()=>d,yW:()=>h,gB:()=>f});var r=n(6775),o=n(2263),a=n(9935);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,o.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const s=e=>e.versions.find((e=>e.isLast));function c(e,t){const n=function(e,t){const n=s(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),o=null==n?void 0:n.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:o,alternateDocVersions:o?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(o.id):{}}}const l={},u=()=>i("docusaurus-plugin-content-docs")??l,d=e=>function(e,t,n){void 0===t&&(t=a.m),void 0===n&&(n={});const r=i(e),o=null==r?void 0:r[t];if(!o&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return o}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=u(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const o=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),a=o?{pluginId:o[0],pluginData:o[1]}:void 0;if(!a&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return a}(t,n,e)}function f(e){return d(e).versions}function h(e){const t=d(e);return s(t)}function m(e){const t=d(e),{pathname:n}=(0,r.TH)();return c(t,n)}function g(e){const t=d(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=s(e);return{latestDocSuggestion:c(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>a});var r=n(4865),o=n.n(r);o().configure({showSpinner:!1});const a={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{o().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){o().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(7410),o=n(6809);!function(e){const{themeConfig:{prism:t}}=o.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(4806)(`./prism-${e}`)})),delete globalThis.Prism}(r.Z)},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(7294);const o="iconExternalLink_nPIU";function a(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:o},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},3929:(e,t,n)=>{"use strict";n.d(t,{Z:()=>Wt});var r=n(7294),o=n(6010),a=n(4763),i=n(1944),s=n(7462),c=n(6775),l=n(5999),u=n(5936);const d="docusaurus_skipToContent_fallback";function p(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,r.useRef)(null),{action:t}=(0,c.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&p(t)}),[]);return(0,u.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const h=(0,l.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function m(e){const t=e.children??h,{containerRef:n,onClick:o}=f();return r.createElement("div",{ref:n,role:"region","aria-label":h},r.createElement("a",(0,s.Z)({},e,{href:`#${d}`,onClick:o}),t))}var g=n(5281),b=n(9727);const v="skipToContent_fXgn";function y(){return r.createElement(m,{className:v})}var k=n(6668),E=n(9689);function w(e){let{width:t=21,height:n=21,color:o="currentColor",strokeWidth:a=1.2,className:i,...c}=e;return r.createElement("svg",(0,s.Z)({viewBox:"0 0 15 15",width:t,height:n},c),r.createElement("g",{stroke:o,strokeWidth:a},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const x="closeButton_CVFx";function S(e){return r.createElement("button",(0,s.Z)({type:"button","aria-label":(0,l.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,o.Z)("clean-btn close",x,e.className)}),r.createElement(w,{width:14,height:14,strokeWidth:3.1}))}const _="content_knG7";function T(e){const{announcementBar:t}=(0,k.L)(),{content:n}=t;return r.createElement("div",(0,s.Z)({},e,{className:(0,o.Z)(_,e.className),dangerouslySetInnerHTML:{__html:n}}))}const C="announcementBar_mb4j",L="announcementBarPlaceholder_vyr4",N="announcementBarClose_gvF7",I="announcementBarContent_xLdY";function O(){const{announcementBar:e}=(0,k.L)(),{isActive:t,close:n}=(0,E.nT)();if(!t)return null;const{backgroundColor:o,textColor:a,isCloseable:i}=e;return r.createElement("div",{className:C,style:{backgroundColor:o,color:a},role:"banner"},i&&r.createElement("div",{className:L}),r.createElement(T,{className:I}),i&&r.createElement(S,{onClick:n,className:N}))}var A=n(2961),R=n(2466);var P=n(902),D=n(3102);const M=r.createContext(null);function F(e){let{children:t}=e;const n=function(){const e=(0,A.e)(),t=(0,D.HY)(),[n,o]=(0,r.useState)(!1),a=null!==t.component,i=(0,P.D9)(a);return(0,r.useEffect)((()=>{a&&!i&&o(!0)}),[a,i]),(0,r.useEffect)((()=>{a?e.shown||o(!0):o(!1)}),[e.shown,a]),(0,r.useMemo)((()=>[n,o]),[n])}();return r.createElement(M.Provider,{value:n},t)}function z(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function B(){const e=(0,r.useContext)(M);if(!e)throw new P.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,o=(0,r.useCallback)((()=>n(!1)),[n]),a=(0,D.HY)();return(0,r.useMemo)((()=>({shown:t,hide:o,content:z(a)})),[o,a,t])}function U(e){let{header:t,primaryMenu:n,secondaryMenu:a}=e;const{shown:i}=B();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,o.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},a)))}var j=n(2949),$=n(2389);function H(e){return r.createElement("svg",(0,s.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function Z(e){return r.createElement("svg",(0,s.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const V={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function Q(e){let{className:t,value:n,onChange:a}=e;const i=(0,$.Z)(),s=(0,l.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===n?(0,l.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,l.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,o.Z)(V.toggle,t)},r.createElement("button",{className:(0,o.Z)("clean-btn",V.toggleButton,!i&&V.toggleButtonDisabled),type:"button",onClick:()=>a("dark"===n?"light":"dark"),disabled:!i,title:s,"aria-label":s,"aria-live":"polite"},r.createElement(H,{className:(0,o.Z)(V.toggleIcon,V.lightToggleIcon)}),r.createElement(Z,{className:(0,o.Z)(V.toggleIcon,V.darkToggleIcon)})))}const W=r.memo(Q);function G(e){let{className:t}=e;const n=(0,k.L)().colorMode.disableSwitch,{colorMode:o,setColorMode:a}=(0,j.I)();return n?null:r.createElement(W,{className:t,value:o,onChange:a})}var q=n(1327);function Y(){return r.createElement(q.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function K(){const e=(0,A.e)();return r.createElement("button",{type:"button","aria-label":(0,l.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(w,{color:"var(--ifm-color-emphasis-600)"}))}function X(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(Y,null),r.createElement(G,{className:"margin-right--md"}),r.createElement(K,null))}var J=n(9960),ee=n(4996),te=n(3919);function ne(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var re=n(9471);function oe(e){let{activeBasePath:t,activeBaseRegex:n,to:o,href:a,label:i,html:c,isDropdownLink:l,prependBaseUrlToHref:u,...d}=e;const p=(0,ee.Z)(o),f=(0,ee.Z)(t),h=(0,ee.Z)(a,{forcePrependBaseUrl:!0}),m=i&&a&&!(0,te.Z)(a),g=c?{dangerouslySetInnerHTML:{__html:c}}:{children:r.createElement(r.Fragment,null,i,m&&r.createElement(re.Z,l&&{width:12,height:12}))};return a?r.createElement(J.Z,(0,s.Z)({href:u?h:a},d,g)):r.createElement(J.Z,(0,s.Z)({to:p,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?ne(n,t.pathname):t.pathname.startsWith(f)},d,g))}function ae(e){let{className:t,isDropdownItem:n=!1,...a}=e;const i=r.createElement(oe,(0,s.Z)({className:(0,o.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},a));return n?r.createElement("li",null,i):i}function ie(e){let{className:t,isDropdownItem:n,...a}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(oe,(0,s.Z)({className:(0,o.Z)("menu__link",t)},a)))}function se(e){let{mobile:t=!1,position:n,...o}=e;const a=t?ie:ae;return r.createElement(a,(0,s.Z)({},o,{activeClassName:o.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ce=n(6043),le=n(8596),ue=n(2263);function de(e,t){return e.some((e=>function(e,t){return!!(0,le.Mg)(e.to,t)||!!ne(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function pe(e){let{items:t,position:n,className:a,onClick:i,...c}=e;const l=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{l.current&&!l.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e)}}),[l]),r.createElement("div",{ref:l,className:(0,o.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},r.createElement(oe,(0,s.Z)({"aria-haspopup":"true","aria-expanded":u,role:"button",href:c.to?void 0:"#",className:(0,o.Z)("navbar__link",a)},c,{onClick:c.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!u))}}),c.children??c.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,n)=>r.createElement(dt,(0,s.Z)({isDropdownItem:!0,onKeyDown:e=>{if(n===t.length-1&&"Tab"===e.key){e.preventDefault(),d(!1);const t=l.current.nextElementSibling;if(t){(t instanceof HTMLAnchorElement?t:t.querySelector("a")).focus()}}},activeClassName:"dropdown__link--active"},e,{key:n}))))))}function fe(e){let{items:t,className:n,position:a,onClick:i,...l}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,ue.Z)(),{pathname:t}=(0,c.TH)();return t.replace(e,"/")}(),d=de(t,u),{collapsed:p,toggleCollapsed:f,setCollapsed:h}=(0,ce.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&h(!d)}),[u,d,h]),r.createElement("li",{className:(0,o.Z)("menu__list-item",{"menu__list-item--collapsed":p})},r.createElement(oe,(0,s.Z)({role:"button",className:(0,o.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},l,{onClick:e=>{e.preventDefault(),f()}}),l.children??l.label),r.createElement(ce.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:p},t.map(((e,t)=>r.createElement(dt,(0,s.Z)({mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active"},e,{key:t}))))))}function he(e){let{mobile:t=!1,...n}=e;const o=t?fe:pe;return r.createElement(o,n)}var me=n(4711);function ge(e){let{width:t=20,height:n=20,...o}=e;return r.createElement("svg",(0,s.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},o),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const be="iconLanguage_nlXk";var ve=n(1029),ye=n(412),ke=n(373),Ee=n(143),we=n(22),xe=n(8202),Se=n(3926),_e=n(1073),Te=n(2539),Ce=n(726);const Le="searchBar_RVTs",Ne="dropdownMenu_qbY6",Ie="searchBarLeft_MXDe",Oe="suggestion_fB_2",Ae="cursor_eG29",Re="hitTree_kk6K",Pe="hitIcon_a7Zy",De="hitPath_ieM4",Me="noResultsIcon_EBY5",Fe="hitFooter_E9YW",ze="hitWrapper_sAK8",Be="hitTitle_vyVt",Ue="hitAction_NqkB",je="noResults_l6Q3",$e="searchBarContainer_NW3z",He="searchBarLoadingRing_YnHq",Ze="searchClearButton_qk4g",Ve="searchIndexLoading_EJ1f",Qe="searchHintContainer_Pkmr",We="searchHint_iIMx",Ge="focused_OWtg",qe="input_FOTf",Ye="hint_URu1",Ke="suggestions_X8XU",Xe="dataset_QiCy",Je="empty_eITn";function et(e){let{document:t,type:n,page:r,metadata:o,tokens:a,isInterOfTree:i,isLastOfTree:s}=e;const c=0===n,l=1===n,u=[];i?u.push('<svg viewBox="0 0 24 54"><g stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6v42M20 27H8.3"></path></g></svg>'):s&&u.push('<svg viewBox="0 0 24 54"><g stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6v21M20 27H8.3"></path></g></svg>');const d=u.map((e=>`<span class="${Re}">${e}</span>`)),p=`<span class="${Pe}">${c?'<svg width="20" height="20" viewBox="0 0 20 20"><path d="M17 6v12c0 .52-.2 1-1 1H4c-.7 0-1-.33-1-1V2c0-.55.42-1 1-1h8l5 5zM14 8h-3.13c-.51 0-.87-.34-.87-.87V4" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linejoin="round"></path></svg>':l?'<svg width="20" height="20" viewBox="0 0 20 20"><path d="M13 13h4-4V8H7v5h6v4-4H7V8H3h4V3v5h6V3v5h4-4v5zm-6 0v4-4H3h4z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg>':'<svg width="20" height="20" viewBox="0 0 20 20"><path d="M17 5H3h14zm0 5H3h14zm0 5H3h14z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linejoin="round"></path></svg>'}</span>`,f=[`<span class="${Be}">${(0,Ce.o)(t.t,(0,_e.m)(o,"t"),a)}</span>`];if(!i&&!s&&ve.H6){const e=r?(r.b??[]).concat(r.t).concat(t.s&&t.s!==r.t?t.s:[]):t.b;f.push(`<span class="${De}">${(0,Se.e)(e??[])}</span>`)}else c||f.push(`<span class="${De}">${(0,Te.C)(r.t||(t.u.startsWith("/docs/api-reference/")?"API Reference":""),a)}</span>`);const h=`<span class="${Ue}"><svg width="20" height="20" viewBox="0 0 20 20"><g stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M18 3v4c0 2-2 4-4 4H2"></path><path d="M8 17l-6-6 6-6"></path></g></svg></span>`;return[...d,p,`<span class="${ze}">`,...f,"</span>",h].join("")}function tt(){return`<span class="${je}"><span class="${Me}"><svg width="40" height="40" viewBox="0 0 20 20" fill="none" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M15.5 4.8c2 3 1.7 7-1 9.7h0l4.3 4.3-4.3-4.3a7.8 7.8 0 01-9.8 1m-2.2-2.2A7.8 7.8 0 0113.2 2.4M2 18L18 2"></path></svg></span><span>${(0,l.I)({id:"theme.SearchBar.noResultsText",message:"No results"})}</span></span>`}var nt=n(311);async function rt(){const e=await Promise.all([n.e(8443),n.e(5525)]).then(n.t.bind(n,8443,23)),t=e.default;return t.noConflict?t.noConflict():e.noConflict&&e.noConflict(),t}const ot="_highlight";const at=function(e){var t;let{handleSearchBarToggle:n}=e;const{siteConfig:{baseUrl:a}}=(0,ue.Z)(),i=(0,Ee.gA)();let s=a;try{const{preferredVersion:e}=(0,ke.J)((null==i?void 0:i.pluginId)??ve.gQ);e&&!e.isLast&&(s=e.path+"/")}catch(M){if(ve.l9&&!(M instanceof P.i6))throw M}const u=(0,c.k6)(),d=(0,c.TH)(),p=(0,r.useRef)(null),f=(0,r.useRef)(new Map),h=(0,r.useRef)(!1),[m,g]=(0,r.useState)(!1),[b,v]=(0,r.useState)(!1),[y,k]=(0,r.useState)(""),E=(0,r.useRef)(null),w=(0,r.useRef)(""),[x,S]=(0,r.useState)("");(0,r.useEffect)((()=>{if(!Array.isArray(ve.Kc))return;let e="";if(d.pathname.startsWith(s)){const t=d.pathname.substring(s.length),n=ve.Kc.find((e=>t===e||t.startsWith(`${e}/`)));n&&(e=n)}w.current!==e&&(f.current.delete(e),w.current=e),S(e)}),[d.pathname,s]);const _=!!ve.hG&&Array.isArray(ve.Kc)&&""===x,T=(0,r.useCallback)((async()=>{var e;if(_||f.current.get(x))return;f.current.set(x,"loading"),null==(e=E.current)||e.autocomplete.destroy(),g(!0);const[{wrappedIndexes:t,zhDictionary:n},r]=await Promise.all([(0,we.w)(s,x),rt()]);if(E.current=r(p.current,{hint:!1,autoselect:!0,openOnFocus:!0,cssClasses:{root:(0,o.Z)(Le,{[Ie]:"left"===ve.pu}),noPrefix:!0,dropdownMenu:Ne,input:qe,hint:Ye,suggestions:Ke,suggestion:Oe,cursor:Ae,dataset:Xe,empty:Je}},[{source:(0,xe.v)(t,n,ve.qo),templates:{suggestion:et,empty:tt,footer:e=>{let{query:t,isEmpty:n}=e;if(n)return;const r=document.createElement("a"),o=new URLSearchParams;if(o.set("q",t),Array.isArray(ve.Kc)&&o.set("ctx",x),s!==a){if(!s.startsWith(a))throw new Error(`Version url '${s}' does not start with base url '${a}', this is a bug of \`@easyops-cn/docusaurus-search-local\`, please report it.`);o.set("version",s.substring(a.length))}const i=`${a}search?${o.toString()}`;r.href=i,r.textContent=(0,l.I)({id:"theme.SearchBar.seeAll",message:"See all results"}),r.addEventListener("click",(e=>{var t;e.ctrlKey||e.metaKey||(e.preventDefault(),null==(t=E.current)||t.autocomplete.close(),u.push(i))}));const c=document.createElement("div");return c.className=Fe,c.appendChild(r),c}}}]).on("autocomplete:selected",(function(e,t){var n;let{document:{u:r,h:o},tokens:a}=t;null==(n=p.current)||n.blur();let i=r;if(ve.vc&&a.length>0){const e=new URLSearchParams;for(const t of a)e.append(ot,t);i+=`?${e.toString()}`}o&&(i+=o),u.push(i)})).on("autocomplete:closed",(()=>{var e;null==(e=p.current)||e.blur()})),f.current.set(x,"done"),g(!1),h.current){const e=p.current;var i;if(e.value)null==(i=E.current)||i.autocomplete.open();e.focus()}}),[_,x,s,a,u]);(0,r.useEffect)((()=>{if(!ve.vc)return;const e=ye.Z.canUseDOM?new URLSearchParams(d.search).getAll(ot):[];setTimeout((()=>{var t;const n=document.querySelector("article");if(!n)return;const r=new ve.vc(n);r.unmark(),0!==e.length&&r.mark(e),k(e.join(" ")),null==(t=E.current)||t.autocomplete.setVal(e.join(" "))}))}),[d.search,d.pathname]);const[C,L]=(0,r.useState)(!1),N=(0,r.useCallback)((()=>{h.current=!0,T(),L(!0),null==n||n(!0)}),[n,T]),I=(0,r.useCallback)((()=>{L(!1),null==n||n(!1)}),[n]),O=(0,r.useCallback)((()=>{T()}),[T]),A=(0,r.useCallback)((e=>{k(e.target.value),e.target.value&&v(!0)}),[]),R=!!ye.Z.canUseDOM&&/mac/i.test((null==(t=navigator.userAgentData)?void 0:t.platform)??navigator.platform);(0,r.useEffect)((()=>{if(!ve.AY)return;const e=e=>{var t;(R?e.metaKey:e.ctrlKey)&&"KeyK"===e.code&&(e.preventDefault(),null==(t=p.current)||t.focus(),N())};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}}),[R,N]);const D=(0,r.useCallback)((()=>{var e;const t=new URLSearchParams(d.search);t.delete(ot);const n=t.toString(),r=d.pathname+(""!=n?`?${n}`:"")+d.hash;r!=d.pathname+d.search+d.hash&&u.push(r),k(""),null==(e=E.current)||e.autocomplete.setVal("")}),[d.pathname,d.search,d.hash,u]);return r.createElement("div",{className:(0,o.Z)("navbar__search",$e,{[Ve]:m&&b,[Ge]:C}),hidden:_},r.createElement("input",{placeholder:(0,l.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"}),"aria-label":"Search",className:"navbar__search-input",onMouseEnter:O,onFocus:N,onBlur:I,onChange:A,ref:p,value:y}),r.createElement(nt.Z,{className:He}),ve.AY&&ve.t_&&(""!==y?r.createElement("button",{className:Ze,onClick:D},"\u2715"):r.createElement("div",{className:Qe},r.createElement("kbd",{className:We},R?"\u2318":"ctrl"),r.createElement("kbd",{className:We},"K"))))},it="searchBox_ZlJk";function st(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,o.Z)(n,it)},t)}var ct=n(2802);const lt=e=>e.docs.find((t=>t.id===e.mainDocId));const ut={default:se,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:o,...a}=e;const{i18n:{currentLocale:i,locales:u,localeConfigs:d}}=(0,ue.Z)(),p=(0,me.l)(),{search:f,hash:h}=(0,c.TH)(),m=[...n,...u.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${h}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...o],g=t?(0,l.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return r.createElement(he,(0,s.Z)({},a,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(ge,{className:be}),g),items:m}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(st,{className:n},r.createElement(at,null))},dropdown:he,html:function(e){let{value:t,className:n,mobile:a=!1,isDropdownItem:i=!1}=e;const s=i?"li":"div";return r.createElement(s,{className:(0,o.Z)({navbar__item:!a&&!i,"menu__list-item":a},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:o,...a}=e;const{activeDoc:i}=(0,Ee.Iw)(o),c=(0,ct.vY)(t,o);return null===c?null:r.createElement(se,(0,s.Z)({exact:!0},a,{isActive:()=>(null==i?void 0:i.path)===c.path||!(null==i||!i.sidebar)&&i.sidebar===c.sidebar,label:n??c.id,to:c.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:o,...a}=e;const{activeDoc:i}=(0,Ee.Iw)(o),c=(0,ct.oz)(t,o).link;if(!c)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(se,(0,s.Z)({exact:!0},a,{isActive:()=>(null==i?void 0:i.sidebar)===t,label:n??c.label,to:c.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:o,...a}=e;const i=(0,ct.lO)(o)[0],c=t??i.label,l=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return r.createElement(se,(0,s.Z)({},a,{label:c,to:l}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:o,dropdownItemsBefore:a,dropdownItemsAfter:i,...u}=e;const{search:d,hash:p}=(0,c.TH)(),f=(0,Ee.Iw)(n),h=(0,Ee.gB)(n),{savePreferredVersionName:m}=(0,ke.J)(n),g=[...a,...h.map((e=>{const t=f.alternateDocVersions[e.name]??lt(e);return{label:e.label,to:`${t.path}${d}${p}`,isActive:()=>e===f.activeVersion,onClick:()=>m(e.name)}})),...i],b=(0,ct.lO)(n)[0],v=t&&g.length>1?(0,l.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&g.length>1?void 0:lt(b).path;return g.length<=1?r.createElement(se,(0,s.Z)({},u,{mobile:t,label:v,to:y,isActive:o?()=>!1:void 0})):r.createElement(he,(0,s.Z)({},u,{mobile:t,label:v,to:y,items:g,isActive:o?()=>!1:void 0}))}};function dt(e){let{type:t,...n}=e;const o=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),a=ut[o];if(!a)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(a,n)}function pt(){const e=(0,A.e)(),t=(0,k.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(dt,(0,s.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function ft(e){return r.createElement("button",(0,s.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(l.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function ht(){const e=0===(0,k.L)().navbar.items.length,t=B();return r.createElement(r.Fragment,null,!e&&r.createElement(ft,{onClick:()=>t.hide()}),t.content)}function mt(){const e=(0,A.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(U,{header:r.createElement(X,null),primaryMenu:r.createElement(pt,null),secondaryMenu:r.createElement(ht,null)}):null}const gt="navbarHideable_m1mJ",bt="navbarHidden_jGov";function vt(e){return r.createElement("div",(0,s.Z)({role:"presentation"},e,{className:(0,o.Z)("navbar-sidebar__backdrop",e.className)}))}function yt(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:a}}=(0,k.L)(),i=(0,A.e)(),{navbarRef:s,isNavbarVisible:c}=function(e){const[t,n]=(0,r.useState)(e),o=(0,r.useRef)(!1),a=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(a.current=e.getBoundingClientRect().height)}),[]);return(0,R.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i<a.current)return void n(!0);if(o.current)return void(o.current=!1);const s=null==r?void 0:r.scrollY,c=document.documentElement.scrollHeight-a.current,l=window.innerHeight;s&&i>=s?n(!1):i+l<c&&n(!0)})),(0,u.S)((t=>{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return o.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:s,"aria-label":(0,l.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,o.Z)("navbar","navbar--fixed-top",n&&[gt,!c&&bt],{"navbar--dark":"dark"===a,"navbar--primary":"primary"===a,"navbar-sidebar--show":i.shown})},t,r.createElement(vt,{onClick:i.toggle}),r.createElement(mt,null))}function kt(e){let{width:t=30,height:n=30,className:o,...a}=e;return r.createElement("svg",(0,s.Z)({className:o,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},a),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Et(){const{toggle:e,shown:t}=(0,A.e)();return r.createElement("button",{onClick:e,"aria-label":(0,l.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(kt,null))}const wt="colorModeToggle_DEke";function xt(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(dt,(0,s.Z)({},e,{key:t})))))}function St(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function _t(){const e=(0,A.e)(),t=(0,k.L)().navbar.items,[n,o]=function(e){function t(e){return"left"===(e.position??"right")}return[e.filter(t),e.filter((e=>!t(e)))]}(t),a=t.find((e=>"search"===e.type));return r.createElement(St,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(Et,null),r.createElement(Y,null),r.createElement(xt,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(xt,{items:o}),r.createElement(G,{className:wt}),!a&&r.createElement(st,null,r.createElement(at,null)))})}function Tt(){return r.createElement(yt,null,r.createElement(_t,null))}function Ct(e){let{item:t}=e;const{to:n,href:o,label:a,prependBaseUrlToHref:i,...c}=t,l=(0,ee.Z)(n),u=(0,ee.Z)(o,{forcePrependBaseUrl:!0});return r.createElement(J.Z,(0,s.Z)({className:"footer__link-item"},o?{href:i?u:o}:{to:l},c),a,o&&!(0,te.Z)(o)&&r.createElement(re.Z,null))}function Lt(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement(Ct,{item:t}))}function Nt(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(Lt,{key:t,item:e})))))}function It(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(Nt,{key:t,column:e}))))}function Ot(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function At(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(Ct,{item:t})}function Rt(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(At,{item:e}),t.length!==n+1&&r.createElement(Ot,null))))))}function Pt(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(It,{columns:t}):r.createElement(Rt,{links:t})}var Dt=n(941);const Mt="footerLogoLink_BH7S";function Ft(e){let{logo:t}=e;const{withBaseUrl:n}=(0,ee.C)(),a={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(Dt.Z,{className:(0,o.Z)("footer__logo",t.className),alt:t.alt,sources:a,width:t.width,height:t.height,style:t.style})}function zt(e){let{logo:t}=e;return t.href?r.createElement(J.Z,{href:t.href,className:Mt,target:t.target},r.createElement(Ft,{logo:t})):r.createElement(Ft,{logo:t})}function Bt(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function Ut(e){let{style:t,links:n,logo:a,copyright:i}=e;return r.createElement("footer",{className:(0,o.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(a||i)&&r.createElement("div",{className:"footer__bottom text--center"},a&&r.createElement("div",{className:"margin-bottom--sm"},a),i)))}function jt(){const{footer:e}=(0,k.L)();if(!e)return null;const{copyright:t,links:n,logo:o,style:a}=e;return r.createElement(Ut,{style:a,links:n&&n.length>0&&r.createElement(Pt,{links:n}),logo:o&&r.createElement(zt,{logo:o}),copyright:t&&r.createElement(Bt,{copyright:t})})}const $t=r.memo(jt),Ht=(0,P.Qc)([j.S,E.pl,R.OC,ke.L5,i.VC,function(e){let{children:t}=e;return r.createElement(D.n2,null,r.createElement(A.M,null,r.createElement(F,null,t)))}]);function Zt(e){let{children:t}=e;return r.createElement(Ht,null,t)}function Vt(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(l.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("p",null,t.message),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},r.createElement(l.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again when the page crashed"},"Try again"))))))}const Qt="mainWrapper_z2l0";function Wt(e){const{children:t,noFooter:n,wrapperClassName:s,title:c,description:l}=e;return(0,b.t)(),r.createElement(Zt,null,r.createElement(i.d,{title:c,description:l}),r.createElement(y,null),r.createElement(O,null),r.createElement(Tt,null),r.createElement("div",{id:d,className:(0,o.Z)(g.k.wrapper.main,Qt,s)},r.createElement(a.Z,{fallback:e=>r.createElement(Vt,e)},t)),!n&&r.createElement($t,null))}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(7462),o=n(7294),a=n(9960),i=n(4996),s=n(2263),c=n(6668),l=n(941);function u(e){let{logo:t,alt:n,imageClassName:r}=e;const a={light:(0,i.Z)(t.src),dark:(0,i.Z)(t.srcDark||t.src)},s=o.createElement(l.Z,{className:t.className,sources:a,height:t.height,width:t.width,alt:n,style:t.style});return r?o.createElement("div",{className:r},s):s}function d(e){const{siteConfig:{title:t}}=(0,s.Z)(),{navbar:{title:n,logo:l}}=(0,c.L)(),{imageClassName:d,titleClassName:p,...f}=e,h=(0,i.Z)((null==l?void 0:l.href)||"/"),m=n?"":t,g=(null==l?void 0:l.alt)??m;return o.createElement(a.Z,(0,r.Z)({to:h},f,(null==l?void 0:l.target)&&{target:l.target}),l&&o.createElement(u,{logo:l,alt:g,imageClassName:d}),null!=n&&o.createElement("b",{className:p},n))}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=n(7294),o=n(5742);function a(e){let{locale:t,version:n,tag:a}=e;const i=t;return r.createElement(o.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),a&&r.createElement("meta",{name:"docusaurus_tag",content:a}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),a&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:a}))}},941:(e,t,n)=>{"use strict";n.d(t,{Z:()=>l});var r=n(7462),o=n(7294),a=n(6010),i=n(2389),s=n(2949);const c={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function l(e){const t=(0,i.Z)(),{colorMode:n}=(0,s.I)(),{sources:l,className:u,alt:d,...p}=e,f=t?"dark"===n?["dark"]:["light"]:["light","dark"];return o.createElement(o.Fragment,null,f.map((e=>o.createElement("img",(0,r.Z)({key:e,src:l[e],alt:d,className:(0,a.Z)(c.themedImage,c[`themedImage--${e}`],u)},p)))))}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>i,z:()=>h});var r=n(7462),o=n(7294),a=n(412);function i(e){let{initialState:t}=e;const[n,r]=(0,o.useState)(t??!1),a=(0,o.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:a}}const s={display:"none",overflow:"hidden",height:"0px"},c={display:"block",overflow:"visible",height:"auto"};function l(e,t){const n=t?s:c;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function u(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const a=(0,o.useRef)(!1);(0,o.useEffect)((()=>{const e=t.current;function o(){const t=e.scrollHeight,n=(null==r?void 0:r.duration)??function(e){const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${(null==r?void 0:r.easing)??"ease-in-out"}`,height:`${t}px`}}function i(){const t=o();e.style.transition=t.transition,e.style.height=t.height}if(!a.current)return l(e,n),void(a.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(i(),requestAnimationFrame((()=>{e.style.height=s.height,e.style.overflow=s.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{i()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function d(e){if(!a.Z.canUseDOM)return e?s:c}function p(e){let{as:t="div",collapsed:n,children:r,animation:a,onCollapseTransitionEnd:i,className:s,disableSSRStyle:c}=e;const p=(0,o.useRef)(null);return u({collapsibleRef:p,collapsed:n,animation:a}),o.createElement(t,{ref:p,style:c?void 0:d(n),onTransitionEnd:e=>{"height"===e.propertyName&&(l(p.current,n),null==i||i(n))},className:s},r)}function f(e){let{collapsed:t,...n}=e;const[a,i]=(0,o.useState)(!t),[s,c]=(0,o.useState)(t);return(0,o.useLayoutEffect)((()=>{t||i(!0)}),[t]),(0,o.useLayoutEffect)((()=>{a&&c(t)}),[a,t]),a?o.createElement(p,(0,r.Z)({},n,{collapsed:s})):null}function h(e){let{lazy:t,...n}=e;const r=t?f:p;return o.createElement(r,n)}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>h,pl:()=>f});var r=n(7294),o=n(2389),a=n(12),i=n(902),s=n(6668);const c=(0,a.WA)("docusaurus.announcement.dismiss"),l=(0,a.WA)("docusaurus.announcement.id"),u=()=>"true"===c.get(),d=e=>c.set(String(e)),p=r.createContext(null);function f(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,s.L)(),t=(0,o.Z)(),[n,a]=(0,r.useState)((()=>!!t&&u()));(0,r.useEffect)((()=>{a(u())}),[]);const i=(0,r.useCallback)((()=>{d(!0),a(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=l.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;l.set(t),r&&d(!1),!r&&u()||a(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return r.createElement(p.Provider,{value:n},t)}function h(){const e=(0,r.useContext)(p);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>g,S:()=>m});var r=n(7294),o=n(412),a=n(902),i=n(12),s=n(6668);const c=r.createContext(void 0),l="theme",u=(0,i.WA)(l),d="light",p="dark",f=e=>e===p?p:d;function h(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,s.L)(),[a,i]=(0,r.useState)((e=>o.Z.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e))(e));(0,r.useEffect)((()=>{t&&u.del()}),[t]);const c=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:o=!0}=r;t?(i(t),o&&(e=>{u.set(f(e))})(t)):(i(n?window.matchMedia("(prefers-color-scheme: dark)").matches?p:d:e),u.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==l)return;const t=u.get();null!==t&&c(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,c]);const h=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||h.current?h.current=window.matchMedia("print").matches:c(null)};return e.addListener(r),()=>e.removeListener(r)}),[c,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:c,get isDarkTheme(){return a===p},setLightTheme(){c(d)},setDarkTheme(){c(p)}})),[a,c])}function m(e){let{children:t}=e;const n=h();return r.createElement(c.Provider,{value:n},t)}function g(){const e=(0,r.useContext)(c);if(null==e)throw new a.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>y,L5:()=>b});var r=n(7294),o=n(143),a=n(9935),i=n(6668),s=n(2802),c=n(902),l=n(12);const u=e=>`docs-preferred-version-${e}`,d=(e,t,n)=>{(0,l.WA)(u(e),{persistence:t}).set(n)},p=(e,t)=>(0,l.WA)(u(e),{persistence:t}).get(),f=(e,t)=>{(0,l.WA)(u(e),{persistence:t}).del()};const h=r.createContext(null);function m(){const e=(0,o._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[a,s]=(0,r.useState)((()=>(e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}]))))(n)));(0,r.useEffect)((()=>{s(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function o(e){const t=p(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(f(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,o(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[a,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d(e,t,n),s((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=m();return r.createElement(h.Provider,{value:n},t)}function b(e){let{children:t}=e;return s.cE?r.createElement(g,null,t):r.createElement(r.Fragment,null,t)}function v(){const e=(0,r.useContext)(h);if(!e)throw new c.i6("DocsPreferredVersionContextProvider");return e}function y(e){void 0===e&&(e=a.m);const t=(0,o.zh)(e),[n,i]=v(),{preferredVersionName:s}=n[e];return{preferredVersion:t.versions.find((e=>e.name===s))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>c,b:()=>s});var r=n(7294),o=n(902);const a=Symbol("EmptyContext"),i=r.createContext(a);function s(e){let{children:t,name:n,items:o}=e;const a=(0,r.useMemo)((()=>n&&o?{name:n,items:o}:null),[n,o]);return r.createElement(i.Provider,{value:a},t)}function c(){const e=(0,r.useContext)(i);if(e===a)throw new o.i6("DocsSidebarProvider");return e}},2961:(e,t,n)=>{"use strict";n.d(t,{M:()=>p,e:()=>f});var r=n(7294),o=n(3102),a=n(7524),i=n(6775),s=(n(1688),n(902));function c(e){!function(e){const t=(0,i.k6)(),n=(0,s.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var l=n(6668);const u=r.createContext(void 0);function d(){const e=function(){const e=(0,o.HY)(),{items:t}=(0,l.L)().navbar;return 0===t.length&&!e.component}(),t=(0,a.i)(),n=!e&&"mobile"===t,[i,s]=(0,r.useState)(!1);c((()=>{if(i)return s(!1),!1}));const u=(0,r.useCallback)((()=>{s((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&s(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:i})),[e,n,u,i])}function p(e){let{children:t}=e;const n=d();return r.createElement(u.Provider,{value:n},t)}function f(){const e=r.useContext(u);if(void 0===e)throw new s.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>s,Zo:()=>c,n2:()=>i});var r=n(7294),o=n(902);const a=r.createContext(null);function i(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(a.Provider,{value:n},t)}function s(){const e=(0,r.useContext)(a);if(!e)throw new o.i6("NavbarSecondaryMenuContentProvider");return e[0]}function c(e){let{component:t,props:n}=e;const i=(0,r.useContext)(a);if(!i)throw new o.i6("NavbarSecondaryMenuContentProvider");const[,s]=i,c=(0,o.Ql)(n);return(0,r.useEffect)((()=>{s({component:t,props:c})}),[s,t,c]),(0,r.useEffect)((()=>()=>s({component:null,props:null})),[s]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>o,t:()=>a});var r=n(7294);const o="navigation-with-keyboard";function a(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(o),"mousedown"===e.type&&document.body.classList.remove(o)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(o),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>l});var r=n(7294),o=n(412);const a="desktop",i="mobile",s="ssr";function c(){return o.Z.canUseDOM?window.innerWidth>996?a:i:s}function l(){const[e,t]=(0,r.useState)((()=>c()));return(0,r.useEffect)((()=>{function e(){t(c())}return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(undefined)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},2802:(e,t,n)=>{"use strict";n.d(t,{Wl:()=>p,_F:()=>h,cE:()=>d,hI:()=>k,lO:()=>b,vY:()=>y,oz:()=>v,s1:()=>g});var r=n(7294),o=n(6775),a=n(8790),i=n(143),s=n(373),c=n(1116);function l(e){return Array.from(new Set(e))}var u=n(8596);const d=!!i._r;function p(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=p(t);if(e)return e}}}const f=(e,t)=>void 0!==e&&(0,u.Mg)(e,t);function h(e,t){return"link"===e.type?f(e.href,t):"category"===e.type&&(f(e.href,t)||((e,t)=>e.some((e=>h(e,t))))(e.items,t))}function m(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const o=[];return function e(t){for(const a of t)if("category"===a.type&&((0,u.Mg)(a.href,n)||e(a.items))||"link"===a.type&&(0,u.Mg)(a.href,n)){return r&&"category"!==a.type||o.unshift(a),!0}return!1}(t),o}function g(){var e;const t=(0,c.V)(),{pathname:n}=(0,o.TH)();return!1!==(null==(e=(0,i.gA)())?void 0:e.pluginData.breadcrumbs)&&t?m({sidebarItems:t.items,pathname:n}):null}function b(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,s.J)(e),o=(0,i.yW)(e);return(0,r.useMemo)((()=>l([t,n,o].filter(Boolean))),[t,n,o])}function v(e,t){const n=b(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\n Available sidebar ids are:\n - ${Object.keys(t).join("\n- ")}`);return r[1]}),[e,n])}function y(e,t){const n=b(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`DocNavbarItem: couldn't find any doc with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${l(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function k(e){let{route:t,versionMetadata:n}=e;const r=(0,o.TH)(),i=t.routes,s=i.find((e=>(0,o.LX)(r.pathname,e)));if(!s)return null;const c=s.sidebar,l=c?n.docsSidebars[c]:void 0;return{docElement:(0,a.H)(i),sidebarName:c,sidebarItems:l}}},1944:(e,t,n)=>{"use strict";n.d(t,{FG:()=>p,d:()=>u,VC:()=>f});var r=n(7294),o=n(6010),a=n(5742),i=n(226);function s(){const e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var c=n(4996),l=n(2263);function u(e){let{title:t,description:n,keywords:o,image:i,children:s}=e;const u=function(e){const{siteConfig:t}=(0,l.Z)(),{title:n,titleDelimiter:r}=t;return null!=e&&e.trim().length?`${e.trim()} ${r} ${n}`:n}(t),{withBaseUrl:d}=(0,c.C)(),p=i?d(i,{absolute:!0}):void 0;return r.createElement(a.Z,null,t&&r.createElement("title",null,u),t&&r.createElement("meta",{property:"og:title",content:u}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),o&&r.createElement("meta",{name:"keywords",content:Array.isArray(o)?o.join(","):o}),p&&r.createElement("meta",{property:"og:image",content:p}),p&&r.createElement("meta",{name:"twitter:image",content:p}),s)}const d=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const i=r.useContext(d),s=(0,o.Z)(i,t);return r.createElement(d.Provider,{value:s},r.createElement(a.Z,null,r.createElement("html",{className:s})),n)}function f(e){let{children:t}=e;const n=s(),a=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return r.createElement(p,{className:(0,o.Z)(a,i)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>i,Qc:()=>l,Ql:()=>c,i6:()=>s,zX:()=>a});var r=n(7294);const o=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function a(e){const t=(0,r.useRef)(e);return o((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function i(e){const t=(0,r.useRef)();return o((()=>{t.current=e})),t.current}class s extends Error{constructor(e,t){var n,r,o;super(),this.name="ReactContextError",this.message=`Hook ${(null==(n=this.stack)||null==(r=n.split("\n")[1])||null==(o=r.match(/at (?:\w+\.)?(?<name>\w+)/))?void 0:o.groups.name)??""} is called outside the <${e}>. ${t??""}`}}function c(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function l(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>i,Ns:()=>s});var r=n(7294),o=n(723),a=n(2263);function i(e,t){const n=e=>{var t;return null==(t=!e||e.endsWith("/")?e:`${e}/`)?void 0:t.toLowerCase()};return n(e)===n(t)}function s(){const{baseUrl:e}=(0,a.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function o(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(o).flatMap((e=>e.routes??[])))}(n)}({routes:o.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>p,OC:()=>c,RF:()=>d});var r=n(7294),o=n(412),a=n(2389),i=n(902);const s=r.createContext(void 0);function c(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(s.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(s);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const u=()=>o.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=l(),o=(0,r.useRef)(u()),a=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();a(e,o.current),o.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[a,n,...t])}function p(){const e=(0,r.useRef)(null),t=(0,a.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const o=document.documentElement.scrollTop;(n&&o>e||!n&&o<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(o-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>null==e.current?void 0:e.current()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>r,os:()=>o});n(2263);const r="default";function o(e,t){return`docs-${e}-${t}`}},12:(e,t,n)=>{"use strict";n.d(t,{WA:()=>c});n(7294),n(1688);const r="localStorage";function o(e){let{key:t,oldValue:n,newValue:r,storage:o}=e;if(n===r)return;const a=document.createEvent("StorageEvent");a.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,o),window.dispatchEvent(a)}function a(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,i||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),i=!0),null}var t}let i=!1;const s={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function c(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=a(null==t?void 0:t.persistence);return null===n?s:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),o({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),o({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>a});var r=n(2263),o=n(6775);function a(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:a}}=(0,r.Z)(),{pathname:i}=(0,o.TH)(),s=a===n?e:e.replace(`/${a}/`,"/"),c=i.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:o}=e;return`${o?t:""}${function(e){return e===n?`${s}`:`${s}${e}/`}(r)}${c}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>i});var r=n(7294),o=n(6775),a=n(902);function i(e){const t=(0,o.TH)(),n=(0,a.D9)(t),i=(0,a.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>o});var r=n(2263);function o(){return(0,r.Z)().siteConfig.themeConfig}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[o]=e.split(/[#?]/),a="/"===o||o===r?o:(i=o,n?function(e){return e.endsWith("/")?e:`${e}/`}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(o,a)}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="post-content";var o=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(o).default}})},311:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(7294),o=n(6010);const a="loadingRing_RJI3";function i(e){let{className:t}=e;return r.createElement("div",{className:(0,o.Z)(a,t)},r.createElement("div",null),r.createElement("div",null),r.createElement("div",null),r.createElement("div",null))}},22:(e,t,n)=>{"use strict";n.d(t,{w:()=>s});var r=n(1336),o=n.n(r),a=n(1029);const i=new Map;function s(e,t){const n=`${e}${t}`;let r=i.get(n);return r||(r=async function(e,t){{const n=`${e}${a.J.replace("{dir}",t?`-${t.replace(/\//g,"-")}`:"")}`;if(new URL(n,location.origin).origin!==location.origin)throw new Error("Unexpected version url");const r=await(await fetch(n)).json(),i=r.map(((e,t)=>{let{documents:n,index:r}=e;return{type:t,documents:n,index:o().Index.load(r)}})),s=r.reduce(((e,t)=>{for(const n of t.index.invertedIndex)/\p{Unified_Ideograph}/u.test(n[0][0])&&e.add(n[0]);return e}),new Set);return{wrappedIndexes:i,zhDictionary:Array.from(s)}}return{wrappedIndexes:[],zhDictionary:[]}}(e,t),i.set(n,r)),r}},8202:(e,t,n)=>{"use strict";n.d(t,{v:()=>c});var r=n(1336),o=n.n(r);var a=n(1029);function i(e){return s(e).concat(s(e.filter((e=>{const t=e[e.length-1];return!t.trailing&&t.maybeTyping})),!0))}function s(e,t){return e.map((e=>({tokens:e.map((e=>e.value)),term:e.map((e=>({value:e.value,presence:o().Query.presence.REQUIRED,wildcard:(t?e.trailing||e.maybeTyping:e.trailing)?o().Query.wildcard.TRAILING:o().Query.wildcard.NONE})))})))}function c(e,t,n){return function(r,s){const c=function(e,t){if(1===t.length&&["ja","jp","th"].includes(t[0]))return o()[t[0]].tokenizer(e).map((e=>e.toString()));let n=/[^-\s]+/g;return t.includes("zh")&&(n=/\w+|\p{Unified_Ideograph}+/gu),e.toLowerCase().match(n)||[]}(r,a.dK);if(0===c.length)return void s([]);const l=function(e,t){const n=function(e,t){const n=[];return function e(r,o){if(0===r.length)return void n.push(o);const a=r[0];if(/\p{Unified_Ideograph}/u.test(a)){const n=function(e,t){const n=[];return function e(r,o){let a=0,i=!1;for(const s of t)if(r.substr(0,s.length)===s){const t={missed:o.missed,term:o.term.concat({value:s})};r.length>s.length?e(r.substr(s.length),t):n.push(t),i=!0}else for(let t=s.length-1;t>a;t-=1){const c=s.substr(0,t);if(r.substr(0,t)===c){a=t;const s={missed:o.missed,term:o.term.concat({value:c,trailing:!0})};r.length>t?e(r.substr(t),s):n.push(s),i=!0;break}}i||(r.length>0?e(r.substr(1),{missed:o.missed+1,term:o.term}):o.term.length>0&&n.push(o))}(e,{missed:0,term:[]}),n.sort(((e,t)=>{const n=e.missed>0?1:0,r=t.missed>0?1:0;return n!==r?n-r:e.term.length-t.term.length})).map((e=>e.term))}(a,t);for(const t of n){const n=o.concat(...t);e(r.slice(1),n)}}else{const t=o.concat({value:a});e(r.slice(1),t)}}(e,[]),n}(e,t);if(0===n.length)return[{tokens:e,term:e.map((e=>({value:e,presence:o().Query.presence.REQUIRED,wildcard:o().Query.wildcard.LEADING|o().Query.wildcard.TRAILING})))}];for(const o of n)o[o.length-1].maybeTyping=!0;const r=[];for(const i of a.dK)if("en"===i)a._k||r.unshift(o().stopWordFilter);else{const e=o()[i];e.stopWordFilter&&r.unshift(e.stopWordFilter)}let s;if(r.length>0){const e=e=>r.reduce(((e,t)=>e.filter((e=>t(e.value)))),e);s=[];const t=[];for(const r of n){const n=e(r);s.push(n),n.length<r.length&&n.length>0&&t.push(n)}n.push(...t)}else s=n.slice();const c=[];for(const o of s)if(o.length>2)for(let e=o.length-1;e>=0;e-=1)c.push(o.slice(0,e).concat(o.slice(e+1)));return i(n).concat(i(c))}(c,t),u=[];e:for(const{term:t,tokens:o}of l)for(const{documents:r,index:a,type:i}of e)if(u.push(...a.query((e=>{for(const n of t)e.term(n.value,{wildcard:n.wildcard,presence:n.presence})})).slice(0,n).filter((e=>!u.some((t=>t.document.i.toString()===e.ref)))).slice(0,n-u.length).map((t=>{const n=r.find((e=>e.i.toString()===t.ref));return{document:n,type:i,page:0!==i&&e[0].documents.find((e=>e.i===n.p)),metadata:t.matchData.metadata,tokens:o,score:t.score}}))),u.length>=n)break e;!function(e){e.forEach(((e,t)=>{e.index=t})),e.sort(((t,n)=>{let r=t.type>0&&t.page?e.findIndex((e=>e.document===t.page)):t.index,o=n.type>0&&n.page?e.findIndex((e=>e.document===n.page)):n.index;return-1===r&&(r=t.index),-1===o&&(o=n.index),r===o?0===t.type?-1:0===n.type?1:t.index-n.index:r-o}))}(u),function(e){e.forEach(((t,n)=>{n>0&&t.page&&e.some((e=>e.document===t.page))&&(n<e.length-1&&e[n+1].page===t.page?t.isInterOfTree=!0:t.isLastOfTree=!0)}))}(u),s(u)}}},3926:(e,t,n)=>{"use strict";function r(e){return e.join(" \u203a ")}n.d(t,{e:()=>r})},1690:(e,t,n)=>{"use strict";function r(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}n.d(t,{X:()=>r})},1073:(e,t,n)=>{"use strict";function r(e,t){const n=[];for(const r of Object.values(e))r[t]&&n.push(...r[t].position);return n.sort(((e,t)=>e[0]-t[0]||t[1]-e[1]))}n.d(t,{m:()=>r})},2539:(e,t,n)=>{"use strict";n.d(t,{C:()=>o});var r=n(1690);function o(e,t,n){const a=[];for(const i of t){const n=e.toLowerCase().indexOf(i);if(n>=0){n>0&&a.push(o(e.substr(0,n),t)),a.push(`<mark>${(0,r.X)(e.substr(n,i.length))}</mark>`);const s=n+i.length;s<e.length&&a.push(o(e.substr(s),t));break}}return 0===a.length?n?`<mark>${(0,r.X)(e)}</mark>`:(0,r.X)(e):a.join("")}},726:(e,t,n)=>{"use strict";n.d(t,{o:()=>c});var r=n(1690),o=n(2539);const a=/\w+|\p{Unified_Ideograph}/u;function i(e){const t=[];let n=0,r=e;for(;r.length>0;){const o=r.match(a);if(!o){t.push(r);break}o.index>0&&t.push(r.substring(0,o.index)),t.push(o[0]),n+=o.index+o[0].length,r=e.substring(n)}return t}var s=n(1029);function c(e,t,n,a){void 0===a&&(a=s.Hk);const{chunkIndex:c,chunks:l}=function(e,t,n){const a=[];let s=0,c=0,l=-1;for(;s<t.length;){const[u,d]=t[s];if(s+=1,!(u<c)){if(u>c){const t=i(e.substring(c,u)).map((e=>({html:(0,r.X)(e),textLength:e.length})));for(const e of t)a.push(e)}-1===l&&(l=a.length),c=u+d,a.push({html:(0,o.C)(e.substring(u,c),n,!0),textLength:d})}}if(c<e.length){const t=i(e.substring(c)).map((e=>({html:(0,r.X)(e),textLength:e.length})));for(const e of t)a.push(e)}return{chunkIndex:l,chunks:a}}(e,t,n),u=l.slice(0,c),d=l[c],p=[d.html],f=l.slice(c+1);let h=d.textLength,m=0,g=0,b=!1,v=!1;for(;h<a;)if((m<=g||0===f.length)&&u.length>0){const e=u.pop();h+e.textLength<=a?(p.unshift(e.html),m+=e.textLength,h+=e.textLength):(b=!0,u.length=0)}else{if(!(f.length>0))break;{const e=f.shift();h+e.textLength<=a?(p.push(e.html),g+=e.textLength,h+=e.textLength):(v=!0,f.length=0)}}return(b||u.length>0)&&p.unshift("\u2026"),(v||f.length>0)&&p.push("\u2026"),p.join("")}},1029:(e,t,n)=>{"use strict";n.d(t,{vc:()=>i(),gQ:()=>g,H6:()=>p,hG:()=>y,l9:()=>b,dK:()=>s,_k:()=>c,pu:()=>m,AY:()=>f,t_:()=>h,Kc:()=>v,J:()=>l,Hk:()=>d,qo:()=>u});var r=n(1336),o=n.n(r),a=n(813),i=n.n(a);n(892)(o()),n(1728).w(o()),n(4182)(o());const s=["en","zh"],c=!1,l="search-index{dir}.json?_=3882c0b5",u=8,d=50,p=!0,f=!0,h=!0,m="right",g=void 0,b=!0,v=null,y=!1},1728:(e,t,n)=>{"use strict";function r(e){const t=new RegExp("^[^"+e+"]+","u"),n=new RegExp("[^"+e+"]+$","u");return function(e){return e.update((function(e){return e.replace(t,"").replace(n,"")}))}}function o(e,t){e.trimmerSupport.generateTrimmer=r,e.zh=function(){this.pipeline.reset(),this.pipeline.add(e.zh.trimmer,e.zh.stopWordFilter),t&&(this.tokenizer=t)},t&&(e.zh.tokenizer=t),e.zh.wordCharacters="\\u3400-\\u4DBF\\u4E00-\\u9FFC\\uFA0E\\uFA0F\\uFA11\\uFA13\\uFA14\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29\\u{20000}-\\u{2A6DD}\\u{2A700}-\\u{2B734}\\u{2B740}-\\u{2B81D}\\u{2B820}-\\u{2CEA1}\\u{2CEB0}-\\u{2EBE0}\\u{30000}-\\u{3134A}",e.zh.trimmer=e.trimmerSupport.generateTrimmer(e.zh.wordCharacters),e.Pipeline.registerFunction(e.zh.trimmer,"trimmer-zh"),e.zh.stopWordFilter=e.generateStopWordFilter("\u7684 \u4e00 \u4e0d \u5728 \u4eba \u6709 \u662f \u4e3a \u4ee5 \u4e8e \u4e0a \u4ed6 \u800c \u540e \u4e4b \u6765 \u53ca \u4e86 \u56e0 \u4e0b \u53ef \u5230 \u7531 \u8fd9 \u4e0e \u4e5f \u6b64 \u4f46 \u5e76 \u4e2a \u5176 \u5df2 \u65e0 \u5c0f \u6211 \u4eec \u8d77 \u6700 \u518d \u4eca \u53bb \u597d \u53ea \u53c8 \u6216 \u5f88 \u4ea6 \u67d0 \u628a \u90a3 \u4f60 \u4e43 \u5b83 \u5427 \u88ab \u6bd4 \u522b \u8d81 \u5f53 \u4ece \u5230 \u5f97 \u6253 \u51e1 \u513f \u5c14 \u8be5 \u5404 \u7ed9 \u8ddf \u548c \u4f55 \u8fd8 \u5373 \u51e0 \u65e2 \u770b \u636e \u8ddd \u9760 \u5566 \u4e86 \u53e6 \u4e48 \u6bcf \u4eec \u561b \u62ff \u54ea \u90a3 \u60a8 \u51ed \u4e14 \u5374 \u8ba9 \u4ecd \u5565 \u5982 \u82e5 \u4f7f \u8c01 \u867d \u968f \u540c \u6240 \u5979 \u54c7 \u55e1 \u5f80 \u54ea \u4e9b \u5411 \u6cbf \u54df \u7528 \u4e8e \u54b1 \u5219 \u600e \u66fe \u81f3 \u81f4 \u7740 \u8bf8 \u81ea".split(" ")),e.Pipeline.registerFunction(e.zh.stopWordFilter,"stopWordFilter-zh")}n.d(t,{w:()=>o})},4811:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>m});var r=n(6809),o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},a=function(e){return"IMG"===e.tagName},i=function(e){return e&&1===e.nodeType},s=function(e){return".svg"===(e.currentSrc||e.src).substr(-4).toLowerCase()},c=function(e){try{return Array.isArray(e)?e.filter(a):function(e){return NodeList.prototype.isPrototypeOf(e)}(e)?[].slice.call(e).filter(a):i(e)?[e].filter(a):"string"==typeof e?[].slice.call(document.querySelectorAll(e)).filter(a):[]}catch(t){throw new TypeError("The provided selector is invalid.\nExpects a CSS selector, a Node element, a NodeList or an array.\nSee: https://github.com/francoischalifour/medium-zoom")}},l=function(e){var t=document.createElement("div");return t.classList.add("medium-zoom-overlay"),t.style.background=e,t},u=function(e){var t=e.getBoundingClientRect(),n=t.top,r=t.left,o=t.width,a=t.height,i=e.cloneNode(),s=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,c=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;return i.removeAttribute("id"),i.style.position="absolute",i.style.top=n+s+"px",i.style.left=r+c+"px",i.style.width=o+"px",i.style.height=a+"px",i.style.transform="",i},d=function(e,t){var n=o({bubbles:!1,cancelable:!1,detail:void 0},t);if("function"==typeof window.CustomEvent)return new CustomEvent(e,n);var r=document.createEvent("CustomEvent");return r.initCustomEvent(e,n.bubbles,n.cancelable,n.detail),r};!function(e,t){void 0===t&&(t={});var n=t.insertAt;if(e&&"undefined"!=typeof document){var r=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css","top"===n&&r.firstChild?r.insertBefore(o,r.firstChild):r.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e))}}(".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}");const p=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=window.Promise||function(e){function t(){}e(t,t)},a=function(e){var t=e.target;t!==A?-1!==T.indexOf(t)&&w({target:t}):E()},p=function(){if(!L&&O.original){var e=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;Math.abs(N-e)>I.scrollOffset&&setTimeout(E,150)}},f=function(e){var t=e.key||e.keyCode;"Escape"!==t&&"Esc"!==t&&27!==t||E()},h=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e;if(e.background&&(A.style.background=e.background),e.container&&e.container instanceof Object&&(t.container=o({},I.container,e.container)),e.template){var n=i(e.template)?e.template:document.querySelector(e.template);t.template=n}return I=o({},I,t),T.forEach((function(e){e.dispatchEvent(d("medium-zoom:update",{detail:{zoom:R}}))})),R},m=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return e(o({},I,t))},g=function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];var r=t.reduce((function(e,t){return[].concat(e,c(t))}),[]);return r.filter((function(e){return-1===T.indexOf(e)})).forEach((function(e){T.push(e),e.classList.add("medium-zoom-image")})),C.forEach((function(e){var t=e.type,n=e.listener,o=e.options;r.forEach((function(e){e.addEventListener(t,n,o)}))})),R},b=function(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];O.zoomed&&E();var r=t.length>0?t.reduce((function(e,t){return[].concat(e,c(t))}),[]):T;return r.forEach((function(e){e.classList.remove("medium-zoom-image"),e.dispatchEvent(d("medium-zoom:detach",{detail:{zoom:R}}))})),T=T.filter((function(e){return-1===r.indexOf(e)})),R},v=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return T.forEach((function(r){r.addEventListener("medium-zoom:"+e,t,n)})),C.push({type:"medium-zoom:"+e,listener:t,options:n}),R},y=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return T.forEach((function(r){r.removeEventListener("medium-zoom:"+e,t,n)})),C=C.filter((function(n){return!(n.type==="medium-zoom:"+e&&n.listener.toString()===t.toString())})),R},k=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.target,n=function(){var e={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},t=void 0,n=void 0;if(I.container)if(I.container instanceof Object)t=(e=o({},e,I.container)).width-e.left-e.right-2*I.margin,n=e.height-e.top-e.bottom-2*I.margin;else{var r=(i(I.container)?I.container:document.querySelector(I.container)).getBoundingClientRect(),a=r.width,c=r.height,l=r.left,u=r.top;e=o({},e,{width:a,height:c,left:l,top:u})}t=t||e.width-2*I.margin,n=n||e.height-2*I.margin;var d=O.zoomedHd||O.original,p=s(d)?t:d.naturalWidth||t,f=s(d)?n:d.naturalHeight||n,h=d.getBoundingClientRect(),m=h.top,g=h.left,b=h.width,v=h.height,y=Math.min(Math.max(b,p),t)/b,k=Math.min(Math.max(v,f),n)/v,E=Math.min(y,k),w="scale("+E+") translate3d("+((t-b)/2-g+I.margin+e.left)/E+"px, "+((n-v)/2-m+I.margin+e.top)/E+"px, 0)";O.zoomed.style.transform=w,O.zoomedHd&&(O.zoomedHd.style.transform=w)};return new r((function(e){if(t&&-1===T.indexOf(t))e(R);else{if(O.zoomed)e(R);else{if(t)O.original=t;else{if(!(T.length>0))return void e(R);var r=T;O.original=r[0]}if(O.original.dispatchEvent(d("medium-zoom:open",{detail:{zoom:R}})),N=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,L=!0,O.zoomed=u(O.original),document.body.appendChild(A),I.template){var o=i(I.template)?I.template:document.querySelector(I.template);O.template=document.createElement("div"),O.template.appendChild(o.content.cloneNode(!0)),document.body.appendChild(O.template)}if(O.original.parentElement&&"PICTURE"===O.original.parentElement.tagName&&O.original.currentSrc&&(O.zoomed.src=O.original.currentSrc),document.body.appendChild(O.zoomed),window.requestAnimationFrame((function(){document.body.classList.add("medium-zoom--opened")})),O.original.classList.add("medium-zoom-image--hidden"),O.zoomed.classList.add("medium-zoom-image--opened"),O.zoomed.addEventListener("click",E),O.zoomed.addEventListener("transitionend",(function t(){L=!1,O.zoomed.removeEventListener("transitionend",t),O.original.dispatchEvent(d("medium-zoom:opened",{detail:{zoom:R}})),e(R)})),O.original.getAttribute("data-zoom-src")){O.zoomedHd=O.zoomed.cloneNode(),O.zoomedHd.removeAttribute("srcset"),O.zoomedHd.removeAttribute("sizes"),O.zoomedHd.removeAttribute("loading"),O.zoomedHd.src=O.zoomed.getAttribute("data-zoom-src"),O.zoomedHd.onerror=function(){clearInterval(a),console.warn("Unable to reach the zoom image target "+O.zoomedHd.src),O.zoomedHd=null,n()};var a=setInterval((function(){O.zoomedHd.complete&&(clearInterval(a),O.zoomedHd.classList.add("medium-zoom-image--opened"),O.zoomedHd.addEventListener("click",E),document.body.appendChild(O.zoomedHd),n())}),10)}else if(O.original.hasAttribute("srcset")){O.zoomedHd=O.zoomed.cloneNode(),O.zoomedHd.removeAttribute("sizes"),O.zoomedHd.removeAttribute("loading");var s=O.zoomedHd.addEventListener("load",(function(){O.zoomedHd.removeEventListener("load",s),O.zoomedHd.classList.add("medium-zoom-image--opened"),O.zoomedHd.addEventListener("click",E),document.body.appendChild(O.zoomedHd),n()}))}else n()}}}))},E=function(){return new r((function(e){if(!L&&O.original){L=!0,document.body.classList.remove("medium-zoom--opened"),O.zoomed.style.transform="",O.zoomedHd&&(O.zoomedHd.style.transform=""),O.template&&(O.template.style.transition="opacity 150ms",O.template.style.opacity=0),O.original.dispatchEvent(d("medium-zoom:close",{detail:{zoom:R}})),O.zoomed.addEventListener("transitionend",(function t(){O.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(O.zoomed),O.zoomedHd&&document.body.removeChild(O.zoomedHd),document.body.removeChild(A),O.zoomed.classList.remove("medium-zoom-image--opened"),O.template&&document.body.removeChild(O.template),L=!1,O.zoomed.removeEventListener("transitionend",t),O.original.dispatchEvent(d("medium-zoom:closed",{detail:{zoom:R}})),O.original=null,O.zoomed=null,O.zoomedHd=null,O.template=null,e(R)}))}else e(R)}))},w=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.target;return O.original?E():k({target:t})},x=function(){return I},S=function(){return T},_=function(){return O.original},T=[],C=[],L=!1,N=0,I=n,O={original:null,zoomed:null,zoomedHd:null,template:null};"[object Object]"===Object.prototype.toString.call(t)?I=t:(t||"string"==typeof t)&&g(t),I=o({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},I);var A=l(I.background);document.addEventListener("click",a),document.addEventListener("keyup",f),document.addEventListener("scroll",p),window.addEventListener("resize",E);var R={open:k,close:E,toggle:w,update:h,clone:m,attach:g,detach:b,on:v,off:y,getOptions:x,getImages:S,getZoomedImage:_};return R},{themeConfig:f}=r.default;function h(e){var t,n;return document.querySelector('html[data-theme="dark"]')?(null==(t=e.background)?void 0:t.dark)||"rgb(50, 50, 50)":(null==(n=e.background)?void 0:n.light)||"rgb(255, 255, 255)"}const m=function(){if("undefined"==typeof window)return null;let e;const{zoom:t}=f,{selector:n=".markdown img",config:r={}}=t||{};return r.background=h(t),new MutationObserver((function(n){e&&e.update({background:h(t)})})).observe(document.querySelector("html"),{attributes:!0,attributeFilter:["data-theme"]}),setTimeout((()=>{e&&e.detach(),e=p(n,r)}),1e3),{onRouteUpdate(){setTimeout((()=>{e&&e.detach(),e=p(n,r)}),1e3)}}}()},6010:(e,t,n)=>{"use strict";function r(e){var t,n,o="";if("string"==typeof e||"number"==typeof e)o+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=r(e[t]))&&(o&&(o+=" "),o+=n);else for(t in e)e[t]&&(o&&(o+=" "),o+=t);return o}n.d(t,{Z:()=>o});const o=function(){for(var e,t,n=0,o="";n<arguments.length;)(e=arguments[n++])&&(t=r(e))&&(o&&(o+=" "),o+=t);return o}},9318:(e,t,n)=>{"use strict";n.d(t,{lX:()=>k,q_:()=>T,ob:()=>f,PP:()=>L,Ep:()=>p});var r=n(7462);function o(e){return"/"===e.charAt(0)}function a(e,t){for(var n=t,r=n+1,o=e.length;r<o;n+=1,r+=1)e[n]=e[r];e.pop()}const i=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],i=t&&t.split("/")||[],s=e&&o(e),c=t&&o(t),l=s||c;if(e&&o(e)?i=r:r.length&&(i.pop(),i=i.concat(r)),!i.length)return"/";if(i.length){var u=i[i.length-1];n="."===u||".."===u||""===u}else n=!1;for(var d=0,p=i.length;p>=0;p--){var f=i[p];"."===f?a(i,p):".."===f?(a(i,p),d++):d&&(a(i,p),d--)}if(!l)for(;d--;d)i.unshift("..");!l||""===i[0]||i[0]&&o(i[0])||i.unshift("");var h=i.join("/");return n&&"/"!==h.substr(-1)&&(h+="/"),h};var s=n(2177);function c(e){return"/"===e.charAt(0)?e:"/"+e}function l(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,r=e.hash,o=t||"/";return n&&"?"!==n&&(o+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(o+="#"===r.charAt(0)?r:"#"+r),o}function f(e,t,n,o){var a;"string"==typeof e?(a=function(e){var t=e||"/",n="",r="",o=t.indexOf("#");-1!==o&&(r=t.substr(o),t=t.substr(0,o));var a=t.indexOf("?");return-1!==a&&(n=t.substr(a),t=t.substr(0,a)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),a.state=t):(void 0===(a=(0,r.Z)({},e)).pathname&&(a.pathname=""),a.search?"?"!==a.search.charAt(0)&&(a.search="?"+a.search):a.search="",a.hash?"#"!==a.hash.charAt(0)&&(a.hash="#"+a.hash):a.hash="",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(s){throw s instanceof URIError?new URIError('Pathname "'+a.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):s}return n&&(a.key=n),o?a.pathname?"/"!==a.pathname.charAt(0)&&(a.pathname=i(a.pathname,o.pathname)):a.pathname=o.pathname:a.pathname||(a.pathname="/"),a}function h(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,o){if(null!=e){var a="function"==typeof e?e(t,n):e;"string"==typeof a?"function"==typeof r?r(a,o):o(!0):o(!1!==a)}else o(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var m=!("undefined"==typeof window||!window.document||!window.document.createElement);function g(e,t){t(window.confirm(e))}var b="popstate",v="hashchange";function y(){try{return window.history.state||{}}catch(e){return{}}}function k(e){void 0===e&&(e={}),m||(0,s.Z)(!1);var t,n=window.history,o=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,a=!(-1===window.navigator.userAgent.indexOf("Trident")),i=e,l=i.forceRefresh,k=void 0!==l&&l,E=i.getUserConfirmation,w=void 0===E?g:E,x=i.keyLength,S=void 0===x?6:x,_=e.basename?d(c(e.basename)):"";function T(e){var t=e||{},n=t.key,r=t.state,o=window.location,a=o.pathname+o.search+o.hash;return _&&(a=u(a,_)),f(a,r,n)}function C(){return Math.random().toString(36).substr(2,S)}var L=h();function N(e){(0,r.Z)(j,e),j.length=n.length,L.notifyListeners(j.location,j.action)}function I(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||R(T(e.state))}function O(){R(T(y()))}var A=!1;function R(e){if(A)A=!1,N();else{L.confirmTransitionTo(e,"POP",w,(function(t){t?N({action:"POP",location:e}):function(e){var t=j.location,n=D.indexOf(t.key);-1===n&&(n=0);var r=D.indexOf(e.key);-1===r&&(r=0);var o=n-r;o&&(A=!0,F(o))}(e)}))}}var P=T(y()),D=[P.key];function M(e){return _+p(e)}function F(e){n.go(e)}var z=0;function B(e){1===(z+=e)&&1===e?(window.addEventListener(b,I),a&&window.addEventListener(v,O)):0===z&&(window.removeEventListener(b,I),a&&window.removeEventListener(v,O))}var U=!1;var j={length:n.length,action:"POP",location:P,createHref:M,push:function(e,t){var r="PUSH",a=f(e,t,C(),j.location);L.confirmTransitionTo(a,r,w,(function(e){if(e){var t=M(a),i=a.key,s=a.state;if(o)if(n.pushState({key:i,state:s},null,t),k)window.location.href=t;else{var c=D.indexOf(j.location.key),l=D.slice(0,c+1);l.push(a.key),D=l,N({action:r,location:a})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",a=f(e,t,C(),j.location);L.confirmTransitionTo(a,r,w,(function(e){if(e){var t=M(a),i=a.key,s=a.state;if(o)if(n.replaceState({key:i,state:s},null,t),k)window.location.replace(t);else{var c=D.indexOf(j.location.key);-1!==c&&(D[c]=a.key),N({action:r,location:a})}else window.location.replace(t)}}))},go:F,goBack:function(){F(-1)},goForward:function(){F(1)},block:function(e){void 0===e&&(e=!1);var t=L.setPrompt(e);return U||(B(1),U=!0),function(){return U&&(U=!1,B(-1)),t()}},listen:function(e){var t=L.appendListener(e);return B(1),function(){B(-1),t()}}};return j}var E="hashchange",w={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+l(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:l,decodePath:c},slash:{encodePath:c,decodePath:c}};function x(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function S(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function _(e){window.location.replace(x(window.location.href)+"#"+e)}function T(e){void 0===e&&(e={}),m||(0,s.Z)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),o=n.getUserConfirmation,a=void 0===o?g:o,i=n.hashType,l=void 0===i?"slash":i,b=e.basename?d(c(e.basename)):"",v=w[l],y=v.encodePath,k=v.decodePath;function T(){var e=k(S());return b&&(e=u(e,b)),f(e)}var C=h();function L(e){(0,r.Z)(U,e),U.length=t.length,C.notifyListeners(U.location,U.action)}var N=!1,I=null;function O(){var e,t,n=S(),r=y(n);if(n!==r)_(r);else{var o=T(),i=U.location;if(!N&&(t=o,(e=i).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(I===p(o))return;I=null,function(e){if(N)N=!1,L();else{var t="POP";C.confirmTransitionTo(e,t,a,(function(n){n?L({action:t,location:e}):function(e){var t=U.location,n=D.lastIndexOf(p(t));-1===n&&(n=0);var r=D.lastIndexOf(p(e));-1===r&&(r=0);var o=n-r;o&&(N=!0,M(o))}(e)}))}}(o)}}var A=S(),R=y(A);A!==R&&_(R);var P=T(),D=[p(P)];function M(e){t.go(e)}var F=0;function z(e){1===(F+=e)&&1===e?window.addEventListener(E,O):0===F&&window.removeEventListener(E,O)}var B=!1;var U={length:t.length,action:"POP",location:P,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=x(window.location.href)),n+"#"+y(b+p(e))},push:function(e,t){var n="PUSH",r=f(e,void 0,void 0,U.location);C.confirmTransitionTo(r,n,a,(function(e){if(e){var t=p(r),o=y(b+t);if(S()!==o){I=t,function(e){window.location.hash=e}(o);var a=D.lastIndexOf(p(U.location)),i=D.slice(0,a+1);i.push(t),D=i,L({action:n,location:r})}else L()}}))},replace:function(e,t){var n="REPLACE",r=f(e,void 0,void 0,U.location);C.confirmTransitionTo(r,n,a,(function(e){if(e){var t=p(r),o=y(b+t);S()!==o&&(I=t,_(o));var a=D.indexOf(p(U.location));-1!==a&&(D[a]=t),L({action:n,location:r})}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=C.setPrompt(e);return B||(z(1),B=!0),function(){return B&&(B=!1,z(-1)),t()}},listen:function(e){var t=C.appendListener(e);return z(1),function(){z(-1),t()}}};return U}function C(e,t,n){return Math.min(Math.max(e,t),n)}function L(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,o=t.initialEntries,a=void 0===o?["/"]:o,i=t.initialIndex,s=void 0===i?0:i,c=t.keyLength,l=void 0===c?6:c,u=h();function d(e){(0,r.Z)(k,e),k.length=k.entries.length,u.notifyListeners(k.location,k.action)}function m(){return Math.random().toString(36).substr(2,l)}var g=C(s,0,a.length-1),b=a.map((function(e){return f(e,void 0,"string"==typeof e?m():e.key||m())})),v=p;function y(e){var t=C(k.index+e,0,k.entries.length-1),r=k.entries[t];u.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var k={length:b.length,action:"POP",location:b[g],index:g,entries:b,createHref:v,push:function(e,t){var r="PUSH",o=f(e,t,m(),k.location);u.confirmTransitionTo(o,r,n,(function(e){if(e){var t=k.index+1,n=k.entries.slice(0);n.length>t?n.splice(t,n.length-t,o):n.push(o),d({action:r,location:o,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",o=f(e,t,m(),k.location);u.confirmTransitionTo(o,r,n,(function(e){e&&(k.entries[k.index]=o,d({action:r,location:o}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=k.index+e;return t>=0&&t<k.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return k}},8679:(e,t,n)=>{"use strict";var r=n(9864),o={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},a={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},s={};function c(e){return r.isMemo(e)?i:s[e.$$typeof]||o}s[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},s[r.Memo]=i;var l=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,h=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(h){var o=f(n);o&&o!==h&&e(t,o,r)}var i=u(n);d&&(i=i.concat(d(n)));for(var s=c(t),m=c(n),g=0;g<i.length;++g){var b=i[g];if(!(a[b]||r&&r[b]||m&&m[b]||s&&s[b])){var v=p(n,b);try{l(t,b,v)}catch(y){}}}}return t}},1143:e=>{"use strict";e.exports=function(e,t,n,r,o,a,i,s){if(!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,r,o,a,i,s],u=0;(c=new Error(t.replace(/%s/g,(function(){return l[u++]})))).name="Invariant Violation"}throw c.framesToPop=1,c}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},4182:function(e,t,n){var r,o;r=function(){return function(e){e.multiLanguage=function(){for(var t=Array.prototype.slice.call(arguments),n=t.join("-"),r="",o=[],a=[],i=0;i<t.length;++i)"en"==t[i]?(r+="\\w",o.unshift(e.stopWordFilter),o.push(e.stemmer),a.push(e.stemmer)):(r+=e[t[i]].wordCharacters,e[t[i]].stopWordFilter&&o.unshift(e[t[i]].stopWordFilter),e[t[i]].stemmer&&(o.push(e[t[i]].stemmer),a.push(e[t[i]].stemmer)));var s=e.trimmerSupport.generateTrimmer(r);return e.Pipeline.registerFunction(s,"lunr-multi-trimmer-"+n),o.unshift(s),function(){this.pipeline.reset(),this.pipeline.add.apply(this.pipeline,o),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add.apply(this.searchPipeline,a))}}}},void 0===(o="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=o)},892:function(e,t,n){var r,o;void 0===(o="function"==typeof(r=function(){return function(e){e.stemmerSupport={Among:function(e,t,n,r){if(this.toCharArray=function(e){for(var t=e.length,n=new Array(t),r=0;r<t;r++)n[r]=e.charCodeAt(r);return n},!e&&""!=e||!t&&0!=t||!n)throw"Bad Among initialisation: s:"+e+", substring_i: "+t+", result: "+n;this.s_size=e.length,this.s=this.toCharArray(e),this.substring_i=t,this.result=n,this.method=r},SnowballProgram:function(){var e;return{bra:0,ket:0,limit:0,cursor:0,limit_backward:0,setCurrent:function(t){e=t,this.cursor=0,this.limit=t.length,this.limit_backward=0,this.bra=this.cursor,this.ket=this.limit},getCurrent:function(){var t=e;return e=null,t},in_grouping:function(t,n,r){if(this.cursor<this.limit){var o=e.charCodeAt(this.cursor);if(o<=r&&o>=n&&t[(o-=n)>>3]&1<<(7&o))return this.cursor++,!0}return!1},in_grouping_b:function(t,n,r){if(this.cursor>this.limit_backward){var o=e.charCodeAt(this.cursor-1);if(o<=r&&o>=n&&t[(o-=n)>>3]&1<<(7&o))return this.cursor--,!0}return!1},out_grouping:function(t,n,r){if(this.cursor<this.limit){var o=e.charCodeAt(this.cursor);if(o>r||o<n)return this.cursor++,!0;if(!(t[(o-=n)>>3]&1<<(7&o)))return this.cursor++,!0}return!1},out_grouping_b:function(t,n,r){if(this.cursor>this.limit_backward){var o=e.charCodeAt(this.cursor-1);if(o>r||o<n)return this.cursor--,!0;if(!(t[(o-=n)>>3]&1<<(7&o)))return this.cursor--,!0}return!1},eq_s:function(t,n){if(this.limit-this.cursor<t)return!1;for(var r=0;r<t;r++)if(e.charCodeAt(this.cursor+r)!=n.charCodeAt(r))return!1;return this.cursor+=t,!0},eq_s_b:function(t,n){if(this.cursor-this.limit_backward<t)return!1;for(var r=0;r<t;r++)if(e.charCodeAt(this.cursor-t+r)!=n.charCodeAt(r))return!1;return this.cursor-=t,!0},find_among:function(t,n){for(var r=0,o=n,a=this.cursor,i=this.limit,s=0,c=0,l=!1;;){for(var u=r+(o-r>>1),d=0,p=s<c?s:c,f=t[u],h=p;h<f.s_size;h++){if(a+p==i){d=-1;break}if(d=e.charCodeAt(a+p)-f.s[h])break;p++}if(d<0?(o=u,c=p):(r=u,s=p),o-r<=1){if(r>0||o==r||l)break;l=!0}}for(;;){if(s>=(f=t[r]).s_size){if(this.cursor=a+f.s_size,!f.method)return f.result;var m=f.method();if(this.cursor=a+f.s_size,m)return f.result}if((r=f.substring_i)<0)return 0}},find_among_b:function(t,n){for(var r=0,o=n,a=this.cursor,i=this.limit_backward,s=0,c=0,l=!1;;){for(var u=r+(o-r>>1),d=0,p=s<c?s:c,f=(h=t[u]).s_size-1-p;f>=0;f--){if(a-p==i){d=-1;break}if(d=e.charCodeAt(a-1-p)-h.s[f])break;p++}if(d<0?(o=u,c=p):(r=u,s=p),o-r<=1){if(r>0||o==r||l)break;l=!0}}for(;;){var h;if(s>=(h=t[r]).s_size){if(this.cursor=a-h.s_size,!h.method)return h.result;var m=h.method();if(this.cursor=a-h.s_size,m)return h.result}if((r=h.substring_i)<0)return 0}},replace_s:function(t,n,r){var o=r.length-(n-t),a=e.substring(0,t),i=e.substring(n);return e=a+r+i,this.limit+=o,this.cursor>=n?this.cursor+=o:this.cursor>t&&(this.cursor=t),o},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>e.length)throw"faulty slice operation"},slice_from:function(e){this.slice_check(),this.replace_s(this.bra,this.ket,e)},slice_del:function(){this.slice_from("")},insert:function(e,t,n){var r=this.replace_s(e,t,n);e<=this.bra&&(this.bra+=r),e<=this.ket&&(this.ket+=r)},slice_to:function(){return this.slice_check(),e.substring(this.bra,this.ket)},eq_v_b:function(e){return this.eq_s_b(e.length,e)}}}},e.trimmerSupport={generateTrimmer:function(e){var t=new RegExp("^[^"+e+"]+"),n=new RegExp("[^"+e+"]+$");return function(e){return"function"==typeof e.update?e.update((function(e){return e.replace(t,"").replace(n,"")})):e.replace(t,"").replace(n,"")}}}}})?r.call(t,n,t,e):r)||(e.exports=o)},1336:(e,t,n)=>{var r,o;!function(){var a,i,s,c,l,u,d,p,f,h,m,g,b,v,y,k,E,w,x,S,_,T,C,L,N,I,O=function(e){var t=new O.Builder;return t.pipeline.add(O.trimmer,O.stopWordFilter,O.stemmer),t.searchPipeline.add(O.stemmer),e.call(t,t),t.build()};O.version="2.3.9",O.utils={},O.utils.warn=(a=this,function(e){a.console&&console.warn&&console.warn(e)}),O.utils.asString=function(e){return null==e?"":e.toString()},O.utils.clone=function(e){if(null==e)return e;for(var t=Object.create(null),n=Object.keys(e),r=0;r<n.length;r++){var o=n[r],a=e[o];if(Array.isArray(a))t[o]=a.slice();else{if("string"!=typeof a&&"number"!=typeof a&&"boolean"!=typeof a)throw new TypeError("clone is not deep and does not support nested objects");t[o]=a}}return t},O.FieldRef=function(e,t,n){this.docRef=e,this.fieldName=t,this._stringValue=n},O.FieldRef.joiner="/",O.FieldRef.fromString=function(e){var t=e.indexOf(O.FieldRef.joiner);if(-1===t)throw"malformed field ref string";var n=e.slice(0,t),r=e.slice(t+1);return new O.FieldRef(r,n,e)},O.FieldRef.prototype.toString=function(){return null==this._stringValue&&(this._stringValue=this.fieldName+O.FieldRef.joiner+this.docRef),this._stringValue},O.Set=function(e){if(this.elements=Object.create(null),e){this.length=e.length;for(var t=0;t<this.length;t++)this.elements[e[t]]=!0}else this.length=0},O.Set.complete={intersect:function(e){return e},union:function(){return this},contains:function(){return!0}},O.Set.empty={intersect:function(){return this},union:function(e){return e},contains:function(){return!1}},O.Set.prototype.contains=function(e){return!!this.elements[e]},O.Set.prototype.intersect=function(e){var t,n,r,o=[];if(e===O.Set.complete)return this;if(e===O.Set.empty)return e;this.length<e.length?(t=this,n=e):(t=e,n=this),r=Object.keys(t.elements);for(var a=0;a<r.length;a++){var i=r[a];i in n.elements&&o.push(i)}return new O.Set(o)},O.Set.prototype.union=function(e){return e===O.Set.complete?O.Set.complete:e===O.Set.empty?this:new O.Set(Object.keys(this.elements).concat(Object.keys(e.elements)))},O.idf=function(e,t){var n=0;for(var r in e)"_index"!=r&&(n+=Object.keys(e[r]).length);var o=(t-n+.5)/(n+.5);return Math.log(1+Math.abs(o))},O.Token=function(e,t){this.str=e||"",this.metadata=t||{}},O.Token.prototype.toString=function(){return this.str},O.Token.prototype.update=function(e){return this.str=e(this.str,this.metadata),this},O.Token.prototype.clone=function(e){return e=e||function(e){return e},new O.Token(e(this.str,this.metadata),this.metadata)},O.tokenizer=function(e,t){if(null==e||null==e)return[];if(Array.isArray(e))return e.map((function(e){return new O.Token(O.utils.asString(e).toLowerCase(),O.utils.clone(t))}));for(var n=e.toString().toLowerCase(),r=n.length,o=[],a=0,i=0;a<=r;a++){var s=a-i;if(n.charAt(a).match(O.tokenizer.separator)||a==r){if(s>0){var c=O.utils.clone(t)||{};c.position=[i,s],c.index=o.length,o.push(new O.Token(n.slice(i,a),c))}i=a+1}}return o},O.tokenizer.separator=/[\s\-]+/,O.Pipeline=function(){this._stack=[]},O.Pipeline.registeredFunctions=Object.create(null),O.Pipeline.registerFunction=function(e,t){t in this.registeredFunctions&&O.utils.warn("Overwriting existing registered function: "+t),e.label=t,O.Pipeline.registeredFunctions[e.label]=e},O.Pipeline.warnIfFunctionNotRegistered=function(e){e.label&&e.label in this.registeredFunctions||O.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},O.Pipeline.load=function(e){var t=new O.Pipeline;return e.forEach((function(e){var n=O.Pipeline.registeredFunctions[e];if(!n)throw new Error("Cannot load unregistered function: "+e);t.add(n)})),t},O.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach((function(e){O.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)}),this)},O.Pipeline.prototype.after=function(e,t){O.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);if(-1==n)throw new Error("Cannot find existingFn");n+=1,this._stack.splice(n,0,t)},O.Pipeline.prototype.before=function(e,t){O.Pipeline.warnIfFunctionNotRegistered(t);var n=this._stack.indexOf(e);if(-1==n)throw new Error("Cannot find existingFn");this._stack.splice(n,0,t)},O.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);-1!=t&&this._stack.splice(t,1)},O.Pipeline.prototype.run=function(e){for(var t=this._stack.length,n=0;n<t;n++){for(var r=this._stack[n],o=[],a=0;a<e.length;a++){var i=r(e[a],a,e);if(null!=i&&""!==i)if(Array.isArray(i))for(var s=0;s<i.length;s++)o.push(i[s]);else o.push(i)}e=o}return e},O.Pipeline.prototype.runString=function(e,t){var n=new O.Token(e,t);return this.run([n]).map((function(e){return e.toString()}))},O.Pipeline.prototype.reset=function(){this._stack=[]},O.Pipeline.prototype.toJSON=function(){return this._stack.map((function(e){return O.Pipeline.warnIfFunctionNotRegistered(e),e.label}))},O.Vector=function(e){this._magnitude=0,this.elements=e||[]},O.Vector.prototype.positionForIndex=function(e){if(0==this.elements.length)return 0;for(var t=0,n=this.elements.length/2,r=n-t,o=Math.floor(r/2),a=this.elements[2*o];r>1&&(a<e&&(t=o),a>e&&(n=o),a!=e);)r=n-t,o=t+Math.floor(r/2),a=this.elements[2*o];return a==e||a>e?2*o:a<e?2*(o+1):void 0},O.Vector.prototype.insert=function(e,t){this.upsert(e,t,(function(){throw"duplicate index"}))},O.Vector.prototype.upsert=function(e,t,n){this._magnitude=0;var r=this.positionForIndex(e);this.elements[r]==e?this.elements[r+1]=n(this.elements[r+1],t):this.elements.splice(r,0,e,t)},O.Vector.prototype.magnitude=function(){if(this._magnitude)return this._magnitude;for(var e=0,t=this.elements.length,n=1;n<t;n+=2){var r=this.elements[n];e+=r*r}return this._magnitude=Math.sqrt(e)},O.Vector.prototype.dot=function(e){for(var t=0,n=this.elements,r=e.elements,o=n.length,a=r.length,i=0,s=0,c=0,l=0;c<o&&l<a;)(i=n[c])<(s=r[l])?c+=2:i>s?l+=2:i==s&&(t+=n[c+1]*r[l+1],c+=2,l+=2);return t},O.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},O.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,n=0;t<this.elements.length;t+=2,n++)e[n]=this.elements[t];return e},O.Vector.prototype.toJSON=function(){return this.elements},O.stemmer=(i={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},s={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},c="[aeiouy]",l="[^aeiou][^aeiouy]*",u=new RegExp("^([^aeiou][^aeiouy]*)?[aeiouy][aeiou]*[^aeiou][^aeiouy]*"),d=new RegExp("^([^aeiou][^aeiouy]*)?[aeiouy][aeiou]*[^aeiou][^aeiouy]*[aeiouy][aeiou]*[^aeiou][^aeiouy]*"),p=new RegExp("^([^aeiou][^aeiouy]*)?[aeiouy][aeiou]*[^aeiou][^aeiouy]*([aeiouy][aeiou]*)?$"),f=new RegExp("^([^aeiou][^aeiouy]*)?[aeiouy]"),h=/^(.+?)(ss|i)es$/,m=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,b=/^(.+?)(ed|ing)$/,v=/.$/,y=/(at|bl|iz)$/,k=new RegExp("([^aeiouylsz])\\1$"),E=new RegExp("^"+l+c+"[^aeiouwxy]$"),w=/^(.+?[^aeiou])y$/,x=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,S=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,_=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,T=/^(.+?)(s|t)(ion)$/,C=/^(.+?)e$/,L=/ll$/,N=new RegExp("^"+l+c+"[^aeiouwxy]$"),I=function(e){var t,n,r,o,a,c,l;if(e.length<3)return e;if("y"==(r=e.substr(0,1))&&(e=r.toUpperCase()+e.substr(1)),a=m,(o=h).test(e)?e=e.replace(o,"$1$2"):a.test(e)&&(e=e.replace(a,"$1$2")),a=b,(o=g).test(e)){var I=o.exec(e);(o=u).test(I[1])&&(o=v,e=e.replace(o,""))}else a.test(e)&&(t=(I=a.exec(e))[1],(a=f).test(t)&&(c=k,l=E,(a=y).test(e=t)?e+="e":c.test(e)?(o=v,e=e.replace(o,"")):l.test(e)&&(e+="e")));return(o=w).test(e)&&(e=(t=(I=o.exec(e))[1])+"i"),(o=x).test(e)&&(t=(I=o.exec(e))[1],n=I[2],(o=u).test(t)&&(e=t+i[n])),(o=S).test(e)&&(t=(I=o.exec(e))[1],n=I[2],(o=u).test(t)&&(e=t+s[n])),a=T,(o=_).test(e)?(t=(I=o.exec(e))[1],(o=d).test(t)&&(e=t)):a.test(e)&&(t=(I=a.exec(e))[1]+I[2],(a=d).test(t)&&(e=t)),(o=C).test(e)&&(t=(I=o.exec(e))[1],a=p,c=N,((o=d).test(t)||a.test(t)&&!c.test(t))&&(e=t)),a=d,(o=L).test(e)&&a.test(e)&&(o=v,e=e.replace(o,"")),"y"==r&&(e=r.toLowerCase()+e.substr(1)),e},function(e){return e.update(I)}),O.Pipeline.registerFunction(O.stemmer,"stemmer"),O.generateStopWordFilter=function(e){var t=e.reduce((function(e,t){return e[t]=t,e}),{});return function(e){if(e&&t[e.toString()]!==e.toString())return e}},O.stopWordFilter=O.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),O.Pipeline.registerFunction(O.stopWordFilter,"stopWordFilter"),O.trimmer=function(e){return e.update((function(e){return e.replace(/^\W+/,"").replace(/\W+$/,"")}))},O.Pipeline.registerFunction(O.trimmer,"trimmer"),O.TokenSet=function(){this.final=!1,this.edges={},this.id=O.TokenSet._nextId,O.TokenSet._nextId+=1},O.TokenSet._nextId=1,O.TokenSet.fromArray=function(e){for(var t=new O.TokenSet.Builder,n=0,r=e.length;n<r;n++)t.insert(e[n]);return t.finish(),t.root},O.TokenSet.fromClause=function(e){return"editDistance"in e?O.TokenSet.fromFuzzyString(e.term,e.editDistance):O.TokenSet.fromString(e.term)},O.TokenSet.fromFuzzyString=function(e,t){for(var n=new O.TokenSet,r=[{node:n,editsRemaining:t,str:e}];r.length;){var o=r.pop();if(o.str.length>0){var a,i=o.str.charAt(0);i in o.node.edges?a=o.node.edges[i]:(a=new O.TokenSet,o.node.edges[i]=a),1==o.str.length&&(a.final=!0),r.push({node:a,editsRemaining:o.editsRemaining,str:o.str.slice(1)})}if(0!=o.editsRemaining){if("*"in o.node.edges)var s=o.node.edges["*"];else{s=new O.TokenSet;o.node.edges["*"]=s}if(0==o.str.length&&(s.final=!0),r.push({node:s,editsRemaining:o.editsRemaining-1,str:o.str}),o.str.length>1&&r.push({node:o.node,editsRemaining:o.editsRemaining-1,str:o.str.slice(1)}),1==o.str.length&&(o.node.final=!0),o.str.length>=1){if("*"in o.node.edges)var c=o.node.edges["*"];else{c=new O.TokenSet;o.node.edges["*"]=c}1==o.str.length&&(c.final=!0),r.push({node:c,editsRemaining:o.editsRemaining-1,str:o.str.slice(1)})}if(o.str.length>1){var l,u=o.str.charAt(0),d=o.str.charAt(1);d in o.node.edges?l=o.node.edges[d]:(l=new O.TokenSet,o.node.edges[d]=l),1==o.str.length&&(l.final=!0),r.push({node:l,editsRemaining:o.editsRemaining-1,str:u+o.str.slice(2)})}}}return n},O.TokenSet.fromString=function(e){for(var t=new O.TokenSet,n=t,r=0,o=e.length;r<o;r++){var a=e[r],i=r==o-1;if("*"==a)t.edges[a]=t,t.final=i;else{var s=new O.TokenSet;s.final=i,t.edges[a]=s,t=s}}return n},O.TokenSet.prototype.toArray=function(){for(var e=[],t=[{prefix:"",node:this}];t.length;){var n=t.pop(),r=Object.keys(n.node.edges),o=r.length;n.node.final&&(n.prefix.charAt(0),e.push(n.prefix));for(var a=0;a<o;a++){var i=r[a];t.push({prefix:n.prefix.concat(i),node:n.node.edges[i]})}}return e},O.TokenSet.prototype.toString=function(){if(this._str)return this._str;for(var e=this.final?"1":"0",t=Object.keys(this.edges).sort(),n=t.length,r=0;r<n;r++){var o=t[r];e=e+o+this.edges[o].id}return e},O.TokenSet.prototype.intersect=function(e){for(var t=new O.TokenSet,n=void 0,r=[{qNode:e,output:t,node:this}];r.length;){n=r.pop();for(var o=Object.keys(n.qNode.edges),a=o.length,i=Object.keys(n.node.edges),s=i.length,c=0;c<a;c++)for(var l=o[c],u=0;u<s;u++){var d=i[u];if(d==l||"*"==l){var p=n.node.edges[d],f=n.qNode.edges[l],h=p.final&&f.final,m=void 0;d in n.output.edges?(m=n.output.edges[d]).final=m.final||h:((m=new O.TokenSet).final=h,n.output.edges[d]=m),r.push({qNode:f,output:m,node:p})}}}return t},O.TokenSet.Builder=function(){this.previousWord="",this.root=new O.TokenSet,this.uncheckedNodes=[],this.minimizedNodes={}},O.TokenSet.Builder.prototype.insert=function(e){var t,n=0;if(e<this.previousWord)throw new Error("Out of order word insertion");for(var r=0;r<e.length&&r<this.previousWord.length&&e[r]==this.previousWord[r];r++)n++;this.minimize(n),t=0==this.uncheckedNodes.length?this.root:this.uncheckedNodes[this.uncheckedNodes.length-1].child;for(r=n;r<e.length;r++){var o=new O.TokenSet,a=e[r];t.edges[a]=o,this.uncheckedNodes.push({parent:t,char:a,child:o}),t=o}t.final=!0,this.previousWord=e},O.TokenSet.Builder.prototype.finish=function(){this.minimize(0)},O.TokenSet.Builder.prototype.minimize=function(e){for(var t=this.uncheckedNodes.length-1;t>=e;t--){var n=this.uncheckedNodes[t],r=n.child.toString();r in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[r]:(n.child._str=r,this.minimizedNodes[r]=n.child),this.uncheckedNodes.pop()}},O.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},O.Index.prototype.search=function(e){return this.query((function(t){new O.QueryParser(e,t).parse()}))},O.Index.prototype.query=function(e){for(var t=new O.Query(this.fields),n=Object.create(null),r=Object.create(null),o=Object.create(null),a=Object.create(null),i=Object.create(null),s=0;s<this.fields.length;s++)r[this.fields[s]]=new O.Vector;e.call(t,t);for(s=0;s<t.clauses.length;s++){var c=t.clauses[s],l=null,u=O.Set.empty;l=c.usePipeline?this.pipeline.runString(c.term,{fields:c.fields}):[c.term];for(var d=0;d<l.length;d++){var p=l[d];c.term=p;var f=O.TokenSet.fromClause(c),h=this.tokenSet.intersect(f).toArray();if(0===h.length&&c.presence===O.Query.presence.REQUIRED){for(var m=0;m<c.fields.length;m++){a[A=c.fields[m]]=O.Set.empty}break}for(var g=0;g<h.length;g++){var b=h[g],v=this.invertedIndex[b],y=v._index;for(m=0;m<c.fields.length;m++){var k=v[A=c.fields[m]],E=Object.keys(k),w=b+"/"+A,x=new O.Set(E);if(c.presence==O.Query.presence.REQUIRED&&(u=u.union(x),void 0===a[A]&&(a[A]=O.Set.complete)),c.presence!=O.Query.presence.PROHIBITED){if(r[A].upsert(y,c.boost,(function(e,t){return e+t})),!o[w]){for(var S=0;S<E.length;S++){var _,T=E[S],C=new O.FieldRef(T,A),L=k[T];void 0===(_=n[C])?n[C]=new O.MatchData(b,A,L):_.add(b,A,L)}o[w]=!0}}else void 0===i[A]&&(i[A]=O.Set.empty),i[A]=i[A].union(x)}}}if(c.presence===O.Query.presence.REQUIRED)for(m=0;m<c.fields.length;m++){a[A=c.fields[m]]=a[A].intersect(u)}}var N=O.Set.complete,I=O.Set.empty;for(s=0;s<this.fields.length;s++){var A;a[A=this.fields[s]]&&(N=N.intersect(a[A])),i[A]&&(I=I.union(i[A]))}var R=Object.keys(n),P=[],D=Object.create(null);if(t.isNegated()){R=Object.keys(this.fieldVectors);for(s=0;s<R.length;s++){C=R[s];var M=O.FieldRef.fromString(C);n[C]=new O.MatchData}}for(s=0;s<R.length;s++){var F=(M=O.FieldRef.fromString(R[s])).docRef;if(N.contains(F)&&!I.contains(F)){var z,B=this.fieldVectors[M],U=r[M.fieldName].similarity(B);if(void 0!==(z=D[F]))z.score+=U,z.matchData.combine(n[M]);else{var j={ref:F,score:U,matchData:n[M]};D[F]=j,P.push(j)}}}return P.sort((function(e,t){return t.score-e.score}))},O.Index.prototype.toJSON=function(){var e=Object.keys(this.invertedIndex).sort().map((function(e){return[e,this.invertedIndex[e]]}),this),t=Object.keys(this.fieldVectors).map((function(e){return[e,this.fieldVectors[e].toJSON()]}),this);return{version:O.version,fields:this.fields,fieldVectors:t,invertedIndex:e,pipeline:this.pipeline.toJSON()}},O.Index.load=function(e){var t={},n={},r=e.fieldVectors,o=Object.create(null),a=e.invertedIndex,i=new O.TokenSet.Builder,s=O.Pipeline.load(e.pipeline);e.version!=O.version&&O.utils.warn("Version mismatch when loading serialised index. Current version of lunr '"+O.version+"' does not match serialized index '"+e.version+"'");for(var c=0;c<r.length;c++){var l=(d=r[c])[0],u=d[1];n[l]=new O.Vector(u)}for(c=0;c<a.length;c++){var d,p=(d=a[c])[0],f=d[1];i.insert(p),o[p]=f}return i.finish(),t.fields=e.fields,t.fieldVectors=n,t.invertedIndex=o,t.tokenSet=i.root,t.pipeline=s,new O.Index(t)},O.Builder=function(){this._ref="id",this._fields=Object.create(null),this._documents=Object.create(null),this.invertedIndex=Object.create(null),this.fieldTermFrequencies={},this.fieldLengths={},this.tokenizer=O.tokenizer,this.pipeline=new O.Pipeline,this.searchPipeline=new O.Pipeline,this.documentCount=0,this._b=.75,this._k1=1.2,this.termIndex=0,this.metadataWhitelist=[]},O.Builder.prototype.ref=function(e){this._ref=e},O.Builder.prototype.field=function(e,t){if(/\//.test(e))throw new RangeError("Field '"+e+"' contains illegal character '/'");this._fields[e]=t||{}},O.Builder.prototype.b=function(e){this._b=e<0?0:e>1?1:e},O.Builder.prototype.k1=function(e){this._k1=e},O.Builder.prototype.add=function(e,t){var n=e[this._ref],r=Object.keys(this._fields);this._documents[n]=t||{},this.documentCount+=1;for(var o=0;o<r.length;o++){var a=r[o],i=this._fields[a].extractor,s=i?i(e):e[a],c=this.tokenizer(s,{fields:[a]}),l=this.pipeline.run(c),u=new O.FieldRef(n,a),d=Object.create(null);this.fieldTermFrequencies[u]=d,this.fieldLengths[u]=0,this.fieldLengths[u]+=l.length;for(var p=0;p<l.length;p++){var f=l[p];if(null==d[f]&&(d[f]=0),d[f]+=1,null==this.invertedIndex[f]){var h=Object.create(null);h._index=this.termIndex,this.termIndex+=1;for(var m=0;m<r.length;m++)h[r[m]]=Object.create(null);this.invertedIndex[f]=h}null==this.invertedIndex[f][a][n]&&(this.invertedIndex[f][a][n]=Object.create(null));for(var g=0;g<this.metadataWhitelist.length;g++){var b=this.metadataWhitelist[g],v=f.metadata[b];null==this.invertedIndex[f][a][n][b]&&(this.invertedIndex[f][a][n][b]=[]),this.invertedIndex[f][a][n][b].push(v)}}}},O.Builder.prototype.calculateAverageFieldLengths=function(){for(var e=Object.keys(this.fieldLengths),t=e.length,n={},r={},o=0;o<t;o++){var a=O.FieldRef.fromString(e[o]),i=a.fieldName;r[i]||(r[i]=0),r[i]+=1,n[i]||(n[i]=0),n[i]+=this.fieldLengths[a]}var s=Object.keys(this._fields);for(o=0;o<s.length;o++){var c=s[o];n[c]=n[c]/r[c]}this.averageFieldLength=n},O.Builder.prototype.createFieldVectors=function(){for(var e={},t=Object.keys(this.fieldTermFrequencies),n=t.length,r=Object.create(null),o=0;o<n;o++){for(var a=O.FieldRef.fromString(t[o]),i=a.fieldName,s=this.fieldLengths[a],c=new O.Vector,l=this.fieldTermFrequencies[a],u=Object.keys(l),d=u.length,p=this._fields[i].boost||1,f=this._documents[a.docRef].boost||1,h=0;h<d;h++){var m,g,b,v=u[h],y=l[v],k=this.invertedIndex[v]._index;void 0===r[v]?(m=O.idf(this.invertedIndex[v],this.documentCount),r[v]=m):m=r[v],g=m*((this._k1+1)*y)/(this._k1*(1-this._b+this._b*(s/this.averageFieldLength[i]))+y),g*=p,g*=f,b=Math.round(1e3*g)/1e3,c.insert(k,b)}e[a]=c}this.fieldVectors=e},O.Builder.prototype.createTokenSet=function(){this.tokenSet=O.TokenSet.fromArray(Object.keys(this.invertedIndex).sort())},O.Builder.prototype.build=function(){return this.calculateAverageFieldLengths(),this.createFieldVectors(),this.createTokenSet(),new O.Index({invertedIndex:this.invertedIndex,fieldVectors:this.fieldVectors,tokenSet:this.tokenSet,fields:Object.keys(this._fields),pipeline:this.searchPipeline})},O.Builder.prototype.use=function(e){var t=Array.prototype.slice.call(arguments,1);t.unshift(this),e.apply(this,t)},O.MatchData=function(e,t,n){for(var r=Object.create(null),o=Object.keys(n||{}),a=0;a<o.length;a++){var i=o[a];r[i]=n[i].slice()}this.metadata=Object.create(null),void 0!==e&&(this.metadata[e]=Object.create(null),this.metadata[e][t]=r)},O.MatchData.prototype.combine=function(e){for(var t=Object.keys(e.metadata),n=0;n<t.length;n++){var r=t[n],o=Object.keys(e.metadata[r]);null==this.metadata[r]&&(this.metadata[r]=Object.create(null));for(var a=0;a<o.length;a++){var i=o[a],s=Object.keys(e.metadata[r][i]);null==this.metadata[r][i]&&(this.metadata[r][i]=Object.create(null));for(var c=0;c<s.length;c++){var l=s[c];null==this.metadata[r][i][l]?this.metadata[r][i][l]=e.metadata[r][i][l]:this.metadata[r][i][l]=this.metadata[r][i][l].concat(e.metadata[r][i][l])}}}},O.MatchData.prototype.add=function(e,t,n){if(!(e in this.metadata))return this.metadata[e]=Object.create(null),void(this.metadata[e][t]=n);if(t in this.metadata[e])for(var r=Object.keys(n),o=0;o<r.length;o++){var a=r[o];a in this.metadata[e][t]?this.metadata[e][t][a]=this.metadata[e][t][a].concat(n[a]):this.metadata[e][t][a]=n[a]}else this.metadata[e][t]=n},O.Query=function(e){this.clauses=[],this.allFields=e},O.Query.wildcard=new String("*"),O.Query.wildcard.NONE=0,O.Query.wildcard.LEADING=1,O.Query.wildcard.TRAILING=2,O.Query.presence={OPTIONAL:1,REQUIRED:2,PROHIBITED:3},O.Query.prototype.clause=function(e){return"fields"in e||(e.fields=this.allFields),"boost"in e||(e.boost=1),"usePipeline"in e||(e.usePipeline=!0),"wildcard"in e||(e.wildcard=O.Query.wildcard.NONE),e.wildcard&O.Query.wildcard.LEADING&&e.term.charAt(0)!=O.Query.wildcard&&(e.term="*"+e.term),e.wildcard&O.Query.wildcard.TRAILING&&e.term.slice(-1)!=O.Query.wildcard&&(e.term=e.term+"*"),"presence"in e||(e.presence=O.Query.presence.OPTIONAL),this.clauses.push(e),this},O.Query.prototype.isNegated=function(){for(var e=0;e<this.clauses.length;e++)if(this.clauses[e].presence!=O.Query.presence.PROHIBITED)return!1;return!0},O.Query.prototype.term=function(e,t){if(Array.isArray(e))return e.forEach((function(e){this.term(e,O.utils.clone(t))}),this),this;var n=t||{};return n.term=e.toString(),this.clause(n),this},O.QueryParseError=function(e,t,n){this.name="QueryParseError",this.message=e,this.start=t,this.end=n},O.QueryParseError.prototype=new Error,O.QueryLexer=function(e){this.lexemes=[],this.str=e,this.length=e.length,this.pos=0,this.start=0,this.escapeCharPositions=[]},O.QueryLexer.prototype.run=function(){for(var e=O.QueryLexer.lexText;e;)e=e(this)},O.QueryLexer.prototype.sliceString=function(){for(var e=[],t=this.start,n=this.pos,r=0;r<this.escapeCharPositions.length;r++)n=this.escapeCharPositions[r],e.push(this.str.slice(t,n)),t=n+1;return e.push(this.str.slice(t,this.pos)),this.escapeCharPositions.length=0,e.join("")},O.QueryLexer.prototype.emit=function(e){this.lexemes.push({type:e,str:this.sliceString(),start:this.start,end:this.pos}),this.start=this.pos},O.QueryLexer.prototype.escapeCharacter=function(){this.escapeCharPositions.push(this.pos-1),this.pos+=1},O.QueryLexer.prototype.next=function(){if(this.pos>=this.length)return O.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},O.QueryLexer.prototype.width=function(){return this.pos-this.start},O.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},O.QueryLexer.prototype.backup=function(){this.pos-=1},O.QueryLexer.prototype.acceptDigitRun=function(){var e,t;do{t=(e=this.next()).charCodeAt(0)}while(t>47&&t<58);e!=O.QueryLexer.EOS&&this.backup()},O.QueryLexer.prototype.more=function(){return this.pos<this.length},O.QueryLexer.EOS="EOS",O.QueryLexer.FIELD="FIELD",O.QueryLexer.TERM="TERM",O.QueryLexer.EDIT_DISTANCE="EDIT_DISTANCE",O.QueryLexer.BOOST="BOOST",O.QueryLexer.PRESENCE="PRESENCE",O.QueryLexer.lexField=function(e){return e.backup(),e.emit(O.QueryLexer.FIELD),e.ignore(),O.QueryLexer.lexText},O.QueryLexer.lexTerm=function(e){if(e.width()>1&&(e.backup(),e.emit(O.QueryLexer.TERM)),e.ignore(),e.more())return O.QueryLexer.lexText},O.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(O.QueryLexer.EDIT_DISTANCE),O.QueryLexer.lexText},O.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(O.QueryLexer.BOOST),O.QueryLexer.lexText},O.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(O.QueryLexer.TERM)},O.QueryLexer.termSeparator=O.tokenizer.separator,O.QueryLexer.lexText=function(e){for(;;){var t=e.next();if(t==O.QueryLexer.EOS)return O.QueryLexer.lexEOS;if(92!=t.charCodeAt(0)){if(":"==t)return O.QueryLexer.lexField;if("~"==t)return e.backup(),e.width()>0&&e.emit(O.QueryLexer.TERM),O.QueryLexer.lexEditDistance;if("^"==t)return e.backup(),e.width()>0&&e.emit(O.QueryLexer.TERM),O.QueryLexer.lexBoost;if("+"==t&&1===e.width())return e.emit(O.QueryLexer.PRESENCE),O.QueryLexer.lexText;if("-"==t&&1===e.width())return e.emit(O.QueryLexer.PRESENCE),O.QueryLexer.lexText;if(t.match(O.QueryLexer.termSeparator))return O.QueryLexer.lexTerm}else e.escapeCharacter()}},O.QueryParser=function(e,t){this.lexer=new O.QueryLexer(e),this.query=t,this.currentClause={},this.lexemeIdx=0},O.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=O.QueryParser.parseClause;e;)e=e(this);return this.query},O.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},O.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},O.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},O.QueryParser.parseClause=function(e){var t=e.peekLexeme();if(null!=t)switch(t.type){case O.QueryLexer.PRESENCE:return O.QueryParser.parsePresence;case O.QueryLexer.FIELD:return O.QueryParser.parseField;case O.QueryLexer.TERM:return O.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+t.type;throw t.str.length>=1&&(n+=" with value '"+t.str+"'"),new O.QueryParseError(n,t.start,t.end)}},O.QueryParser.parsePresence=function(e){var t=e.consumeLexeme();if(null!=t){switch(t.str){case"-":e.currentClause.presence=O.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=O.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+t.str+"'";throw new O.QueryParseError(n,t.start,t.end)}var r=e.peekLexeme();if(null==r){n="expecting term or field, found nothing";throw new O.QueryParseError(n,t.start,t.end)}switch(r.type){case O.QueryLexer.FIELD:return O.QueryParser.parseField;case O.QueryLexer.TERM:return O.QueryParser.parseTerm;default:n="expecting term or field, found '"+r.type+"'";throw new O.QueryParseError(n,r.start,r.end)}}},O.QueryParser.parseField=function(e){var t=e.consumeLexeme();if(null!=t){if(-1==e.query.allFields.indexOf(t.str)){var n=e.query.allFields.map((function(e){return"'"+e+"'"})).join(", "),r="unrecognised field '"+t.str+"', possible fields: "+n;throw new O.QueryParseError(r,t.start,t.end)}e.currentClause.fields=[t.str];var o=e.peekLexeme();if(null==o){r="expecting term, found nothing";throw new O.QueryParseError(r,t.start,t.end)}if(o.type===O.QueryLexer.TERM)return O.QueryParser.parseTerm;r="expecting term, found '"+o.type+"'";throw new O.QueryParseError(r,o.start,o.end)}},O.QueryParser.parseTerm=function(e){var t=e.consumeLexeme();if(null!=t){e.currentClause.term=t.str.toLowerCase(),-1!=t.str.indexOf("*")&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(null!=n)switch(n.type){case O.QueryLexer.TERM:return e.nextClause(),O.QueryParser.parseTerm;case O.QueryLexer.FIELD:return e.nextClause(),O.QueryParser.parseField;case O.QueryLexer.EDIT_DISTANCE:return O.QueryParser.parseEditDistance;case O.QueryLexer.BOOST:return O.QueryParser.parseBoost;case O.QueryLexer.PRESENCE:return e.nextClause(),O.QueryParser.parsePresence;default:var r="Unexpected lexeme type '"+n.type+"'";throw new O.QueryParseError(r,n.start,n.end)}else e.nextClause()}},O.QueryParser.parseEditDistance=function(e){var t=e.consumeLexeme();if(null!=t){var n=parseInt(t.str,10);if(isNaN(n)){var r="edit distance must be numeric";throw new O.QueryParseError(r,t.start,t.end)}e.currentClause.editDistance=n;var o=e.peekLexeme();if(null!=o)switch(o.type){case O.QueryLexer.TERM:return e.nextClause(),O.QueryParser.parseTerm;case O.QueryLexer.FIELD:return e.nextClause(),O.QueryParser.parseField;case O.QueryLexer.EDIT_DISTANCE:return O.QueryParser.parseEditDistance;case O.QueryLexer.BOOST:return O.QueryParser.parseBoost;case O.QueryLexer.PRESENCE:return e.nextClause(),O.QueryParser.parsePresence;default:r="Unexpected lexeme type '"+o.type+"'";throw new O.QueryParseError(r,o.start,o.end)}else e.nextClause()}},O.QueryParser.parseBoost=function(e){var t=e.consumeLexeme();if(null!=t){var n=parseInt(t.str,10);if(isNaN(n)){var r="boost must be numeric";throw new O.QueryParseError(r,t.start,t.end)}e.currentClause.boost=n;var o=e.peekLexeme();if(null!=o)switch(o.type){case O.QueryLexer.TERM:return e.nextClause(),O.QueryParser.parseTerm;case O.QueryLexer.FIELD:return e.nextClause(),O.QueryParser.parseField;case O.QueryLexer.EDIT_DISTANCE:return O.QueryParser.parseEditDistance;case O.QueryLexer.BOOST:return O.QueryParser.parseBoost;case O.QueryLexer.PRESENCE:return e.nextClause(),O.QueryParser.parsePresence;default:r="Unexpected lexeme type '"+o.type+"'";throw new O.QueryParseError(r,o.start,o.end)}else e.nextClause()}},void 0===(o="function"==typeof(r=function(){return O})?r.call(t,n,t,e):r)||(e.exports=o)}()},813:function(e){e.exports=function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),r=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},o=function(){function e(n){var r=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=o,this.iframesTimeout=a}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach((function(t){var n=e.filter((function(e){return e.contains(t)})).length>0;-1!==e.indexOf(t)||n||e.push(t)})),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var o=e.contentWindow;if(r=o.document,!o||!r)throw new Error("iframe inaccessible")}catch(a){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t="about:blank",n=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&n!==t&&n}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,o=!1,a=null,i=function i(){if(!o){o=!0,clearTimeout(a);try{r.isIframeBlank(e)||(e.removeEventListener("load",i),r.getIframeContents(e,t,n))}catch(s){n()}}};e.addEventListener("load",i),a=setTimeout(i,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(r){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,(function(){return!0}),(function(e){r++,n.waitForIframes(e.querySelector("html"),(function(){--r||t()}))}),(function(e){e||t()}))}},{key:"forEachIframe",value:function(t,n,r){var o=this,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},i=t.querySelectorAll("iframe"),s=i.length,c=0;i=Array.prototype.slice.call(i);var l=function(){--s<=0&&a(c)};s||l(),i.forEach((function(t){e.matches(t,o.exclude)?l():o.onIframeReady(t,(function(e){n(t)&&(c++,r(e)),l()}),l)}))}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:(null===t||e.nextNode())&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var o=!1,a=!1;return r.forEach((function(e,t){e.val===n&&(o=t,a=e.handled)})),this.compareNodeIframe(e,t,n)?(!1!==o||a?!1===o||a||(r[o].handled=!0):r.push({val:n,handled:!0}),!0):(!1===o&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var o=this;e.forEach((function(e){e.handled||o.getIframeContents(e.val,(function(e){o.createInstanceOnIframe(e).forEachNode(t,n,r)}))}))}},{key:"iterateThroughNodes",value:function(e,t,n,r,o){for(var a=this,i=this.createIterator(t,e,r),s=[],c=[],l=void 0,u=void 0,d=function(){var e=a.getIteratorNode(i);return u=e.prevNode,l=e.node};d();)this.iframes&&this.forEachIframe(t,(function(e){return a.checkIframeFilter(l,u,e,s)}),(function(t){a.createInstanceOnIframe(t).forEachNode(e,(function(e){return c.push(e)}),r)})),c.push(l);c.forEach((function(e){n(e)})),this.iframes&&this.handleOpenIframes(s,e,n,r),o()}},{key:"forEachNode",value:function(e,t,n){var r=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=this.getContexts(),i=a.length;i||o(),a.forEach((function(a){var s=function(){r.iterateThroughNodes(e,a,t,n,(function(){--i<=0&&o()}))};r.iframes?r.waitForIframes(a,s):s()}))}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var o=!1;return n.every((function(t){return!r.call(e,t)||(o=!0,!1)})),o}return!1}}]),e}(),a=function(){function a(e){t(this,a),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(a,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createRegExp",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var o in t)if(t.hasOwnProperty(o)){var a=t[o],i="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(a):this.escapeStr(a);""!==i&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(i)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynomyms(i)+"|"+this.processSynomyms(s)+")"+r))}return e}},{key:"processSynomyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,(function(e){return"\\"===e.charAt(0)?"?":"\x01"}))).replace(/(?:\\)*\*/g,(function(e){return"\\"===e.charAt(0)?"*":"\x02"}))}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,(function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"}))}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["a\xe0\xe1\u1ea3\xe3\u1ea1\u0103\u1eb1\u1eaf\u1eb3\u1eb5\u1eb7\xe2\u1ea7\u1ea5\u1ea9\u1eab\u1ead\xe4\xe5\u0101\u0105","A\xc0\xc1\u1ea2\xc3\u1ea0\u0102\u1eb0\u1eae\u1eb2\u1eb4\u1eb6\xc2\u1ea6\u1ea4\u1ea8\u1eaa\u1eac\xc4\xc5\u0100\u0104","c\xe7\u0107\u010d","C\xc7\u0106\u010c","d\u0111\u010f","D\u0110\u010e","e\xe8\xe9\u1ebb\u1ebd\u1eb9\xea\u1ec1\u1ebf\u1ec3\u1ec5\u1ec7\xeb\u011b\u0113\u0119","E\xc8\xc9\u1eba\u1ebc\u1eb8\xca\u1ec0\u1ebe\u1ec2\u1ec4\u1ec6\xcb\u011a\u0112\u0118","i\xec\xed\u1ec9\u0129\u1ecb\xee\xef\u012b","I\xcc\xcd\u1ec8\u0128\u1eca\xce\xcf\u012a","l\u0142","L\u0141","n\xf1\u0148\u0144","N\xd1\u0147\u0143","o\xf2\xf3\u1ecf\xf5\u1ecd\xf4\u1ed3\u1ed1\u1ed5\u1ed7\u1ed9\u01a1\u1edf\u1ee1\u1edb\u1edd\u1ee3\xf6\xf8\u014d","O\xd2\xd3\u1ece\xd5\u1ecc\xd4\u1ed2\u1ed0\u1ed4\u1ed6\u1ed8\u01a0\u1ede\u1ee0\u1eda\u1edc\u1ee2\xd6\xd8\u014c","r\u0159","R\u0158","s\u0161\u015b\u0219\u015f","S\u0160\u015a\u0218\u015e","t\u0165\u021b\u0163","T\u0164\u021a\u0162","u\xf9\xfa\u1ee7\u0169\u1ee5\u01b0\u1eeb\u1ee9\u1eed\u1eef\u1ef1\xfb\xfc\u016f\u016b","U\xd9\xda\u1ee6\u0168\u1ee4\u01af\u1eea\u1ee8\u1eec\u1eee\u1ef0\xdb\xdc\u016e\u016a","y\xfd\u1ef3\u1ef7\u1ef9\u1ef5\xff","Y\xdd\u1ef2\u1ef6\u1ef8\u1ef4\u0178","z\u017e\u017c\u017a","Z\u017d\u017b\u0179"]:["a\xe0\xe1\u1ea3\xe3\u1ea1\u0103\u1eb1\u1eaf\u1eb3\u1eb5\u1eb7\xe2\u1ea7\u1ea5\u1ea9\u1eab\u1ead\xe4\xe5\u0101\u0105A\xc0\xc1\u1ea2\xc3\u1ea0\u0102\u1eb0\u1eae\u1eb2\u1eb4\u1eb6\xc2\u1ea6\u1ea4\u1ea8\u1eaa\u1eac\xc4\xc5\u0100\u0104","c\xe7\u0107\u010dC\xc7\u0106\u010c","d\u0111\u010fD\u0110\u010e","e\xe8\xe9\u1ebb\u1ebd\u1eb9\xea\u1ec1\u1ebf\u1ec3\u1ec5\u1ec7\xeb\u011b\u0113\u0119E\xc8\xc9\u1eba\u1ebc\u1eb8\xca\u1ec0\u1ebe\u1ec2\u1ec4\u1ec6\xcb\u011a\u0112\u0118","i\xec\xed\u1ec9\u0129\u1ecb\xee\xef\u012bI\xcc\xcd\u1ec8\u0128\u1eca\xce\xcf\u012a","l\u0142L\u0141","n\xf1\u0148\u0144N\xd1\u0147\u0143","o\xf2\xf3\u1ecf\xf5\u1ecd\xf4\u1ed3\u1ed1\u1ed5\u1ed7\u1ed9\u01a1\u1edf\u1ee1\u1edb\u1edd\u1ee3\xf6\xf8\u014dO\xd2\xd3\u1ece\xd5\u1ecc\xd4\u1ed2\u1ed0\u1ed4\u1ed6\u1ed8\u01a0\u1ede\u1ee0\u1eda\u1edc\u1ee2\xd6\xd8\u014c","r\u0159R\u0158","s\u0161\u015b\u0219\u015fS\u0160\u015a\u0218\u015e","t\u0165\u021b\u0163T\u0164\u021a\u0162","u\xf9\xfa\u1ee7\u0169\u1ee5\u01b0\u1eeb\u1ee9\u1eed\u1eef\u1ef1\xfb\xfc\u016f\u016bU\xd9\xda\u1ee6\u0168\u1ee4\u01af\u1eea\u1ee8\u1eec\u1eee\u1ef0\xdb\xdc\u016e\u016a","y\xfd\u1ef3\u1ef7\u1ef9\u1ef5\xffY\xdd\u1ef2\u1ef6\u1ef8\u1ef4\u0178","z\u017e\u017c\u017aZ\u017d\u017b\u0179"],r=[];return e.split("").forEach((function(o){n.every((function(n){if(-1!==n.indexOf(o)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0}))})),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\xa1\xbf",r=this.opt.accuracy,o="string"==typeof r?r:r.value,a="string"==typeof r?[]:r.limiters,i="";switch(a.forEach((function(e){i+="|"+t.escapeStr(e)})),o){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr(n)))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach((function(e){t.opt.separateWordSearch?e.split(" ").forEach((function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)})):e.trim()&&-1===n.indexOf(e)&&n.push(e)})),{keywords:n.sort((function(e,t){return t.length-e.length})),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort((function(e,t){return e.start-t.start})).forEach((function(e){var o=t.callNoMatchOnInvalidRanges(e,r),a=o.start,i=o.end;o.valid&&(e.start=a,e.length=i-a,n.push(e),r=i)})),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,o=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?o=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:o}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,o=!0,a=n.length,i=t-a,s=parseInt(e.start,10)-i;return(r=(s=s>a?a:s)+parseInt(e.length,10))>a&&(r=a,this.log("End range automatically set to the max value of "+a)),s<0||r-s<0||s>a||r>a?(o=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(o=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:o}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,(function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})}),(function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}),(function(){e({value:n,nodes:r})}))}},{key:"matchesExclude",value:function(e){return o.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",o=e.splitText(t),a=o.splitText(n-t),i=document.createElement(r);return i.setAttribute("data-markjs","true"),this.opt.className&&i.setAttribute("class",this.opt.className),i.textContent=o.textContent,o.parentNode.replaceChild(i,o),a}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,o){var a=this;e.nodes.every((function(i,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(i.node))return!1;var l=t-i.start,u=(n>i.end?i.end:n)-i.start,d=e.value.substr(0,i.start),p=e.value.substr(u+i.start);if(i.node=a.wrapRangeInTextNode(i.node,l,u),e.value=d+p,e.nodes.forEach((function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=u),e.nodes[n].end-=u)})),n-=u,o(i.node.previousSibling,i.start),!(n>i.end))return!1;t=i.end}return!0}))}},{key:"wrapMatches",value:function(e,t,n,r,o){var a=this,i=0===t?0:t+1;this.getTextNodes((function(t){t.nodes.forEach((function(t){t=t.node;for(var o=void 0;null!==(o=e.exec(t.textContent))&&""!==o[i];)if(n(o[i],t)){var s=o.index;if(0!==i)for(var c=1;c<i;c++)s+=o[c].length;t=a.wrapRangeInTextNode(t,s,s+o[i].length),r(t.previousSibling),e.lastIndex=0}})),o()}))}},{key:"wrapMatchesAcrossElements",value:function(e,t,n,r,o){var a=this,i=0===t?0:t+1;this.getTextNodes((function(t){for(var s=void 0;null!==(s=e.exec(t.value))&&""!==s[i];){var c=s.index;if(0!==i)for(var l=1;l<i;l++)c+=s[l].length;var u=c+s[i].length;a.wrapRangeInMappedTextNode(t,c,u,(function(e){return n(s[i],e)}),(function(t,n){e.lastIndex=n,r(t)}))}o()}))}},{key:"wrapRangeFromIndex",value:function(e,t,n,r){var o=this;this.getTextNodes((function(a){var i=a.value.length;e.forEach((function(e,r){var s=o.checkWhitespaceRanges(e,i,a.value),c=s.start,l=s.end;s.valid&&o.wrapRangeInMappedTextNode(a,c,l,(function(n){return t(n,e,a.value.substring(c,l),r)}),(function(t){n(t,e)}))})),r()}))}},{key:"unwrapMatches",value:function(e){for(var t=e.parentNode,n=document.createDocumentFragment();e.firstChild;)n.appendChild(e.removeChild(e.firstChild));t.replaceChild(n,e),this.ie?this.normalizeTextNode(t):t.normalize()}},{key:"normalizeTextNode",value:function(e){if(e){if(3===e.nodeType)for(;e.nextSibling&&3===e.nextSibling.nodeType;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}},{key:"markRegExp",value:function(e,t){var n=this;this.opt=t,this.log('Searching with expression "'+e+'"');var r=0,o="wrapMatches",a=function(e){r++,n.opt.each(e)};this.opt.acrossElements&&(o="wrapMatchesAcrossElements"),this[o](e,this.opt.ignoreGroups,(function(e,t){return n.opt.filter(t,e,r)}),a,(function(){0===r&&n.opt.noMatch(e),n.opt.done(r)}))}},{key:"mark",value:function(e,t){var n=this;this.opt=t;var r=0,o="wrapMatches",a=this.getSeparatedKeywords("string"==typeof e?[e]:e),i=a.keywords,s=a.length,c=this.opt.caseSensitive?"":"i",l=function e(t){var a=new RegExp(n.createRegExp(t),"gm"+c),l=0;n.log('Searching with expression "'+a+'"'),n[o](a,1,(function(e,o){return n.opt.filter(o,t,r,l)}),(function(e){l++,r++,n.opt.each(e)}),(function(){0===l&&n.opt.noMatch(t),i[s-1]===t?n.opt.done(r):e(i[i.indexOf(t)+1])}))};this.opt.acrossElements&&(o="wrapMatchesAcrossElements"),0===s?this.opt.done(r):l(i[0])}},{key:"markRanges",value:function(e,t){var n=this;this.opt=t;var r=0,o=this.checkRanges(e);o&&o.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(o)),this.wrapRangeFromIndex(o,(function(e,t,r,o){return n.opt.filter(e,t,r,o)}),(function(e,t){r++,n.opt.each(e,t)}),(function(){n.opt.done(r)}))):this.opt.done(r)}},{key:"unmark",value:function(e){var t=this;this.opt=e;var n=this.opt.element?this.opt.element:"*";n+="[data-markjs]",this.opt.className&&(n+="."+this.opt.className),this.log('Removal selector "'+n+'"'),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,(function(e){t.unwrapMatches(e)}),(function(e){var r=o.matches(e,n),a=t.matchesExclude(e);return!r||a?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}),this.opt.done)}},{key:"opt",set:function(e){this._opt=r({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:function(){},noMatch:function(){},filter:function(){return!0},done:function(){},debug:!1,log:window.console},e)},get:function(){return this._opt}},{key:"iterator",get:function(){return new o(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}}]),a}();function i(e){var t=this,n=new a(e);return this.mark=function(e,r){return n.mark(e,r),t},this.markRegExp=function(e,r){return n.markRegExp(e,r),t},this.markRanges=function(e,r){return n.markRanges(e,r),t},this.unmark=function(e){return n.unmark(e),t},this}return i}()},2497:(e,t,n)=>{"use strict";n.r(t)},2295:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,o;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function o(e,t,n){return e<t?t:e>n?n:e}function a(e){return 100*(-1+e)}function i(e,t,n){var o;return(o="translate3d"===r.positionUsing?{transform:"translate3d("+a(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+a(e)+"%,0)"}:{"margin-left":a(e)+"%"}).transition="all "+t+"ms "+n,o}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=o(e,r.minimum,1),n.status=1===e?null:e;var a=n.render(!t),l=a.querySelector(r.barSelector),u=r.speed,d=r.easing;return a.offsetWidth,s((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),c(l,i(e,u,d)),1===e?(c(a,{transition:"none",opacity:1}),a.offsetWidth,setTimeout((function(){c(a,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*o(Math.random()*t,.1,.95)),t=o(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var o,i=t.querySelector(r.barSelector),s=e?"-100":a(n.status||0),l=document.querySelector(r.parent);return c(i,{transition:"all 0 linear",transform:"translate3d("+s+"%,0,0)"}),r.showSpinner||(o=t.querySelector(r.spinnerSelector))&&f(o),l!=document.body&&u(l,"nprogress-custom-parent"),l.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var s=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),c=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,o=e.length,a=t.charAt(0).toUpperCase()+t.slice(1);o--;)if((r=e[o]+a)in n)return r;return t}function o(e){return e=n(e),t[e]||(t[e]=r(e))}function a(e,t,n){t=o(t),e.style[t]=n}return function(e,t){var n,r,o=arguments;if(2==o.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&a(e,n,r);else a(e,o[1],o[2])}}();function l(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=p(e),r=n+t;l(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=p(e);l(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(o="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=o)},7418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;function o(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(o){return!1}}()?Object.assign:function(e,a){for(var i,s,c=o(e),l=1;l<arguments.length;l++){for(var u in i=Object(arguments[l]))n.call(i,u)&&(c[u]=i[u]);if(t){s=t(i);for(var d=0;d<s.length;d++)r.call(i,s[d])&&(c[s[d]]=i[s[d]])}}return c}},4779:(e,t,n)=>{var r=n(5826);e.exports=f,e.exports.parse=a,e.exports.compile=function(e,t){return s(a(e,t),t)},e.exports.tokensToFunction=s,e.exports.tokensToRegExp=p;var o=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function a(e,t){for(var n,r=[],a=0,i=0,s="",u=t&&t.delimiter||"/";null!=(n=o.exec(e));){var d=n[0],p=n[1],f=n.index;if(s+=e.slice(i,f),i=f+d.length,p)s+=p[1];else{var h=e[i],m=n[2],g=n[3],b=n[4],v=n[5],y=n[6],k=n[7];s&&(r.push(s),s="");var E=null!=m&&null!=h&&h!==m,w="+"===y||"*"===y,x="?"===y||"*"===y,S=n[2]||u,_=b||v;r.push({name:g||a++,prefix:m||"",delimiter:S,optional:x,repeat:w,partial:E,asterisk:!!k,pattern:_?l(_):k?".*":"[^"+c(S)+"]+?"})}}return i<e.length&&(s+=e.substr(i)),s&&r.push(s),r}function i(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function s(e,t){for(var n=new Array(e.length),o=0;o<e.length;o++)"object"==typeof e[o]&&(n[o]=new RegExp("^(?:"+e[o].pattern+")$",d(t)));return function(t,o){for(var a="",s=t||{},c=(o||{}).pretty?i:encodeURIComponent,l=0;l<e.length;l++){var u=e[l];if("string"!=typeof u){var d,p=s[u.name];if(null==p){if(u.optional){u.partial&&(a+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(r(p)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(p)+"`");if(0===p.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var f=0;f<p.length;f++){if(d=c(p[f]),!n[l].test(d))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(d)+"`");a+=(0===f?u.prefix:u.delimiter)+d}}else{if(d=u.asterisk?encodeURI(p).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):c(p),!n[l].test(d))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+d+'"');a+=u.prefix+d}}else a+=u}return a}}function c(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function l(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function u(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function p(e,t,n){r(t)||(n=t||n,t=[]);for(var o=(n=n||{}).strict,a=!1!==n.end,i="",s=0;s<e.length;s++){var l=e[s];if("string"==typeof l)i+=c(l);else{var p=c(l.prefix),f="(?:"+l.pattern+")";t.push(l),l.repeat&&(f+="(?:"+p+f+")*"),i+=f=l.optional?l.partial?p+"("+f+")?":"(?:"+p+"("+f+"))?":p+"("+f+")"}}var h=c(n.delimiter||"/"),m=i.slice(-h.length)===h;return o||(i=(m?i.slice(0,-h.length):i)+"(?:"+h+"(?=$))?"),i+=a?"$":o&&m?"":"(?="+h+"|$)",u(new RegExp("^"+i,d(n)),t)}function f(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return u(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],o=0;o<e.length;o++)r.push(f(e[o],t,n).source);return u(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return p(a(e,n),t,n)}(e,t,n)}},7410:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof o?new o(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var o,a;switch(n=n||{},r.util.type(t)){case"Object":if(a=r.util.objId(t),n[a])return n[a];for(var i in o={},n[a]=o,t)t.hasOwnProperty(i)&&(o[i]=e(t[i],n));return o;case"Array":return a=r.util.objId(t),n[a]?n[a]:(o=[],n[a]=o,t.forEach((function(t,r){o[r]=e(t,n)})),o);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var o=e.classList;if(o.contains(t))return!0;if(o.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var o in t)n[o]=t[o];return n},insertBefore:function(e,t,n,o){var a=(o=o||r.languages)[e],i={};for(var s in a)if(a.hasOwnProperty(s)){if(s==t)for(var c in n)n.hasOwnProperty(c)&&(i[c]=n[c]);n.hasOwnProperty(s)||(i[s]=a[s])}var l=o[e];return o[e]=i,r.languages.DFS(r.languages,(function(t,n){n===l&&t!=e&&(this[t]=i)})),i},DFS:function e(t,n,o,a){a=a||{};var i=r.util.objId;for(var s in t)if(t.hasOwnProperty(s)){n.call(t,s,t[s],o||s);var c=t[s],l=r.util.type(c);"Object"!==l||a[i(c)]?"Array"!==l||a[i(c)]||(a[i(c)]=!0,e(c,n,s,a)):(a[i(c)]=!0,e(c,n,null,a))}}},plugins:{},highlight:function(e,t,n){var a={code:e,grammar:t,language:n};return r.hooks.run("before-tokenize",a),a.tokens=r.tokenize(a.code,a.grammar),r.hooks.run("after-tokenize",a),o.stringify(r.util.encode(a.tokens),a.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var o=new s;return c(o,o.head,e),i(e,o,t,o.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(o)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var o,a=0;o=n[a++];)o(t)}},Token:o};function o(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function a(e,t,n,r){e.lastIndex=t;var o=e.exec(n);if(o&&r&&o[1]){var a=o[1].length;o.index+=a,o[0]=o[0].slice(a)}return o}function i(e,t,n,s,u,d){for(var p in n)if(n.hasOwnProperty(p)&&n[p]){var f=n[p];f=Array.isArray(f)?f:[f];for(var h=0;h<f.length;++h){if(d&&d.cause==p+","+h)return;var m=f[h],g=m.inside,b=!!m.lookbehind,v=!!m.greedy,y=m.alias;if(v&&!m.pattern.global){var k=m.pattern.toString().match(/[imsuy]*$/)[0];m.pattern=RegExp(m.pattern.source,k+"g")}for(var E=m.pattern||m,w=s.next,x=u;w!==t.tail&&!(d&&x>=d.reach);x+=w.value.length,w=w.next){var S=w.value;if(t.length>e.length)return;if(!(S instanceof o)){var _,T=1;if(v){if(!(_=a(E,x,e,b))||_.index>=e.length)break;var C=_.index,L=_.index+_[0].length,N=x;for(N+=w.value.length;C>=N;)N+=(w=w.next).value.length;if(x=N-=w.value.length,w.value instanceof o)continue;for(var I=w;I!==t.tail&&(N<L||"string"==typeof I.value);I=I.next)T++,N+=I.value.length;T--,S=e.slice(x,N),_.index-=x}else if(!(_=a(E,0,S,b)))continue;C=_.index;var O=_[0],A=S.slice(0,C),R=S.slice(C+O.length),P=x+S.length;d&&P>d.reach&&(d.reach=P);var D=w.prev;if(A&&(D=c(t,D,A),x+=A.length),l(t,D,T),w=c(t,D,new o(p,g?r.tokenize(O,g):O,y,O)),R&&c(t,w,R),T>1){var M={cause:p+","+h,reach:P};i(e,t,n,w.prev,x,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function c(e,t,n){var r=t.next,o={value:n,prev:t,next:r};return t.next=o,r.prev=o,e.length++,o}function l(e,t,n){for(var r=t.next,o=0;o<n&&r!==e.tail;o++)r=r.next;t.next=r,r.prev=t,e.length-=o}return o.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var o="";return t.forEach((function(t){o+=e(t,n)})),o}var a={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},i=t.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(a.classes,i):a.classes.push(i)),r.hooks.run("wrap",a);var s="";for(var c in a.attributes)s+=" "+c+'="'+(a.attributes[c]||"").replace(/"/g,""")+'"';return"<"+a.tag+' class="'+a.classes.join(" ")+'"'+s+">"+a.content+"</"+a.tag+">"},r}(),o=r;r.default=r,o.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},o.languages.markup.tag.inside["attr-value"].inside.entity=o.languages.markup.entity,o.languages.markup.doctype.inside["internal-subset"].inside=o.languages.markup,o.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(o.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:o.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var r={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:o.languages[t]};var a={};a[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},o.languages.insertBefore("markup","cdata",a)}}),Object.defineProperty(o.languages.markup.tag,"addAttribute",{value:function(e,t){o.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:o.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),o.languages.html=o.languages.markup,o.languages.mathml=o.languages.markup,o.languages.svg=o.languages.markup,o.languages.xml=o.languages.extend("markup",{}),o.languages.ssml=o.languages.xml,o.languages.atom=o.languages.xml,o.languages.rss=o.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var o=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],a=r.variable[1].inside,i=0;i<o.length;i++)a[o[i]]=e.languages.bash[o[i]];e.languages.shell=e.languages.bash}(o),o.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},o.languages.c=o.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),o.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),o.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},o.languages.c.string],char:o.languages.c.char,comment:o.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:o.languages.c}}}}),o.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete o.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(o),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(o),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},o={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:o,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:o})}(o),o.languages.javascript=o.languages.extend("clike",{"class-name":[o.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),o.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,o.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:o.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:o.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:o.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:o.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:o.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),o.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:o.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),o.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),o.languages.markup&&(o.languages.markup.tag.addInlined("script","javascript"),o.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),o.languages.js=o.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(o),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",o=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),a=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+o+"|"+a+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(a),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(o),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,o=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),a=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+o+a+"(?:"+o+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+o+a+")(?:"+o+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+o+")"+a+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+o+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var o=t[n];if("code"===o.type){var a=o.content[1],i=o.content[3];if(a&&i&&"code-language"===a.type&&"code-block"===i.type&&"string"==typeof a.content){var s=a.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),c="language-"+(s=(/[a-z][\w-]*/i.exec(s)||[""])[0].toLowerCase());i.alias?"string"==typeof i.alias?i.alias=[i.alias,c]:i.alias.push(c):i.alias=[c]}}else e(o.content)}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,o=t.classes.length;r<o;r++){var a=t.classes[r],l=/language-(.+)/.exec(a);if(l){n=l[1];break}}var u,d=e.languages[n];if(d)t.content=e.highlight((u=t.content,u.replace(i,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;if("#"===(t=t.toLowerCase())[0])return n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),c(n);var r=s[t];return r||e}))),d,n);else if(n&&"none"!==n&&e.plugins.autoloader){var p="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random());t.attributes.id=p,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(p);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))}))}}}));var i=RegExp(e.languages.markup.tag.pattern.source,"gi"),s={amp:"&",lt:"<",gt:">",quot:'"'},c=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(o),o.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:o.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},o.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var o=[];if(d(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var a=p(/^\($/,/^\)$/);if(-1===a)continue;for(;n<a;n++){var i=u(0);"variable"===i.type&&(f(i,"variable-input"),o.push(i.content))}n=a+1}if(d(["punctuation","property-query"])&&"{"===u(0).content&&(n++,f(u(0),"property-mutation"),o.length>0)){var s=p(/^\{$/,/^\}$/);if(-1===s)continue;for(var c=n;c<s;c++){var l=t[c];"variable"===l.type&&o.indexOf(l.content)>=0&&f(l,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=u(n+t);if(!r||r.type!==e[n])return!1}return!0}function p(e,r){for(var o=1,a=n;a<t.length;a++){var i=t[a],s=i.content;if("punctuation"===i.type&&"string"==typeof s)if(e.test(s))o++;else if(r.test(s)&&0===--o)return a}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),o.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,o=r.inside["interpolation-punctuation"],a=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function s(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function c(t,n,r){var o={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",o),o.tokens=e.tokenize(o.code,o.grammar),e.hooks.run("after-tokenize",o),o.tokens}function l(t){var n={};n["interpolation-punctuation"]=o;var a=e.tokenize(t,n);if(3===a.length){var i=[1,1];i.push.apply(i,c(a[1],e.languages.javascript,"javascript")),a.splice.apply(a,i)}return new e.Token("interpolation",a,r.alias,t)}function u(t,n,r){var o=e.tokenize(t,{interpolation:{pattern:RegExp(a),lookbehind:!0}}),i=0,u={},d=c(o.map((function(e){if("string"==typeof e)return e;for(var n,o=e.content;-1!==t.indexOf(n=s(i++,r)););return u[n]=o,n})).join(""),n,r),p=Object.keys(u);return i=0,function e(t){for(var n=0;n<t.length;n++){if(i>=p.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var o=p[i],a="string"==typeof r?r:r.content,s=a.indexOf(o);if(-1!==s){++i;var c=a.substring(0,s),d=l(u[o]),f=a.substring(s+o.length),h=[];if(c&&h.push(c),h.push(d),f){var m=[f];e(m),h.push.apply(h,m)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(h)),n+=h.length-1):r.content=h}}else{var g=r.content;Array.isArray(g)?e(g):e([g])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(p).join(""):p(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,o=n.length;r<o;r++){var a=n[r];if("string"!=typeof a){var i=a.content;if(Array.isArray(i))if("template-string"===a.type){var s=i[1];if(3===i.length&&"string"!=typeof s&&"embedded-code"===s.type){var c=p(s),l=s.alias,d=Array.isArray(l)?l[0]:l,f=e.languages[d];if(!f)continue;i[1]=u(c,f,d)}}else t(i);else"string"!=typeof i&&t([i])}}}(t.tokens)}))}(o),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(o),function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var o=n[r],a=e.languages.javascript[o];"RegExp"===e.util.type(a)&&(a=e.languages.javascript[o]={pattern:a});var i=a.inside||{};a.inside=i,i["maybe-class-name"]=/^[A-Z][\s\S]*/}}(o),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,o=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function a(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/g,(function(){return o})),RegExp(e,t)}o=a(o).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=a(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:a(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:a(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var i=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(i).join(""):""},s=function(t){for(var n=[],r=0;r<t.length;r++){var o=t[r],a=!1;if("string"!=typeof o&&("tag"===o.type&&o.content[0]&&"tag"===o.content[0].type?"</"===o.content[0].content[0].content?n.length>0&&n[n.length-1].tagName===i(o.content[0].content[1])&&n.pop():"/>"===o.content[o.content.length-1].content||n.push({tagName:i(o.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===o.type&&"{"===o.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===o.type&&"}"===o.content?n[n.length-1].openedBraces--:a=!0),(a||"string"==typeof o)&&n.length>0&&0===n[n.length-1].openedBraces){var c=i(o);r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(c+=i(t[r+1]),t.splice(r+1,1)),r>0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(c=i(t[r-1])+c,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",c,null,c)}o.content&&"string"!=typeof o.content&&s(o.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||s(e.tokens)}))}(o),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],o=[];/^\w+$/.test(n)||o.push(/\w+/.exec(n)[0]),"diff"===n&&o.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:o,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(o),o.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},o.languages.go=o.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),o.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete o.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,o,a){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(o,(function(e){if("function"==typeof a&&!a(e))return e;for(var o,s=i.length;-1!==n.code.indexOf(o=t(r,s));)++s;return i[s]=e,o})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var o=0,a=Object.keys(n.tokenStack);!function i(s){for(var c=0;c<s.length&&!(o>=a.length);c++){var l=s[c];if("string"==typeof l||l.content&&"string"==typeof l.content){var u=a[o],d=n.tokenStack[u],p="string"==typeof l?l:l.content,f=t(r,u),h=p.indexOf(f);if(h>-1){++o;var m=p.substring(0,h),g=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=p.substring(h+f.length),v=[];m&&v.push.apply(v,i([m])),v.push(g),b&&v.push.apply(v,i([b])),"string"==typeof l?s.splice.apply(s,[c,1].concat(v)):l.content=v}}else l.content&&i(l.content)}return s}(n.tokens)}}}})}(o),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(o),o.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},o.languages.webmanifest=o.languages.json,o.languages.less=o.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),o.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),o.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},o.languages.objectivec=o.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete o.languages.objectivec["class-name"],o.languages.objc=o.languages.objectivec,o.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},o.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},o.languages.python["string-interpolation"].inside.interpolation.inside.rest=o.languages.python,o.languages.py=o.languages.python,o.languages.reason=o.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),o.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete o.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(o),o.languages.scss=o.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),o.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),o.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),o.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),o.languages.scss.atrule.inside.rest=o.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(o),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(o),o.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const a=o},9016:()=>{!function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,(function(e,n){return"(?:"+t[+n]+")"}))}function n(e,n,r){return RegExp(t(e,n),r||"")}function r(e,t){for(var n=0;n<t;n++)e=e.replace(/<<self>>/g,(function(){return"(?:"+e+")"}));return e.replace(/<<self>>/g,"[^\\s\\S]")}var o="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",a="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",s="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function c(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var l=c(a),u=RegExp(c(o+" "+a+" "+i+" "+s)),d=c(a+" "+i+" "+s),p=c(o+" "+a+" "+s),f=r(/<(?:[^<>;=+\-*/%&|^]|<<self>>)*>/.source,2),h=r(/\((?:[^()]|<<self>>)*\)/.source,2),m=/@?\b[A-Za-z_]\w*\b/.source,g=t(/<<0>>(?:\s*<<1>>)?/.source,[m,f]),b=t(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[d,g]),v=/\[\s*(?:,\s*)*\]/.source,y=t(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[b,v]),k=t(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[f,h,v]),E=t(/\(<<0>>+(?:,<<0>>+)+\)/.source,[k]),w=t(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[E,b,v]),x={keyword:u,punctuation:/[<>()?,.:[\]]/},S=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,_=/"(?:\\.|[^\\"\r\n])*"/.source,T=/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source;e.languages.csharp=e.languages.extend("clike",{string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[T]),lookbehind:!0,greedy:!0},{pattern:n(/(^|[^@$\\])<<0>>/.source,[_]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:n(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[b]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[m,w]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+)<<0>>(?=\s*=)/.source,[m]),lookbehind:!0},{pattern:n(/(\b<<0>>\s+)<<1>>/.source,[l,g]),lookbehind:!0,inside:x},{pattern:n(/(\bcatch\s*\(\s*)<<0>>/.source,[b]),lookbehind:!0,inside:x},{pattern:n(/(\bwhere\s+)<<0>>/.source,[m]),lookbehind:!0},{pattern:n(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[y]),lookbehind:!0,inside:x},{pattern:n(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[w,p,m]),inside:x}],keyword:u,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:n(/([(,]\s*)<<0>>(?=\s*:)/.source,[m]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:n(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[m]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:n(/(\b(?:default|sizeof|typeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[h]),lookbehind:!0,alias:"class-name",inside:x},"return-type":{pattern:n(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[w,b]),inside:x,alias:"class-name"},"constructor-invocation":{pattern:n(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[w]),lookbehind:!0,inside:x,alias:"class-name"},"generic-method":{pattern:n(/<<0>>\s*<<1>>(?=\s*\()/.source,[m,f]),inside:{function:n(/^<<0>>/.source,[m]),generic:{pattern:RegExp(f),alias:"class-name",inside:x}}},"type-list":{pattern:n(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[l,g,m,w,u.source,h,/\bnew\s*\(\s*\)/.source]),lookbehind:!0,inside:{"record-arguments":{pattern:n(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source,[g,h]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:u,"class-name":{pattern:RegExp(w),greedy:!0,inside:x},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var C=_+"|"+S,L=t(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[C]),N=r(t(/[^"'/()]|<<0>>|\(<<self>>*\)/.source,[L]),2),I=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,O=t(/<<0>>(?:\s*\(<<1>>*\))?/.source,[b,N]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:n(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[I,O]),lookbehind:!0,greedy:!0,inside:{target:{pattern:n(/^<<0>>(?=\s*:)/.source,[I]),alias:"keyword"},"attribute-arguments":{pattern:n(/\(<<0>>*\)/.source,[N]),inside:e.languages.csharp},"class-name":{pattern:RegExp(b),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var A=/:[^}\r\n]+/.source,R=r(t(/[^"'/()]|<<0>>|\(<<self>>*\)/.source,[L]),2),P=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[R,A]),D=r(t(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<<self>>*\)/.source,[C]),2),M=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[D,A]);function F(t,r){return{interpolation:{pattern:n(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{"format-string":{pattern:n(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[r,A]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:n(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[P]),lookbehind:!0,greedy:!0,inside:F(P,R)},{pattern:n(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[M]),lookbehind:!0,greedy:!0,inside:F(M,D)}],char:{pattern:RegExp(S),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(Prism)},6862:()=>{!function(e){var t=e.languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:null},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:false|true)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/};t.string[0].inside={function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:t},boolean:t.boolean,variable:t.variable}}(Prism)},5266:()=>{Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/}},4806:(e,t,n)=>{var r={"./prism-csharp":9016,"./prism-powershell":6862,"./prism-sql":5266};function o(e){var t=a(e);return n(t)}function a(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}o.keys=function(){return Object.keys(r)},o.resolve=a,e.exports=o,o.id=4806},2703:(e,t,n)=>{"use strict";var r=n(414);function o(){}function a(){}a.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,a,i){if(i!==r){var s=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw s.name="Invariant Violation",s}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:o};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),o=n(7418),a=n(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}if(!r)throw Error(i(227));var s=new Set,c={};function l(e,t){u(e,t),u(e+"Capture",t)}function u(e,t){for(c[e]=t,e=0;e<t.length;e++)s.add(t[e])}var d=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),p=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,f=Object.prototype.hasOwnProperty,h={},m={};function g(e,t,n,r,o,a,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=i}var b={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){b[e]=new g(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];b[t]=new g(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){b[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){b[e]=new g(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){b[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){b[e]=new g(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){b[e]=new g(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){b[e]=new g(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){b[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)}));var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}function k(e,t,n,r){var o=b.hasOwnProperty(t)?b[t]:null;(null!==o?0===o.type:!r&&(2<t.length&&("o"===t[0]||"O"===t[0])&&("n"===t[1]||"N"===t[1])))||(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,o,r)&&(n=null),r||null===o?function(e){return!!f.call(m,e)||!f.call(h,e)&&(p.test(e)?m[e]=!0:(h[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):o.mustUseProperty?e[o.propertyName]=null===n?3!==o.type&&"":n:(t=o.attributeName,r=o.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(o=o.type)||4===o&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){b[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)})),b.xlinkHref=new g("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){b[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)}));var E=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,w=60103,x=60106,S=60107,_=60108,T=60114,C=60109,L=60110,N=60112,I=60113,O=60120,A=60115,R=60116,P=60121,D=60128,M=60129,F=60130,z=60131;if("function"==typeof Symbol&&Symbol.for){var B=Symbol.for;w=B("react.element"),x=B("react.portal"),S=B("react.fragment"),_=B("react.strict_mode"),T=B("react.profiler"),C=B("react.provider"),L=B("react.context"),N=B("react.forward_ref"),I=B("react.suspense"),O=B("react.suspense_list"),A=B("react.memo"),R=B("react.lazy"),P=B("react.block"),B("react.scope"),D=B("react.opaque.id"),M=B("react.debug_trace_mode"),F=B("react.offscreen"),z=B("react.legacy_hidden")}var U,j="function"==typeof Symbol&&Symbol.iterator;function $(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=j&&e[j]||e["@@iterator"])?e:null}function H(e){if(void 0===U)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);U=t&&t[1]||""}return"\n"+U+e}var Z=!1;function V(e,t){if(!e||Z)return"";Z=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(c){var r=c}Reflect.construct(e,[],t)}else{try{t.call()}catch(c){r=c}e.call(t.prototype)}else{try{throw Error()}catch(c){r=c}e()}}catch(c){if(c&&r&&"string"==typeof c.stack){for(var o=c.stack.split("\n"),a=r.stack.split("\n"),i=o.length-1,s=a.length-1;1<=i&&0<=s&&o[i]!==a[s];)s--;for(;1<=i&&0<=s;i--,s--)if(o[i]!==a[s]){if(1!==i||1!==s)do{if(i--,0>--s||o[i]!==a[s])return"\n"+o[i].replace(" at new "," at ")}while(1<=i&&0<=s);break}}}finally{Z=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?H(e):""}function Q(e){switch(e.tag){case 5:return H(e.type);case 16:return H("Lazy");case 13:return H("Suspense");case 19:return H("SuspenseList");case 0:case 2:case 15:return e=V(e.type,!1);case 11:return e=V(e.type.render,!1);case 22:return e=V(e.type._render,!1);case 1:return e=V(e.type,!0);default:return""}}function W(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case S:return"Fragment";case x:return"Portal";case T:return"Profiler";case _:return"StrictMode";case I:return"Suspense";case O:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case L:return(e.displayName||"Context")+".Consumer";case C:return(e._context.displayName||"Context")+".Provider";case N:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(""!==t?"ForwardRef("+t+")":"ForwardRef");case A:return W(e.type);case P:return W(e._render);case R:t=e._payload,e=e._init;try{return W(e(t))}catch(n){}}return null}function G(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function q(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function Y(e){e._valueTracker||(e._valueTracker=function(e){var t=q(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var o=n.get,a=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(e){r=""+e,a.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function K(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=q(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function X(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function J(e,t){var n=t.checked;return o({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function ee(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=G(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function te(e,t){null!=(t=t.checked)&&k(e,"checked",t,!1)}function ne(e,t){te(e,t);var n=G(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?oe(e,t.type,n):t.hasOwnProperty("defaultValue")&&oe(e,t.type,G(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function re(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function oe(e,t,n){"number"===t&&X(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}function ae(e,t){return e=o({children:void 0},t),(t=function(e){var t="";return r.Children.forEach(e,(function(e){null!=e&&(t+=e)})),t}(t.children))&&(e.children=t),e}function ie(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o<n.length;o++)t["$"+n[o]]=!0;for(n=0;n<e.length;n++)o=t.hasOwnProperty("$"+e[n].value),e[n].selected!==o&&(e[n].selected=o),o&&r&&(e[n].defaultSelected=!0)}else{for(n=""+G(n),t=null,o=0;o<e.length;o++){if(e[o].value===n)return e[o].selected=!0,void(r&&(e[o].defaultSelected=!0));null!==t||e[o].disabled||(t=e[o])}null!==t&&(t.selected=!0)}}function se(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(i(91));return o({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function ce(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(i(92));if(Array.isArray(n)){if(!(1>=n.length))throw Error(i(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:G(n)}}function le(e,t){var n=G(t.value),r=G(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function ue(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}var de="http://www.w3.org/1999/xhtml",pe="http://www.w3.org/2000/svg";function fe(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function he(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?fe(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var me,ge,be=(ge=function(e,t){if(e.namespaceURI!==pe||"innerHTML"in e)e.innerHTML=t;else{for((me=me||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=me.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return ge(e,t)}))}:ge);function ve(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var ye={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},ke=["Webkit","ms","Moz","O"];function Ee(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||ye.hasOwnProperty(e)&&ye[e]?(""+t).trim():t+"px"}function we(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),o=Ee(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}Object.keys(ye).forEach((function(e){ke.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ye[t]=ye[e]}))}));var xe=o({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Se(e,t){if(t){if(xe[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(i(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(i(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(i(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(i(62))}}function _e(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}function Te(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var Ce=null,Le=null,Ne=null;function Ie(e){if(e=ro(e)){if("function"!=typeof Ce)throw Error(i(280));var t=e.stateNode;t&&(t=ao(t),Ce(e.stateNode,e.type,t))}}function Oe(e){Le?Ne?Ne.push(e):Ne=[e]:Le=e}function Ae(){if(Le){var e=Le,t=Ne;if(Ne=Le=null,Ie(e),t)for(e=0;e<t.length;e++)Ie(t[e])}}function Re(e,t){return e(t)}function Pe(e,t,n,r,o){return e(t,n,r,o)}function De(){}var Me=Re,Fe=!1,ze=!1;function Be(){null===Le&&null===Ne||(De(),Ae())}function Ue(e,t){var n=e.stateNode;if(null===n)return null;var r=ao(n);if(null===r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(i(231,t,typeof n));return n}var je=!1;if(d)try{var $e={};Object.defineProperty($e,"passive",{get:function(){je=!0}}),window.addEventListener("test",$e,$e),window.removeEventListener("test",$e,$e)}catch(ge){je=!1}function He(e,t,n,r,o,a,i,s,c){var l=Array.prototype.slice.call(arguments,3);try{t.apply(n,l)}catch(u){this.onError(u)}}var Ze=!1,Ve=null,Qe=!1,We=null,Ge={onError:function(e){Ze=!0,Ve=e}};function qe(e,t,n,r,o,a,i,s,c){Ze=!1,Ve=null,He.apply(Ge,arguments)}function Ye(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{0!=(1026&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function Ke(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function Xe(e){if(Ye(e)!==e)throw Error(i(188))}function Je(e){if(e=function(e){var t=e.alternate;if(!t){if(null===(t=Ye(e)))throw Error(i(188));return t!==e?null:e}for(var n=e,r=t;;){var o=n.return;if(null===o)break;var a=o.alternate;if(null===a){if(null!==(r=o.return)){n=r;continue}break}if(o.child===a.child){for(a=o.child;a;){if(a===n)return Xe(o),e;if(a===r)return Xe(o),t;a=a.sibling}throw Error(i(188))}if(n.return!==r.return)n=o,r=a;else{for(var s=!1,c=o.child;c;){if(c===n){s=!0,n=o,r=a;break}if(c===r){s=!0,r=o,n=a;break}c=c.sibling}if(!s){for(c=a.child;c;){if(c===n){s=!0,n=a,r=o;break}if(c===r){s=!0,r=a,n=o;break}c=c.sibling}if(!s)throw Error(i(189))}}if(n.alternate!==r)throw Error(i(190))}if(3!==n.tag)throw Error(i(188));return n.stateNode.current===n?e:t}(e),!e)return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}function et(e,t){for(var n=e.alternate;null!==t;){if(t===e||t===n)return!0;t=t.return}return!1}var tt,nt,rt,ot,at=!1,it=[],st=null,ct=null,lt=null,ut=new Map,dt=new Map,pt=[],ft="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function ht(e,t,n,r,o){return{blockedOn:e,domEventName:t,eventSystemFlags:16|n,nativeEvent:o,targetContainers:[r]}}function mt(e,t){switch(e){case"focusin":case"focusout":st=null;break;case"dragenter":case"dragleave":ct=null;break;case"mouseover":case"mouseout":lt=null;break;case"pointerover":case"pointerout":ut.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":dt.delete(t.pointerId)}}function gt(e,t,n,r,o,a){return null===e||e.nativeEvent!==a?(e=ht(t,n,r,o,a),null!==t&&(null!==(t=ro(t))&&nt(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,null!==o&&-1===t.indexOf(o)&&t.push(o),e)}function bt(e){var t=no(e.target);if(null!==t){var n=Ye(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=Ke(n)))return e.blockedOn=t,void ot(e.lanePriority,(function(){a.unstable_runWithPriority(e.priority,(function(){rt(n)}))}))}else if(3===t&&n.stateNode.hydrate)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function vt(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Jt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=ro(n))&&nt(t),e.blockedOn=n,!1;t.shift()}return!0}function yt(e,t,n){vt(e)&&n.delete(t)}function kt(){for(at=!1;0<it.length;){var e=it[0];if(null!==e.blockedOn){null!==(e=ro(e.blockedOn))&&tt(e);break}for(var t=e.targetContainers;0<t.length;){var n=Jt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n){e.blockedOn=n;break}t.shift()}null===e.blockedOn&&it.shift()}null!==st&&vt(st)&&(st=null),null!==ct&&vt(ct)&&(ct=null),null!==lt&&vt(lt)&&(lt=null),ut.forEach(yt),dt.forEach(yt)}function Et(e,t){e.blockedOn===t&&(e.blockedOn=null,at||(at=!0,a.unstable_scheduleCallback(a.unstable_NormalPriority,kt)))}function wt(e){function t(t){return Et(t,e)}if(0<it.length){Et(it[0],e);for(var n=1;n<it.length;n++){var r=it[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==st&&Et(st,e),null!==ct&&Et(ct,e),null!==lt&&Et(lt,e),ut.forEach(t),dt.forEach(t),n=0;n<pt.length;n++)(r=pt[n]).blockedOn===e&&(r.blockedOn=null);for(;0<pt.length&&null===(n=pt[0]).blockedOn;)bt(n),null===n.blockedOn&&pt.shift()}function xt(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var St={animationend:xt("Animation","AnimationEnd"),animationiteration:xt("Animation","AnimationIteration"),animationstart:xt("Animation","AnimationStart"),transitionend:xt("Transition","TransitionEnd")},_t={},Tt={};function Ct(e){if(_t[e])return _t[e];if(!St[e])return e;var t,n=St[e];for(t in n)if(n.hasOwnProperty(t)&&t in Tt)return _t[e]=n[t];return e}d&&(Tt=document.createElement("div").style,"AnimationEvent"in window||(delete St.animationend.animation,delete St.animationiteration.animation,delete St.animationstart.animation),"TransitionEvent"in window||delete St.transitionend.transition);var Lt=Ct("animationend"),Nt=Ct("animationiteration"),It=Ct("animationstart"),Ot=Ct("transitionend"),At=new Map,Rt=new Map,Pt=["abort","abort",Lt,"animationEnd",Nt,"animationIteration",It,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata","loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",Ot,"transitionEnd","waiting","waiting"];function Dt(e,t){for(var n=0;n<e.length;n+=2){var r=e[n],o=e[n+1];o="on"+(o[0].toUpperCase()+o.slice(1)),Rt.set(r,t),At.set(r,o),l(o,[r])}}(0,a.unstable_now)();var Mt=8;function Ft(e){if(0!=(1&e))return Mt=15,1;if(0!=(2&e))return Mt=14,2;if(0!=(4&e))return Mt=13,4;var t=24&e;return 0!==t?(Mt=12,t):0!=(32&e)?(Mt=11,32):0!==(t=192&e)?(Mt=10,t):0!=(256&e)?(Mt=9,256):0!==(t=3584&e)?(Mt=8,t):0!=(4096&e)?(Mt=7,4096):0!==(t=4186112&e)?(Mt=6,t):0!==(t=62914560&e)?(Mt=5,t):67108864&e?(Mt=4,67108864):0!=(134217728&e)?(Mt=3,134217728):0!==(t=805306368&e)?(Mt=2,t):0!=(1073741824&e)?(Mt=1,1073741824):(Mt=8,e)}function zt(e,t){var n=e.pendingLanes;if(0===n)return Mt=0;var r=0,o=0,a=e.expiredLanes,i=e.suspendedLanes,s=e.pingedLanes;if(0!==a)r=a,o=Mt=15;else if(0!==(a=134217727&n)){var c=a&~i;0!==c?(r=Ft(c),o=Mt):0!==(s&=a)&&(r=Ft(s),o=Mt)}else 0!==(a=n&~i)?(r=Ft(a),o=Mt):0!==s&&(r=Ft(s),o=Mt);if(0===r)return 0;if(r=n&((0>(r=31-Zt(r))?0:1<<r)<<1)-1,0!==t&&t!==r&&0==(t&i)){if(Ft(t),o<=Mt)return t;Mt=o}if(0!==(t=e.entangledLanes))for(e=e.entanglements,t&=r;0<t;)o=1<<(n=31-Zt(t)),r|=e[n],t&=~o;return r}function Bt(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function Ut(e,t){switch(e){case 15:return 1;case 14:return 2;case 12:return 0===(e=jt(24&~t))?Ut(10,t):e;case 10:return 0===(e=jt(192&~t))?Ut(8,t):e;case 8:return 0===(e=jt(3584&~t))&&(0===(e=jt(4186112&~t))&&(e=512)),e;case 2:return 0===(t=jt(805306368&~t))&&(t=268435456),t}throw Error(i(358,e))}function jt(e){return e&-e}function $t(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Ht(e,t,n){e.pendingLanes|=t;var r=t-1;e.suspendedLanes&=r,e.pingedLanes&=r,(e=e.eventTimes)[t=31-Zt(t)]=n}var Zt=Math.clz32?Math.clz32:function(e){return 0===e?32:31-(Vt(e)/Qt|0)|0},Vt=Math.log,Qt=Math.LN2;var Wt=a.unstable_UserBlockingPriority,Gt=a.unstable_runWithPriority,qt=!0;function Yt(e,t,n,r){Fe||De();var o=Xt,a=Fe;Fe=!0;try{Pe(o,e,t,n,r)}finally{(Fe=a)||Be()}}function Kt(e,t,n,r){Gt(Wt,Xt.bind(null,e,t,n,r))}function Xt(e,t,n,r){var o;if(qt)if((o=0==(4&t))&&0<it.length&&-1<ft.indexOf(e))e=ht(null,e,t,n,r),it.push(e);else{var a=Jt(e,t,n,r);if(null===a)o&&mt(e,r);else{if(o){if(-1<ft.indexOf(e))return e=ht(a,e,t,n,r),void it.push(e);if(function(e,t,n,r,o){switch(t){case"focusin":return st=gt(st,e,t,n,r,o),!0;case"dragenter":return ct=gt(ct,e,t,n,r,o),!0;case"mouseover":return lt=gt(lt,e,t,n,r,o),!0;case"pointerover":var a=o.pointerId;return ut.set(a,gt(ut.get(a)||null,e,t,n,r,o)),!0;case"gotpointercapture":return a=o.pointerId,dt.set(a,gt(dt.get(a)||null,e,t,n,r,o)),!0}return!1}(a,e,t,n,r))return;mt(e,r)}Dr(e,t,r,null,n)}}}function Jt(e,t,n,r){var o=Te(r);if(null!==(o=no(o))){var a=Ye(o);if(null===a)o=null;else{var i=a.tag;if(13===i){if(null!==(o=Ke(a)))return o;o=null}else if(3===i){if(a.stateNode.hydrate)return 3===a.tag?a.stateNode.containerInfo:null;o=null}else a!==o&&(o=null)}}return Dr(e,t,r,o,n),null}var en=null,tn=null,nn=null;function rn(){if(nn)return nn;var e,t,n=tn,r=n.length,o="value"in en?en.value:en.textContent,a=o.length;for(e=0;e<r&&n[e]===o[e];e++);var i=r-e;for(t=1;t<=i&&n[r-t]===o[a-t];t++);return nn=o.slice(e,1<t?1-t:void 0)}function on(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function an(){return!0}function sn(){return!1}function cn(e){function t(t,n,r,o,a){for(var i in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=o,this.target=a,this.currentTarget=null,e)e.hasOwnProperty(i)&&(t=e[i],this[i]=t?t(o):o[i]);return this.isDefaultPrevented=(null!=o.defaultPrevented?o.defaultPrevented:!1===o.returnValue)?an:sn,this.isPropagationStopped=sn,this}return o(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=an)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=an)},persist:function(){},isPersistent:an}),t}var ln,un,dn,pn={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},fn=cn(pn),hn=o({},pn,{view:0,detail:0}),mn=cn(hn),gn=o({},hn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Ln,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==dn&&(dn&&"mousemove"===e.type?(ln=e.screenX-dn.screenX,un=e.screenY-dn.screenY):un=ln=0,dn=e),ln)},movementY:function(e){return"movementY"in e?e.movementY:un}}),bn=cn(gn),vn=cn(o({},gn,{dataTransfer:0})),yn=cn(o({},hn,{relatedTarget:0})),kn=cn(o({},pn,{animationName:0,elapsedTime:0,pseudoElement:0})),En=o({},pn,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),wn=cn(En),xn=cn(o({},pn,{data:0})),Sn={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},_n={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},Tn={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function Cn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=Tn[e])&&!!t[e]}function Ln(){return Cn}var Nn=o({},hn,{key:function(e){if(e.key){var t=Sn[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=on(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?_n[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:Ln,charCode:function(e){return"keypress"===e.type?on(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?on(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),In=cn(Nn),On=cn(o({},gn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),An=cn(o({},hn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:Ln})),Rn=cn(o({},pn,{propertyName:0,elapsedTime:0,pseudoElement:0})),Pn=o({},gn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),Dn=cn(Pn),Mn=[9,13,27,32],Fn=d&&"CompositionEvent"in window,zn=null;d&&"documentMode"in document&&(zn=document.documentMode);var Bn=d&&"TextEvent"in window&&!zn,Un=d&&(!Fn||zn&&8<zn&&11>=zn),jn=String.fromCharCode(32),$n=!1;function Hn(e,t){switch(e){case"keyup":return-1!==Mn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Zn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Vn=!1;var Qn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Wn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Qn[e.type]:"textarea"===t}function Gn(e,t,n,r){Oe(r),0<(t=Fr(t,"onChange")).length&&(n=new fn("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var qn=null,Yn=null;function Kn(e){Nr(e,0)}function Xn(e){if(K(oo(e)))return e}function Jn(e,t){if("change"===e)return t}var er=!1;if(d){var tr;if(d){var nr="oninput"in document;if(!nr){var rr=document.createElement("div");rr.setAttribute("oninput","return;"),nr="function"==typeof rr.oninput}tr=nr}else tr=!1;er=tr&&(!document.documentMode||9<document.documentMode)}function or(){qn&&(qn.detachEvent("onpropertychange",ar),Yn=qn=null)}function ar(e){if("value"===e.propertyName&&Xn(Yn)){var t=[];if(Gn(t,Yn,e,Te(e)),e=Kn,Fe)e(t);else{Fe=!0;try{Re(e,t)}finally{Fe=!1,Be()}}}}function ir(e,t,n){"focusin"===e?(or(),Yn=n,(qn=t).attachEvent("onpropertychange",ar)):"focusout"===e&&or()}function sr(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return Xn(Yn)}function cr(e,t){if("click"===e)return Xn(t)}function lr(e,t){if("input"===e||"change"===e)return Xn(t)}var ur="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},dr=Object.prototype.hasOwnProperty;function pr(e,t){if(ur(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++)if(!dr.call(t,n[r])||!ur(e[n[r]],t[n[r]]))return!1;return!0}function fr(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function hr(e,t){var n,r=fr(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=fr(r)}}function mr(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?mr(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function gr(){for(var e=window,t=X();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=X((e=t.contentWindow).document)}return t}function br(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var vr=d&&"documentMode"in document&&11>=document.documentMode,yr=null,kr=null,Er=null,wr=!1;function xr(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;wr||null==yr||yr!==X(r)||("selectionStart"in(r=yr)&&br(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},Er&&pr(Er,r)||(Er=r,0<(r=Fr(kr,"onSelect")).length&&(t=new fn("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=yr)))}Dt("cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focusin focus focusout blur input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),0),Dt("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1),Dt(Pt,2);for(var Sr="change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),_r=0;_r<Sr.length;_r++)Rt.set(Sr[_r],0);u("onMouseEnter",["mouseout","mouseover"]),u("onMouseLeave",["mouseout","mouseover"]),u("onPointerEnter",["pointerout","pointerover"]),u("onPointerLeave",["pointerout","pointerover"]),l("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),l("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),l("onBeforeInput",["compositionend","keypress","textInput","paste"]),l("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),l("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),l("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var Tr="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Cr=new Set("cancel close invalid load scroll toggle".split(" ").concat(Tr));function Lr(e,t,n){var r=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,r,o,a,s,c,l){if(qe.apply(this,arguments),Ze){if(!Ze)throw Error(i(198));var u=Ve;Ze=!1,Ve=null,Qe||(Qe=!0,We=u)}}(r,t,void 0,e),e.currentTarget=null}function Nr(e,t){t=0!=(4&t);for(var n=0;n<e.length;n++){var r=e[n],o=r.event;r=r.listeners;e:{var a=void 0;if(t)for(var i=r.length-1;0<=i;i--){var s=r[i],c=s.instance,l=s.currentTarget;if(s=s.listener,c!==a&&o.isPropagationStopped())break e;Lr(o,s,l),a=c}else for(i=0;i<r.length;i++){if(c=(s=r[i]).instance,l=s.currentTarget,s=s.listener,c!==a&&o.isPropagationStopped())break e;Lr(o,s,l),a=c}}}if(Qe)throw e=We,Qe=!1,We=null,e}function Ir(e,t){var n=io(t),r=e+"__bubble";n.has(r)||(Pr(t,e,2,!1),n.add(r))}var Or="_reactListening"+Math.random().toString(36).slice(2);function Ar(e){e[Or]||(e[Or]=!0,s.forEach((function(t){Cr.has(t)||Rr(t,!1,e,null),Rr(t,!0,e,null)})))}function Rr(e,t,n,r){var o=4<arguments.length&&void 0!==arguments[4]?arguments[4]:0,a=n;if("selectionchange"===e&&9!==n.nodeType&&(a=n.ownerDocument),null!==r&&!t&&Cr.has(e)){if("scroll"!==e)return;o|=2,a=r}var i=io(a),s=e+"__"+(t?"capture":"bubble");i.has(s)||(t&&(o|=4),Pr(a,e,o,t),i.add(s))}function Pr(e,t,n,r){var o=Rt.get(t);switch(void 0===o?2:o){case 0:o=Yt;break;case 1:o=Kt;break;default:o=Xt}n=o.bind(null,t,n,e),o=void 0,!je||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(o=!0),r?void 0!==o?e.addEventListener(t,n,{capture:!0,passive:o}):e.addEventListener(t,n,!0):void 0!==o?e.addEventListener(t,n,{passive:o}):e.addEventListener(t,n,!1)}function Dr(e,t,n,r,o){var a=r;if(0==(1&t)&&0==(2&t)&&null!==r)e:for(;;){if(null===r)return;var i=r.tag;if(3===i||4===i){var s=r.stateNode.containerInfo;if(s===o||8===s.nodeType&&s.parentNode===o)break;if(4===i)for(i=r.return;null!==i;){var c=i.tag;if((3===c||4===c)&&((c=i.stateNode.containerInfo)===o||8===c.nodeType&&c.parentNode===o))return;i=i.return}for(;null!==s;){if(null===(i=no(s)))return;if(5===(c=i.tag)||6===c){r=a=i;continue e}s=s.parentNode}}r=r.return}!function(e,t,n){if(ze)return e(t,n);ze=!0;try{Me(e,t,n)}finally{ze=!1,Be()}}((function(){var r=a,o=Te(n),i=[];e:{var s=At.get(e);if(void 0!==s){var c=fn,l=e;switch(e){case"keypress":if(0===on(n))break e;case"keydown":case"keyup":c=In;break;case"focusin":l="focus",c=yn;break;case"focusout":l="blur",c=yn;break;case"beforeblur":case"afterblur":c=yn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":c=bn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":c=vn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":c=An;break;case Lt:case Nt:case It:c=kn;break;case Ot:c=Rn;break;case"scroll":c=mn;break;case"wheel":c=Dn;break;case"copy":case"cut":case"paste":c=wn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":c=On}var u=0!=(4&t),d=!u&&"scroll"===e,p=u?null!==s?s+"Capture":null:s;u=[];for(var f,h=r;null!==h;){var m=(f=h).stateNode;if(5===f.tag&&null!==m&&(f=m,null!==p&&(null!=(m=Ue(h,p))&&u.push(Mr(h,m,f)))),d)break;h=h.return}0<u.length&&(s=new c(s,l,null,n,o),i.push({event:s,listeners:u}))}}if(0==(7&t)){if(c="mouseout"===e||"pointerout"===e,(!(s="mouseover"===e||"pointerover"===e)||0!=(16&t)||!(l=n.relatedTarget||n.fromElement)||!no(l)&&!l[eo])&&(c||s)&&(s=o.window===o?o:(s=o.ownerDocument)?s.defaultView||s.parentWindow:window,c?(c=r,null!==(l=(l=n.relatedTarget||n.toElement)?no(l):null)&&(l!==(d=Ye(l))||5!==l.tag&&6!==l.tag)&&(l=null)):(c=null,l=r),c!==l)){if(u=bn,m="onMouseLeave",p="onMouseEnter",h="mouse","pointerout"!==e&&"pointerover"!==e||(u=On,m="onPointerLeave",p="onPointerEnter",h="pointer"),d=null==c?s:oo(c),f=null==l?s:oo(l),(s=new u(m,h+"leave",c,n,o)).target=d,s.relatedTarget=f,m=null,no(o)===r&&((u=new u(p,h+"enter",l,n,o)).target=f,u.relatedTarget=d,m=u),d=m,c&&l)e:{for(p=l,h=0,f=u=c;f;f=zr(f))h++;for(f=0,m=p;m;m=zr(m))f++;for(;0<h-f;)u=zr(u),h--;for(;0<f-h;)p=zr(p),f--;for(;h--;){if(u===p||null!==p&&u===p.alternate)break e;u=zr(u),p=zr(p)}u=null}else u=null;null!==c&&Br(i,s,c,u,!1),null!==l&&null!==d&&Br(i,d,l,u,!0)}if("select"===(c=(s=r?oo(r):window).nodeName&&s.nodeName.toLowerCase())||"input"===c&&"file"===s.type)var g=Jn;else if(Wn(s))if(er)g=lr;else{g=sr;var b=ir}else(c=s.nodeName)&&"input"===c.toLowerCase()&&("checkbox"===s.type||"radio"===s.type)&&(g=cr);switch(g&&(g=g(e,r))?Gn(i,g,n,o):(b&&b(e,s,r),"focusout"===e&&(b=s._wrapperState)&&b.controlled&&"number"===s.type&&oe(s,"number",s.value)),b=r?oo(r):window,e){case"focusin":(Wn(b)||"true"===b.contentEditable)&&(yr=b,kr=r,Er=null);break;case"focusout":Er=kr=yr=null;break;case"mousedown":wr=!0;break;case"contextmenu":case"mouseup":case"dragend":wr=!1,xr(i,n,o);break;case"selectionchange":if(vr)break;case"keydown":case"keyup":xr(i,n,o)}var v;if(Fn)e:{switch(e){case"compositionstart":var y="onCompositionStart";break e;case"compositionend":y="onCompositionEnd";break e;case"compositionupdate":y="onCompositionUpdate";break e}y=void 0}else Vn?Hn(e,n)&&(y="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(y="onCompositionStart");y&&(Un&&"ko"!==n.locale&&(Vn||"onCompositionStart"!==y?"onCompositionEnd"===y&&Vn&&(v=rn()):(tn="value"in(en=o)?en.value:en.textContent,Vn=!0)),0<(b=Fr(r,y)).length&&(y=new xn(y,e,null,n,o),i.push({event:y,listeners:b}),v?y.data=v:null!==(v=Zn(n))&&(y.data=v))),(v=Bn?function(e,t){switch(e){case"compositionend":return Zn(t);case"keypress":return 32!==t.which?null:($n=!0,jn);case"textInput":return(e=t.data)===jn&&$n?null:e;default:return null}}(e,n):function(e,t){if(Vn)return"compositionend"===e||!Fn&&Hn(e,t)?(e=rn(),nn=tn=en=null,Vn=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return Un&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(r=Fr(r,"onBeforeInput")).length&&(o=new xn("onBeforeInput","beforeinput",null,n,o),i.push({event:o,listeners:r}),o.data=v))}Nr(i,t)}))}function Mr(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Fr(e,t){for(var n=t+"Capture",r=[];null!==e;){var o=e,a=o.stateNode;5===o.tag&&null!==a&&(o=a,null!=(a=Ue(e,n))&&r.unshift(Mr(e,a,o)),null!=(a=Ue(e,t))&&r.push(Mr(e,a,o))),e=e.return}return r}function zr(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Br(e,t,n,r,o){for(var a=t._reactName,i=[];null!==n&&n!==r;){var s=n,c=s.alternate,l=s.stateNode;if(null!==c&&c===r)break;5===s.tag&&null!==l&&(s=l,o?null!=(c=Ue(n,a))&&i.unshift(Mr(n,c,s)):o||null!=(c=Ue(n,a))&&i.push(Mr(n,c,s))),n=n.return}0!==i.length&&e.push({event:t,listeners:i})}function Ur(){}var jr=null,$r=null;function Hr(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function Zr(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var Vr="function"==typeof setTimeout?setTimeout:void 0,Qr="function"==typeof clearTimeout?clearTimeout:void 0;function Wr(e){1===e.nodeType?e.textContent="":9===e.nodeType&&(null!=(e=e.body)&&(e.textContent=""))}function Gr(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function qr(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var Yr=0;var Kr=Math.random().toString(36).slice(2),Xr="__reactFiber$"+Kr,Jr="__reactProps$"+Kr,eo="__reactContainer$"+Kr,to="__reactEvents$"+Kr;function no(e){var t=e[Xr];if(t)return t;for(var n=e.parentNode;n;){if(t=n[eo]||n[Xr]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=qr(e);null!==e;){if(n=e[Xr])return n;e=qr(e)}return t}n=(e=n).parentNode}return null}function ro(e){return!(e=e[Xr]||e[eo])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function oo(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(i(33))}function ao(e){return e[Jr]||null}function io(e){var t=e[to];return void 0===t&&(t=e[to]=new Set),t}var so=[],co=-1;function lo(e){return{current:e}}function uo(e){0>co||(e.current=so[co],so[co]=null,co--)}function po(e,t){co++,so[co]=e.current,e.current=t}var fo={},ho=lo(fo),mo=lo(!1),go=fo;function bo(e,t){var n=e.type.contextTypes;if(!n)return fo;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o,a={};for(o in n)a[o]=t[o];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=a),a}function vo(e){return null!=(e=e.childContextTypes)}function yo(){uo(mo),uo(ho)}function ko(e,t,n){if(ho.current!==fo)throw Error(i(168));po(ho,t),po(mo,n)}function Eo(e,t,n){var r=e.stateNode;if(e=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var a in r=r.getChildContext())if(!(a in e))throw Error(i(108,W(t)||"Unknown",a));return o({},n,r)}function wo(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||fo,go=ho.current,po(ho,e),po(mo,mo.current),!0}function xo(e,t,n){var r=e.stateNode;if(!r)throw Error(i(169));n?(e=Eo(e,t,go),r.__reactInternalMemoizedMergedChildContext=e,uo(mo),uo(ho),po(ho,e)):uo(mo),po(mo,n)}var So=null,_o=null,To=a.unstable_runWithPriority,Co=a.unstable_scheduleCallback,Lo=a.unstable_cancelCallback,No=a.unstable_shouldYield,Io=a.unstable_requestPaint,Oo=a.unstable_now,Ao=a.unstable_getCurrentPriorityLevel,Ro=a.unstable_ImmediatePriority,Po=a.unstable_UserBlockingPriority,Do=a.unstable_NormalPriority,Mo=a.unstable_LowPriority,Fo=a.unstable_IdlePriority,zo={},Bo=void 0!==Io?Io:function(){},Uo=null,jo=null,$o=!1,Ho=Oo(),Zo=1e4>Ho?Oo:function(){return Oo()-Ho};function Vo(){switch(Ao()){case Ro:return 99;case Po:return 98;case Do:return 97;case Mo:return 96;case Fo:return 95;default:throw Error(i(332))}}function Qo(e){switch(e){case 99:return Ro;case 98:return Po;case 97:return Do;case 96:return Mo;case 95:return Fo;default:throw Error(i(332))}}function Wo(e,t){return e=Qo(e),To(e,t)}function Go(e,t,n){return e=Qo(e),Co(e,t,n)}function qo(){if(null!==jo){var e=jo;jo=null,Lo(e)}Yo()}function Yo(){if(!$o&&null!==Uo){$o=!0;var e=0;try{var t=Uo;Wo(99,(function(){for(;e<t.length;e++){var n=t[e];do{n=n(!0)}while(null!==n)}})),Uo=null}catch(n){throw null!==Uo&&(Uo=Uo.slice(e+1)),Co(Ro,qo),n}finally{$o=!1}}}var Ko=E.ReactCurrentBatchConfig;function Xo(e,t){if(e&&e.defaultProps){for(var n in t=o({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}var Jo=lo(null),ea=null,ta=null,na=null;function ra(){na=ta=ea=null}function oa(e){var t=Jo.current;uo(Jo),e.type._context._currentValue=t}function aa(e,t){for(;null!==e;){var n=e.alternate;if((e.childLanes&t)===t){if(null===n||(n.childLanes&t)===t)break;n.childLanes|=t}else e.childLanes|=t,null!==n&&(n.childLanes|=t);e=e.return}}function ia(e,t){ea=e,na=ta=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(0!=(e.lanes&t)&&(Fi=!0),e.firstContext=null)}function sa(e,t){if(na!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741823!==t||(na=e,t=1073741823),t={context:e,observedBits:t,next:null},null===ta){if(null===ea)throw Error(i(308));ta=t,ea.dependencies={lanes:0,firstContext:t,responders:null}}else ta=ta.next=t;return e._currentValue}var ca=!1;function la(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null},effects:null}}function ua(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function da(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function pa(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}}function fa(e,t){var n=e.updateQueue,r=e.alternate;if(null!==r&&n===(r=r.updateQueue)){var o=null,a=null;if(null!==(n=n.firstBaseUpdate)){do{var i={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===a?o=a=i:a=a.next=i,n=n.next}while(null!==n);null===a?o=a=t:a=a.next=t}else o=a=t;return n={baseState:r.baseState,firstBaseUpdate:o,lastBaseUpdate:a,shared:r.shared,effects:r.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function ha(e,t,n,r){var a=e.updateQueue;ca=!1;var i=a.firstBaseUpdate,s=a.lastBaseUpdate,c=a.shared.pending;if(null!==c){a.shared.pending=null;var l=c,u=l.next;l.next=null,null===s?i=u:s.next=u,s=l;var d=e.alternate;if(null!==d){var p=(d=d.updateQueue).lastBaseUpdate;p!==s&&(null===p?d.firstBaseUpdate=u:p.next=u,d.lastBaseUpdate=l)}}if(null!==i){for(p=a.baseState,s=0,d=u=l=null;;){c=i.lane;var f=i.eventTime;if((r&c)===c){null!==d&&(d=d.next={eventTime:f,lane:0,tag:i.tag,payload:i.payload,callback:i.callback,next:null});e:{var h=e,m=i;switch(c=t,f=n,m.tag){case 1:if("function"==typeof(h=m.payload)){p=h.call(f,p,c);break e}p=h;break e;case 3:h.flags=-4097&h.flags|64;case 0:if(null==(c="function"==typeof(h=m.payload)?h.call(f,p,c):h))break e;p=o({},p,c);break e;case 2:ca=!0}}null!==i.callback&&(e.flags|=32,null===(c=a.effects)?a.effects=[i]:c.push(i))}else f={eventTime:f,lane:c,tag:i.tag,payload:i.payload,callback:i.callback,next:null},null===d?(u=d=f,l=p):d=d.next=f,s|=c;if(null===(i=i.next)){if(null===(c=a.shared.pending))break;i=c.next,c.next=null,a.lastBaseUpdate=c,a.shared.pending=null}}null===d&&(l=p),a.baseState=l,a.firstBaseUpdate=u,a.lastBaseUpdate=d,js|=s,e.lanes=s,e.memoizedState=p}}function ma(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],o=r.callback;if(null!==o){if(r.callback=null,r=n,"function"!=typeof o)throw Error(i(191,o));o.call(r)}}}var ga=(new r.Component).refs;function ba(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:o({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var va={isMounted:function(e){return!!(e=e._reactInternals)&&Ye(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var r=pc(),o=fc(e),a=da(r,o);a.payload=t,null!=n&&(a.callback=n),pa(e,a),hc(e,o,r)},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=pc(),o=fc(e),a=da(r,o);a.tag=1,a.payload=t,null!=n&&(a.callback=n),pa(e,a),hc(e,o,r)},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=pc(),r=fc(e),o=da(n,r);o.tag=2,null!=t&&(o.callback=t),pa(e,o),hc(e,r,n)}};function ya(e,t,n,r,o,a,i){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,a,i):!t.prototype||!t.prototype.isPureReactComponent||(!pr(n,r)||!pr(o,a))}function ka(e,t,n){var r=!1,o=fo,a=t.contextType;return"object"==typeof a&&null!==a?a=sa(a):(o=vo(t)?go:ho.current,a=(r=null!=(r=t.contextTypes))?bo(e,o):fo),t=new t(n,a),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=va,e.stateNode=t,t._reactInternals=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=o,e.__reactInternalMemoizedMaskedChildContext=a),t}function Ea(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&va.enqueueReplaceState(t,t.state,null)}function wa(e,t,n,r){var o=e.stateNode;o.props=n,o.state=e.memoizedState,o.refs=ga,la(e);var a=t.contextType;"object"==typeof a&&null!==a?o.context=sa(a):(a=vo(t)?go:ho.current,o.context=bo(e,a)),ha(e,n,o,r),o.state=e.memoizedState,"function"==typeof(a=t.getDerivedStateFromProps)&&(ba(e,t,a,n),o.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof o.getSnapshotBeforeUpdate||"function"!=typeof o.UNSAFE_componentWillMount&&"function"!=typeof o.componentWillMount||(t=o.state,"function"==typeof o.componentWillMount&&o.componentWillMount(),"function"==typeof o.UNSAFE_componentWillMount&&o.UNSAFE_componentWillMount(),t!==o.state&&va.enqueueReplaceState(o,o.state,null),ha(e,n,o,r),o.state=e.memoizedState),"function"==typeof o.componentDidMount&&(e.flags|=4)}var xa=Array.isArray;function Sa(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(i(309));var r=n.stateNode}if(!r)throw Error(i(147,e));var o=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===o?t.ref:(t=function(e){var t=r.refs;t===ga&&(t=r.refs={}),null===e?delete t[o]:t[o]=e},t._stringRef=o,t)}if("string"!=typeof e)throw Error(i(284));if(!n._owner)throw Error(i(290,e))}return e}function _a(e,t){if("textarea"!==e.type)throw Error(i(31,"[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t))}function Ta(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.flags=8}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function o(e,t){return(e=Qc(e,t)).index=0,e.sibling=null,e}function a(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.flags=2,n):r:(t.flags=2,n):n}function s(t){return e&&null===t.alternate&&(t.flags=2),t}function c(e,t,n,r){return null===t||6!==t.tag?((t=Yc(n,e.mode,r)).return=e,t):((t=o(t,n)).return=e,t)}function l(e,t,n,r){return null!==t&&t.elementType===n.type?((r=o(t,n.props)).ref=Sa(e,t,n),r.return=e,r):((r=Wc(n.type,n.key,n.props,null,e.mode,r)).ref=Sa(e,t,n),r.return=e,r)}function u(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Kc(n,e.mode,r)).return=e,t):((t=o(t,n.children||[])).return=e,t)}function d(e,t,n,r,a){return null===t||7!==t.tag?((t=Gc(n,e.mode,r,a)).return=e,t):((t=o(t,n)).return=e,t)}function p(e,t,n){if("string"==typeof t||"number"==typeof t)return(t=Yc(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case w:return(n=Wc(t.type,t.key,t.props,null,e.mode,n)).ref=Sa(e,null,t),n.return=e,n;case x:return(t=Kc(t,e.mode,n)).return=e,t}if(xa(t)||$(t))return(t=Gc(t,e.mode,n,null)).return=e,t;_a(e,t)}return null}function f(e,t,n,r){var o=null!==t?t.key:null;if("string"==typeof n||"number"==typeof n)return null!==o?null:c(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case w:return n.key===o?n.type===S?d(e,t,n.props.children,r,o):l(e,t,n,r):null;case x:return n.key===o?u(e,t,n,r):null}if(xa(n)||$(n))return null!==o?null:d(e,t,n,r,null);_a(e,n)}return null}function h(e,t,n,r,o){if("string"==typeof r||"number"==typeof r)return c(t,e=e.get(n)||null,""+r,o);if("object"==typeof r&&null!==r){switch(r.$$typeof){case w:return e=e.get(null===r.key?n:r.key)||null,r.type===S?d(t,e,r.props.children,o,r.key):l(t,e,r,o);case x:return u(t,e=e.get(null===r.key?n:r.key)||null,r,o)}if(xa(r)||$(r))return d(t,e=e.get(n)||null,r,o,null);_a(t,r)}return null}function m(o,i,s,c){for(var l=null,u=null,d=i,m=i=0,g=null;null!==d&&m<s.length;m++){d.index>m?(g=d,d=null):g=d.sibling;var b=f(o,d,s[m],c);if(null===b){null===d&&(d=g);break}e&&d&&null===b.alternate&&t(o,d),i=a(b,i,m),null===u?l=b:u.sibling=b,u=b,d=g}if(m===s.length)return n(o,d),l;if(null===d){for(;m<s.length;m++)null!==(d=p(o,s[m],c))&&(i=a(d,i,m),null===u?l=d:u.sibling=d,u=d);return l}for(d=r(o,d);m<s.length;m++)null!==(g=h(d,o,m,s[m],c))&&(e&&null!==g.alternate&&d.delete(null===g.key?m:g.key),i=a(g,i,m),null===u?l=g:u.sibling=g,u=g);return e&&d.forEach((function(e){return t(o,e)})),l}function g(o,s,c,l){var u=$(c);if("function"!=typeof u)throw Error(i(150));if(null==(c=u.call(c)))throw Error(i(151));for(var d=u=null,m=s,g=s=0,b=null,v=c.next();null!==m&&!v.done;g++,v=c.next()){m.index>g?(b=m,m=null):b=m.sibling;var y=f(o,m,v.value,l);if(null===y){null===m&&(m=b);break}e&&m&&null===y.alternate&&t(o,m),s=a(y,s,g),null===d?u=y:d.sibling=y,d=y,m=b}if(v.done)return n(o,m),u;if(null===m){for(;!v.done;g++,v=c.next())null!==(v=p(o,v.value,l))&&(s=a(v,s,g),null===d?u=v:d.sibling=v,d=v);return u}for(m=r(o,m);!v.done;g++,v=c.next())null!==(v=h(m,o,g,v.value,l))&&(e&&null!==v.alternate&&m.delete(null===v.key?g:v.key),s=a(v,s,g),null===d?u=v:d.sibling=v,d=v);return e&&m.forEach((function(e){return t(o,e)})),u}return function(e,r,a,c){var l="object"==typeof a&&null!==a&&a.type===S&&null===a.key;l&&(a=a.props.children);var u="object"==typeof a&&null!==a;if(u)switch(a.$$typeof){case w:e:{for(u=a.key,l=r;null!==l;){if(l.key===u){if(7===l.tag){if(a.type===S){n(e,l.sibling),(r=o(l,a.props.children)).return=e,e=r;break e}}else if(l.elementType===a.type){n(e,l.sibling),(r=o(l,a.props)).ref=Sa(e,l,a),r.return=e,e=r;break e}n(e,l);break}t(e,l),l=l.sibling}a.type===S?((r=Gc(a.props.children,e.mode,c,a.key)).return=e,e=r):((c=Wc(a.type,a.key,a.props,null,e.mode,c)).ref=Sa(e,r,a),c.return=e,e=c)}return s(e);case x:e:{for(l=a.key;null!==r;){if(r.key===l){if(4===r.tag&&r.stateNode.containerInfo===a.containerInfo&&r.stateNode.implementation===a.implementation){n(e,r.sibling),(r=o(r,a.children||[])).return=e,e=r;break e}n(e,r);break}t(e,r),r=r.sibling}(r=Kc(a,e.mode,c)).return=e,e=r}return s(e)}if("string"==typeof a||"number"==typeof a)return a=""+a,null!==r&&6===r.tag?(n(e,r.sibling),(r=o(r,a)).return=e,e=r):(n(e,r),(r=Yc(a,e.mode,c)).return=e,e=r),s(e);if(xa(a))return m(e,r,a,c);if($(a))return g(e,r,a,c);if(u&&_a(e,a),void 0===a&&!l)switch(e.tag){case 1:case 22:case 0:case 11:case 15:throw Error(i(152,W(e.type)||"Component"))}return n(e,r)}}var Ca=Ta(!0),La=Ta(!1),Na={},Ia=lo(Na),Oa=lo(Na),Aa=lo(Na);function Ra(e){if(e===Na)throw Error(i(174));return e}function Pa(e,t){switch(po(Aa,t),po(Oa,e),po(Ia,Na),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:he(null,"");break;default:t=he(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}uo(Ia),po(Ia,t)}function Da(){uo(Ia),uo(Oa),uo(Aa)}function Ma(e){Ra(Aa.current);var t=Ra(Ia.current),n=he(t,e.type);t!==n&&(po(Oa,e),po(Ia,n))}function Fa(e){Oa.current===e&&(uo(Ia),uo(Oa))}var za=lo(0);function Ba(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(0!=(64&t.flags))return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var Ua=null,ja=null,$a=!1;function Ha(e,t){var n=Zc(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.flags=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function Za(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function Va(e){if($a){var t=ja;if(t){var n=t;if(!Za(e,t)){if(!(t=Gr(n.nextSibling))||!Za(e,t))return e.flags=-1025&e.flags|2,$a=!1,void(Ua=e);Ha(Ua,n)}Ua=e,ja=Gr(t.firstChild)}else e.flags=-1025&e.flags|2,$a=!1,Ua=e}}function Qa(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;Ua=e}function Wa(e){if(e!==Ua)return!1;if(!$a)return Qa(e),$a=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!Zr(t,e.memoizedProps))for(t=ja;t;)Ha(e,t),t=Gr(t.nextSibling);if(Qa(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(i(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){ja=Gr(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}ja=null}}else ja=Ua?Gr(e.stateNode.nextSibling):null;return!0}function Ga(){ja=Ua=null,$a=!1}var qa=[];function Ya(){for(var e=0;e<qa.length;e++)qa[e]._workInProgressVersionPrimary=null;qa.length=0}var Ka=E.ReactCurrentDispatcher,Xa=E.ReactCurrentBatchConfig,Ja=0,ei=null,ti=null,ni=null,ri=!1,oi=!1;function ai(){throw Error(i(321))}function ii(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!ur(e[n],t[n]))return!1;return!0}function si(e,t,n,r,o,a){if(Ja=a,ei=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,Ka.current=null===e||null===e.memoizedState?Ri:Pi,e=n(r,o),oi){a=0;do{if(oi=!1,!(25>a))throw Error(i(301));a+=1,ni=ti=null,t.updateQueue=null,Ka.current=Di,e=n(r,o)}while(oi)}if(Ka.current=Ai,t=null!==ti&&null!==ti.next,Ja=0,ni=ti=ei=null,ri=!1,t)throw Error(i(300));return e}function ci(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===ni?ei.memoizedState=ni=e:ni=ni.next=e,ni}function li(){if(null===ti){var e=ei.alternate;e=null!==e?e.memoizedState:null}else e=ti.next;var t=null===ni?ei.memoizedState:ni.next;if(null!==t)ni=t,ti=e;else{if(null===e)throw Error(i(310));e={memoizedState:(ti=e).memoizedState,baseState:ti.baseState,baseQueue:ti.baseQueue,queue:ti.queue,next:null},null===ni?ei.memoizedState=ni=e:ni=ni.next=e}return ni}function ui(e,t){return"function"==typeof t?t(e):t}function di(e){var t=li(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=ti,o=r.baseQueue,a=n.pending;if(null!==a){if(null!==o){var s=o.next;o.next=a.next,a.next=s}r.baseQueue=o=a,n.pending=null}if(null!==o){o=o.next,r=r.baseState;var c=s=a=null,l=o;do{var u=l.lane;if((Ja&u)===u)null!==c&&(c=c.next={lane:0,action:l.action,eagerReducer:l.eagerReducer,eagerState:l.eagerState,next:null}),r=l.eagerReducer===e?l.eagerState:e(r,l.action);else{var d={lane:u,action:l.action,eagerReducer:l.eagerReducer,eagerState:l.eagerState,next:null};null===c?(s=c=d,a=r):c=c.next=d,ei.lanes|=u,js|=u}l=l.next}while(null!==l&&l!==o);null===c?a=r:c.next=s,ur(r,t.memoizedState)||(Fi=!0),t.memoizedState=r,t.baseState=a,t.baseQueue=c,n.lastRenderedState=r}return[t.memoizedState,n.dispatch]}function pi(e){var t=li(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=n.dispatch,o=n.pending,a=t.memoizedState;if(null!==o){n.pending=null;var s=o=o.next;do{a=e(a,s.action),s=s.next}while(s!==o);ur(a,t.memoizedState)||(Fi=!0),t.memoizedState=a,null===t.baseQueue&&(t.baseState=a),n.lastRenderedState=a}return[a,r]}function fi(e,t,n){var r=t._getVersion;r=r(t._source);var o=t._workInProgressVersionPrimary;if(null!==o?e=o===r:(e=e.mutableReadLanes,(e=(Ja&e)===e)&&(t._workInProgressVersionPrimary=r,qa.push(t))),e)return n(t._source);throw qa.push(t),Error(i(350))}function hi(e,t,n,r){var o=Rs;if(null===o)throw Error(i(349));var a=t._getVersion,s=a(t._source),c=Ka.current,l=c.useState((function(){return fi(o,t,n)})),u=l[1],d=l[0];l=ni;var p=e.memoizedState,f=p.refs,h=f.getSnapshot,m=p.source;p=p.subscribe;var g=ei;return e.memoizedState={refs:f,source:t,subscribe:r},c.useEffect((function(){f.getSnapshot=n,f.setSnapshot=u;var e=a(t._source);if(!ur(s,e)){e=n(t._source),ur(d,e)||(u(e),e=fc(g),o.mutableReadLanes|=e&o.pendingLanes),e=o.mutableReadLanes,o.entangledLanes|=e;for(var r=o.entanglements,i=e;0<i;){var c=31-Zt(i),l=1<<c;r[c]|=e,i&=~l}}}),[n,t,r]),c.useEffect((function(){return r(t._source,(function(){var e=f.getSnapshot,n=f.setSnapshot;try{n(e(t._source));var r=fc(g);o.mutableReadLanes|=r&o.pendingLanes}catch(a){n((function(){throw a}))}}))}),[t,r]),ur(h,n)&&ur(m,t)&&ur(p,r)||((e={pending:null,dispatch:null,lastRenderedReducer:ui,lastRenderedState:d}).dispatch=u=Oi.bind(null,ei,e),l.queue=e,l.baseQueue=null,d=fi(o,t,n),l.memoizedState=l.baseState=d),d}function mi(e,t,n){return hi(li(),e,t,n)}function gi(e){var t=ci();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={pending:null,dispatch:null,lastRenderedReducer:ui,lastRenderedState:e}).dispatch=Oi.bind(null,ei,e),[t.memoizedState,e]}function bi(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=ei.updateQueue)?(t={lastEffect:null},ei.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function vi(e){return e={current:e},ci().memoizedState=e}function yi(){return li().memoizedState}function ki(e,t,n,r){var o=ci();ei.flags|=e,o.memoizedState=bi(1|t,n,void 0,void 0===r?null:r)}function Ei(e,t,n,r){var o=li();r=void 0===r?null:r;var a=void 0;if(null!==ti){var i=ti.memoizedState;if(a=i.destroy,null!==r&&ii(r,i.deps))return void bi(t,n,a,r)}ei.flags|=e,o.memoizedState=bi(1|t,n,a,r)}function wi(e,t){return ki(516,4,e,t)}function xi(e,t){return Ei(516,4,e,t)}function Si(e,t){return Ei(4,2,e,t)}function _i(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function Ti(e,t,n){return n=null!=n?n.concat([e]):null,Ei(4,2,_i.bind(null,t,e),n)}function Ci(){}function Li(e,t){var n=li();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&ii(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Ni(e,t){var n=li();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&ii(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function Ii(e,t){var n=Vo();Wo(98>n?98:n,(function(){e(!0)})),Wo(97<n?97:n,(function(){var n=Xa.transition;Xa.transition=1;try{e(!1),t()}finally{Xa.transition=n}}))}function Oi(e,t,n){var r=pc(),o=fc(e),a={lane:o,action:n,eagerReducer:null,eagerState:null,next:null},i=t.pending;if(null===i?a.next=a:(a.next=i.next,i.next=a),t.pending=a,i=e.alternate,e===ei||null!==i&&i===ei)oi=ri=!0;else{if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=t.lastRenderedReducer))try{var s=t.lastRenderedState,c=i(s,n);if(a.eagerReducer=i,a.eagerState=c,ur(c,s))return}catch(l){}hc(e,o,r)}}var Ai={readContext:sa,useCallback:ai,useContext:ai,useEffect:ai,useImperativeHandle:ai,useLayoutEffect:ai,useMemo:ai,useReducer:ai,useRef:ai,useState:ai,useDebugValue:ai,useDeferredValue:ai,useTransition:ai,useMutableSource:ai,useOpaqueIdentifier:ai,unstable_isNewReconciler:!1},Ri={readContext:sa,useCallback:function(e,t){return ci().memoizedState=[e,void 0===t?null:t],e},useContext:sa,useEffect:wi,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,ki(4,2,_i.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ki(4,2,e,t)},useMemo:function(e,t){var n=ci();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=ci();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e=(e=r.queue={pending:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=Oi.bind(null,ei,e),[r.memoizedState,e]},useRef:vi,useState:gi,useDebugValue:Ci,useDeferredValue:function(e){var t=gi(e),n=t[0],r=t[1];return wi((function(){var t=Xa.transition;Xa.transition=1;try{r(e)}finally{Xa.transition=t}}),[e]),n},useTransition:function(){var e=gi(!1),t=e[0];return vi(e=Ii.bind(null,e[1])),[e,t]},useMutableSource:function(e,t,n){var r=ci();return r.memoizedState={refs:{getSnapshot:t,setSnapshot:null},source:e,subscribe:n},hi(r,e,t,n)},useOpaqueIdentifier:function(){if($a){var e=!1,t=function(e){return{$$typeof:D,toString:e,valueOf:e}}((function(){throw e||(e=!0,n("r:"+(Yr++).toString(36))),Error(i(355))})),n=gi(t)[1];return 0==(2&ei.mode)&&(ei.flags|=516,bi(5,(function(){n("r:"+(Yr++).toString(36))}),void 0,null)),t}return gi(t="r:"+(Yr++).toString(36)),t},unstable_isNewReconciler:!1},Pi={readContext:sa,useCallback:Li,useContext:sa,useEffect:xi,useImperativeHandle:Ti,useLayoutEffect:Si,useMemo:Ni,useReducer:di,useRef:yi,useState:function(){return di(ui)},useDebugValue:Ci,useDeferredValue:function(e){var t=di(ui),n=t[0],r=t[1];return xi((function(){var t=Xa.transition;Xa.transition=1;try{r(e)}finally{Xa.transition=t}}),[e]),n},useTransition:function(){var e=di(ui)[0];return[yi().current,e]},useMutableSource:mi,useOpaqueIdentifier:function(){return di(ui)[0]},unstable_isNewReconciler:!1},Di={readContext:sa,useCallback:Li,useContext:sa,useEffect:xi,useImperativeHandle:Ti,useLayoutEffect:Si,useMemo:Ni,useReducer:pi,useRef:yi,useState:function(){return pi(ui)},useDebugValue:Ci,useDeferredValue:function(e){var t=pi(ui),n=t[0],r=t[1];return xi((function(){var t=Xa.transition;Xa.transition=1;try{r(e)}finally{Xa.transition=t}}),[e]),n},useTransition:function(){var e=pi(ui)[0];return[yi().current,e]},useMutableSource:mi,useOpaqueIdentifier:function(){return pi(ui)[0]},unstable_isNewReconciler:!1},Mi=E.ReactCurrentOwner,Fi=!1;function zi(e,t,n,r){t.child=null===e?La(t,null,n,r):Ca(t,e.child,n,r)}function Bi(e,t,n,r,o){n=n.render;var a=t.ref;return ia(t,o),r=si(e,t,n,r,a,o),null===e||Fi?(t.flags|=1,zi(e,t,r,o),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~o,as(e,t,o))}function Ui(e,t,n,r,o,a){if(null===e){var i=n.type;return"function"!=typeof i||Vc(i)||void 0!==i.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Wc(n.type,null,r,t,t.mode,a)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=i,ji(e,t,i,r,o,a))}return i=e.child,0==(o&a)&&(o=i.memoizedProps,(n=null!==(n=n.compare)?n:pr)(o,r)&&e.ref===t.ref)?as(e,t,a):(t.flags|=1,(e=Qc(i,r)).ref=t.ref,e.return=t,t.child=e)}function ji(e,t,n,r,o,a){if(null!==e&&pr(e.memoizedProps,r)&&e.ref===t.ref){if(Fi=!1,0==(a&o))return t.lanes=e.lanes,as(e,t,a);0!=(16384&e.flags)&&(Fi=!0)}return Zi(e,t,n,r,a)}function $i(e,t,n){var r=t.pendingProps,o=r.children,a=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(4&t.mode))t.memoizedState={baseLanes:0},wc(t,n);else{if(0==(1073741824&n))return e=null!==a?a.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e},wc(t,e),null;t.memoizedState={baseLanes:0},wc(t,null!==a?a.baseLanes:n)}else null!==a?(r=a.baseLanes|n,t.memoizedState=null):r=n,wc(t,r);return zi(e,t,o,n),t.child}function Hi(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=128)}function Zi(e,t,n,r,o){var a=vo(n)?go:ho.current;return a=bo(t,a),ia(t,o),n=si(e,t,n,r,a,o),null===e||Fi?(t.flags|=1,zi(e,t,n,o),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~o,as(e,t,o))}function Vi(e,t,n,r,o){if(vo(n)){var a=!0;wo(t)}else a=!1;if(ia(t,o),null===t.stateNode)null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),ka(t,n,r),wa(t,n,r,o),r=!0;else if(null===e){var i=t.stateNode,s=t.memoizedProps;i.props=s;var c=i.context,l=n.contextType;"object"==typeof l&&null!==l?l=sa(l):l=bo(t,l=vo(n)?go:ho.current);var u=n.getDerivedStateFromProps,d="function"==typeof u||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(s!==r||c!==l)&&Ea(t,i,r,l),ca=!1;var p=t.memoizedState;i.state=p,ha(t,r,i,o),c=t.memoizedState,s!==r||p!==c||mo.current||ca?("function"==typeof u&&(ba(t,n,u,r),c=t.memoizedState),(s=ca||ya(t,n,s,r,p,c,l))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(t.flags|=4)):("function"==typeof i.componentDidMount&&(t.flags|=4),t.memoizedProps=r,t.memoizedState=c),i.props=r,i.state=c,i.context=l,r=s):("function"==typeof i.componentDidMount&&(t.flags|=4),r=!1)}else{i=t.stateNode,ua(e,t),s=t.memoizedProps,l=t.type===t.elementType?s:Xo(t.type,s),i.props=l,d=t.pendingProps,p=i.context,"object"==typeof(c=n.contextType)&&null!==c?c=sa(c):c=bo(t,c=vo(n)?go:ho.current);var f=n.getDerivedStateFromProps;(u="function"==typeof f||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(s!==d||p!==c)&&Ea(t,i,r,c),ca=!1,p=t.memoizedState,i.state=p,ha(t,r,i,o);var h=t.memoizedState;s!==d||p!==h||mo.current||ca?("function"==typeof f&&(ba(t,n,f,r),h=t.memoizedState),(l=ca||ya(t,n,l,r,p,h,c))?(u||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,h,c),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,h,c)),"function"==typeof i.componentDidUpdate&&(t.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(t.flags|=256)):("function"!=typeof i.componentDidUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=256),t.memoizedProps=r,t.memoizedState=h),i.props=r,i.state=h,i.context=c,r=l):("function"!=typeof i.componentDidUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||s===e.memoizedProps&&p===e.memoizedState||(t.flags|=256),r=!1)}return Qi(e,t,n,r,a,o)}function Qi(e,t,n,r,o,a){Hi(e,t);var i=0!=(64&t.flags);if(!r&&!i)return o&&xo(t,n,!1),as(e,t,a);r=t.stateNode,Mi.current=t;var s=i&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.flags|=1,null!==e&&i?(t.child=Ca(t,e.child,null,a),t.child=Ca(t,null,s,a)):zi(e,t,s,a),t.memoizedState=r.state,o&&xo(t,n,!0),t.child}function Wi(e){var t=e.stateNode;t.pendingContext?ko(0,t.pendingContext,t.pendingContext!==t.context):t.context&&ko(0,t.context,!1),Pa(e,t.containerInfo)}var Gi,qi,Yi,Ki={dehydrated:null,retryLane:0};function Xi(e,t,n){var r,o=t.pendingProps,a=za.current,i=!1;return(r=0!=(64&t.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&a)),r?(i=!0,t.flags&=-65):null!==e&&null===e.memoizedState||void 0===o.fallback||!0===o.unstable_avoidThisFallback||(a|=1),po(za,1&a),null===e?(void 0!==o.fallback&&Va(t),e=o.children,a=o.fallback,i?(e=Ji(t,e,a,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Ki,e):"number"==typeof o.unstable_expectedLoadTime?(e=Ji(t,e,a,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Ki,t.lanes=33554432,e):((n=qc({mode:"visible",children:e},t.mode,n,null)).return=t,t.child=n)):(e.memoizedState,i?(o=ts(e,t,o.children,o.fallback,n),i=t.child,a=e.child.memoizedState,i.memoizedState=null===a?{baseLanes:n}:{baseLanes:a.baseLanes|n},i.childLanes=e.childLanes&~n,t.memoizedState=Ki,o):(n=es(e,t,o.children,n),t.memoizedState=null,n))}function Ji(e,t,n,r){var o=e.mode,a=e.child;return t={mode:"hidden",children:t},0==(2&o)&&null!==a?(a.childLanes=0,a.pendingProps=t):a=qc(t,o,0,null),n=Gc(n,o,r,null),a.return=e,n.return=e,a.sibling=n,e.child=a,n}function es(e,t,n,r){var o=e.child;return e=o.sibling,n=Qc(o,{mode:"visible",children:n}),0==(2&t.mode)&&(n.lanes=r),n.return=t,n.sibling=null,null!==e&&(e.nextEffect=null,e.flags=8,t.firstEffect=t.lastEffect=e),t.child=n}function ts(e,t,n,r,o){var a=t.mode,i=e.child;e=i.sibling;var s={mode:"hidden",children:n};return 0==(2&a)&&t.child!==i?((n=t.child).childLanes=0,n.pendingProps=s,null!==(i=n.lastEffect)?(t.firstEffect=n.firstEffect,t.lastEffect=i,i.nextEffect=null):t.firstEffect=t.lastEffect=null):n=Qc(i,s),null!==e?r=Qc(e,r):(r=Gc(r,a,o,null)).flags|=2,r.return=t,n.return=t,n.sibling=r,t.child=n,r}function ns(e,t){e.lanes|=t;var n=e.alternate;null!==n&&(n.lanes|=t),aa(e.return,t)}function rs(e,t,n,r,o,a){var i=e.memoizedState;null===i?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:o,lastEffect:a}:(i.isBackwards=t,i.rendering=null,i.renderingStartTime=0,i.last=r,i.tail=n,i.tailMode=o,i.lastEffect=a)}function os(e,t,n){var r=t.pendingProps,o=r.revealOrder,a=r.tail;if(zi(e,t,r.children,n),0!=(2&(r=za.current)))r=1&r|2,t.flags|=64;else{if(null!==e&&0!=(64&e.flags))e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&ns(e,n);else if(19===e.tag)ns(e,n);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(po(za,r),0==(2&t.mode))t.memoizedState=null;else switch(o){case"forwards":for(n=t.child,o=null;null!==n;)null!==(e=n.alternate)&&null===Ba(e)&&(o=n),n=n.sibling;null===(n=o)?(o=t.child,t.child=null):(o=n.sibling,n.sibling=null),rs(t,!1,o,n,a,t.lastEffect);break;case"backwards":for(n=null,o=t.child,t.child=null;null!==o;){if(null!==(e=o.alternate)&&null===Ba(e)){t.child=o;break}e=o.sibling,o.sibling=n,n=o,o=e}rs(t,!0,n,null,a,t.lastEffect);break;case"together":rs(t,!1,null,null,void 0,t.lastEffect);break;default:t.memoizedState=null}return t.child}function as(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),js|=t.lanes,0!=(n&t.childLanes)){if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=Qc(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Qc(e,e.pendingProps)).return=t;n.sibling=null}return t.child}return null}function is(e,t){if(!$a)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function ss(e,t,n){var r=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:case 17:return vo(t.type)&&yo(),null;case 3:return Da(),uo(mo),uo(ho),Ya(),(r=t.stateNode).pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),null!==e&&null!==e.child||(Wa(t)?t.flags|=4:r.hydrate||(t.flags|=256)),null;case 5:Fa(t);var a=Ra(Aa.current);if(n=t.type,null!==e&&null!=t.stateNode)qi(e,t,n,r),e.ref!==t.ref&&(t.flags|=128);else{if(!r){if(null===t.stateNode)throw Error(i(166));return null}if(e=Ra(Ia.current),Wa(t)){r=t.stateNode,n=t.type;var s=t.memoizedProps;switch(r[Xr]=t,r[Jr]=s,n){case"dialog":Ir("cancel",r),Ir("close",r);break;case"iframe":case"object":case"embed":Ir("load",r);break;case"video":case"audio":for(e=0;e<Tr.length;e++)Ir(Tr[e],r);break;case"source":Ir("error",r);break;case"img":case"image":case"link":Ir("error",r),Ir("load",r);break;case"details":Ir("toggle",r);break;case"input":ee(r,s),Ir("invalid",r);break;case"select":r._wrapperState={wasMultiple:!!s.multiple},Ir("invalid",r);break;case"textarea":ce(r,s),Ir("invalid",r)}for(var l in Se(n,s),e=null,s)s.hasOwnProperty(l)&&(a=s[l],"children"===l?"string"==typeof a?r.textContent!==a&&(e=["children",a]):"number"==typeof a&&r.textContent!==""+a&&(e=["children",""+a]):c.hasOwnProperty(l)&&null!=a&&"onScroll"===l&&Ir("scroll",r));switch(n){case"input":Y(r),re(r,s,!0);break;case"textarea":Y(r),ue(r);break;case"select":case"option":break;default:"function"==typeof s.onClick&&(r.onclick=Ur)}r=e,t.updateQueue=r,null!==r&&(t.flags|=4)}else{switch(l=9===a.nodeType?a:a.ownerDocument,e===de&&(e=fe(n)),e===de?"script"===n?((e=l.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),"select"===n&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[Xr]=t,e[Jr]=r,Gi(e,t),t.stateNode=e,l=_e(n,r),n){case"dialog":Ir("cancel",e),Ir("close",e),a=r;break;case"iframe":case"object":case"embed":Ir("load",e),a=r;break;case"video":case"audio":for(a=0;a<Tr.length;a++)Ir(Tr[a],e);a=r;break;case"source":Ir("error",e),a=r;break;case"img":case"image":case"link":Ir("error",e),Ir("load",e),a=r;break;case"details":Ir("toggle",e),a=r;break;case"input":ee(e,r),a=J(e,r),Ir("invalid",e);break;case"option":a=ae(e,r);break;case"select":e._wrapperState={wasMultiple:!!r.multiple},a=o({},r,{value:void 0}),Ir("invalid",e);break;case"textarea":ce(e,r),a=se(e,r),Ir("invalid",e);break;default:a=r}Se(n,a);var u=a;for(s in u)if(u.hasOwnProperty(s)){var d=u[s];"style"===s?we(e,d):"dangerouslySetInnerHTML"===s?null!=(d=d?d.__html:void 0)&&be(e,d):"children"===s?"string"==typeof d?("textarea"!==n||""!==d)&&ve(e,d):"number"==typeof d&&ve(e,""+d):"suppressContentEditableWarning"!==s&&"suppressHydrationWarning"!==s&&"autoFocus"!==s&&(c.hasOwnProperty(s)?null!=d&&"onScroll"===s&&Ir("scroll",e):null!=d&&k(e,s,d,l))}switch(n){case"input":Y(e),re(e,r,!1);break;case"textarea":Y(e),ue(e);break;case"option":null!=r.value&&e.setAttribute("value",""+G(r.value));break;case"select":e.multiple=!!r.multiple,null!=(s=r.value)?ie(e,!!r.multiple,s,!1):null!=r.defaultValue&&ie(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof a.onClick&&(e.onclick=Ur)}Hr(n,r)&&(t.flags|=4)}null!==t.ref&&(t.flags|=128)}return null;case 6:if(e&&null!=t.stateNode)Yi(0,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(i(166));n=Ra(Aa.current),Ra(Ia.current),Wa(t)?(r=t.stateNode,n=t.memoizedProps,r[Xr]=t,r.nodeValue!==n&&(t.flags|=4)):((r=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[Xr]=t,t.stateNode=r)}return null;case 13:return uo(za),r=t.memoizedState,0!=(64&t.flags)?(t.lanes=n,t):(r=null!==r,n=!1,null===e?void 0!==t.memoizedProps.fallback&&Wa(t):n=null!==e.memoizedState,r&&!n&&0!=(2&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&za.current)?0===zs&&(zs=3):(0!==zs&&3!==zs||(zs=4),null===Rs||0==(134217727&js)&&0==(134217727&$s)||vc(Rs,Ds))),(r||n)&&(t.flags|=4),null);case 4:return Da(),null===e&&Ar(t.stateNode.containerInfo),null;case 10:return oa(t),null;case 19:if(uo(za),null===(r=t.memoizedState))return null;if(s=0!=(64&t.flags),null===(l=r.rendering))if(s)is(r,!1);else{if(0!==zs||null!==e&&0!=(64&e.flags))for(e=t.child;null!==e;){if(null!==(l=Ba(e))){for(t.flags|=64,is(r,!1),null!==(s=l.updateQueue)&&(t.updateQueue=s,t.flags|=4),null===r.lastEffect&&(t.firstEffect=null),t.lastEffect=r.lastEffect,r=n,n=t.child;null!==n;)e=r,(s=n).flags&=2,s.nextEffect=null,s.firstEffect=null,s.lastEffect=null,null===(l=s.alternate)?(s.childLanes=0,s.lanes=e,s.child=null,s.memoizedProps=null,s.memoizedState=null,s.updateQueue=null,s.dependencies=null,s.stateNode=null):(s.childLanes=l.childLanes,s.lanes=l.lanes,s.child=l.child,s.memoizedProps=l.memoizedProps,s.memoizedState=l.memoizedState,s.updateQueue=l.updateQueue,s.type=l.type,e=l.dependencies,s.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return po(za,1&za.current|2),t.child}e=e.sibling}null!==r.tail&&Zo()>Qs&&(t.flags|=64,s=!0,is(r,!1),t.lanes=33554432)}else{if(!s)if(null!==(e=Ba(l))){if(t.flags|=64,s=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),is(r,!0),null===r.tail&&"hidden"===r.tailMode&&!l.alternate&&!$a)return null!==(t=t.lastEffect=r.lastEffect)&&(t.nextEffect=null),null}else 2*Zo()-r.renderingStartTime>Qs&&1073741824!==n&&(t.flags|=64,s=!0,is(r,!1),t.lanes=33554432);r.isBackwards?(l.sibling=t.child,t.child=l):(null!==(n=r.last)?n.sibling=l:t.child=l,r.last=l)}return null!==r.tail?(n=r.tail,r.rendering=n,r.tail=n.sibling,r.lastEffect=t.lastEffect,r.renderingStartTime=Zo(),n.sibling=null,t=za.current,po(za,s?1&t|2:1&t),n):null;case 23:case 24:return xc(),null!==e&&null!==e.memoizedState!=(null!==t.memoizedState)&&"unstable-defer-without-hiding"!==r.mode&&(t.flags|=4),null}throw Error(i(156,t.tag))}function cs(e){switch(e.tag){case 1:vo(e.type)&&yo();var t=e.flags;return 4096&t?(e.flags=-4097&t|64,e):null;case 3:if(Da(),uo(mo),uo(ho),Ya(),0!=(64&(t=e.flags)))throw Error(i(285));return e.flags=-4097&t|64,e;case 5:return Fa(e),null;case 13:return uo(za),4096&(t=e.flags)?(e.flags=-4097&t|64,e):null;case 19:return uo(za),null;case 4:return Da(),null;case 10:return oa(e),null;case 23:case 24:return xc(),null;default:return null}}function ls(e,t){try{var n="",r=t;do{n+=Q(r),r=r.return}while(r);var o=n}catch(a){o="\nError generating stack: "+a.message+"\n"+a.stack}return{value:e,source:t,stack:o}}function us(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}Gi=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},qi=function(e,t,n,r){var a=e.memoizedProps;if(a!==r){e=t.stateNode,Ra(Ia.current);var i,s=null;switch(n){case"input":a=J(e,a),r=J(e,r),s=[];break;case"option":a=ae(e,a),r=ae(e,r),s=[];break;case"select":a=o({},a,{value:void 0}),r=o({},r,{value:void 0}),s=[];break;case"textarea":a=se(e,a),r=se(e,r),s=[];break;default:"function"!=typeof a.onClick&&"function"==typeof r.onClick&&(e.onclick=Ur)}for(d in Se(n,r),n=null,a)if(!r.hasOwnProperty(d)&&a.hasOwnProperty(d)&&null!=a[d])if("style"===d){var l=a[d];for(i in l)l.hasOwnProperty(i)&&(n||(n={}),n[i]="")}else"dangerouslySetInnerHTML"!==d&&"children"!==d&&"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&"autoFocus"!==d&&(c.hasOwnProperty(d)?s||(s=[]):(s=s||[]).push(d,null));for(d in r){var u=r[d];if(l=null!=a?a[d]:void 0,r.hasOwnProperty(d)&&u!==l&&(null!=u||null!=l))if("style"===d)if(l){for(i in l)!l.hasOwnProperty(i)||u&&u.hasOwnProperty(i)||(n||(n={}),n[i]="");for(i in u)u.hasOwnProperty(i)&&l[i]!==u[i]&&(n||(n={}),n[i]=u[i])}else n||(s||(s=[]),s.push(d,n)),n=u;else"dangerouslySetInnerHTML"===d?(u=u?u.__html:void 0,l=l?l.__html:void 0,null!=u&&l!==u&&(s=s||[]).push(d,u)):"children"===d?"string"!=typeof u&&"number"!=typeof u||(s=s||[]).push(d,""+u):"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&(c.hasOwnProperty(d)?(null!=u&&"onScroll"===d&&Ir("scroll",e),s||l===u||(s=[])):"object"==typeof u&&null!==u&&u.$$typeof===D?u.toString():(s=s||[]).push(d,u))}n&&(s=s||[]).push("style",n);var d=s;(t.updateQueue=d)&&(t.flags|=4)}},Yi=function(e,t,n,r){n!==r&&(t.flags|=4)};var ds="function"==typeof WeakMap?WeakMap:Map;function ps(e,t,n){(n=da(-1,n)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Ys||(Ys=!0,Ks=r),us(0,t)},n}function fs(e,t,n){(n=da(-1,n)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var o=t.value;n.payload=function(){return us(0,t),r(o)}}var a=e.stateNode;return null!==a&&"function"==typeof a.componentDidCatch&&(n.callback=function(){"function"!=typeof r&&(null===Xs?Xs=new Set([this]):Xs.add(this),us(0,t));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}var hs="function"==typeof WeakSet?WeakSet:Set;function ms(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(n){Uc(e,n)}else t.current=null}function gs(e,t){switch(t.tag){case 0:case 11:case 15:case 22:case 5:case 6:case 4:case 17:return;case 1:if(256&t.flags&&null!==e){var n=e.memoizedProps,r=e.memoizedState;t=(e=t.stateNode).getSnapshotBeforeUpdate(t.elementType===t.type?n:Xo(t.type,n),r),e.__reactInternalSnapshotBeforeUpdate=t}return;case 3:return void(256&t.flags&&Wr(t.stateNode.containerInfo))}throw Error(i(163))}function bs(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{if(3==(3&e.tag)){var r=e.create;e.destroy=r()}e=e.next}while(e!==t)}if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{var o=e;r=o.next,0!=(4&(o=o.tag))&&0!=(1&o)&&(Fc(n,e),Mc(n,e)),e=r}while(e!==t)}return;case 1:return e=n.stateNode,4&n.flags&&(null===t?e.componentDidMount():(r=n.elementType===n.type?t.memoizedProps:Xo(n.type,t.memoizedProps),e.componentDidUpdate(r,t.memoizedState,e.__reactInternalSnapshotBeforeUpdate))),void(null!==(t=n.updateQueue)&&ma(n,t,e));case 3:if(null!==(t=n.updateQueue)){if(e=null,null!==n.child)switch(n.child.tag){case 5:case 1:e=n.child.stateNode}ma(n,t,e)}return;case 5:return e=n.stateNode,void(null===t&&4&n.flags&&Hr(n.type,n.memoizedProps)&&e.focus());case 6:case 4:case 12:case 19:case 17:case 20:case 21:case 23:case 24:return;case 13:return void(null===n.memoizedState&&(n=n.alternate,null!==n&&(n=n.memoizedState,null!==n&&(n=n.dehydrated,null!==n&&wt(n)))))}throw Error(i(163))}function vs(e,t){for(var n=e;;){if(5===n.tag){var r=n.stateNode;if(t)"function"==typeof(r=r.style).setProperty?r.setProperty("display","none","important"):r.display="none";else{r=n.stateNode;var o=n.memoizedProps.style;o=null!=o&&o.hasOwnProperty("display")?o.display:null,r.style.display=Ee("display",o)}}else if(6===n.tag)n.stateNode.nodeValue=t?"":n.memoizedProps;else if((23!==n.tag&&24!==n.tag||null===n.memoizedState||n===e)&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return;n=n.return}n.sibling.return=n.return,n=n.sibling}}function ys(e,t){if(_o&&"function"==typeof _o.onCommitFiberUnmount)try{_o.onCommitFiberUnmount(So,t)}catch(a){}switch(t.tag){case 0:case 11:case 14:case 15:case 22:if(null!==(e=t.updateQueue)&&null!==(e=e.lastEffect)){var n=e=e.next;do{var r=n,o=r.destroy;if(r=r.tag,void 0!==o)if(0!=(4&r))Fc(t,n);else{r=t;try{o()}catch(a){Uc(r,a)}}n=n.next}while(n!==e)}break;case 1:if(ms(t),"function"==typeof(e=t.stateNode).componentWillUnmount)try{e.props=t.memoizedProps,e.state=t.memoizedState,e.componentWillUnmount()}catch(a){Uc(t,a)}break;case 5:ms(t);break;case 4:_s(e,t)}}function ks(e){e.alternate=null,e.child=null,e.dependencies=null,e.firstEffect=null,e.lastEffect=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.return=null,e.updateQueue=null}function Es(e){return 5===e.tag||3===e.tag||4===e.tag}function ws(e){e:{for(var t=e.return;null!==t;){if(Es(t))break e;t=t.return}throw Error(i(160))}var n=t;switch(t=n.stateNode,n.tag){case 5:var r=!1;break;case 3:case 4:t=t.containerInfo,r=!0;break;default:throw Error(i(161))}16&n.flags&&(ve(t,""),n.flags&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||Es(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag&&18!==n.tag;){if(2&n.flags)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.flags)){n=n.stateNode;break e}}r?xs(e,n,t):Ss(e,n,t)}function xs(e,t,n){var r=e.tag,o=5===r||6===r;if(o)e=o?e.stateNode:e.stateNode.instance,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=Ur));else if(4!==r&&null!==(e=e.child))for(xs(e,t,n),e=e.sibling;null!==e;)xs(e,t,n),e=e.sibling}function Ss(e,t,n){var r=e.tag,o=5===r||6===r;if(o)e=o?e.stateNode:e.stateNode.instance,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(Ss(e,t,n),e=e.sibling;null!==e;)Ss(e,t,n),e=e.sibling}function _s(e,t){for(var n,r,o=t,a=!1;;){if(!a){a=o.return;e:for(;;){if(null===a)throw Error(i(160));switch(n=a.stateNode,a.tag){case 5:r=!1;break e;case 3:case 4:n=n.containerInfo,r=!0;break e}a=a.return}a=!0}if(5===o.tag||6===o.tag){e:for(var s=e,c=o,l=c;;)if(ys(s,l),null!==l.child&&4!==l.tag)l.child.return=l,l=l.child;else{if(l===c)break e;for(;null===l.sibling;){if(null===l.return||l.return===c)break e;l=l.return}l.sibling.return=l.return,l=l.sibling}r?(s=n,c=o.stateNode,8===s.nodeType?s.parentNode.removeChild(c):s.removeChild(c)):n.removeChild(o.stateNode)}else if(4===o.tag){if(null!==o.child){n=o.stateNode.containerInfo,r=!0,o.child.return=o,o=o.child;continue}}else if(ys(e,o),null!==o.child){o.child.return=o,o=o.child;continue}if(o===t)break;for(;null===o.sibling;){if(null===o.return||o.return===t)return;4===(o=o.return).tag&&(a=!1)}o.sibling.return=o.return,o=o.sibling}}function Ts(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:var n=t.updateQueue;if(null!==(n=null!==n?n.lastEffect:null)){var r=n=n.next;do{3==(3&r.tag)&&(e=r.destroy,r.destroy=void 0,void 0!==e&&e()),r=r.next}while(r!==n)}return;case 1:case 12:case 17:return;case 5:if(null!=(n=t.stateNode)){r=t.memoizedProps;var o=null!==e?e.memoizedProps:r;e=t.type;var a=t.updateQueue;if(t.updateQueue=null,null!==a){for(n[Jr]=r,"input"===e&&"radio"===r.type&&null!=r.name&&te(n,r),_e(e,o),t=_e(e,r),o=0;o<a.length;o+=2){var s=a[o],c=a[o+1];"style"===s?we(n,c):"dangerouslySetInnerHTML"===s?be(n,c):"children"===s?ve(n,c):k(n,s,c,t)}switch(e){case"input":ne(n,r);break;case"textarea":le(n,r);break;case"select":e=n._wrapperState.wasMultiple,n._wrapperState.wasMultiple=!!r.multiple,null!=(a=r.value)?ie(n,!!r.multiple,a,!1):e!==!!r.multiple&&(null!=r.defaultValue?ie(n,!!r.multiple,r.defaultValue,!0):ie(n,!!r.multiple,r.multiple?[]:"",!1))}}}return;case 6:if(null===t.stateNode)throw Error(i(162));return void(t.stateNode.nodeValue=t.memoizedProps);case 3:return void((n=t.stateNode).hydrate&&(n.hydrate=!1,wt(n.containerInfo)));case 13:return null!==t.memoizedState&&(Vs=Zo(),vs(t.child,!0)),void Cs(t);case 19:return void Cs(t);case 23:case 24:return void vs(t,null!==t.memoizedState)}throw Error(i(163))}function Cs(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new hs),t.forEach((function(t){var r=$c.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}function Ls(e,t){return null!==e&&(null===(e=e.memoizedState)||null!==e.dehydrated)&&(null!==(t=t.memoizedState)&&null===t.dehydrated)}var Ns=Math.ceil,Is=E.ReactCurrentDispatcher,Os=E.ReactCurrentOwner,As=0,Rs=null,Ps=null,Ds=0,Ms=0,Fs=lo(0),zs=0,Bs=null,Us=0,js=0,$s=0,Hs=0,Zs=null,Vs=0,Qs=1/0;function Ws(){Qs=Zo()+500}var Gs,qs=null,Ys=!1,Ks=null,Xs=null,Js=!1,ec=null,tc=90,nc=[],rc=[],oc=null,ac=0,ic=null,sc=-1,cc=0,lc=0,uc=null,dc=!1;function pc(){return 0!=(48&As)?Zo():-1!==sc?sc:sc=Zo()}function fc(e){if(0==(2&(e=e.mode)))return 1;if(0==(4&e))return 99===Vo()?1:2;if(0===cc&&(cc=Us),0!==Ko.transition){0!==lc&&(lc=null!==Zs?Zs.pendingLanes:0),e=cc;var t=4186112&~lc;return 0===(t&=-t)&&(0===(t=(e=4186112&~e)&-e)&&(t=8192)),t}return e=Vo(),0!=(4&As)&&98===e?e=Ut(12,cc):e=Ut(e=function(e){switch(e){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}(e),cc),e}function hc(e,t,n){if(50<ac)throw ac=0,ic=null,Error(i(185));if(null===(e=mc(e,t)))return null;Ht(e,t,n),e===Rs&&($s|=t,4===zs&&vc(e,Ds));var r=Vo();1===t?0!=(8&As)&&0==(48&As)?yc(e):(gc(e,n),0===As&&(Ws(),qo())):(0==(4&As)||98!==r&&99!==r||(null===oc?oc=new Set([e]):oc.add(e)),gc(e,n)),Zs=e}function mc(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}function gc(e,t){for(var n=e.callbackNode,r=e.suspendedLanes,o=e.pingedLanes,a=e.expirationTimes,s=e.pendingLanes;0<s;){var c=31-Zt(s),l=1<<c,u=a[c];if(-1===u){if(0==(l&r)||0!=(l&o)){u=t,Ft(l);var d=Mt;a[c]=10<=d?u+250:6<=d?u+5e3:-1}}else u<=t&&(e.expiredLanes|=l);s&=~l}if(r=zt(e,e===Rs?Ds:0),t=Mt,0===r)null!==n&&(n!==zo&&Lo(n),e.callbackNode=null,e.callbackPriority=0);else{if(null!==n){if(e.callbackPriority===t)return;n!==zo&&Lo(n)}15===t?(n=yc.bind(null,e),null===Uo?(Uo=[n],jo=Co(Ro,Yo)):Uo.push(n),n=zo):14===t?n=Go(99,yc.bind(null,e)):(n=function(e){switch(e){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(i(358,e))}}(t),n=Go(n,bc.bind(null,e))),e.callbackPriority=t,e.callbackNode=n}}function bc(e){if(sc=-1,lc=cc=0,0!=(48&As))throw Error(i(327));var t=e.callbackNode;if(Dc()&&e.callbackNode!==t)return null;var n=zt(e,e===Rs?Ds:0);if(0===n)return null;var r=n,o=As;As|=16;var a=Tc();for(Rs===e&&Ds===r||(Ws(),Sc(e,r));;)try{Nc();break}catch(c){_c(e,c)}if(ra(),Is.current=a,As=o,null!==Ps?r=0:(Rs=null,Ds=0,r=zs),0!=(Us&$s))Sc(e,0);else if(0!==r){if(2===r&&(As|=64,e.hydrate&&(e.hydrate=!1,Wr(e.containerInfo)),0!==(n=Bt(e))&&(r=Cc(e,n))),1===r)throw t=Bs,Sc(e,0),vc(e,n),gc(e,Zo()),t;switch(e.finishedWork=e.current.alternate,e.finishedLanes=n,r){case 0:case 1:throw Error(i(345));case 2:case 5:Ac(e);break;case 3:if(vc(e,n),(62914560&n)===n&&10<(r=Vs+500-Zo())){if(0!==zt(e,0))break;if(((o=e.suspendedLanes)&n)!==n){pc(),e.pingedLanes|=e.suspendedLanes&o;break}e.timeoutHandle=Vr(Ac.bind(null,e),r);break}Ac(e);break;case 4:if(vc(e,n),(4186112&n)===n)break;for(r=e.eventTimes,o=-1;0<n;){var s=31-Zt(n);a=1<<s,(s=r[s])>o&&(o=s),n&=~a}if(n=o,10<(n=(120>(n=Zo()-n)?120:480>n?480:1080>n?1080:1920>n?1920:3e3>n?3e3:4320>n?4320:1960*Ns(n/1960))-n)){e.timeoutHandle=Vr(Ac.bind(null,e),n);break}Ac(e);break;default:throw Error(i(329))}}return gc(e,Zo()),e.callbackNode===t?bc.bind(null,e):null}function vc(e,t){for(t&=~Hs,t&=~$s,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-Zt(t),r=1<<n;e[n]=-1,t&=~r}}function yc(e){if(0!=(48&As))throw Error(i(327));if(Dc(),e===Rs&&0!=(e.expiredLanes&Ds)){var t=Ds,n=Cc(e,t);0!=(Us&$s)&&(n=Cc(e,t=zt(e,t)))}else n=Cc(e,t=zt(e,0));if(0!==e.tag&&2===n&&(As|=64,e.hydrate&&(e.hydrate=!1,Wr(e.containerInfo)),0!==(t=Bt(e))&&(n=Cc(e,t))),1===n)throw n=Bs,Sc(e,0),vc(e,t),gc(e,Zo()),n;return e.finishedWork=e.current.alternate,e.finishedLanes=t,Ac(e),gc(e,Zo()),null}function kc(e,t){var n=As;As|=1;try{return e(t)}finally{0===(As=n)&&(Ws(),qo())}}function Ec(e,t){var n=As;As&=-2,As|=8;try{return e(t)}finally{0===(As=n)&&(Ws(),qo())}}function wc(e,t){po(Fs,Ms),Ms|=t,Us|=t}function xc(){Ms=Fs.current,uo(Fs)}function Sc(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,Qr(n)),null!==Ps)for(n=Ps.return;null!==n;){var r=n;switch(r.tag){case 1:null!=(r=r.type.childContextTypes)&&yo();break;case 3:Da(),uo(mo),uo(ho),Ya();break;case 5:Fa(r);break;case 4:Da();break;case 13:case 19:uo(za);break;case 10:oa(r);break;case 23:case 24:xc()}n=n.return}Rs=e,Ps=Qc(e.current,null),Ds=Ms=Us=t,zs=0,Bs=null,Hs=$s=js=0}function _c(e,t){for(;;){var n=Ps;try{if(ra(),Ka.current=Ai,ri){for(var r=ei.memoizedState;null!==r;){var o=r.queue;null!==o&&(o.pending=null),r=r.next}ri=!1}if(Ja=0,ni=ti=ei=null,oi=!1,Os.current=null,null===n||null===n.return){zs=1,Bs=t,Ps=null;break}e:{var a=e,i=n.return,s=n,c=t;if(t=Ds,s.flags|=2048,s.firstEffect=s.lastEffect=null,null!==c&&"object"==typeof c&&"function"==typeof c.then){var l=c;if(0==(2&s.mode)){var u=s.alternate;u?(s.updateQueue=u.updateQueue,s.memoizedState=u.memoizedState,s.lanes=u.lanes):(s.updateQueue=null,s.memoizedState=null)}var d=0!=(1&za.current),p=i;do{var f;if(f=13===p.tag){var h=p.memoizedState;if(null!==h)f=null!==h.dehydrated;else{var m=p.memoizedProps;f=void 0!==m.fallback&&(!0!==m.unstable_avoidThisFallback||!d)}}if(f){var g=p.updateQueue;if(null===g){var b=new Set;b.add(l),p.updateQueue=b}else g.add(l);if(0==(2&p.mode)){if(p.flags|=64,s.flags|=16384,s.flags&=-2981,1===s.tag)if(null===s.alternate)s.tag=17;else{var v=da(-1,1);v.tag=2,pa(s,v)}s.lanes|=1;break e}c=void 0,s=t;var y=a.pingCache;if(null===y?(y=a.pingCache=new ds,c=new Set,y.set(l,c)):void 0===(c=y.get(l))&&(c=new Set,y.set(l,c)),!c.has(s)){c.add(s);var k=jc.bind(null,a,l,s);l.then(k,k)}p.flags|=4096,p.lanes=t;break e}p=p.return}while(null!==p);c=Error((W(s.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.")}5!==zs&&(zs=2),c=ls(c,s),p=i;do{switch(p.tag){case 3:a=c,p.flags|=4096,t&=-t,p.lanes|=t,fa(p,ps(0,a,t));break e;case 1:a=c;var E=p.type,w=p.stateNode;if(0==(64&p.flags)&&("function"==typeof E.getDerivedStateFromError||null!==w&&"function"==typeof w.componentDidCatch&&(null===Xs||!Xs.has(w)))){p.flags|=4096,t&=-t,p.lanes|=t,fa(p,fs(p,a,t));break e}}p=p.return}while(null!==p)}Oc(n)}catch(x){t=x,Ps===n&&null!==n&&(Ps=n=n.return);continue}break}}function Tc(){var e=Is.current;return Is.current=Ai,null===e?Ai:e}function Cc(e,t){var n=As;As|=16;var r=Tc();for(Rs===e&&Ds===t||Sc(e,t);;)try{Lc();break}catch(o){_c(e,o)}if(ra(),As=n,Is.current=r,null!==Ps)throw Error(i(261));return Rs=null,Ds=0,zs}function Lc(){for(;null!==Ps;)Ic(Ps)}function Nc(){for(;null!==Ps&&!No();)Ic(Ps)}function Ic(e){var t=Gs(e.alternate,e,Ms);e.memoizedProps=e.pendingProps,null===t?Oc(e):Ps=t,Os.current=null}function Oc(e){var t=e;do{var n=t.alternate;if(e=t.return,0==(2048&t.flags)){if(null!==(n=ss(n,t,Ms)))return void(Ps=n);if(24!==(n=t).tag&&23!==n.tag||null===n.memoizedState||0!=(1073741824&Ms)||0==(4&n.mode)){for(var r=0,o=n.child;null!==o;)r|=o.lanes|o.childLanes,o=o.sibling;n.childLanes=r}null!==e&&0==(2048&e.flags)&&(null===e.firstEffect&&(e.firstEffect=t.firstEffect),null!==t.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=t.firstEffect),e.lastEffect=t.lastEffect),1<t.flags&&(null!==e.lastEffect?e.lastEffect.nextEffect=t:e.firstEffect=t,e.lastEffect=t))}else{if(null!==(n=cs(t)))return n.flags&=2047,void(Ps=n);null!==e&&(e.firstEffect=e.lastEffect=null,e.flags|=2048)}if(null!==(t=t.sibling))return void(Ps=t);Ps=t=e}while(null!==t);0===zs&&(zs=5)}function Ac(e){var t=Vo();return Wo(99,Rc.bind(null,e,t)),null}function Rc(e,t){do{Dc()}while(null!==ec);if(0!=(48&As))throw Error(i(327));var n=e.finishedWork;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(i(177));e.callbackNode=null;var r=n.lanes|n.childLanes,o=r,a=e.pendingLanes&~o;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=o,e.mutableReadLanes&=o,e.entangledLanes&=o,o=e.entanglements;for(var s=e.eventTimes,c=e.expirationTimes;0<a;){var l=31-Zt(a),u=1<<l;o[l]=0,s[l]=-1,c[l]=-1,a&=~u}if(null!==oc&&0==(24&r)&&oc.has(e)&&oc.delete(e),e===Rs&&(Ps=Rs=null,Ds=0),1<n.flags?null!==n.lastEffect?(n.lastEffect.nextEffect=n,r=n.firstEffect):r=n:r=n.firstEffect,null!==r){if(o=As,As|=32,Os.current=null,jr=qt,br(s=gr())){if("selectionStart"in s)c={start:s.selectionStart,end:s.selectionEnd};else e:if(c=(c=s.ownerDocument)&&c.defaultView||window,(u=c.getSelection&&c.getSelection())&&0!==u.rangeCount){c=u.anchorNode,a=u.anchorOffset,l=u.focusNode,u=u.focusOffset;try{c.nodeType,l.nodeType}catch(T){c=null;break e}var d=0,p=-1,f=-1,h=0,m=0,g=s,b=null;t:for(;;){for(var v;g!==c||0!==a&&3!==g.nodeType||(p=d+a),g!==l||0!==u&&3!==g.nodeType||(f=d+u),3===g.nodeType&&(d+=g.nodeValue.length),null!==(v=g.firstChild);)b=g,g=v;for(;;){if(g===s)break t;if(b===c&&++h===a&&(p=d),b===l&&++m===u&&(f=d),null!==(v=g.nextSibling))break;b=(g=b).parentNode}g=v}c=-1===p||-1===f?null:{start:p,end:f}}else c=null;c=c||{start:0,end:0}}else c=null;$r={focusedElem:s,selectionRange:c},qt=!1,uc=null,dc=!1,qs=r;do{try{Pc()}catch(T){if(null===qs)throw Error(i(330));Uc(qs,T),qs=qs.nextEffect}}while(null!==qs);uc=null,qs=r;do{try{for(s=e;null!==qs;){var y=qs.flags;if(16&y&&ve(qs.stateNode,""),128&y){var k=qs.alternate;if(null!==k){var E=k.ref;null!==E&&("function"==typeof E?E(null):E.current=null)}}switch(1038&y){case 2:ws(qs),qs.flags&=-3;break;case 6:ws(qs),qs.flags&=-3,Ts(qs.alternate,qs);break;case 1024:qs.flags&=-1025;break;case 1028:qs.flags&=-1025,Ts(qs.alternate,qs);break;case 4:Ts(qs.alternate,qs);break;case 8:_s(s,c=qs);var w=c.alternate;ks(c),null!==w&&ks(w)}qs=qs.nextEffect}}catch(T){if(null===qs)throw Error(i(330));Uc(qs,T),qs=qs.nextEffect}}while(null!==qs);if(E=$r,k=gr(),y=E.focusedElem,s=E.selectionRange,k!==y&&y&&y.ownerDocument&&mr(y.ownerDocument.documentElement,y)){null!==s&&br(y)&&(k=s.start,void 0===(E=s.end)&&(E=k),"selectionStart"in y?(y.selectionStart=k,y.selectionEnd=Math.min(E,y.value.length)):(E=(k=y.ownerDocument||document)&&k.defaultView||window).getSelection&&(E=E.getSelection(),c=y.textContent.length,w=Math.min(s.start,c),s=void 0===s.end?w:Math.min(s.end,c),!E.extend&&w>s&&(c=s,s=w,w=c),c=hr(y,w),a=hr(y,s),c&&a&&(1!==E.rangeCount||E.anchorNode!==c.node||E.anchorOffset!==c.offset||E.focusNode!==a.node||E.focusOffset!==a.offset)&&((k=k.createRange()).setStart(c.node,c.offset),E.removeAllRanges(),w>s?(E.addRange(k),E.extend(a.node,a.offset)):(k.setEnd(a.node,a.offset),E.addRange(k))))),k=[];for(E=y;E=E.parentNode;)1===E.nodeType&&k.push({element:E,left:E.scrollLeft,top:E.scrollTop});for("function"==typeof y.focus&&y.focus(),y=0;y<k.length;y++)(E=k[y]).element.scrollLeft=E.left,E.element.scrollTop=E.top}qt=!!jr,$r=jr=null,e.current=n,qs=r;do{try{for(y=e;null!==qs;){var x=qs.flags;if(36&x&&bs(y,qs.alternate,qs),128&x){k=void 0;var S=qs.ref;if(null!==S){var _=qs.stateNode;qs.tag,k=_,"function"==typeof S?S(k):S.current=k}}qs=qs.nextEffect}}catch(T){if(null===qs)throw Error(i(330));Uc(qs,T),qs=qs.nextEffect}}while(null!==qs);qs=null,Bo(),As=o}else e.current=n;if(Js)Js=!1,ec=e,tc=t;else for(qs=r;null!==qs;)t=qs.nextEffect,qs.nextEffect=null,8&qs.flags&&((x=qs).sibling=null,x.stateNode=null),qs=t;if(0===(r=e.pendingLanes)&&(Xs=null),1===r?e===ic?ac++:(ac=0,ic=e):ac=0,n=n.stateNode,_o&&"function"==typeof _o.onCommitFiberRoot)try{_o.onCommitFiberRoot(So,n,void 0,64==(64&n.current.flags))}catch(T){}if(gc(e,Zo()),Ys)throw Ys=!1,e=Ks,Ks=null,e;return 0!=(8&As)||qo(),null}function Pc(){for(;null!==qs;){var e=qs.alternate;dc||null===uc||(0!=(8&qs.flags)?et(qs,uc)&&(dc=!0):13===qs.tag&&Ls(e,qs)&&et(qs,uc)&&(dc=!0));var t=qs.flags;0!=(256&t)&&gs(e,qs),0==(512&t)||Js||(Js=!0,Go(97,(function(){return Dc(),null}))),qs=qs.nextEffect}}function Dc(){if(90!==tc){var e=97<tc?97:tc;return tc=90,Wo(e,zc)}return!1}function Mc(e,t){nc.push(t,e),Js||(Js=!0,Go(97,(function(){return Dc(),null})))}function Fc(e,t){rc.push(t,e),Js||(Js=!0,Go(97,(function(){return Dc(),null})))}function zc(){if(null===ec)return!1;var e=ec;if(ec=null,0!=(48&As))throw Error(i(331));var t=As;As|=32;var n=rc;rc=[];for(var r=0;r<n.length;r+=2){var o=n[r],a=n[r+1],s=o.destroy;if(o.destroy=void 0,"function"==typeof s)try{s()}catch(l){if(null===a)throw Error(i(330));Uc(a,l)}}for(n=nc,nc=[],r=0;r<n.length;r+=2){o=n[r],a=n[r+1];try{var c=o.create;o.destroy=c()}catch(l){if(null===a)throw Error(i(330));Uc(a,l)}}for(c=e.current.firstEffect;null!==c;)e=c.nextEffect,c.nextEffect=null,8&c.flags&&(c.sibling=null,c.stateNode=null),c=e;return As=t,qo(),!0}function Bc(e,t,n){pa(e,t=ps(0,t=ls(n,t),1)),t=pc(),null!==(e=mc(e,1))&&(Ht(e,1,t),gc(e,t))}function Uc(e,t){if(3===e.tag)Bc(e,e,t);else for(var n=e.return;null!==n;){if(3===n.tag){Bc(n,e,t);break}if(1===n.tag){var r=n.stateNode;if("function"==typeof n.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===Xs||!Xs.has(r))){var o=fs(n,e=ls(t,e),1);if(pa(n,o),o=pc(),null!==(n=mc(n,1)))Ht(n,1,o),gc(n,o);else if("function"==typeof r.componentDidCatch&&(null===Xs||!Xs.has(r)))try{r.componentDidCatch(t,e)}catch(a){}break}}n=n.return}}function jc(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),t=pc(),e.pingedLanes|=e.suspendedLanes&n,Rs===e&&(Ds&n)===n&&(4===zs||3===zs&&(62914560&Ds)===Ds&&500>Zo()-Vs?Sc(e,0):Hs|=n),gc(e,t)}function $c(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(0==(2&(t=e.mode))?t=1:0==(4&t)?t=99===Vo()?1:2:(0===cc&&(cc=Us),0===(t=jt(62914560&~cc))&&(t=4194304))),n=pc(),null!==(e=mc(e,t))&&(Ht(e,t,n),gc(e,n))}function Hc(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.flags=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childLanes=this.lanes=0,this.alternate=null}function Zc(e,t,n,r){return new Hc(e,t,n,r)}function Vc(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Qc(e,t){var n=e.alternate;return null===n?((n=Zc(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.nextEffect=null,n.firstEffect=null,n.lastEffect=null),n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Wc(e,t,n,r,o,a){var s=2;if(r=e,"function"==typeof e)Vc(e)&&(s=1);else if("string"==typeof e)s=5;else e:switch(e){case S:return Gc(n.children,o,a,t);case M:s=8,o|=16;break;case _:s=8,o|=1;break;case T:return(e=Zc(12,n,t,8|o)).elementType=T,e.type=T,e.lanes=a,e;case I:return(e=Zc(13,n,t,o)).type=I,e.elementType=I,e.lanes=a,e;case O:return(e=Zc(19,n,t,o)).elementType=O,e.lanes=a,e;case F:return qc(n,o,a,t);case z:return(e=Zc(24,n,t,o)).elementType=z,e.lanes=a,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case C:s=10;break e;case L:s=9;break e;case N:s=11;break e;case A:s=14;break e;case R:s=16,r=null;break e;case P:s=22;break e}throw Error(i(130,null==e?e:typeof e,""))}return(t=Zc(s,n,t,o)).elementType=e,t.type=r,t.lanes=a,t}function Gc(e,t,n,r){return(e=Zc(7,e,r,t)).lanes=n,e}function qc(e,t,n,r){return(e=Zc(23,e,r,t)).elementType=F,e.lanes=n,e}function Yc(e,t,n){return(e=Zc(6,e,null,t)).lanes=n,e}function Kc(e,t,n){return(t=Zc(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Xc(e,t,n){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=n,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=$t(0),this.expirationTimes=$t(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=$t(0),this.mutableSourceEagerHydrationData=null}function Jc(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:x,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}function el(e,t,n,r){var o=t.current,a=pc(),s=fc(o);e:if(n){t:{if(Ye(n=n._reactInternals)!==n||1!==n.tag)throw Error(i(170));var c=n;do{switch(c.tag){case 3:c=c.stateNode.context;break t;case 1:if(vo(c.type)){c=c.stateNode.__reactInternalMemoizedMergedChildContext;break t}}c=c.return}while(null!==c);throw Error(i(171))}if(1===n.tag){var l=n.type;if(vo(l)){n=Eo(n,l,c);break e}}n=c}else n=fo;return null===t.context?t.context=n:t.pendingContext=n,(t=da(a,s)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),pa(o,t),hc(o,s,a),s}function tl(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function nl(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function rl(e,t){nl(e,t),(e=e.alternate)&&nl(e,t)}function ol(e,t,n){var r=null!=n&&null!=n.hydrationOptions&&n.hydrationOptions.mutableSources||null;if(n=new Xc(e,t,null!=n&&!0===n.hydrate),t=Zc(3,null,null,2===t?7:1===t?3:0),n.current=t,t.stateNode=n,la(t),e[eo]=n.current,Ar(8===e.nodeType?e.parentNode:e),r)for(e=0;e<r.length;e++){var o=(t=r[e])._getVersion;o=o(t._source),null==n.mutableSourceEagerHydrationData?n.mutableSourceEagerHydrationData=[t,o]:n.mutableSourceEagerHydrationData.push(t,o)}this._internalRoot=n}function al(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function il(e,t,n,r,o){var a=n._reactRootContainer;if(a){var i=a._internalRoot;if("function"==typeof o){var s=o;o=function(){var e=tl(i);s.call(e)}}el(t,i,e,o)}else{if(a=n._reactRootContainer=function(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.firstChild:null)||1!==t.nodeType||!t.hasAttribute("data-reactroot"))),!t)for(var n;n=e.lastChild;)e.removeChild(n);return new ol(e,0,t?{hydrate:!0}:void 0)}(n,r),i=a._internalRoot,"function"==typeof o){var c=o;o=function(){var e=tl(i);c.call(e)}}Ec((function(){el(t,i,e,o)}))}return tl(i)}function sl(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!al(t))throw Error(i(200));return Jc(e,t,null,n)}Gs=function(e,t,n){var r=t.lanes;if(null!==e)if(e.memoizedProps!==t.pendingProps||mo.current)Fi=!0;else{if(0==(n&r)){switch(Fi=!1,t.tag){case 3:Wi(t),Ga();break;case 5:Ma(t);break;case 1:vo(t.type)&&wo(t);break;case 4:Pa(t,t.stateNode.containerInfo);break;case 10:r=t.memoizedProps.value;var o=t.type._context;po(Jo,o._currentValue),o._currentValue=r;break;case 13:if(null!==t.memoizedState)return 0!=(n&t.child.childLanes)?Xi(e,t,n):(po(za,1&za.current),null!==(t=as(e,t,n))?t.sibling:null);po(za,1&za.current);break;case 19:if(r=0!=(n&t.childLanes),0!=(64&e.flags)){if(r)return os(e,t,n);t.flags|=64}if(null!==(o=t.memoizedState)&&(o.rendering=null,o.tail=null,o.lastEffect=null),po(za,za.current),r)break;return null;case 23:case 24:return t.lanes=0,$i(e,t,n)}return as(e,t,n)}Fi=0!=(16384&e.flags)}else Fi=!1;switch(t.lanes=0,t.tag){case 2:if(r=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,o=bo(t,ho.current),ia(t,n),o=si(null,t,r,e,o,n),t.flags|=1,"object"==typeof o&&null!==o&&"function"==typeof o.render&&void 0===o.$$typeof){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,vo(r)){var a=!0;wo(t)}else a=!1;t.memoizedState=null!==o.state&&void 0!==o.state?o.state:null,la(t);var s=r.getDerivedStateFromProps;"function"==typeof s&&ba(t,r,s,e),o.updater=va,t.stateNode=o,o._reactInternals=t,wa(t,r,e,n),t=Qi(null,t,r,!0,a,n)}else t.tag=0,zi(null,t,o,n),t=t.child;return t;case 16:o=t.elementType;e:{switch(null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,o=(a=o._init)(o._payload),t.type=o,a=t.tag=function(e){if("function"==typeof e)return Vc(e)?1:0;if(null!=e){if((e=e.$$typeof)===N)return 11;if(e===A)return 14}return 2}(o),e=Xo(o,e),a){case 0:t=Zi(null,t,o,e,n);break e;case 1:t=Vi(null,t,o,e,n);break e;case 11:t=Bi(null,t,o,e,n);break e;case 14:t=Ui(null,t,o,Xo(o.type,e),r,n);break e}throw Error(i(306,o,""))}return t;case 0:return r=t.type,o=t.pendingProps,Zi(e,t,r,o=t.elementType===r?o:Xo(r,o),n);case 1:return r=t.type,o=t.pendingProps,Vi(e,t,r,o=t.elementType===r?o:Xo(r,o),n);case 3:if(Wi(t),r=t.updateQueue,null===e||null===r)throw Error(i(282));if(r=t.pendingProps,o=null!==(o=t.memoizedState)?o.element:null,ua(e,t),ha(t,r,null,n),(r=t.memoizedState.element)===o)Ga(),t=as(e,t,n);else{if((a=(o=t.stateNode).hydrate)&&(ja=Gr(t.stateNode.containerInfo.firstChild),Ua=t,a=$a=!0),a){if(null!=(e=o.mutableSourceEagerHydrationData))for(o=0;o<e.length;o+=2)(a=e[o])._workInProgressVersionPrimary=e[o+1],qa.push(a);for(n=La(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|1024,n=n.sibling}else zi(e,t,r,n),Ga();t=t.child}return t;case 5:return Ma(t),null===e&&Va(t),r=t.type,o=t.pendingProps,a=null!==e?e.memoizedProps:null,s=o.children,Zr(r,o)?s=null:null!==a&&Zr(r,a)&&(t.flags|=16),Hi(e,t),zi(e,t,s,n),t.child;case 6:return null===e&&Va(t),null;case 13:return Xi(e,t,n);case 4:return Pa(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=Ca(t,null,r,n):zi(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,Bi(e,t,r,o=t.elementType===r?o:Xo(r,o),n);case 7:return zi(e,t,t.pendingProps,n),t.child;case 8:case 12:return zi(e,t,t.pendingProps.children,n),t.child;case 10:e:{r=t.type._context,o=t.pendingProps,s=t.memoizedProps,a=o.value;var c=t.type._context;if(po(Jo,c._currentValue),c._currentValue=a,null!==s)if(c=s.value,0===(a=ur(c,a)?0:0|("function"==typeof r._calculateChangedBits?r._calculateChangedBits(c,a):1073741823))){if(s.children===o.children&&!mo.current){t=as(e,t,n);break e}}else for(null!==(c=t.child)&&(c.return=t);null!==c;){var l=c.dependencies;if(null!==l){s=c.child;for(var u=l.firstContext;null!==u;){if(u.context===r&&0!=(u.observedBits&a)){1===c.tag&&((u=da(-1,n&-n)).tag=2,pa(c,u)),c.lanes|=n,null!==(u=c.alternate)&&(u.lanes|=n),aa(c.return,n),l.lanes|=n;break}u=u.next}}else s=10===c.tag&&c.type===t.type?null:c.child;if(null!==s)s.return=c;else for(s=c;null!==s;){if(s===t){s=null;break}if(null!==(c=s.sibling)){c.return=s.return,s=c;break}s=s.return}c=s}zi(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=(a=t.pendingProps).children,ia(t,n),r=r(o=sa(o,a.unstable_observedBits)),t.flags|=1,zi(e,t,r,n),t.child;case 14:return a=Xo(o=t.type,t.pendingProps),Ui(e,t,o,a=Xo(o.type,a),r,n);case 15:return ji(e,t,t.type,t.pendingProps,r,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Xo(r,o),null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),t.tag=1,vo(r)?(e=!0,wo(t)):e=!1,ia(t,n),ka(t,r,o),wa(t,r,o,n),Qi(null,t,r,!0,e,n);case 19:return os(e,t,n);case 23:case 24:return $i(e,t,n)}throw Error(i(156,t.tag))},ol.prototype.render=function(e){el(e,this._internalRoot,null,null)},ol.prototype.unmount=function(){var e=this._internalRoot,t=e.containerInfo;el(null,e,null,(function(){t[eo]=null}))},tt=function(e){13===e.tag&&(hc(e,4,pc()),rl(e,4))},nt=function(e){13===e.tag&&(hc(e,67108864,pc()),rl(e,67108864))},rt=function(e){if(13===e.tag){var t=pc(),n=fc(e);hc(e,n,t),rl(e,n)}},ot=function(e,t){return t()},Ce=function(e,t,n){switch(t){case"input":if(ne(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var o=ao(r);if(!o)throw Error(i(90));K(r),ne(r,o)}}}break;case"textarea":le(e,n);break;case"select":null!=(t=n.value)&&ie(e,!!n.multiple,t,!1)}},Re=kc,Pe=function(e,t,n,r,o){var a=As;As|=4;try{return Wo(98,e.bind(null,t,n,r,o))}finally{0===(As=a)&&(Ws(),qo())}},De=function(){0==(49&As)&&(function(){if(null!==oc){var e=oc;oc=null,e.forEach((function(e){e.expiredLanes|=24&e.pendingLanes,gc(e,Zo())}))}qo()}(),Dc())},Me=function(e,t){var n=As;As|=2;try{return e(t)}finally{0===(As=n)&&(Ws(),qo())}};var cl={Events:[ro,oo,ao,Oe,Ae,Dc,{current:!1}]},ll={findFiberByHostInstance:no,bundleType:0,version:"17.0.2",rendererPackageName:"react-dom"},ul={bundleType:ll.bundleType,version:ll.version,rendererPackageName:ll.rendererPackageName,rendererConfig:ll.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:E.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=Je(e))?null:e.stateNode},findFiberByHostInstance:ll.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var dl=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!dl.isDisabled&&dl.supportsFiber)try{So=dl.inject(ul),_o=dl}catch(ge){}}t.hydrate=function(e,t,n){if(!al(t))throw Error(i(200));return il(null,e,t,!0,n)}},3935:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(4448)},9590:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,o="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function a(e,i){if(e===i)return!0;if(e&&i&&"object"==typeof e&&"object"==typeof i){if(e.constructor!==i.constructor)return!1;var s,c,l,u;if(Array.isArray(e)){if((s=e.length)!=i.length)return!1;for(c=s;0!=c--;)if(!a(e[c],i[c]))return!1;return!0}if(n&&e instanceof Map&&i instanceof Map){if(e.size!==i.size)return!1;for(u=e.entries();!(c=u.next()).done;)if(!i.has(c.value[0]))return!1;for(u=e.entries();!(c=u.next()).done;)if(!a(c.value[1],i.get(c.value[0])))return!1;return!0}if(r&&e instanceof Set&&i instanceof Set){if(e.size!==i.size)return!1;for(u=e.entries();!(c=u.next()).done;)if(!i.has(c.value[0]))return!1;return!0}if(o&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(i)){if((s=e.length)!=i.length)return!1;for(c=s;0!=c--;)if(e[c]!==i[c])return!1;return!0}if(e.constructor===RegExp)return e.source===i.source&&e.flags===i.flags;if(e.valueOf!==Object.prototype.valueOf)return e.valueOf()===i.valueOf();if(e.toString!==Object.prototype.toString)return e.toString()===i.toString();if((s=(l=Object.keys(e)).length)!==Object.keys(i).length)return!1;for(c=s;0!=c--;)if(!Object.prototype.hasOwnProperty.call(i,l[c]))return!1;if(t&&e instanceof Element)return!1;for(c=s;0!=c--;)if(("_owner"!==l[c]&&"__v"!==l[c]&&"__o"!==l[c]||!e.$$typeof)&&!a(e[l[c]],i[l[c]]))return!1;return!0}return e!=e&&i!=i}e.exports=function(e,t){try{return a(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},405:(e,t,n)=>{"use strict";n.d(t,{B6:()=>V,ql:()=>J});var r=n(7294),o=n(5697),a=n.n(o),i=n(9590),s=n.n(i),c=n(1143),l=n.n(c),u=n(6774),d=n.n(u);function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},p.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,h(e,t)}function h(e,t){return h=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},h(e,t)}function m(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)t.indexOf(n=a[r])>=0||(o[n]=e[n]);return o}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},v={type:["application/ld+json"]},y={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},k=Object.keys(g).map((function(e){return g[e]})),E={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},w=Object.keys(E).reduce((function(e,t){return e[E[t]]=t,e}),{}),x=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},S=function(e){var t=x(e,g.TITLE),n=x(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=x(e,"defaultTitle");return t||r||void 0},_=function(e){return x(e,"onChangeClientState")||function(){}},T=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},C=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),o=0;o<r.length;o+=1){var a=r[o].toLowerCase();if(-1!==e.indexOf(a)&&n[a])return t.concat(n)}return t}),[])},L=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var o={};n.filter((function(e){for(var n,a=Object.keys(e),i=0;i<a.length;i+=1){var s=a[i],c=s.toLowerCase();-1===t.indexOf(c)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===c&&"stylesheet"===e[c].toLowerCase()||(n=c),-1===t.indexOf(s)||"innerHTML"!==s&&"cssText"!==s&&"itemprop"!==s||(n=s)}if(!n||!e[n])return!1;var l=e[n].toLowerCase();return r[n]||(r[n]={}),o[n]||(o[n]={}),!r[n][l]&&(o[n][l]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var a=Object.keys(o),i=0;i<a.length;i+=1){var s=a[i],c=p({},r[s],o[s]);r[s]=c}return e}),[]).reverse()},N=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},I=function(e){return Array.isArray(e)?e.join(""):e},O=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},A=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},R=[g.NOSCRIPT,g.SCRIPT,g.STYLE],P=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},D=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},M=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[E[n]||n]=e[n],t}),t)},F=function(e,t){return t.map((function(t,n){var o,a=((o={key:n})["data-rh"]=!0,o);return Object.keys(t).forEach((function(e){var n=E[e]||e;"innerHTML"===n||"cssText"===n?a.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:a[n]=t[e]})),r.createElement(e,a)}))},z=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(o={key:e=t.title})["data-rh"]=!0,a=M(n,o),[r.createElement(g.TITLE,a,e)];var e,n,o,a},toString:function(){return function(e,t,n,r){var o=D(n),a=I(t);return o?"<"+e+' data-rh="true" '+o+">"+P(a,r)+"</"+e+">":"<"+e+' data-rh="true">'+P(a,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return M(t)},toString:function(){return D(t)}};default:return{toComponent:function(){return F(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var o=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var o=void 0===r[t]?t:t+'="'+P(r[t],n)+'"';return e?e+" "+o:o}),""),a=r.innerHTML||r.cssText||"",i=-1===R.indexOf(e);return t+"<"+e+' data-rh="true" '+o+(i?"/>":">"+a+"</"+e+">")}),"")}(e,t,n)}}}},B=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,o=e.htmlAttributes,a=e.noscriptTags,i=e.styleTags,s=e.title,c=void 0===s?"":s,l=e.titleAttributes,u=e.linkTags,d=e.metaTags,p=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var h=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,o=O(e.metaTags,y),a=O(t,b),i=O(n,v);return{priorityMethods:{toComponent:function(){return[].concat(F(g.META,o.priority),F(g.LINK,a.priority),F(g.SCRIPT,i.priority))},toString:function(){return z(g.META,o.priority,r)+" "+z(g.LINK,a.priority,r)+" "+z(g.SCRIPT,i.priority,r)}},metaTags:o.default,linkTags:a.default,scriptTags:i.default}}(e);f=h.priorityMethods,u=h.linkTags,d=h.metaTags,p=h.scriptTags}return{priority:f,base:z(g.BASE,t,r),bodyAttributes:z("bodyAttributes",n,r),htmlAttributes:z("htmlAttributes",o,r),link:z(g.LINK,u,r),meta:z(g.META,d,r),noscript:z(g.NOSCRIPT,a,r),script:z(g.SCRIPT,p,r),style:z(g.STYLE,i,r),title:z(g.TITLE,{title:c,titleAttributes:l},r)}},U=[],j=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?U:n.instances},add:function(e){(n.canUseDOM?U:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?U:n.instances).indexOf(e);(n.canUseDOM?U:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=B({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},$=r.createContext({}),H=a().shape({setHelmet:a().func,helmetInstances:a().shape({get:a().func,add:a().func,remove:a().func})}),Z="undefined"!=typeof document,V=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new j(r.props.context,t.canUseDOM),r}return f(t,e),t.prototype.render=function(){return r.createElement($.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);V.canUseDOM=Z,V.propTypes={context:a().shape({helmet:a().shape()}),children:a().node.isRequired},V.defaultProps={context:{}},V.displayName="HelmetProvider";var Q=function(e,t){var n,r=document.head||document.querySelector(g.HEAD),o=r.querySelectorAll(e+"[data-rh]"),a=[].slice.call(o),i=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&("innerHTML"===o?r.innerHTML=t.innerHTML:"cssText"===o?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(o,void 0===t[o]?"":t[o]));r.setAttribute("data-rh","true"),a.some((function(e,t){return n=t,r.isEqualNode(e)}))?a.splice(n,1):i.push(r)})),a.forEach((function(e){return e.parentNode.removeChild(e)})),i.forEach((function(e){return r.appendChild(e)})),{oldTags:a,newTags:i}},W=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),o=r?r.split(","):[],a=[].concat(o),i=Object.keys(t),s=0;s<i.length;s+=1){var c=i[s],l=t[c]||"";n.getAttribute(c)!==l&&n.setAttribute(c,l),-1===o.indexOf(c)&&o.push(c);var u=a.indexOf(c);-1!==u&&a.splice(u,1)}for(var d=a.length-1;d>=0;d-=1)n.removeAttribute(a[d]);o.length===a.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==i.join(",")&&n.setAttribute("data-rh",i.join(","))}},G=function(e,t){var n=e.baseTag,r=e.htmlAttributes,o=e.linkTags,a=e.metaTags,i=e.noscriptTags,s=e.onChangeClientState,c=e.scriptTags,l=e.styleTags,u=e.title,d=e.titleAttributes;W(g.BODY,e.bodyAttributes),W(g.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=I(e)),W(g.TITLE,t)}(u,d);var p={baseTag:Q(g.BASE,n),linkTags:Q(g.LINK,o),metaTags:Q(g.META,a),noscriptTags:Q(g.NOSCRIPT,i),scriptTags:Q(g.SCRIPT,c),styleTags:Q(g.STYLE,l)},f={},h={};Object.keys(p).forEach((function(e){var t=p[e],n=t.newTags,r=t.oldTags;n.length&&(f[e]=n),r.length&&(h[e]=p[e].oldTags)})),t&&t(),s(e,f,h)},q=null,Y=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,o=null,a=(e=n.helmetInstances.get().map((function(e){var t=p({},e.props);return delete t.context,t})),{baseTag:C(["href"],e),bodyAttributes:T("bodyAttributes",e),defer:x(e,"defer"),encode:x(e,"encodeSpecialCharacters"),htmlAttributes:T("htmlAttributes",e),linkTags:L(g.LINK,["rel","href"],e),metaTags:L(g.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:L(g.NOSCRIPT,["innerHTML"],e),onChangeClientState:_(e),scriptTags:L(g.SCRIPT,["src","innerHTML"],e),styleTags:L(g.STYLE,["cssText"],e),title:S(e),titleAttributes:T("titleAttributes",e),prioritizeSeoTags:N(e,"prioritizeSeoTags")});V.canUseDOM?(t=a,q&&cancelAnimationFrame(q),t.defer?q=requestAnimationFrame((function(){G(t,(function(){q=null}))})):(G(t),q=null)):B&&(o=B(a)),r(o)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);Y.propTypes={context:H.isRequired},Y.displayName="HelmetDispatcher";var K=["children"],X=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!s()(A(this.props,"helmetData"),A(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:t};case g.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return p({},r,((t={})[n.type]=[].concat(r[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,o=e.newProps,a=e.newChildProps,i=e.nestedChildren;switch(r.type){case g.TITLE:return p({},o,((t={})[r.type]=i,t.titleAttributes=p({},a),t));case g.BODY:return p({},o,{bodyAttributes:p({},a)});case g.HTML:return p({},o,{htmlAttributes:p({},a)});default:return p({},o,((n={})[r.type]=p({},a),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var r;n=p({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return l()(k.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+k.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),l()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,o={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,a=r.children,i=m(r,K),s=Object.keys(i).reduce((function(e,t){return e[w[t]||t]=i[t],e}),{}),c=e.type;switch("symbol"==typeof c?c=c.toString():n.warnOnInvalidChildren(e,a),c){case g.FRAGMENT:t=n.mapChildrenToProps(a,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:o=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:o,newChildProps:s,nestedChildren:a});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:s,nestedChildren:a})}}})),this.mapArrayTypeChildrenToProps(o,t)},n.render=function(){var e=this.props,t=e.children,n=m(e,X),o=p({},n),a=n.helmetData;return t&&(o=this.mapChildrenToProps(t,o)),!a||a instanceof j||(a=new j(a.context,a.instances)),a?r.createElement(Y,p({},o,{context:a.value,helmetData:void 0})):r.createElement($.Consumer,null,(function(e){return r.createElement(Y,p({},o,{context:e}))}))},t}(r.Component);J.propTypes={base:a().object,bodyAttributes:a().object,children:a().oneOfType([a().arrayOf(a().node),a().node]),defaultTitle:a().string,defer:a().bool,encodeSpecialCharacters:a().bool,htmlAttributes:a().object,link:a().arrayOf(a().object),meta:a().arrayOf(a().object),noscript:a().arrayOf(a().object),onChangeClientState:a().func,script:a().arrayOf(a().object),style:a().arrayOf(a().object),title:a().string,titleAttributes:a().object,titleTemplate:a().string,prioritizeSeoTags:a().bool,helmetData:a().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},9921:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,o=n?Symbol.for("react.portal"):60106,a=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,s=n?Symbol.for("react.profiler"):60114,c=n?Symbol.for("react.provider"):60109,l=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,h=n?Symbol.for("react.suspense_list"):60120,m=n?Symbol.for("react.memo"):60115,g=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,k=n?Symbol.for("react.scope"):60119;function E(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case a:case s:case i:case f:return e;default:switch(e=e&&e.$$typeof){case l:case p:case g:case m:case c:return e;default:return t}}case o:return t}}}function w(e){return E(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=l,t.ContextProvider=c,t.Element=r,t.ForwardRef=p,t.Fragment=a,t.Lazy=g,t.Memo=m,t.Portal=o,t.Profiler=s,t.StrictMode=i,t.Suspense=f,t.isAsyncMode=function(e){return w(e)||E(e)===u},t.isConcurrentMode=w,t.isContextConsumer=function(e){return E(e)===l},t.isContextProvider=function(e){return E(e)===c},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return E(e)===p},t.isFragment=function(e){return E(e)===a},t.isLazy=function(e){return E(e)===g},t.isMemo=function(e){return E(e)===m},t.isPortal=function(e){return E(e)===o},t.isProfiler=function(e){return E(e)===s},t.isStrictMode=function(e){return E(e)===i},t.isSuspense=function(e){return E(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===a||e===d||e===s||e===i||e===f||e===h||"object"==typeof e&&null!==e&&(e.$$typeof===g||e.$$typeof===m||e.$$typeof===c||e.$$typeof===l||e.$$typeof===p||e.$$typeof===v||e.$$typeof===y||e.$$typeof===k||e.$$typeof===b)},t.typeOf=E},9864:(e,t,n)=>{"use strict";e.exports=n(9921)},8356:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function o(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(){return i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},i.apply(this,arguments)}var s=n(7294),c=n(5697),l=[],u=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function p(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var o=d(e[r]);o.loading?t.loading=!0:(t.loaded[r]=o.loaded,t.error=o.error),n.push(o.promise),o.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return s.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function h(e,t){var d,p;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var h=i({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),m=null;function g(){return m||(m=e(h.loader)),m.promise}return l.push(g),"function"==typeof h.webpack&&u.push((function(){if((0,h.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return g()})),p=d=function(t){function n(n){var r;return a(o(o(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),m=e(h.loader),r._loadModule()})),g(),r.state={error:m.error,pastDelay:!1,timedOut:!1,loading:m.loading,loaded:m.loaded},r}r(n,t),n.preload=function(){return g()};var i=n.prototype;return i.UNSAFE_componentWillMount=function(){this._loadModule()},i.componentDidMount=function(){this._mounted=!0},i._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(h.modules)&&h.modules.forEach((function(t){e.context.loadable.report(t)})),m.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof h.delay&&(0===h.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),h.delay)),"number"==typeof h.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),h.timeout));var n=function(){t({error:m.error,loaded:m.loaded,loading:m.loading}),e._clearTimeouts()};m.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},i.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},i._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},i.render=function(){return this.state.loading||this.state.error?s.createElement(h.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?h.render(this.state.loaded,this.props):null},n}(s.Component),a(d,"contextTypes",{loadable:c.shape({report:c.func.isRequired})}),p}function m(e){return h(d,e)}m.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return h(p,e)};var g=function(e){function t(){return e.apply(this,arguments)||this}r(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return s.Children.only(this.props.children)},t}(s.Component);function b(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return b(e)}))}a(g,"propTypes",{report:c.func.isRequired}),a(g,"childContextTypes",{loadable:c.shape({report:c.func.isRequired}).isRequired}),m.Capture=g,m.preloadAll=function(){return new Promise((function(e,t){b(l).then(e,t)}))},m.preloadReady=function(){return new Promise((function(e,t){b(u).then(e,e)}))},e.exports=m},8790:(e,t,n)=>{"use strict";n.d(t,{H:()=>s,f:()=>i});var r=n(6775),o=n(7462),a=n(7294);function i(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var o=e.path?(0,r.LX)(t,e):n.length?n[n.length-1].match:r.F0.computeRootMatch(t);return o&&(n.push({route:e,match:o}),e.routes&&i(e.routes,t,n)),o})),n}function s(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?a.createElement(r.rs,n,e.map((function(e,n){return a.createElement(r.AW,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,o.Z)({},n,{},t,{route:e})):a.createElement(e.component,(0,o.Z)({},n,t,{route:e}))}})}))):null}},3727:(e,t,n)=>{"use strict";n.d(t,{OL:()=>y,VK:()=>u,rU:()=>g});var r=n(6775),o=n(5068),a=n(7294),i=n(9318),s=n(7462),c=n(3366),l=n(2177),u=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,i.lX)(t.props),t}return(0,o.Z)(t,e),t.prototype.render=function(){return a.createElement(r.F0,{history:this.history,children:this.props.children})},t}(a.Component);a.Component;var d=function(e,t){return"function"==typeof e?e(t):e},p=function(e,t){return"string"==typeof e?(0,i.ob)(e,null,null,t):e},f=function(e){return e},h=a.forwardRef;void 0===h&&(h=f);var m=h((function(e,t){var n=e.innerRef,r=e.navigate,o=e.onClick,i=(0,c.Z)(e,["innerRef","navigate","onClick"]),l=i.target,u=(0,s.Z)({},i,{onClick:function(e){try{o&&o(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||l&&"_self"!==l||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return u.ref=f!==h&&t||n,a.createElement("a",u)}));var g=h((function(e,t){var n=e.component,o=void 0===n?m:n,u=e.replace,g=e.to,b=e.innerRef,v=(0,c.Z)(e,["component","replace","to","innerRef"]);return a.createElement(r.s6.Consumer,null,(function(e){e||(0,l.Z)(!1);var n=e.history,r=p(d(g,e.location),e.location),c=r?n.createHref(r):"",m=(0,s.Z)({},v,{href:c,navigate:function(){var t=d(g,e.location),r=(0,i.Ep)(e.location)===(0,i.Ep)(p(t));(u||r?n.replace:n.push)(t)}});return f!==h?m.ref=t||b:m.innerRef=b,a.createElement(o,m)}))})),b=function(e){return e},v=a.forwardRef;void 0===v&&(v=b);var y=v((function(e,t){var n=e["aria-current"],o=void 0===n?"page":n,i=e.activeClassName,u=void 0===i?"active":i,f=e.activeStyle,h=e.className,m=e.exact,y=e.isActive,k=e.location,E=e.sensitive,w=e.strict,x=e.style,S=e.to,_=e.innerRef,T=(0,c.Z)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return a.createElement(r.s6.Consumer,null,(function(e){e||(0,l.Z)(!1);var n=k||e.location,i=p(d(S,n),n),c=i.pathname,C=c&&c.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),L=C?(0,r.LX)(n.pathname,{path:C,exact:m,sensitive:E,strict:w}):null,N=!!(y?y(L,n):L),I="function"==typeof h?h(N):h,O="function"==typeof x?x(N):x;N&&(I=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(I,u),O=(0,s.Z)({},O,f));var A=(0,s.Z)({"aria-current":N&&o||null,className:I,style:O,to:i},T);return b!==v?A.ref=t||_:A.innerRef=_,a.createElement(g,A)}))}))},6775:(e,t,n)=>{"use strict";n.d(t,{AW:()=>_,F0:()=>E,rs:()=>O,s6:()=>k,LX:()=>S,k6:()=>R,TH:()=>P});var r=n(5068),o=n(7294),a=n(9318),i=n(5697),s=n.n(i),c=1073741823,l="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};function u(e){var t=[];return{on:function(e){t.push(e)},off:function(e){t=t.filter((function(t){return t!==e}))},get:function(){return e},set:function(n,r){e=n,t.forEach((function(t){return t(e,r)}))}}}var d=o.createContext||function(e,t){var n,a,i="__create-react-context-"+function(){var e="__global_unique_id__";return l[e]=(l[e]||0)+1}()+"__",d=function(e){function n(){var t;return(t=e.apply(this,arguments)||this).emitter=u(t.props.value),t}(0,r.Z)(n,e);var o=n.prototype;return o.getChildContext=function(){var e;return(e={})[i]=this.emitter,e},o.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,o=e.value;((a=r)===(i=o)?0!==a||1/a==1/i:a!=a&&i!=i)?n=0:(n="function"==typeof t?t(r,o):c,0!==(n|=0)&&this.emitter.set(e.value,n))}var a,i},o.render=function(){return this.props.children},n}(o.Component);d.childContextTypes=((n={})[i]=s().object.isRequired,n);var p=function(t){function n(){var e;return(e=t.apply(this,arguments)||this).state={value:e.getValue()},e.onUpdate=function(t,n){0!=((0|e.observedBits)&n)&&e.setState({value:e.getValue()})},e}(0,r.Z)(n,t);var o=n.prototype;return o.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?c:t},o.componentDidMount=function(){this.context[i]&&this.context[i].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?c:e},o.componentWillUnmount=function(){this.context[i]&&this.context[i].off(this.onUpdate)},o.getValue=function(){return this.context[i]?this.context[i].get():e},o.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(o.Component);return p.contextTypes=((a={})[i]=s().object,a),{Provider:d,Consumer:p}};const p=d;var f=n(2177),h=n(7462),m=n(4779),g=n.n(m),b=(n(9864),n(3366)),v=(n(8679),function(e){var t=p();return t.displayName=e,t}),y=v("Router-History"),k=v("Router"),E=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.Z)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return o.createElement(k.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},o.createElement(y.Provider,{children:this.props.children||null,value:this.props.history}))},t}(o.Component);o.Component;o.Component;var w={},x=0;function S(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,o=n.exact,a=void 0!==o&&o,i=n.strict,s=void 0!==i&&i,c=n.sensitive,l=void 0!==c&&c;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=w[n]||(w[n]={});if(r[e])return r[e];var o=[],a={regexp:g()(e,o,t),keys:o};return x<1e4&&(r[e]=a,x++),a}(n,{end:a,strict:s,sensitive:l}),o=r.regexp,i=r.keys,c=o.exec(e);if(!c)return null;var u=c[0],d=c.slice(1),p=e===u;return a&&!p?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:p,params:i.reduce((function(e,t,n){return e[t.name]=d[n],e}),{})}}),null)}var _=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return o.createElement(k.Consumer,null,(function(t){t||(0,f.Z)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?S(n.pathname,e.props):t.match,a=(0,h.Z)({},t,{location:n,match:r}),i=e.props,s=i.children,c=i.component,l=i.render;return Array.isArray(s)&&function(e){return 0===o.Children.count(e)}(s)&&(s=null),o.createElement(k.Provider,{value:a},a.match?s?"function"==typeof s?s(a):s:c?o.createElement(c,a):l?l(a):null:"function"==typeof s?s(a):null)}))},t}(o.Component);function T(e){return"/"===e.charAt(0)?e:"/"+e}function C(e,t){if(!e)return t;var n=T(e);return 0!==t.pathname.indexOf(n)?t:(0,h.Z)({},t,{pathname:t.pathname.substr(n.length)})}function L(e){return"string"==typeof e?e:(0,a.Ep)(e)}function N(e){return function(){(0,f.Z)(!1)}}function I(){}o.Component;var O=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return o.createElement(k.Consumer,null,(function(t){t||(0,f.Z)(!1);var n,r,a=e.props.location||t.location;return o.Children.forEach(e.props.children,(function(e){if(null==r&&o.isValidElement(e)){n=e;var i=e.props.path||e.props.from;r=i?S(a.pathname,(0,h.Z)({},e.props,{path:i})):t.match}})),r?o.cloneElement(n,{location:a,computedMatch:r}):null}))},t}(o.Component);var A=o.useContext;function R(){return A(y)}function P(){return A(k).location}},2408:(e,t,n)=>{"use strict";var r=n(7418),o=60103,a=60106;t.Fragment=60107,t.StrictMode=60108,t.Profiler=60114;var i=60109,s=60110,c=60112;t.Suspense=60113;var l=60115,u=60116;if("function"==typeof Symbol&&Symbol.for){var d=Symbol.for;o=d("react.element"),a=d("react.portal"),t.Fragment=d("react.fragment"),t.StrictMode=d("react.strict_mode"),t.Profiler=d("react.profiler"),i=d("react.provider"),s=d("react.context"),c=d("react.forward_ref"),t.Suspense=d("react.suspense"),l=d("react.memo"),u=d("react.lazy")}var p="function"==typeof Symbol&&Symbol.iterator;function f(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},m={};function g(e,t,n){this.props=e,this.context=t,this.refs=m,this.updater=n||h}function b(){}function v(e,t,n){this.props=e,this.context=t,this.refs=m,this.updater=n||h}g.prototype.isReactComponent={},g.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(f(85));this.updater.enqueueSetState(this,e,t,"setState")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=g.prototype;var y=v.prototype=new b;y.constructor=v,r(y,g.prototype),y.isPureReactComponent=!0;var k={current:null},E=Object.prototype.hasOwnProperty,w={key:!0,ref:!0,__self:!0,__source:!0};function x(e,t,n){var r,a={},i=null,s=null;if(null!=t)for(r in void 0!==t.ref&&(s=t.ref),void 0!==t.key&&(i=""+t.key),t)E.call(t,r)&&!w.hasOwnProperty(r)&&(a[r]=t[r]);var c=arguments.length-2;if(1===c)a.children=n;else if(1<c){for(var l=Array(c),u=0;u<c;u++)l[u]=arguments[u+2];a.children=l}if(e&&e.defaultProps)for(r in c=e.defaultProps)void 0===a[r]&&(a[r]=c[r]);return{$$typeof:o,type:e,key:i,ref:s,props:a,_owner:k.current}}function S(e){return"object"==typeof e&&null!==e&&e.$$typeof===o}var _=/\/+/g;function T(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function C(e,t,n,r,i){var s=typeof e;"undefined"!==s&&"boolean"!==s||(e=null);var c=!1;if(null===e)c=!0;else switch(s){case"string":case"number":c=!0;break;case"object":switch(e.$$typeof){case o:case a:c=!0}}if(c)return i=i(c=e),e=""===r?"."+T(c,0):r,Array.isArray(i)?(n="",null!=e&&(n=e.replace(_,"$&/")+"/"),C(i,t,n,"",(function(e){return e}))):null!=i&&(S(i)&&(i=function(e,t){return{$$typeof:o,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(i,n+(!i.key||c&&c.key===i.key?"":(""+i.key).replace(_,"$&/")+"/")+e)),t.push(i)),1;if(c=0,r=""===r?".":r+":",Array.isArray(e))for(var l=0;l<e.length;l++){var u=r+T(s=e[l],l);c+=C(s,t,n,u,i)}else if(u=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=p&&e[p]||e["@@iterator"])?e:null}(e),"function"==typeof u)for(e=u.call(e),l=0;!(s=e.next()).done;)c+=C(s=s.value,t,n,u=r+T(s,l++),i);else if("object"===s)throw t=""+e,Error(f(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t));return c}function L(e,t,n){if(null==e)return e;var r=[],o=0;return C(e,r,"","",(function(e){return t.call(n,e,o++)})),r}function N(e){if(-1===e._status){var t=e._result;t=t(),e._status=0,e._result=t,t.then((function(t){0===e._status&&(t=t.default,e._status=1,e._result=t)}),(function(t){0===e._status&&(e._status=2,e._result=t)}))}if(1===e._status)return e._result;throw e._result}var I={current:null};function O(){var e=I.current;if(null===e)throw Error(f(321));return e}var A={ReactCurrentDispatcher:I,ReactCurrentBatchConfig:{transition:0},ReactCurrentOwner:k,IsSomeRendererActing:{current:!1},assign:r};t.Children={map:L,forEach:function(e,t,n){L(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return L(e,(function(){t++})),t},toArray:function(e){return L(e,(function(e){return e}))||[]},only:function(e){if(!S(e))throw Error(f(143));return e}},t.Component=g,t.PureComponent=v,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=A,t.cloneElement=function(e,t,n){if(null==e)throw Error(f(267,e));var a=r({},e.props),i=e.key,s=e.ref,c=e._owner;if(null!=t){if(void 0!==t.ref&&(s=t.ref,c=k.current),void 0!==t.key&&(i=""+t.key),e.type&&e.type.defaultProps)var l=e.type.defaultProps;for(u in t)E.call(t,u)&&!w.hasOwnProperty(u)&&(a[u]=void 0===t[u]&&void 0!==l?l[u]:t[u])}var u=arguments.length-2;if(1===u)a.children=n;else if(1<u){l=Array(u);for(var d=0;d<u;d++)l[d]=arguments[d+2];a.children=l}return{$$typeof:o,type:e.type,key:i,ref:s,props:a,_owner:c}},t.createContext=function(e,t){return void 0===t&&(t=null),(e={$$typeof:s,_calculateChangedBits:t,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:i,_context:e},e.Consumer=e},t.createElement=x,t.createFactory=function(e){var t=x.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:c,render:e}},t.isValidElement=S,t.lazy=function(e){return{$$typeof:u,_payload:{_status:-1,_result:e},_init:N}},t.memo=function(e,t){return{$$typeof:l,type:e,compare:void 0===t?null:t}},t.useCallback=function(e,t){return O().useCallback(e,t)},t.useContext=function(e,t){return O().useContext(e,t)},t.useDebugValue=function(){},t.useEffect=function(e,t){return O().useEffect(e,t)},t.useImperativeHandle=function(e,t,n){return O().useImperativeHandle(e,t,n)},t.useLayoutEffect=function(e,t){return O().useLayoutEffect(e,t)},t.useMemo=function(e,t){return O().useMemo(e,t)},t.useReducer=function(e,t,n){return O().useReducer(e,t,n)},t.useRef=function(e){return O().useRef(e)},t.useState=function(e){return O().useState(e)},t.version="17.0.2"},7294:(e,t,n)=>{"use strict";e.exports=n(2408)},53:(e,t)=>{"use strict";var n,r,o,a;if("object"==typeof performance&&"function"==typeof performance.now){var i=performance;t.unstable_now=function(){return i.now()}}else{var s=Date,c=s.now();t.unstable_now=function(){return s.now()-c}}if("undefined"==typeof window||"function"!=typeof MessageChannel){var l=null,u=null,d=function(){if(null!==l)try{var e=t.unstable_now();l(!0,e),l=null}catch(n){throw setTimeout(d,0),n}};n=function(e){null!==l?setTimeout(n,0,e):(l=e,setTimeout(d,0))},r=function(e,t){u=setTimeout(e,t)},o=function(){clearTimeout(u)},t.unstable_shouldYield=function(){return!1},a=t.unstable_forceFrameRate=function(){}}else{var p=window.setTimeout,f=window.clearTimeout;if("undefined"!=typeof console){var h=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),"function"!=typeof h&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")}var m=!1,g=null,b=-1,v=5,y=0;t.unstable_shouldYield=function(){return t.unstable_now()>=y},a=function(){},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):v=0<e?Math.floor(1e3/e):5};var k=new MessageChannel,E=k.port2;k.port1.onmessage=function(){if(null!==g){var e=t.unstable_now();y=e+v;try{g(!0,e)?E.postMessage(null):(m=!1,g=null)}catch(n){throw E.postMessage(null),n}}else m=!1},n=function(e){g=e,m||(m=!0,E.postMessage(null))},r=function(e,n){b=p((function(){e(t.unstable_now())}),n)},o=function(){f(b),b=-1}}function w(e,t){var n=e.length;e.push(t);e:for(;;){var r=n-1>>>1,o=e[r];if(!(void 0!==o&&0<_(o,t)))break e;e[r]=t,e[n]=o,n=r}}function x(e){return void 0===(e=e[0])?null:e}function S(e){var t=e[0];if(void 0!==t){var n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,o=e.length;r<o;){var a=2*(r+1)-1,i=e[a],s=a+1,c=e[s];if(void 0!==i&&0>_(i,n))void 0!==c&&0>_(c,i)?(e[r]=c,e[s]=n,r=s):(e[r]=i,e[a]=n,r=a);else{if(!(void 0!==c&&0>_(c,n)))break e;e[r]=c,e[s]=n,r=s}}}return t}return null}function _(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var T=[],C=[],L=1,N=null,I=3,O=!1,A=!1,R=!1;function P(e){for(var t=x(C);null!==t;){if(null===t.callback)S(C);else{if(!(t.startTime<=e))break;S(C),t.sortIndex=t.expirationTime,w(T,t)}t=x(C)}}function D(e){if(R=!1,P(e),!A)if(null!==x(T))A=!0,n(M);else{var t=x(C);null!==t&&r(D,t.startTime-e)}}function M(e,n){A=!1,R&&(R=!1,o()),O=!0;var a=I;try{for(P(n),N=x(T);null!==N&&(!(N.expirationTime>n)||e&&!t.unstable_shouldYield());){var i=N.callback;if("function"==typeof i){N.callback=null,I=N.priorityLevel;var s=i(N.expirationTime<=n);n=t.unstable_now(),"function"==typeof s?N.callback=s:N===x(T)&&S(T),P(n)}else S(T);N=x(T)}if(null!==N)var c=!0;else{var l=x(C);null!==l&&r(D,l.startTime-n),c=!1}return c}finally{N=null,I=a,O=!1}}var F=a;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){A||O||(A=!0,n(M))},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_getFirstCallbackNode=function(){return x(T)},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=F,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,i){var s=t.unstable_now();switch("object"==typeof i&&null!==i?i="number"==typeof(i=i.delay)&&0<i?s+i:s:i=s,e){case 1:var c=-1;break;case 2:c=250;break;case 5:c=1073741823;break;case 4:c=1e4;break;default:c=5e3}return e={id:L++,callback:a,priorityLevel:e,startTime:i,expirationTime:c=i+c,sortIndex:-1},i>s?(e.sortIndex=i,w(C,e),null===x(T)&&e===x(C)&&(R?o():R=!0,r(D,i-s))):(e.sortIndex=c,w(T,e),A||O||(A=!0,n(M))),e},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}}},3840:(e,t,n)=>{"use strict";e.exports=n(53)},6774:e=>{e.exports=function(e,t,n,r){var o=n?n.call(r,e,t):void 0;if(void 0!==o)return!!o;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var a=Object.keys(e),i=Object.keys(t);if(a.length!==i.length)return!1;for(var s=Object.prototype.hasOwnProperty.bind(t),c=0;c<a.length;c++){var l=a[c];if(!s(l))return!1;var u=e[l],d=t[l];if(!1===(o=n?n.call(r,u,d,l):void 0)||void 0===o&&u!==d)return!1}return!0}},2177:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r="Invariant failed";function o(e,t){if(!e)throw new Error(r)}},3250:(e,t,n)=>{"use strict";var r=n(7294);var o="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},a=r.useState,i=r.useEffect,s=r.useLayoutEffect,c=r.useDebugValue;function l(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!o(e,n)}catch(r){return!0}}var u="undefined"==typeof window||void 0===window.document||void 0===window.document.createElement?function(e,t){return t()}:function(e,t){var n=t(),r=a({inst:{value:n,getSnapshot:t}}),o=r[0].inst,u=r[1];return s((function(){o.value=n,o.getSnapshot=t,l(o)&&u({inst:o})}),[e,n,t]),i((function(){return l(o)&&u({inst:o}),e((function(){l(o)&&u({inst:o})}))}),[e]),c(n),n};void 0!==r.useSyncExternalStore&&r.useSyncExternalStore},1688:(e,t,n)=>{"use strict";n(3250)},6809:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>r});const r={title:"TouchSocket",tagline:"\u7f51\u7edc\u5f00\u53d1",url:"https://rrqm_home.gitee.io",baseUrl:"/touchsocket/",onBrokenLinks:"throw",onBrokenMarkdownLinks:"warn",favicon:"img/favicon.ico",projectName:"TouchSocket",scripts:[],themeConfig:{zoom:{selector:".markdown :not(em) > img,.markdown > img, article img[loading]",background:{light:"rgb(255, 255, 255)",dark:"rgb(50, 50, 50)"},config:{}},docs:{sidebar:{hideable:!0,autoCollapseCategories:!0},versionPersistence:"localStorage"},prism:{additionalLanguages:["powershell","csharp","sql"],theme:{plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string","inserted"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag","deleted"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]},magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},navbar:{title:"TouchSocket",logo:{alt:"TouchSocket Logo",src:"img/TouchSocketlogo.png"},hideOnScroll:!0,items:[{to:"docs",activeBasePath:"docs",label:"\u6587\u6863",position:"left"},{label:"\u66f4\u65b0\u65e5\u5fd7",position:"left",to:"docs/upgrade"},{label:"\u6e90\u7801",position:"right",items:[{label:"Gitee\uff08\u4e3b\u5e93\uff09",href:"https://gitee.com/rrqm_home/touchsocket"},{label:"GitHub",href:"https://github.com/RRQM/TouchSocket"},{label:"Nuget",href:"https://www.nuget.org/profiles/rrqm"}]},{label:"\u793e\u533a",position:"right",href:"https://gitee.com/dotnetchina"}]},footer:{style:"dark",links:[{title:"\u6587\u6863",items:[{label:"\u5165\u95e8",to:"docs"},{label:"\u624b\u518c",to:"docs"}]},{title:"\u793e\u533a",items:[{label:"\u8ba8\u8bba",href:"https://gitee.com/rrqm_home/touchsocket/issues"},{label:"\u770b\u677f",href:"https://gitee.com/rrqm_home/touchsocket/board"}]},{title:"\u66f4\u591a",items:[{label:"\u4ed3\u5e93",href:"https://gitee.com/rrqm_home/touchsocket"}]}],copyright:"Copyright \xa9 2020-2023 \u82e5\u6c5d\u68cb\u8317."},colorMode:{defaultMode:"light",disableSwitch:!1,respectPrefersColorScheme:!1},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},presets:[["@docusaurus/preset-classic",{docs:{sidebarPath:"D:\\OpenCode\\TouchSocket\\handbook\\sidebars.js",editUrl:"https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/",showLastUpdateTime:!0,showLastUpdateAuthor:!0,sidebarCollapsible:!0,sidebarCollapsed:!0},theme:{customCss:"D:\\OpenCode\\TouchSocket\\handbook\\src\\css\\custom.css"}}]],plugins:["D:\\OpenCode\\TouchSocket\\handbook\\node_modules\\docusaurus-plugin-image-zoom\\src\\index.js"],themes:[["@easyops-cn/docusaurus-search-local",{hashed:!0,language:["en","zh"],highlightSearchTermsOnTargetPage:!0,explicitSearchResultPath:!0}]],baseUrlIssueBanner:!0,i18n:{defaultLocale:"en",path:"i18n",locales:["en"],localeConfigs:{}},onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{mermaid:!1}}},7462:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{Z:()=>r})},5068:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function o(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>o})},3366:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}n.d(t,{Z:()=>r})},7529:e=>{"use strict";e.exports={}},6887:e=>{"use strict";e.exports=JSON.parse('{"/touchsocket/search-f08":{"__comp":"1a4e3797","__context":{"plugin":"329302c4"}},"/touchsocket/docs-8f3":{"__comp":"1be78505","__context":{"plugin":"cbd4f89d"},"versionMetadata":"935f2afb"},"/touchsocket/docs/-cb6":{"__comp":"17896441","content":"5137840a"},"/touchsocket/docs/adapterdemodescription-a95":{"__comp":"17896441","content":"28d8f037"},"/touchsocket/docs/adapterdescription-b0b":{"__comp":"17896441","content":"fce76f89"},"/touchsocket/docs/appmessenger-66c":{"__comp":"17896441","content":"13b149a4"},"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter-6bb":{"__comp":"17896441","content":"8e1e2f35"},"/touchsocket/docs/bytepool-ef6":{"__comp":"17896441","content":"d5d2094c"},"/touchsocket/docs/calljsonrpc-fd9":{"__comp":"17896441","content":"7a6724ae"},"/touchsocket/docs/callwebapi-a42":{"__comp":"17896441","content":"430053de"},"/touchsocket/docs/callxmlrpc-56e":{"__comp":"17896441","content":"7c171c7d"},"/touchsocket/docs/consoleaction-920":{"__comp":"17896441","content":"0fc86718"},"/touchsocket/docs/cooperation-cab":{"__comp":"17896441","content":"b4d3dab5"},"/touchsocket/docs/createandcallrpc-de5":{"__comp":"17896441","content":"dfe172e5"},"/touchsocket/docs/createhttpclient-11e":{"__comp":"17896441","content":"41627674"},"/touchsocket/docs/createhttpservice-d76":{"__comp":"17896441","content":"355b4941"},"/touchsocket/docs/createtcpclient-b72":{"__comp":"17896441","content":"a81d4448"},"/touchsocket/docs/createtcpservice-aad":{"__comp":"17896441","content":"04ff01fb"},"/touchsocket/docs/createtouchrpcclient-c57":{"__comp":"17896441","content":"9106ea79"},"/touchsocket/docs/createtouchrpcservice-23d":{"__comp":"17896441","content":"1ec5dc39"},"/touchsocket/docs/createudpsession-539":{"__comp":"17896441","content":"2c06b999"},"/touchsocket/docs/createwebsocketclient-58c":{"__comp":"17896441","content":"53cff02b"},"/touchsocket/docs/createwebsocketservice-2f1":{"__comp":"17896441","content":"3ab343cc"},"/touchsocket/docs/custombetweenanddatahandlingadapter-f13":{"__comp":"17896441","content":"b1f68223"},"/touchsocket/docs/customdatahandlingadapter-23d":{"__comp":"17896441","content":"0afce4d0"},"/touchsocket/docs/customfixedheaderdatahandlingadapter-6c6":{"__comp":"17896441","content":"4d13c877"},"/touchsocket/docs/customunfixedheaderdatahandlingadapter-ce0":{"__comp":"17896441","content":"9a8bd036"},"/touchsocket/docs/dataadaptertester-18e":{"__comp":"17896441","content":"1c9cad99"},"/touchsocket/docs/dataforwarding-2ec":{"__comp":"17896441","content":"e5d5df95"},"/touchsocket/docs/datahandleadapter-c50":{"__comp":"17896441","content":"eafaca75"},"/touchsocket/docs/datasecurity-c18":{"__comp":"17896441","content":"e7e0ef60"},"/touchsocket/docs/dependencyproperty-02c":{"__comp":"17896441","content":"7b93349f"},"/touchsocket/docs/donate-bf4":{"__comp":"17896441","content":"d22033f9"},"/touchsocket/docs/engineertoolbox-11e":{"__comp":"17896441","content":"b0d79caf"},"/touchsocket/docs/enterprise-dc8":{"__comp":"17896441","content":"f05a39b7"},"/touchsocket/docs/eventbus-926":{"__comp":"17896441","content":"223951e7"},"/touchsocket/docs/fastbinaryformatter-0dc":{"__comp":"17896441","content":"9bfb9f12"},"/touchsocket/docs/filepool-ca8":{"__comp":"17896441","content":"adf44bc8"},"/touchsocket/docs/filesynchronization-4f8":{"__comp":"17896441","content":"bcf858d2"},"/touchsocket/docs/fixedheaderpackageadapter-e86":{"__comp":"17896441","content":"3030335d"},"/touchsocket/docs/fixedsizepackageadapter-e8a":{"__comp":"17896441","content":"ba9c7ecd"},"/touchsocket/docs/fpsgame-a6d":{"__comp":"17896441","content":"88be757d"},"/touchsocket/docs/generateproxy-b1d":{"__comp":"17896441","content":"19a46420"},"/touchsocket/docs/heartbeat-01b":{"__comp":"17896441","content":"df41208d"},"/touchsocket/docs/httpfiletransfer-af0":{"__comp":"17896441","content":"8e5f0e39"},"/touchsocket/docs/httpstaticpageplugin-82c":{"__comp":"17896441","content":"47f1b9ba"},"/touchsocket/docs/ilog-2f1":{"__comp":"17896441","content":"763782ab"},"/touchsocket/docs/independentusedatahandlingadapter-a22":{"__comp":"17896441","content":"babdfbe3"},"/touchsocket/docs/ioc-0b7":{"__comp":"17896441","content":"c8d1f2bf"},"/touchsocket/docs/ipackage-5da":{"__comp":"17896441","content":"b992e8b3"},"/touchsocket/docs/jsonrpcdescription-83f":{"__comp":"17896441","content":"d6520aa6"},"/touchsocket/docs/jsonrpcservice-06e":{"__comp":"17896441","content":"965c04d6"},"/touchsocket/docs/jsonserialize-995":{"__comp":"17896441","content":"91a311b4"},"/touchsocket/docs/multithreadingfiletransfer-b72":{"__comp":"17896441","content":"da3959dc"},"/touchsocket/docs/natservice-405":{"__comp":"17896441","content":"d6be6cb7"},"/touchsocket/docs/normaldatahandlingadapter-9cc":{"__comp":"17896441","content":"aa4c723b"},"/touchsocket/docs/othercore-943":{"__comp":"17896441","content":"0c2b5d1a"},"/touchsocket/docs/pipelinedatahandlingadapter-e0b":{"__comp":"17896441","content":"078d73b8"},"/touchsocket/docs/pluginsmanager-8e0":{"__comp":"17896441","content":"8973b48c"},"/touchsocket/docs/reconnection-35a":{"__comp":"17896441","content":"915634cf"},"/touchsocket/docs/remotefilecontrol-79b":{"__comp":"17896441","content":"ce02ea51"},"/touchsocket/docs/remotemonitoring-ddf":{"__comp":"17896441","content":"c8245f17"},"/touchsocket/docs/remotestreamaccess-e07":{"__comp":"17896441","content":"b806365f"},"/touchsocket/docs/resetid-256":{"__comp":"17896441","content":"8c4cc064"},"/touchsocket/docs/rpcactionfilter-dd3":{"__comp":"17896441","content":"bc87ecb9"},"/touchsocket/docs/rpcallcontext-f79":{"__comp":"17896441","content":"3b5f8c2c"},"/touchsocket/docs/rpcoption-93c":{"__comp":"17896441","content":"0a7a9b32"},"/touchsocket/docs/rpcstream-4f6":{"__comp":"17896441","content":"94e3a799"},"/touchsocket/docs/serializationselector-152":{"__comp":"17896441","content":"4e9c6747"},"/touchsocket/docs/smallfiletransfer-37f":{"__comp":"17896441","content":"94601e7d"},"/touchsocket/docs/startguide-ea6":{"__comp":"17896441","content":"8aa4b8ad"},"/touchsocket/docs/stategridtransmission-37e":{"__comp":"17896441","content":"389c2360"},"/touchsocket/docs/streamtransfer-5dc":{"__comp":"17896441","content":"578e6f54"},"/touchsocket/docs/tcpcommandlineplugin-1db":{"__comp":"17896441","content":"09a85799"},"/touchsocket/docs/tcpother-0fb":{"__comp":"17896441","content":"11fc8f46"},"/touchsocket/docs/terminatorpackageadapter-4ab":{"__comp":"17896441","content":"01fa1a8d"},"/touchsocket/docs/tlvdatahandlingadapter-116":{"__comp":"17896441","content":"6bf8fe32"},"/touchsocket/docs/touchrpcbase-7a5":{"__comp":"17896441","content":"a2c90a25"},"/touchsocket/docs/touchrpcdescription-bcb":{"__comp":"17896441","content":"a46d2111"},"/touchsocket/docs/touchsocketbitconverter-063":{"__comp":"17896441","content":"aa2c2bac"},"/touchsocket/docs/transferfile-88a":{"__comp":"17896441","content":"17443a98"},"/touchsocket/docs/udpbroadcast-3b5":{"__comp":"17896441","content":"9e2cc891"},"/touchsocket/docs/udpdatahandlingadapter-05f":{"__comp":"17896441","content":"320af078"},"/touchsocket/docs/udptransmitbigdata-3b2":{"__comp":"17896441","content":"e782541c"},"/touchsocket/docs/upgrade-8ca":{"__comp":"17896441","content":"4c79e569"},"/touchsocket/docs/waitingclient-631":{"__comp":"17896441","content":"b7e03a75"},"/touchsocket/docs/webapidescription-f37":{"__comp":"17896441","content":"a82e3754"},"/touchsocket/docs/webapiservice-136":{"__comp":"17896441","content":"177fd31f"},"/touchsocket/docs/webdataforwarding-1bb":{"__comp":"17896441","content":"4ecf139e"},"/touchsocket/docs/websocketdescription-0d3":{"__comp":"17896441","content":"eb7c3b1b"},"/touchsocket/docs/wpfuifiletransfer-ce5":{"__comp":"17896441","content":"8154dd80"},"/touchsocket/docs/wscommandlineplugin-8e5":{"__comp":"17896441","content":"11f9f480"},"/touchsocket/docs/wsjsonrpc-b21":{"__comp":"17896441","content":"41b30073"},"/touchsocket/docs/xmlrpcdescription-4c9":{"__comp":"17896441","content":"0b8ef44c"},"/touchsocket/docs/xmlrpcservice-b6f":{"__comp":"17896441","content":"a14859b4"},"/touchsocket/-c0a":{"__comp":"c4f5d8e4","__context":{"plugin":"0654e75d"},"config":"5e9f5e1a"}}')}},e=>{e.O(0,[532],(()=>{return t=9383,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/handbook/build/assets/js/main.175592cd.js.LICENSE.txt b/handbook/build/assets/js/main.175592cd.js.LICENSE.txt new file mode 100644 index 000000000..105cb517b --- /dev/null +++ b/handbook/build/assets/js/main.175592cd.js.LICENSE.txt @@ -0,0 +1,141 @@ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +/*! + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +/*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + */ + +/*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + */ + +/*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + */ + +/*!*************************************************** +* mark.js v8.11.1 +* https://markjs.io/ +* Copyright (c) 2014–2018, Julian Kühnel +* Released under the MIT license https://git.io/vwTVl +*****************************************************/ + +/** + * @license React + * use-sync-external-store-shim.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT <https://opensource.org/licenses/MIT> + * @author Lea Verou <https://lea.verou.me> + * @namespace + * @public + */ + +/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + */ + +/** @license React v0.20.2 + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ diff --git a/handbook/build/assets/js/runtime~main.ed9a3d98.js b/handbook/build/assets/js/runtime~main.ed9a3d98.js new file mode 100644 index 000000000..ec2a783cc --- /dev/null +++ b/handbook/build/assets/js/runtime~main.ed9a3d98.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,a,f,c,b,d={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var f=t[e]={exports:{}};return d[e].call(f.exports,f,f.exports,r),f.exports}r.m=d,e=[],r.O=(a,f,c,b)=>{if(!f){var d=1/0;for(i=0;i<e.length;i++){f=e[i][0],c=e[i][1],b=e[i][2];for(var t=!0,o=0;o<f.length;o++)(!1&b||d>=b)&&Object.keys(r.O).every((e=>r.O[e](f[o])))?f.splice(o--,1):(t=!1,b<d&&(d=b));if(t){e.splice(i--,1);var n=c();void 0!==n&&(a=n)}}return a}b=b||0;for(var i=e.length;i>0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[f,c,b]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var b=Object.create(null);r.r(b);var d={};a=a||[null,f({}),f([]),f(f)];for(var t=2&c&&e;"object"==typeof t&&!~a.indexOf(t);t=f(t))Object.getOwnPropertyNames(t).forEach((a=>d[a]=()=>e[a]));return d.default=()=>e,r.d(b,d),b},r.d=(e,a)=>{for(var f in a)r.o(a,f)&&!r.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,f)=>(r.f[f](e,a),a)),[])),r.u=e=>"assets/js/"+({53:"935f2afb",138:"fce76f89",230:"329302c4",487:"ba9c7ecd",505:"28d8f037",631:"223951e7",803:"430053de",904:"d5d2094c",908:"8154dd80",1168:"4e9c6747",1285:"1c9cad99",1302:"88be757d",1317:"11fc8f46",1569:"eafaca75",1586:"04ff01fb",1592:"a82e3754",1601:"b806365f",1687:"389c2360",1705:"d6be6cb7",1793:"da3959dc",1822:"f05a39b7",1868:"41b30073",1877:"8aa4b8ad",1895:"9e2cc891",1965:"17443a98",1969:"763782ab",1971:"b0d79caf",2022:"915634cf",2289:"3030335d",2373:"7c171c7d",2375:"578e6f54",2416:"9a8bd036",2671:"11f9f480",2894:"41627674",2903:"0fc86718",2934:"e782541c",2996:"0afce4d0",3214:"8c4cc064",3285:"b1f68223",3371:"d22033f9",3420:"babdfbe3",3503:"b7e03a75",3635:"8973b48c",4018:"078d73b8",4195:"c4f5d8e4",4456:"7a6724ae",4649:"e5d5df95",4724:"b4d3dab5",4850:"91a311b4",4929:"47f1b9ba",5215:"4ecf139e",5264:"9bfb9f12",5683:"355b4941",5725:"19a46420",5873:"3ab343cc",5983:"2c06b999",6050:"d6520aa6",6128:"b992e8b3",6171:"7b93349f",6191:"a81d4448",6373:"320af078",6390:"cbd4f89d",6487:"aa4c723b",6505:"965c04d6",6746:"e7e0ef60",7016:"dfe172e5",7162:"0a7a9b32",7278:"94601e7d",7436:"c8245f17",7453:"94e3a799",7462:"1ec5dc39",7586:"bc87ecb9",7790:"ce02ea51",7918:"17896441",7920:"1a4e3797",7986:"bcf858d2",7987:"0654e75d",8032:"c8d1f2bf",8102:"df41208d",8300:"177fd31f",8411:"aa2c2bac",8494:"5137840a",8610:"eb7c3b1b",8707:"4c79e569",8719:"a2c90a25",8808:"6bf8fe32",8835:"a46d2111",9030:"4d13c877",9035:"01fa1a8d",9171:"3b5f8c2c",9198:"8e1e2f35",9253:"adf44bc8",9311:"53cff02b",9514:"1be78505",9541:"09a85799",9660:"a14859b4",9750:"0b8ef44c",9769:"9106ea79",9911:"13b149a4",9925:"0c2b5d1a",9954:"8e5f0e39"}[e]||e)+"."+{53:"f357c15a",138:"87ef30ad",230:"249a948b",487:"ed9c972b",505:"a45d1145",631:"8d06409f",803:"80700119",904:"734ef0f5",908:"de0713d0",1168:"35f5eddc",1285:"039ee719",1302:"6021c737",1317:"7090702e",1569:"9c10e3ec",1586:"f73cf086",1592:"6c72fa9c",1601:"9ff05ec5",1687:"baae9616",1705:"b3757292",1793:"f28eac04",1822:"7ba7a087",1868:"88c66a11",1877:"20446be6",1895:"072979a0",1965:"2fd798c5",1969:"f77e52b3",1971:"06a5a0f4",2022:"e91d55ad",2289:"3367d96e",2373:"82420f61",2375:"582b3ec5",2416:"135c0c4a",2671:"1f045afd",2894:"e57effb8",2903:"7a7ab966",2934:"36f93477",2996:"ddd32fea",3214:"297bda93",3285:"1dcbed2c",3371:"80f5a5bf",3420:"955f3817",3503:"33d2c017",3635:"310d4fb3",4018:"4dc736f8",4195:"90ede736",4456:"5b8f96aa",4649:"1d148f38",4724:"b452fab0",4850:"db72a3a2",4929:"cdd48a18",4972:"c5f9020b",5215:"eaf47e4a",5264:"4a5babc4",5525:"c53056dc",5683:"b6bf168d",5725:"b6485179",5873:"9358ed6d",5983:"5646f61e",6050:"ca22c63f",6128:"07f49565",6171:"84dc1f60",6191:"6d40d457",6373:"69561817",6390:"cc0b4777",6487:"34e57568",6505:"495d92e3",6746:"a120f8c2",7016:"3113feba",7162:"6d442850",7278:"5d94be73",7436:"df41c7c6",7453:"9dad8103",7462:"5959844a",7586:"45ae90f0",7790:"3f2f2031",7918:"fc5f7a42",7920:"42a57863",7986:"0c59ed82",7987:"8db102f4",8032:"59006bc6",8102:"a4876b14",8300:"ede3771d",8411:"f10823d9",8443:"0060be2a",8494:"ba3ea2d3",8610:"0dba8683",8707:"2b31247d",8719:"03170d44",8808:"dcdba073",8835:"e7fd3370",9030:"321d1ac4",9035:"1831ff50",9171:"9abe936a",9198:"3b62d779",9253:"1067b890",9311:"6893293e",9514:"9cd1e63b",9523:"5d56e621",9541:"29e58d80",9660:"eb042ba8",9750:"49139891",9769:"88d3dc8b",9911:"a34a836b",9925:"6d37bd6a",9954:"927d9bfc"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},b="touchsocket:",r.l=(e,a,f,d)=>{if(c[e])c[e].push(a);else{var t,o;if(void 0!==f)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var u=n[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==b+f){t=u;break}}t||(o=!0,(t=document.createElement("script")).charset="utf-8",t.timeout=120,r.nc&&t.setAttribute("nonce",r.nc),t.setAttribute("data-webpack",b+f),t.src=e),c[e]=[a];var l=(a,f)=>{t.onerror=t.onload=null,clearTimeout(s);var b=c[e];if(delete c[e],t.parentNode&&t.parentNode.removeChild(t),b&&b.forEach((e=>e(f))),a)return a(f)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/touchsocket/",r.gca=function(e){return e={17896441:"7918",41627674:"2894","935f2afb":"53",fce76f89:"138","329302c4":"230",ba9c7ecd:"487","28d8f037":"505","223951e7":"631","430053de":"803",d5d2094c:"904","8154dd80":"908","4e9c6747":"1168","1c9cad99":"1285","88be757d":"1302","11fc8f46":"1317",eafaca75:"1569","04ff01fb":"1586",a82e3754:"1592",b806365f:"1601","389c2360":"1687",d6be6cb7:"1705",da3959dc:"1793",f05a39b7:"1822","41b30073":"1868","8aa4b8ad":"1877","9e2cc891":"1895","17443a98":"1965","763782ab":"1969",b0d79caf:"1971","915634cf":"2022","3030335d":"2289","7c171c7d":"2373","578e6f54":"2375","9a8bd036":"2416","11f9f480":"2671","0fc86718":"2903",e782541c:"2934","0afce4d0":"2996","8c4cc064":"3214",b1f68223:"3285",d22033f9:"3371",babdfbe3:"3420",b7e03a75:"3503","8973b48c":"3635","078d73b8":"4018",c4f5d8e4:"4195","7a6724ae":"4456",e5d5df95:"4649",b4d3dab5:"4724","91a311b4":"4850","47f1b9ba":"4929","4ecf139e":"5215","9bfb9f12":"5264","355b4941":"5683","19a46420":"5725","3ab343cc":"5873","2c06b999":"5983",d6520aa6:"6050",b992e8b3:"6128","7b93349f":"6171",a81d4448:"6191","320af078":"6373",cbd4f89d:"6390",aa4c723b:"6487","965c04d6":"6505",e7e0ef60:"6746",dfe172e5:"7016","0a7a9b32":"7162","94601e7d":"7278",c8245f17:"7436","94e3a799":"7453","1ec5dc39":"7462",bc87ecb9:"7586",ce02ea51:"7790","1a4e3797":"7920",bcf858d2:"7986","0654e75d":"7987",c8d1f2bf:"8032",df41208d:"8102","177fd31f":"8300",aa2c2bac:"8411","5137840a":"8494",eb7c3b1b:"8610","4c79e569":"8707",a2c90a25:"8719","6bf8fe32":"8808",a46d2111:"8835","4d13c877":"9030","01fa1a8d":"9035","3b5f8c2c":"9171","8e1e2f35":"9198",adf44bc8:"9253","53cff02b":"9311","1be78505":"9514","09a85799":"9541",a14859b4:"9660","0b8ef44c":"9750","9106ea79":"9769","13b149a4":"9911","0c2b5d1a":"9925","8e5f0e39":"9954"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(a,f)=>{var c=r.o(e,a)?e[a]:void 0;if(0!==c)if(c)f.push(c[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var b=new Promise(((f,b)=>c=e[a]=[f,b]));f.push(c[2]=b);var d=r.p+r.u(a),t=new Error;r.l(d,(f=>{if(r.o(e,a)&&(0!==(c=e[a])&&(e[a]=void 0),c)){var b=f&&("load"===f.type?"missing":f.type),d=f&&f.target&&f.target.src;t.message="Loading chunk "+a+" failed.\n("+b+": "+d+")",t.name="ChunkLoadError",t.type=b,t.request=d,c[1](t)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,f)=>{var c,b,d=f[0],t=f[1],o=f[2],n=0;if(d.some((a=>0!==e[a]))){for(c in t)r.o(t,c)&&(r.m[c]=t[c]);if(o)var i=o(r)}for(a&&a(f);n<d.length;n++)b=d[n],r.o(e,b)&&e[b]&&e[b][0](),e[b]=0;return r.O(i)},f=self.webpackChunktouchsocket=self.webpackChunktouchsocket||[];f.forEach(a.bind(null,0)),f.push=a.bind(null,f.push.bind(f))})()})(); \ No newline at end of file diff --git a/handbook/build/docs/adapterdemodescription/index.html b/handbook/build/docs/adapterdemodescription/index.html new file mode 100644 index 000000000..fb3a95299 --- /dev/null +++ b/handbook/build/docs/adapterdemodescription/index.html @@ -0,0 +1,16 @@ +<!doctype html> +<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-adapterdemodescription"> +<head> +<meta charset="UTF-8"> +<meta name="generator" content="Docusaurus v2.3.1"> +<title data-rh="true">说明 | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/adapterdescription/index.html b/handbook/build/docs/adapterdescription/index.html new file mode 100644 index 000000000..da5b38e10 --- /dev/null +++ b/handbook/build/docs/adapterdescription/index.html @@ -0,0 +1,19 @@ + + + + + +介绍及使用 | TouchSocket + + + + +
+

介绍及使用

说明

在TouchSocket中,适配器贯穿始终,其作用实际上有两个,分别为:

  • 对发送和接收的数据进行预先的封装和解封,以达到解析数据的作用(可以简单理解为处理黏、分包)。
  • 将特殊数据解析为可以传递的数据结构,以达到解析数据的目的。

很明显,大家看到了,数据处理适配器的作用用一句话说,就是解析数据用的。

设计架构

工作逻辑

数据逻辑

TouchSocket的适配器,在初始阶段(原始TCP),会收到一个ByteBlock数据,然后经过适配器处理以后,可选择两个参数(ByteBlock和IRequestInfo)的任意组合投递数据。

例如:FixedHeaderPackageAdapter,仅投递ByteBlock数据,届时IRequestInfo将为null。而如果是继承的CustomDataHandlingAdapter,则仅投递IRequestInfo,ByteBlock将为null。

设计解释

大家有时候可能会迷惑,为什么TouchSocket要设计两个参数投递,而不像其他的那样的,在会话里面,把适配器直接泛型规范了,直接抛出对应的类型。这是因为泛型约束太大,不够灵活。例如:

  • 第一,不能随时切换适配器,例如适配webSocket,在握手阶段,要解析http数据,所以,此时应该选择http数据处理适配,而完成握手以后,就要解析ws数据格式了,所以此时应该切换适配器为ws数据处理适配器。
  • 第二,两个参数能提高性能。例如HTTP数据处理适配器,在高性能工作模式下,由IRequestInfo投递请求头,由ByteBlock投递Body,这样Body是从内存池获得,就不存在内存消耗了。

三、TCP使用

在TCP系中使用数据处理适配器是非常简单的一个过程。而且为了不同场景,TouchSocket支持多种方式的适配器使用。服务器和客户端使用一致

3.1 在Config配置中使用

在Config配置使用时,相当于初始化赋值。比较单一,但是很可靠。

.SetDataHandlingAdapter(()=> { return new MyCustomBetweenAndDataHandlingAdapter(); })

3.2 订阅Connecting相关事件

只需要在OnConnecting方法(或Connecting事件)中对新连接的Client,调用SetDataHandlingAdapter进行赋值即可。

public class MyTcpService : TcpService<MySocketClient>
{
protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e)
{
socketClient.SetDataHandlingAdapter(new NormalDataHandlingAdapter());//直接对数据处理器赋值,立即生效
base.OnConnecting(socketClient, e);
}
}

3.3 使用插件,代替Connecting相关事件实现

使用插件实现该功能,实际上和步骤2一样,但是因为是基于插件,所以更好于管理。

class MyPlugin : TcpPluginBase
{
protected override void OnConnecting(ITcpClientBase client, ClientOperationEventArgs e)
{
client.SetDataHandlingAdapter(new NormalDataHandlingAdapter());
base.OnConnecting(client, e);
}
}

3.4 任意时刻设置

实际上,大家可以从步骤2、3中看出来,适配器是可以被随意赋值的,这也就说明,适配器是可以随时被替换的。那么也就可以被随时赋值了。

四、UDP使用插件

Udp使用的插件,只能从Config配置。 +【UdpSession

 m_udpSession.Setup(new TouchSocketConfig()
.SetBindIPHost(new IPHost(this.textBox2.Text))
.SetUdpDataHandlingAdapter(()=>
{
return new NormalUdpDataHandlingAdapter();
})
.ConfigureContainer(a =>
{
a.SetSingletonLogger(new LoggerGroup(new EasyLogger(this.ShowMsg), new FileLogger()));
}))
.Start();

注意:同一个适配器实例,只可被赋值一次,不然会异常。如果在构造函数(或其他一次性函数)中设置适配器的话,在重连时,最好重新设置适配器,因为框架在Disconnected时会置空适配器,同时在Connecting执行完后会检测适配器,如果没有再次设置适配器的话,会选择默认适配器(TcpClient会选择普通适配器,Protocol及派生会选择固定包头适配器)。

五、限制使用

限制使用的场景应用于自定义封装。例如:自己封装一个服务器,然后适配器仅特定使用,不允许外部随意赋值,那么可以如下实现:

public class MySocketClient : SocketClient
{
/// <summary>
/// <inheritdoc/>
/// </summary>
public override sealed bool CanSetDataHandlingAdapter => false;//不允许随意赋值

private void InternalSetAdapter(DataHandlingAdapter adapter)
{
this.SetAdapter(adapter);//仅继承内部赋值
}
}

六、缓存超时(仅Tcp适配器)

当适配器在工作时,如果一个数据包在设置的周期内(默认1000ms)没有完成接收,则会清空所有缓存数据,然后重新接收。 +这种设计是为了应对,当接收数据时,如果发送方发送了异常数据(也有可能在移动网时,由运营商发送的无效包)而导致整个接收队列数据无效的问题。 +现在加入缓存超时设置,则如果发送上述情况,也会在一个周期后,快速恢复接收。

相关属性设置:

  • CacheTimeoutEnable:是否启用缓存超时。
  • CacheTimeout:缓存超时时间
  • UpdateCacheTimeWhenRev:是否每次接收就更新缓存时间。默认true,意味着只要有数据接收,则缓存永远不会过期。当为false时,则每个缓存包,必须在设置的周期内完成接收。
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/appmessenger/index.html b/handbook/build/docs/appmessenger/index.html new file mode 100644 index 000000000..a5f361512 --- /dev/null +++ b/handbook/build/docs/appmessenger/index.html @@ -0,0 +1,19 @@ + + + + + +应用信使 | TouchSocket + + + + +
+

应用信使

一、说明

应用信使是在进程内的,行使注册和触发功能的组件。可代替事件,可跨越程序集,可依赖倒置

二、使用

【声明主体】 +实现IMessage接口,然后增加AppMessage标记的公共方法。

public class MessageObject : IMessage
{

[AppMessage]
public int Add(int a, int b)
{
return a + b;
}

[AppMessage]
public int Sub(int a, int b)
{
return a - b;
}
}

【注册】 +下列演示时,是新实例化的AppMessenger,实际上,用户可以直接使用AppMessenger.Default默认实例。

AppMessenger appMessenger = new AppMessenger();
appMessenger.Register<MessageObject>();

【触发】 +触发时,泛型类型,即时返回值类型。

int add = appMessenger.Send<int>("Add", 20, 10);
Assert.Equal(30,add);

int sub = appMessenger.Send<int>("Sub", 20, 10);
Assert.Equal(10, sub);
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/bigfixedheadercustomdatahandlingadapter/index.html b/handbook/build/docs/bigfixedheadercustomdatahandlingadapter/index.html new file mode 100644 index 000000000..6fcb68f4e --- /dev/null +++ b/handbook/build/docs/bigfixedheadercustomdatahandlingadapter/index.html @@ -0,0 +1,18 @@ + + + + + +模板解析“大数据固定包头”数据适配器 | TouchSocket + + + + +
+

模板解析“大数据固定包头”数据适配器

一、说明

大数据固定包头,是对固定的包头模板的补充,一般来是,固定包头适配器,不能工作于超过2G的数据,但是在少数情况下,会有大量的数据传输需求。所以这部分的业务,可以用大数据固定包头实现。

二、特点

  1. 可以自由适配99%的数据协议。
  2. 可以随意定制数据协议。
  3. 可以与任意语言、框架对接数据。
  4. 可以接收理论无限大的数据。

三、使用

客户端与服务器均适用。下列以服务器为例。

步骤

  1. 声明新建类,实现IBigFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。
  2. 声明新建类,继承BigFixedHeaderCustomDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。
  3. TouchSocketConfig配置中设置。
  4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。

【MyBigFixedHeaderRequestInfo】 +首先,新建MyBigFixedHeaderRequestInfo类,然后实现IBigFixedHeaderRequestInfo用户自定义固定包头接口。 +然后在OnParsingHeader函数执行结束时,对实现的BodyLength属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。

/// <summary>
/// 下列示例,没有实现逻辑,仅解释思路。
/// </summary>
class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo
{
public long BodyLength => throw new NotImplementedException();//此处请使用字段实现。

public void OnAppendBody(byte[] buffer, int offset, int length)
{
//在这里会一直追加数据体,用户自行实现数据的保存。
//注意,buffer可能为内存块的成员,所以,一定一定不要直接引用。
}

public bool OnFinished()
{
//触发该方法时,说明数据体接收完毕,返回true时,会触发Receive相关事件,否则不会。
return true;
}

public bool OnParsingHeader(byte[] header)
{
//解析头部。赋值BodyLength
return true;
}
}

新建MyBigFixedHeaderCustomDataHandlingAdapter继承CustomBigFixedHeaderDataHandlingAdapter,然后对HeaderLength作出赋值,以此表明固定包头的长度是多少。

/// <summary>
/// 模板解析“大数据固定包头”数据适配器
/// </summary>
class MyBigFixedHeaderCustomDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter<MyBigFixedHeaderRequestInfo>
{
public override int HeaderLength =>8;

protected override MyBigFixedHeaderRequestInfo GetInstance()
{
return new MyBigFixedHeaderRequestInfo();
}
}

【接收】

TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型
if (requestInfo is MyBigFixedHeaderRequestInfo myRequestInfo)
{
//此处可以处理MyBigFixedHeaderRequestInfo的相关信息了。
string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);
}

};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(() => { return new MyBigFixedHeaderCustomDataHandlingAdapter(); }))//配置适配器
.Start();//启动
提示

上述创建的适配器客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/bytepool/index.html b/handbook/build/docs/bytepool/index.html new file mode 100644 index 000000000..8386c9b72 --- /dev/null +++ b/handbook/build/docs/bytepool/index.html @@ -0,0 +1,19 @@ + + + + + +内存池 | TouchSocket + + + + +
+

内存池

一、说明

内存池是TouchSocketCore的最重要的组成部分,在TouchSocket产品中,BytePool贯穿始终。所以熟悉使用BytePool,也是非常重要的。

Nuget Package:TouchSocket

二、功能

内存池(BytePool)的最小实现单体是内存块(ByteBlock),它是继承自Stream的类,拥有和MemoryStream一样的功能和RRQM的增强功能。而且拥有释放回收能力,所以如果有MemoryStream的使用需求的话,就可以完全让ByteBlock替代。

三、创建

BytePool是静态类,无需创建,直接使用即可。ByteBlock可通过BytePool创建,也可以直接new对象,这两者实际操作一致。 +注意:创建的ByteBlock必须释放(Dispose),虽然不会内存泄露,但是会影响性能。

ByteBlock byteBlock1 = new ByteBlock(byteSize:1024*1024,equalSize:false);
byteBlock1.Dispose();
ByteBlock byteBlock2 = BytePool.GetByteBlock(byteSize:1024*1024,equalSize:false);
byteBlock2.Dispose();
using (ByteBlock byteBlock3=new ByteBlock())
{
}

四、使用

基础使用和MemoryStream一致,下面仅介绍特定使用。

4.1 写入、读取数据对象

using (ByteBlock byteBlock = new ByteBlock())
{
byteBlock.Write(byte.MaxValue);
byteBlock.Write(int.MaxValue);
byteBlock.Write(long.MaxValue);
byteBlock.Write("RRQM");
byteBlock.WriteObject(new Person(), SerializationType.Json);
byteBlock.WriteBytesPackage(new byte[1024]);
byteBlock.Pos = 0;//读取时,先将游标移动到初始写入的位置,然后按写入顺序,依次读取
byte ByteValue = byteBlock.ReadByte();
int IntValue = byteBlock.ReadInt32();
long LongValue = byteBlock.ReadInt64();
string StringValue = byteBlock.ReadString();
Person ObjectValue = byteBlock.ReadObject<Person>(SerializationType.Json);
byte[] BytesValue = byteBlock.ReadBytesPackage();
}

4.2 多线程同步协作(Hold)

在多线程异步时,设计架构应当遵守谁(Thread)创建的ByteBlock,由谁释放,这样就能很好的避免未释放的情况发生。实际上RRQMSocket中,就是秉承这样的设计,任何非用户创建的ByteBlock,都会由创建的线程最后释放。但是在使用中,经常出现异步多线程的操作。 +以RRQMSocket的TcpClient为例。如果直接在收到数据时,使用Task异步,则必定会发生关于ByteBlock的各种各样的异常。 +原因非常简单,byteBlock对象在到达HandleReceivedData时,触发Task异步,此时触发线程会立即返回,并释放byteBlock,而Task异步线程会滞后,然后试图从已释放的byteBlock中获取数据,所以,必定发生异常。

public class MyTClient : TcpClient
{
protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
{
Task.Run(()=>
{
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"已接收到信息:{mes}");
});
}
}

解决方法也非常简单,只需要在异步前锁定,然后使用完成后取消锁定,且不用再调用Dispose。

public class MyTClient : TcpClient
{
protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
{
byteBlock.SetHolding(true);//异步前锁定
Task.Run(()=>
{
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
byteBlock.SetHolding(false);//使用完成后取消锁定,且不用再调用Dispose
Console.WriteLine($"已接收到信息:{mes}");
});
}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/calljsonrpc/index.html b/handbook/build/docs/calljsonrpc/index.html new file mode 100644 index 000000000..b47fbde0c --- /dev/null +++ b/handbook/build/docs/calljsonrpc/index.html @@ -0,0 +1,19 @@ + + + + + +发现、调用服务 | TouchSocket + + + + +
+

发现、调用服务

一、直接调用

因为JsonRpc是通用调用协议,所以可以直接使用Json字符串调用。

以下字符串只是示例,具体的method参数,应当遵循当前路由。

【Tcp协议直接调用】 +在TCP协议时,按照适配器,选择性的是否以\r\n结尾。

{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1}

【Http协议直接调用】 +在Http协议时,以Url+Post方式即可

{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1}

【Websocket协议直接调用】 +在Websocket协议时,以文本类型,直接发送到服务器即可。

{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1}

二、客户端直接调用

TouchSocket提供了JsonRpc的专属客户端,直接调用,则会则是不使用任何代理,直接Call RPC,使用比较简单。

【TCP协议】

JsonRpcClient jsonRpcClient = new JsonRpcClient();
jsonRpcClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7705")
.SetJRPT(JRPT.Tcp));
jsonRpcClient.Connect();

Console.WriteLine("连接成功");
string result = jsonRpcClient.Invoke<string>("jsonrpcconsoleapp.server.testjsonrpc", InvokeOption.WaitInvoke, "TouchSocket");
Console.WriteLine($"Tcp返回结果:{result}");

result = jsonRpcClient.Invoke<string>("TestJsonRpc1", InvokeOption.WaitInvoke, "TouchSocket");
Console.WriteLine($"Tcp返回结果:{result}");

result = jsonRpcClient.Invoke<string>("jsonrpcconsoleapp.server.testgetcontext", InvokeOption.WaitInvoke, "TouchSocket");
Console.WriteLine($"Tcp返回结果:{result}");

JObject obj = new JObject();
obj.Add("A", "A");
obj.Add("B", 10);
obj.Add("C", 100.1);
JObject newObj = jsonRpcClient.Invoke<JObject>("jsonrpcconsoleapp.server.testjobject", InvokeOption.WaitInvoke, obj);
Console.WriteLine($"Tcp返回结果:{newObj}");

【Http协议】

static void JsonRpcClientInvokeByHttp()
{
JsonRpcClient jsonRpcClient = new JsonRpcClient();
jsonRpcClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost("http://127.0.0.1:7706/jsonrpc")
.SetJRPT(JRPT.Http));
jsonRpcClient.Connect();
Console.WriteLine("连接成功");
string result = jsonRpcClient.Invoke<string>("server/testjsonrpc", InvokeOption.WaitInvoke, "TouchSocket");
Console.WriteLine($"Http返回结果:{result}");

JObject obj = new JObject();
obj.Add("A", "A");
obj.Add("B", 10);
obj.Add("C", 100.1);
JObject newObj = jsonRpcClient.Invoke<JObject>("server/testjobject", InvokeOption.WaitInvoke, obj);
Console.WriteLine($"Http返回结果:{newObj}");
}

【Websocket协议】

JsonRpcClient jsonRpcClient = new JsonRpcClient();
jsonRpcClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost("ws://127.0.0.1:7706/ws")//此url就是能连接到websocket的路径。
.SetDataHandlingAdapter(() => new TerminatorPackageAdapter("\r\n"))
.SetJRPT(JRPT.Websocket));
jsonRpcClient.Connect();

Console.WriteLine("连接成功");
string result = jsonRpcClient.TestJsonRpc("RRQM");
Console.WriteLine($"Websocket返回结果:{result}");

result = jsonRpcClient.TestJsonRpc1("RRQM");
Console.WriteLine($"Websocket返回结果:{result}");

result = jsonRpcClient.TestGetContext("RRQM");
Console.WriteLine($"Websocket返回结果:{result}");

JObject obj = new JObject();
obj.Add("A", "A");
obj.Add("B", 10);
obj.Add("C", 100.1);
JObject newObj = jsonRpcClient.TestJObject(obj);
Console.WriteLine($"Websocket返回结果:{newObj}");

代理调用RPC

代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。

如何生成获取代理文件?

获取代理文件详情

调用

当代理被客户端获取以后,客户端项目中会多出一个RRQMProxy(//TODO:这里需要修改,上面的获取代理文件详情的链接失效需要修改,下面截图需要修改)的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的代理方法代理类,可直接由代理类发起调用。

JsonRpcClient jsonRpcClient = new JsonRpcClient(JRPT.Http);
jsonRpcClient.Setup("http://127.0.0.1:7706/jsonrpc");
jsonRpcClient.Connect();
Server server= new Server(jsonRpcClient);//Server是生成的代理类。
server.TestJsonRpc("TouchSocket");//代理调用
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/callwebapi/index.html b/handbook/build/docs/callwebapi/index.html new file mode 100644 index 000000000..2018fa997 --- /dev/null +++ b/handbook/build/docs/callwebapi/index.html @@ -0,0 +1,17 @@ + + + + + +发现、调用服务 | TouchSocket + + + + +
+

发现、调用服务

直接调用

直接调用,则是不使用任何代理,直接Call RPC,使用比较简单,浏览器也能直接调用实现。

【Url请求】

http://127.0.0.1:7789/ApiServer/Sum?a=10&b=20

【HttpClient调用】 +WebApi的客户端和大家所熟识的有一些差距,TouchSocket的WebApi使用的是先连接后请求的逻辑。请求时,先标记GET/POST的函数。如果是GET,则必须留空URL,如果是POST,则只写URL即可。

private static WebApiClient CreateWebApiClient()
{
WebApiClient client = new WebApiClient();
client.Setup("127.0.0.1:7789");
client.Connect();
Console.WriteLine("连接成功");
return client;
}
var client = CreateWebApiClient();

int sum1 = client.Invoke<int>("GET:/ApiServer/Sum?a={0}&b={1}", null, 10, 20);
Console.WriteLine($"Get调用成功,结果:{sum1}");

int sum2 = client.Invoke<int>("POST:/ApiServer/TestPost", null, new MyClass() { A = 10, B = 20 });
Console.WriteLine($"Post调用成功,结果:{sum2}");

代理调用RPC

代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。

如何生成获取代理文件?

获取代理文件详情

调用

当代理被客户端获取以后,客户端项目中会多出一个RRQMProxy的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的代理方法代理类,可直接由代理类发起调用。

int sum3 = client.TestPost(new MyClass() { A = 10, B = 20 });
Console.WriteLine($"代理调用成功,结果:{sum3}");
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/callxmlrpc/index.html b/handbook/build/docs/callxmlrpc/index.html new file mode 100644 index 000000000..9b71de432 --- /dev/null +++ b/handbook/build/docs/callxmlrpc/index.html @@ -0,0 +1,17 @@ + + + + + +发现、调用服务 | TouchSocket + + + + +
+

发现、调用服务

直接调用

直接调用,则是不使用任何代理,直接Call RPC,使用比较简单。

static void Main(string[] args)
{
var client = GetXmlRpcClient();

//直接调用
int result1 = client.Invoke<int>("Sum", InvokeOption.WaitInvoke, 10, 20);
Console.WriteLine($"直接调用,返回结果:{result1}");

Console.ReadKey();
}
static XmlRpcClient GetXmlRpcClient()
{
XmlRpcClient jsonRpcClient = new XmlRpcClient();
jsonRpcClient.Setup("http://127.0.0.1:7706/xmlRpc");
jsonRpcClient.Connect();
Console.WriteLine("连接成功");
return jsonRpcClient;
}

【亦或者直接使用字符串调用】 +在Http-Post方式即可。

<?xml version="1.0"?>
<methodCall>
<methodName>Sum</methodName>
<params>
<param>
<value>
<i4>10</i4>
</value>
</param>
<param>
<value>
<i4>20</i4>
</value>
</param>
</params>
</methodCall>

代理调用RPC

代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。

如何生成获取代理文件?

获取代理文件详情

调用

当代理被客户端获取以后,客户端项目中会多出一个RRQMProxy的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的代理方法代理类,可直接由代理类发起调用。

static void Main(string[] args)
{
var client = GetXmlRpcClient();

Server server = new Server(client);
int result2 = server.Sum(10, 20);
Console.WriteLine($"代理调用,返回结果:{result2}");

Console.ReadKey();
}

static XmlRpcClient GetXmlRpcClient()
{
XmlRpcClient jsonRpcClient = new XmlRpcClient();
jsonRpcClient.Setup("http://127.0.0.1:7706/xmlRpc");
jsonRpcClient.Connect();
Console.WriteLine("连接成功");
return jsonRpcClient;
}

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/consoleaction/index.html b/handbook/build/docs/consoleaction/index.html new file mode 100644 index 000000000..03af92628 --- /dev/null +++ b/handbook/build/docs/consoleaction/index.html @@ -0,0 +1,16 @@ + + + + + +控制台行为 | TouchSocket + + + + +
+

控制台行为

一、说明

这是一个很简单的控制台命令器,重要作用就是很方便的实现控制台控制。

Nuget Package:TouchSocket

二、使用

ConsoleAction consoleAction = new ConsoleAction("h|help|?");//设置帮助命令
consoleAction.OnException += ConsoleAction_OnException;//订阅执行异常输出

//下列的ShareProxy,StopShareProxy,GetAll均为无参数的方法
consoleAction.Add("sp|shareProxy", "分享代理", ShareProxy);//示例命令
consoleAction.Add("ssp|stopShareProxy", "停止分享代理", StopShareProxy);//示例命令
consoleAction.Add("ga|getAll", "获取所有客户端信息", GetAll);//示例命令
consoleAction.ShowAll();
while (true)
{
if (!consoleAction.Run(Console.ReadLine()))
{
Console.WriteLine("命令不正确,请输入“h|help|?”获得帮助。");
}
}

三、效果图

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/cooperation/index.html b/handbook/build/docs/cooperation/index.html new file mode 100644 index 000000000..b70c29434 --- /dev/null +++ b/handbook/build/docs/cooperation/index.html @@ -0,0 +1,16 @@ + + + + + +商业合作 | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/createandcallrpc/index.html b/handbook/build/docs/createandcallrpc/index.html new file mode 100644 index 000000000..04c092ebb --- /dev/null +++ b/handbook/build/docs/createandcallrpc/index.html @@ -0,0 +1,17 @@ + + + + + +创建rpc服务 | TouchSocket + + + + +
+

创建rpc服务

一、说明

RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。RPC它假定某些协议的存在,例如TPC/UDP等,为通信程序之间携带信息数据。在OSI网络七层模型中,RPC跨越了传输层和应用层,RPC使得开发,包括网络分布式多程序在内的应用程序更加容易。

过程是什么? 过程就是业务处理、计算任务,更直白的说,就是程序,就是想调用本地方法一样调用远程的过程。

TouchRpc支持服务器与客户端互相调用,也支持客户端之间相互调用。

二、定义服务

  1. 被调用端中新建一个类名为MyRpcServer
  2. 继承于RpcServer类、或实现IRpcServer。亦或者将服务器声明为瞬时生命的服务,继承TransientRpcServer、或ITransientRpcServer。
  3. 在该类中写公共方法,并用TouchRpc属性标签标记。
public class MyRpcServer : RpcServer
{
[Description("登录")]//服务描述,在生成代理时,会变成注释。
[TouchRpc("Login")]//服务注册的函数键,此处为显式指定。默认不传参的时候,为该函数类全名+方法名的全小写。
public bool Login(string account,string password)
{
if (account=="123"&&password=="abc")
{
return true;
}

return false;
}
}
public class MyRpcServer : TransientRpcServer
{
[Description("登录")]//服务描述,在生成代理时,会变成注释。
[TouchRpc("Login")]//服务注册的函数键,此处为显式指定。默认不传参的时候,为该函数类全名+方法名的全小写。
public bool Login(string account,string password)
{
if (account=="123"&&password=="abc")
{
return true;
}

return false;
}
}
提示

瞬时生命的服务,最大的特点就是,每个请求,都会创建一个新的服务类对象。然后可以通过this.CallContext直接访问当前的调用上下文。

三、启动Rpc服务器

以下仅示例基于Tcp协议TouchRpc。其他协议的服务器请看创建TouchRpc服务器

var service =new  TcpTouchRpcService();
TouchSocketConfig config= new TouchSocketConfig()//配置
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureRpcStore(a=>
{
a.RegisterServer<MyRpcServer>();//注册服务
})
.SetVerifyToken("TouchRpc");

service.Setup(config)
.Start();

service.Logger.Info($"{service.GetType().Name}已启动");

四、调用Rpc

4.1 直接调用

直接调用,则是不使用任何代理,使用字符串参数直接Call Rpc,使用比较简单。

下列以TcpTouchRpcClient为例,其他客户端一模一样。

TcpTouchRpcClient client = new TcpTouchRpcClient();
client.Setup(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.SetVerifyToken("TouchRpc"));
client.Connect();

//直接调用时,第一个参数为调用键
//第二个参数为调用配置参数,可设置调用超时时间,取消调用等功能。示例中使用的预设,实际上可以自行new InvokeOption();
//后续参数为调用参数。
//泛型为返回值类型。
bool result = client.Invoke<bool>("Login", InvokeOption.WaitInvoke, 123, "abc");

4.2、代理调用

代理调用的便捷在于,客户端不用再知道哪些服务可调,也不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。

详细步骤:

  1. 生成代理文件
  2. 将生成的cs文件添加到调用端一起编译。
备注

以上示例,会生成下列代理代码。

【生成的代理】

using TouchSocket.Rpc;
using System.Threading.Tasks;
namespace RpcProxy
{
public interface IMyRpcServer : IRemoteServer
{
///<summary>
///登录
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default);
///<summary>
///登录
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
Task<System.Boolean> LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default);

}
public class MyRpcServer : IMyRpcServer
{
public MyRpcServer(IRpcClient client)
{
this.Client = client;
}
public IRpcClient Client { get; private set; }
///<summary>
///登录
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default)
{
if (Client == null)
{
throw new RpcException("IRpcClient为空,请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client) == false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[] { account, password };
System.Boolean returnData = Client.Invoke<System.Boolean>("Login", invokeOption, parameters);
return returnData;
}
///<summary>
///登录
///</summary>
public Task<System.Boolean> LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default)
{
if (Client == null)
{
throw new RpcException("IRpcClient为空,请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client) == false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[] { account, password };
return Client.InvokeAsync<System.Boolean>("Login", invokeOption, parameters);
}
}
public static class MyRpcServerExtensions
{
///<summary>
///登录
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public static System.Boolean Login<TClient>(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient :
TouchSocket.Rpc.IRpcClient
{
if (client.TryCanInvoke?.Invoke(client) == false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[] { account, password };
System.Boolean returnData = client.Invoke<System.Boolean>("Login", invokeOption, parameters);
return returnData;
}
///<summary>
///登录
///</summary>
public static Task<System.Boolean> LoginAsync<TClient>(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient :
TouchSocket.Rpc.IRpcClient
{
if (client.TryCanInvoke?.Invoke(client) == false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[] { account, password };
return client.InvokeAsync<System.Boolean>("Login", invokeOption, parameters);
}
}
}

使用代理扩展直接调用。

TcpTouchRpcClient client = new TcpTouchRpcClient();
client.Setup(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.SetVerifyToken("TouchRpc"));
client.Connect();

bool result = client.Login(123, "abc");//Login是扩展方法。可能需要额外添加命名空间。

五、反向Rpc

一般的rpc服务都是客户端发起,服务器响应。但是有时候也需要服务器主动调用客户端,所以需要反向rpc。

5.1 定义、发布反向RPC服务

实际上,所有的Rpc客户端(TcpTouchRpcClientUdpTouchRpc(不区分客户端)、HttpTouchRpcClientWSTouchRpcClient)也实现了IRpcParser接口,这意味着反向RPC其实也是RPC,所以,所有操作一模一样。因为当客户端和服务器建立连接以后,就不再区分谁是客户端,谁是服务器了。只关心,谁能提供服务,谁在调用服务

下列就以简单的示例下,由客户端声明服务,服务器调用服务。

具体步骤:

  1. 客户端项目中定义服务
  2. TouchRpc标记
public class ReverseCallbackServer : RpcServer
{
[TouchRpc]
public string SayHello(string name)
{
return $"{name},hi";
}
}

【客户端发布服务】 +发布服务,实际上是让TcpTouchRpcClient也拥有提供RPC的能力。

TcpTouchRpcClient client = new TcpTouchRpcClient();
client.Setup(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
a.AddFileLogger();
})
.ConfigureRpcStore(a =>
{
a.RegisterServer<ReverseCallbackServer>();
})
.SetVerifyToken("TouchRpc"));
client.Connect();

5.2 调用反向RPC

服务器回调客户端,最终必须通过服务器辅助类客户端(ISocketClient的派生类),以TcpTouchRpcService为例,其辅助客户端为TcpTouchRpcSocketClient。

因为,TcpTouchRpcSocketClient已实现IRpcClient接口,意味着,反向RPC也可以使用代理调用。所有用法和RPC一致。

下列示例以TcpTouchRpcSocketClient为例,其余一致。

提示

反向RPC也可以使用代理调用。所有用法和RPC一致。

5.2.1 通过服务器直接获取

可以获取所有终端。

foreach (var item in tcpTouchRpcService.GetClients())
{
client.Logger.Info(item.Invoke<string>("ReverseRpcConsoleApp.ReverseCallbackServer.SayHello".ToLower(), InvokeOption.WaitInvoke, "张三"));
}

也可以先筛选ID,然后再调用。

string id = tcpTouchRpcService.GetIDs().FirstOrDefault(a => a.Equals("特定id"));
if (tcpTouchRpcService.TryGetSocketClient(id, out var rpcSocketClient))
{
rpcSocketClient.Invoke<string>("ReverseRpcConsoleApp.ReverseCallbackServer.SayHello".ToLower(), InvokeOption.WaitInvoke, "张三");
}

5.2.2 通过调用上下文获取

具体步骤

  1. 设置调用上下文
  2. 上下文的Caller,即为服务器辅助类终端,进行强转即可。

六、客户端互Call RPC

除了正向RPC,反向RPC,TouchRpc还支持客户端之间互Call RPC。服务的定义与Rpc一样。

6.1 互Call RPC

客户端A调用客户端B的方法,需要知道对方的ID。和方法名。然后使用下列函数调用即可。

提示

互Call RPC也支持调用上下文。

服务器注意

客户端互Call的时候,每个请求,都需要服务同意路由,才可以被转发。所以服务器需要做一些允许操作。

internal class MyTouchRpcPlugin : TouchRpcPluginBase
{
protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)
{
if (e.RouterType== RouteType.Rpc)
{
e.IsPermitOperation = true;
}
base.OnRouting(client, e);
}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createhttpclient/index.html b/handbook/build/docs/createhttpclient/index.html new file mode 100644 index 000000000..5fd449e05 --- /dev/null +++ b/handbook/build/docs/createhttpclient/index.html @@ -0,0 +1,16 @@ + + + + + +创建HttpClient | TouchSocket + + + + +
+

创建HttpClient

说明

HttpClient是Http客户端类。主要用于请求Http报文。

可配置项

继承TcpClient

支持插件接口

支持ITcpPlugin接口。

创建HttpClient

HttpClient client = new HttpClient();

client.Setup(new TouchSocketConfig()
.UsePlugin()
.SetRemoteIPHost(new IPHost("http://localhost:7219")))
.Connect();//先做连接

HttpRequest request = new HttpRequest();
request
.InitHeaders()
.SetUrl("/WeatherForecast")
.SetHost(client.RemoteIPHost.Host)
.AsGet();

var respose = client.Request(request, timeout: 1000*10);
Console.WriteLine(respose.GetBody());

创建HttpsClient

如果需要连接到Https服务器。则必须手动配置Ssl。示例如下:

如果服务器证书是由证书机构颁发,则只需填充TargetHostSslProtocols

SetClientSslOption(new ClientSslOption() { TargetHost = "localhost", SslProtocols = SslProtocols.Tls12 })

如果服务器证书是由自己制作的,则需要加载证书文件,和必要的验证

.SetClientSslOption(new ClientSslOption()
{
ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") },
SslProtocols = SslProtocols.Tls12,
TargetHost = "127.0.0.1",
CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; }
}));

主要方法简介

方法名功能简介
Request请求Http数据,并等待返回

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createhttpservice/index.html b/handbook/build/docs/createhttpservice/index.html new file mode 100644 index 000000000..575d2ea30 --- /dev/null +++ b/handbook/build/docs/createhttpservice/index.html @@ -0,0 +1,16 @@ + + + + + +创建HttpService | TouchSocket + + + + +
+

创建HttpService

一、说明

HttpService是能够提供Http相关服务的基础类型。

注意

HttpService仅仅支持简单的web服务,如果是和TouchSocket的其他组件配合,则可以使用,如果想单独作为web服务器,则最好不要使用。因为其兼容性比较薄弱。

二、产品特点

  • 支持HTTPS。
  • 多种数据接收模式
  • 多地址监听(可以一次性监听多个IP及端口)

三、产品应用场景

  • HTTP基础使用场景:可跨平台、跨语言使用。

四、服务器架构

服务器在收到新客户端连接时,会创建一个HttpSocketClient的派生类实例,与远程HttpClient对应,后续的数据通信均由此实例负责。

五、支持插件接口

声明自定义实例类,然后实现IHttpPlugin接口,即可实现下列事务的触发。或者继承自HttpPluginBase类,重写相应方法即可。

插件方法功能
OnDelete当收到Delete请求时
OnGet当收到OnGet请求时
OnPost当收到OnPost请求时
OnPut当收到OnPut请求时
OnReceivedOtherHttpRequest当收到OnReceivedOtherHttpRequest请求时

六、创建HttpService

HttpService的创建,基本和TcpService一致,也可以通过继承实现,下列仅演示最简单实现。

HttpService的相关事务,会通过插件触发。

var service = new HttpService();
service.Setup(new TouchSocketConfig()//加载配置
.UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
})
.ConfigurePlugins(a =>
{
a.Add<MyHttpPlug>();

//default插件应该最后添加,其作用是
//1、为找不到的路由返回404
//2、处理header为Option的探视跨域请求。
a.UseDefaultHttpServicePlugin();

}))
.Start();
提示

DefaultHttpServicePlugin插件最好添加在插件中,如果没有添加的话,最好自己做好缺省路由和跨域配置。

在插件中,通过重写(或实现)的方式,进入OnGetOnPostOnDeleteOnPut等函数,即可处理对应请求。

/// <summary>
/// 支持GET、Post、Put,Delete,或者其他
/// </summary>
internal class MyHttpPlug : HttpPluginBase<HttpSocketClient>
{
protected override void OnGet(HttpSocketClient client, HttpContextEventArgs e)
{
if (e.Context.Request.UrlEquals("/success"))
{
//直接响应文字
e.Context.Response.FromText("Success").Answer();//直接回应
Console.WriteLine("处理完毕");
e.Handled = true;
}
else if (e.Context.Request.UrlEquals("/file"))
{
//直接回应文件。
e.Context.Response
.SetStatus()//必须要有状态
.FromFile(@"D:\System\Windows.iso", e.Context.Request);
}
else if (e.Context.Request.UrlEquals("/html"))
{
//回应html
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("<!DOCTYPE html>");
stringBuilder.AppendLine("<html>");
stringBuilder.AppendLine("<head>");
stringBuilder.AppendLine("<meta charset=\"utf-8\"/>");
stringBuilder.AppendLine("<title>TouchSocket</title>");
stringBuilder.AppendLine("</head>");
stringBuilder.AppendLine("<body>");
stringBuilder.AppendLine("<div id=\"kuang\" style=\"width: 50%;height: 85%;left: 25%;top:15%;position: absolute;\">");
stringBuilder.AppendLine("<a id=\"MM\" style=\"font-size: 30px;font-family: 微软雅黑;width: 100%;\">王二麻子</a>");
stringBuilder.AppendLine("<input type=\"text\" id=\"NN\" value=\"\" style=\"font-size: 30px;width:100%;position: relative;top: 30px;\"/>");
stringBuilder.AppendLine("<input type=\"button\" id=\"XX\" value=\"我好\" style=\"font-size: 30px;width: 100%;position: relative;top: 60px;\" onclick=\"javascript:jump()\" />");
stringBuilder.AppendLine("</div>");
stringBuilder.AppendLine("</body>");
stringBuilder.AppendLine("</html>");

e.Context.Response
.SetStatus()//必须要有状态
.SetContentTypeByExtension(".html")
.SetContent(stringBuilder.ToString());
e.Context.Response.Answer();
}
}

protected override void OnPost(HttpSocketClient client, HttpContextEventArgs e)
{

}
}

七、创建加密Ssl的HttpsService

Https服务器,和http服务器几乎一样,只不过增加了一个Ssl的配置。

.SetServiceSslOption(new ServiceSslOption() 
{
Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"),
SslProtocols = SslProtocols.Tls12
}))
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createtcpclient/index.html b/handbook/build/docs/createtcpclient/index.html new file mode 100644 index 000000000..3a4e424eb --- /dev/null +++ b/handbook/build/docs/createtcpclient/index.html @@ -0,0 +1,19 @@ + + + + + +创建TcpClient | TouchSocket + + + + +
+

创建TcpClient

一、说明

TcpClient是Tcp系客户端基类,他直接参与tcp的连接、发送、接收、处理、断开等,他的业务与服务器的SocketClient是一一对应的。

二、特点

  • 简单易用。
  • IOCP多线程。
  • 内存池支持
  • 高性能
  • 适配器预处理,一键式解决分包粘包、对象解析(如HTTP,Json)等。
  • 超简单的同步发送、异步发送、接收等操作。
  • 基于委托、插件驱动,让每一步都能执行AOP。

三、产品应用场景

  • 所有Tcp基础使用场景:可跨平台、跨语言使用。
  • 自定义协议解析场景:可解析任意数据格式的TCP数据报文。

四、可配置项

可配置项

SetBufferLength

发送、接收缓存容量(单位:byte),默认1024×64。设置建议:

  1. 如果数据包较小,建议10k左右的值。更加节约内存。
  2. 如果数据包较大,例如文件传输等,建议64k,甚至更大的值。
  3. 该值虽然无上限,但是一般不要超过1Mb,不然不仅没意义,还很浪费

SetMaxPackageSize

数据包最大值(单位:byte),默认1024×1024×10。该值会在适当时间,直接作用DataHandlingAdapter.MaxPackageSize。

SetThreadCount

多线程数量。该值在Auto模式下指示线程池的最少线程数量和IO线程数量。

设置建议:

  1. 异步处理接收数据,此时线程数量设置为内核线程左右的值即可。
  2. 同步处理接收数据,此时应当考虑两个因素。该操作是否为耗时操作,如果是,则该值在允许范围内,应当设置更可能大的值。如果不是,则设置为内核线程左右的值即可。

SetGetDefaultNewID

配置初始ID的分配策略

SetListenIPHosts

监听IP和端口号组,可以一次性设置多个地址。

SetServerName

服务器标识名称,无实际使用意义。

SetBacklogProperty

Tcp半连接挂起连接队列的最大长度。默认为30

SetMaxCount

最大可连接数,默认为10000

SetReceiveType

接收类型。

  • AUTO:自动接收模式。
  • None:不投递IO接收申请,用户可通过GetStream,获取到流以后,自己处理接收。注意:连接端不会感知主动断开。

UsePlugin

是否启用插件。在启用时或许会带来一点点性能损耗,基本上不是千万数据交互根本不值一提。

SetServiceSslOption

Ssl配置,为Null时则不启用。

UseNoDelay

设置Socket的NoDelay属性,默认false。

UseDelaySender

使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。

使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说:

  1. 如果一个包大于512kb,则不会延迟,直接发送。
  2. 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。

UseReuseAddress

启用端口复用。该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题。

SetRemoteIPHost

链接到的远程IPHost,支持域名。支持类型:

  1. 使用IP&Port,传入形如:127.0.0.1:7789的字符串即可。
  2. 使用域名,必须包含协议类型,形如:http://baidu.com或者https://baidu.com:80

SetClientSslOption

客户端Ssl配置,为Null时则不启用。 +注意,当RemoteIPHost使用https、wss的域名时,该配置会使用系统默认配置生效。

SetKeepAliveValue

为Socket设置的属性。 +注意:该配置仅在window平台生效。

SetBindIPHost

绑定端口。

  • 在UdpSessionBase中表示本地监听地址
  • 在TcpClient中表示固定客户端端口号。

UseDelaySender

使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。

使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说:

如果一个包大于512kb,则不会延迟,直接发送。 +如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。

UseNoDelay

设置Socket的NoDelay属性,默认false。

UseBroadcast

该值指定可以发送或接收广播数据包。

五、支持插件

支持ITcpPlugin接口,或者继承自TcpPluginBase类,重写相应方法即可。

插件方法功能
OnConnecting在Socket完成初始化,但是并未连接时触发。
OnConnected在Socket完成连接,且成功后触发
OnDisconnecting当客户端主动调用Close时触发
OnDisconnected当客户端断开连接后触发
OnReceivingData在收到原始数据时触发,所有的数据均在ByteBlock里面。
OnReceivedData在收到适配器数据时触发,根据适配器类型,数据可能在ByteBlock或者IRequestInfo里面。
OnSendingData当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。

六、创建TcpClient

简单的处理逻辑可通过ConnectingConnectedReceived等委托直接实现。

代码如下:

TcpClient tcpClient = new TcpClient();
tcpClient.Connected += (client, e) => { };//成功连接到服务器
tcpClient.Disconnected += (client, e) => { };//从服务器断开连接,当连接不成功时不会触发。
tcpClient.Received += (client, byteBlock, requestInfo) =>
{
//从服务器收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"接收到信息:{mes}");
};

//声明配置
TouchSocketConfig config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.UsePlugin();

//载入配置
tcpClient.Setup(config);
tcpClient.Connect();
tcpClient.Send("RRQM");

七、接收数据

在TcpClient中,接收数据的方式有很多种。多种方式可以组合使用。

7.1 Received委托处理

当使用TcpClient创建客户端时,内部已经定义好了一个外置委托Received,可以通过该委托直接接收数据。

TcpClient tcpClient = new TcpClient();
tcpClient.Received += (client, byteBlock, requestInfo) =>
{
//从服务器收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"接收到信息:{mes}");
};

//声明配置
TouchSocketConfig config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.UsePlugin();

//载入配置
tcpClient.Setup(config);
tcpClient.Connect();

7.2 插件处理推荐

按照TouchSocket的设计理念,使用插件处理数据,是一项非常简单,且高度解耦的方式。步骤如下:

  1. 服务器配置启用插件(UsePlugin)
  2. 新建插件类
  3. 添加插件

代码如下:

(1)声明插件

public class MyPlugin : TcpPluginBase<TcpClient>
{
public MyPlugin()
{
this.Order = 0;//此值表示插件的执行顺序,当多个插件并存时,该值越大,越在前执行。
}

protected override void OnReceivedData(TcpClient client, ReceivedDataEventArgs e)
{
//这里处理数据接收
//根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。
ByteBlock byteBlock = e.ByteBlock;
IRequestInfo requestInfo = e.RequestInfo;

//e.Handled = true;//表示该数据已经被本插件处理,无需再投递到其他插件。
base.OnReceivedData(client, e);
}
}

(2)创建使用插件处理的客户端

TcpClient client = new TcpClient();
client.Setup(new TouchSocketConfig()
.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.UsePlugin()
.ConfigureContainer(a=>
{
a.AddConsoleLogger();
})
.ConfigurePlugins(a =>
{
a.Add<MyPlugin>();
}))
.Connect();

八、发送数据

【同步发送】

TcpClient已经内置了三种同步发送方法,直接调用就可以发送,但需要注意的是,通过该方法发送的数据,会经过适配器,如果想要直接发送,请使用DefaultSend。如果发送失败,则会立即抛出异常。

public virtual void Send(byte[] buffer);
public virtual void Send(ByteBlock byteBlock);
public virtual void Send(byte[] buffer, int offset, int length);

【异步发送】

TcpClient已经内置了三种异步发送方法,直接调用就可以发送。如果发送失败,await就会触发异常。

public virtual Task SendAsync(byte[] buffer);
public virtual Task SendAsync(byte[] buffer, int offset, int length);
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createtcpservice/index.html b/handbook/build/docs/createtcpservice/index.html new file mode 100644 index 000000000..0b1e38bc1 --- /dev/null +++ b/handbook/build/docs/createtcpservice/index.html @@ -0,0 +1,20 @@ + + + + + +创建TcpService | TouchSocket + + + + +
+

创建TcpService

一、说明

TcpService是Tcp系服务器基类,它不参与实际的数据交互,只是配置、激活、管理、注销、重建SocketClient类实例。而SocketClient是当TcpClient(客户端)成功连接服务器以后,由服务器新建的一个实例类,后续的所有通信,也都是通过该实例完成的。

二、特点

  • 简单易用。
  • IOCP多线程。
  • 内存池支持
  • 高性能(实测服务器单客户端单线程,每秒可接收200w条8字节的信息,接收数据流量可达2.5GB/s)。
  • 多地址监听(可以一次性监听多个IP及端口)
  • 适配器预处理,一键式解决分包粘包、对象解析(如HTTP,Json)等。
  • 超简单的同步发送、异步发送、接收等操作。
  • 基于委托、插件驱动,让每一步都能执行AOP。

三、产品应用场景

  • 所有Tcp基础使用场景:可跨平台、跨语言使用。
  • 自定义协议解析场景:可解析任意数据格式的TCP数据报文。

四、服务器架构

服务器在收到新客户端连接时,会创建一个SocketClient的派生类实例,与客户端TcpClient一一对应,后续的数据通信均由此实例负责。

SocketClient在Service里面以字典映射。ID为键,SocketClient本身为值。

五、可配置项

可配置项

SetBufferLength

发送、接收缓存容量(单位:byte),默认1024×64。设置建议:

  1. 如果数据包较小,建议10k左右的值。更加节约内存。
  2. 如果数据包较大,例如文件传输等,建议64k,甚至更大的值。
  3. 该值虽然无上限,但是一般不要超过1Mb,不然不仅没意义,还很浪费

SetMaxPackageSize

数据包最大值(单位:byte),默认1024×1024×10。该值会在适当时间,直接作用DataHandlingAdapter.MaxPackageSize。

SetThreadCount

多线程数量。该值在Auto模式下指示线程池的最少线程数量和IO线程数量。

设置建议:

  1. 异步处理接收数据,此时线程数量设置为内核线程左右的值即可。
  2. 同步处理接收数据,此时应当考虑两个因素。该操作是否为耗时操作,如果是,则该值在允许范围内,应当设置更可能大的值。如果不是,则设置为内核线程左右的值即可。

SetGetDefaultNewID

配置初始ID的分配策略

SetListenIPHosts

监听IP和端口号组,可以一次性设置多个地址。

SetServerName

服务器标识名称,无实际使用意义。

SetBacklogProperty

Tcp半连接挂起连接队列的最大长度。默认为30

SetMaxCount

最大可连接数,默认为10000

SetReceiveType

接收类型。

  • AUTO:自动接收模式。
  • None:不投递IO接收申请,用户可通过GetStream,获取到流以后,自己处理接收。注意:连接端不会感知主动断开。

UsePlugin

是否启用插件。在启用时或许会带来一点点性能损耗,基本上不是千万数据交互根本不值一提。

SetServiceSslOption

Ssl配置,为Null时则不启用。

UseNoDelay

设置Socket的NoDelay属性,默认false。

UseDelaySender

使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。

使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说:

  1. 如果一个包大于512kb,则不会延迟,直接发送。
  2. 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。

UseReuseAddress

启用端口复用。该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题。

SetRemoteIPHost

链接到的远程IPHost,支持域名。支持类型:

  1. 使用IP&Port,传入形如:127.0.0.1:7789的字符串即可。
  2. 使用域名,必须包含协议类型,形如:http://baidu.com或者https://baidu.com:80

SetClientSslOption

客户端Ssl配置,为Null时则不启用。 +注意,当RemoteIPHost使用https、wss的域名时,该配置会使用系统默认配置生效。

SetKeepAliveValue

为Socket设置的属性。 +注意:该配置仅在window平台生效。

SetBindIPHost

绑定端口。

  • 在UdpSessionBase中表示本地监听地址
  • 在TcpClient中表示固定客户端端口号。

UseDelaySender

使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。

使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说:

如果一个包大于512kb,则不会延迟,直接发送。 +如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。

UseNoDelay

设置Socket的NoDelay属性,默认false。

UseBroadcast

该值指定可以发送或接收广播数据包。

六、支持插件

支持ITcpPlugin接口,或者继承自TcpPluginBase类,重写相应方法即可。

插件方法功能
OnConnecting此时Socket实际上已经完成连接,但是并没有启动接收,然后触发。
OnConnected同意连接,且成功启动接收后触发
OnDisconnecting当客户端主动调用Close时触发
OnDisconnected当客户端断开连接后触发
OnReceivingData在收到原始数据时触发,所有的数据均在ByteBlock里面。
OnReceivedData在收到适配器数据时触发,根据适配器类型,数据可能在ByteBlock或者IRequestInfo里面。
OnSendingData当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。
OnIDChanged当SocketClient的ID发生改变时触发。

七、创建TcpService

7.1 简单创建

直接初始化TcpService,会使用默认的SocketClient。 +简单的处理逻辑可通过ConnectingConnectedReceived等委托直接实现。

代码如下:

TcpService service = new TcpService();
service.Connecting = (client, e) => { };//有客户端正在连接
service.Connected = (client, e) => { };//有客户端成功连接
service.Disconnected = (client, e) => { };//有客户端断开连接
service.Received = (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
client.Logger.Info($"已从{client.ID}接收到信息:{mes}");

client.Send(mes);//将收到的信息直接返回给发送方

//client.Send("id",mes);//将收到的信息返回给特定ID的客户端

var ids = service.GetIDs();
foreach (var clientId in ids)//将收到的信息返回给在线的所有客户端。
{
if (clientId != client.ID)//不给自己发
{
service.Send(clientId, mes);
}
}
};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.ConfigureContainer(a =>//容器的配置顺序应该在最前面
{
a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用)
})
.ConfigurePlugins(a =>
{
//a.Add();//此处可以添加插件
}))
.Start();//启动

7.2 泛型创建

通过泛型创建服务器,可以实现很多有意思,且能重写一些有用的功能。下面就演示,如何通过泛型创建服务器。

代码如下:

(1)建立SocketClient继承类。

public class MySocketClient : SocketClient
{
protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
{
//此处逻辑单线程处理。

//此处处理数据,功能相当于Received委托。
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"已接收到信息:{mes}");
}
}

(2)建立TcpService继承类。实际上如果业务不涉及服务器配置的话,可以省略该步骤,使用TcpService的泛型直接创建。

public class MyService : TcpService<MySocketClient>
{
protected override void LoadConfig(TouchSocketConfig config)
{
//此处加载配置,用户可以从配置中获取配置项。
base.LoadConfig(config);
}

protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e)
{
//此处逻辑会多线程处理。


//e.ID:对新连接的客户端进行ID初始化,例如可以设置为其IP地址。
//e.IsPermitOperation:指示是否允许该客户端链接。
base.OnConnecting(socketClient, e);
}
}

(3)创建服务器(包含MyService)。

MyService service = new MyService();
service.Connecting = (client, e) => { };//有客户端正在连接
service.Connected = (client, e) => { };//有客户端成功连接
service.Disconnected = (client, e) => { };//有客户端断开连接

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.ConfigureContainer(a =>//容器的配置顺序应该在最前面
{
a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用)
})
.ConfigurePlugins(a =>
{
//a.Add();//此处可以添加插件
}))
.Start();//启动

(4)创建服务器(不含MyService)。

TcpService<MySocketClient> service = new TcpService<MySocketClient>();
service.Connecting = (client, e) => { };//有客户端正在连接
service.Connected = (client, e) => { };//有客户端成功连接
service.Disconnected = (client, e) => { };//有客户端断开连接

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.ConfigureContainer(a =>//容器的配置顺序应该在最前面
{
a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用)
})
.ConfigurePlugins(a =>
{
//a.Add();//此处可以添加插件
}))
.Start();//启动
建议

由上述代码可以看出,通过继承,可以更加灵活的实现扩展。但实际上,很多业务我们希望大家能通过插件完成。

八、接收数据

在TcpService中,接收数据的方式有很多种。多种方式可以组合使用。

8.1 Received委托处理

当使用TcpService(非泛型)创建服务器时,内部已经定义好了一个外置委托Received,可以通过该委托直接接收数据。

TcpService service = new TcpService();
service.Received = (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
client.Logger.Info($"已从{client.ID}接收到信息:{mes}");
};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.ConfigureContainer(a =>//容器的配置顺序应该在最前面
{
a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用)
}))
.Start();//启动

8.2 重写SocketClient处理

正如6.2所示,可以直接在MySocketClient的重写HandleReceivedData中直接处理数据。

8.3 插件处理

按照TouchSocket的设计理念,使用插件处理数据,是一项非常简单,且高度解耦的方式。步骤如下:

  1. 服务器配置启用插件(UsePlugin)
  2. 新建插件类
  3. 添加插件

代码如下:

(1)声明插件

public class MyPlugin : TcpPluginBase<SocketClient>
{
public MyPlugin()
{
this.Order = 0;//此值表示插件的执行顺序,当多个插件并存时,该值越大,越在前执行。
}

protected override void OnReceivedData(SocketClient client, ReceivedDataEventArgs e)
{
//这里处理数据接收
//根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。
ByteBlock byteBlock = e.ByteBlock;
IRequestInfo requestInfo = e.RequestInfo;

//e.Handled = true;//表示该数据已经被本插件处理,无需再投递到其他插件。
base.OnReceivedData(client, e);
}
}

(2)创建使用插件处理的服务器

TcpService service = new TcpService();
service.Setup(new TouchSocketConfig()
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })
.UsePlugin()
.ConfigureContainer(a=>
{
a.UseConsoleLogger();
})
.ConfigurePlugins(a =>
{
a.Add<MyPlugin>();
}))
.Start();

九、AspNetCore中创建

首先建议安装TouchSocket.AspNetCore或者TouchSocketPro.AspNetCore,因为这个里面有很多可以直接使用的注入项。

建议

在安装TouchSocket.AspNetCore或者TouchSocketPro.AspNetCore的同时,最好也安装TouchSocket或者TouchSocketPro。这样更新也即时一些。

在AspNetCore中使用TcpService,不应该像普通端一样,订阅Received。应该是通过插件注入等方式实现。步骤如下:

  1. 注入TcpService,并做好配置(和常规服务器配置一样)。
  2. 新建插件,处理收到的数据。

代码如下:

(1)声明插件

public class MyTcpPlugin : TcpPluginBase<SocketClient>
{
private ILogger<MyTcpPlugin> m_logger;

public MyTcpPlugin(ILogger<MyTcpPlugin> logger)
{
this.m_logger = logger;
}

protected override void OnConnected(SocketClient client, TouchSocketEventArgs e)
{
m_logger.LogInformation("客户端连接");
base.OnConnected(client, e);
}

protected override void OnReceivedData(SocketClient client, ReceivedDataEventArgs e)
{
//这里处理数据接收
//根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。
ByteBlock byteBlock = e.ByteBlock;
IRequestInfo requestInfo = e.RequestInfo;
}
}

(2)注入服务

public void ConfigureServices(IServiceCollection services)
{
var tcpService = services.AddTcpService(config =>
{
config.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.UsePlugin()
.UseAspNetCoreContainer(services)
.ConfigurePlugins(a =>
{
a.Add<MyTcpPlugin>();//此插件就可以处理接收数据
});
});
}

然后在任意地方,也可获得服务。

image.png

提示

此时,TcpService与整个AspNetCore是共享IOC容器的。即:TcpService中的任何地方(例如:插件)也能获得AspNetCore已注册的服务。

十、发送数据

按照架构图,每个客户端成功连接后,服务器都会创建一个派生自SocketClient的实例,通过该实例即可将数据发送至客户端

10.1 如何获取SocketClient?

(1)直接获取所有在线客户端

通过service.GetClients方法,获取当前在线的所有客户端。

SocketClient[] socketClients = service.GetClients();
注意

由于SocketClient的生命周期是由框架控制的,所以最好尽量不要直接引用该实例,可以引用SocketClient.ID,然后再通过服务器查找。

(2)通过ID获取

先调用service.GetIDs方法,获取当前在线的所有客户端的ID,然后选择需要的ID,通过TryGetSocketClient方法,获取到想要的客户端。

string[] ids = service.GetIDs();
if (service.TryGetSocketClient(ids[0], out SocketClient socketClient))
{
}

10.2 发送

【同步发送】

SocketClient已经内置了三种同步发送方法,直接调用就可以发送,如果发送失败,则会立即抛出异常。

public virtual void Send(byte[] buffer);
public virtual void Send(ByteBlock byteBlock);
public virtual void Send(byte[] buffer, int offset, int length);

【异步发送】

TcpClient已经内置了三种异步发送方法,直接调用就可以发送。如果发送失败,await就会触发异常。

public virtual Task SendAsync(byte[] buffer);
public virtual Task SendAsync(ByteBlock byteBlock);
public virtual Task SendAsync(byte[] buffer, int offset, int length);
提示

通过上述方法发送的数据,都会经过适配器,如果想要直接发送,请使用DefaultSend

10.3 通过TcpService发送

通过ID发送数据。

public virtual void Send(string id, ByteBlock byteBlock);
public virtual void Send(string id, byte[] buffer, int offset, int length);
public virtual void Send(string id, byte[] buffer);
public virtual Task SendAsync(string id, ByteBlock byteBlock);
public virtual Task SendAsync(string id, byte[] buffer, int offset, int length);
public virtual Task SendAsync(string id, byte[] buffer);
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createtouchrpcclient/index.html b/handbook/build/docs/createtouchrpcclient/index.html new file mode 100644 index 000000000..cf5627380 --- /dev/null +++ b/handbook/build/docs/createtouchrpcclient/index.html @@ -0,0 +1,17 @@ + + + + + +创建TouchRpc客户端 | TouchSocket + + + + +
+

创建TouchRpc客户端

一、说明

TouchRpc客户端对应的,也有四种不同协议的版本。

二、可配置项

可配置项

SetVerifyTimeout

设置验证超时时间,默认3000ms。(仅TcpTouchRpc可用) 。

SetVerifyToken

设置验证口令。

SetHeartbeatFrequency

设置心跳。默认为间隔2000ms,连续3次无响应即视为断开。

SetSerializationSelector

设置序列化选择器。

SetResponseType

设置允许的响应类型

SetRootPath

设置根路径

三、支持插件接口

声明自定义实例类,然后实现ITouchRpcPlugin接口,即可实现下列事务的触发。 +或者继承自TouchRpcPluginBase类,重写相应方法即可。

插件方法功能
OnHandshaking客户端在验证连接。默认情况下,框架会首先验证连接Token是否正确,如果不正确则直接拒绝。不会有任何投递。用户也可以使用Metadata进行动态验证。
OnHandshaked客户端完成连接验证
OnFileTransfering在文件传输即将进行时触发。
OnFileTransfered当文件传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。
OnLoadingStream在远程请求加载流时触发。
OnReceivedProtocolData收到协议数据
OnRemoteAccessing在远程操作访问之前。
OnRemoteAccessed在远程操作访问之后。
OnRouting当需要转发路由包时。一般所有的客户端之间的数据传输,都需要经过该函数的运行。
OnStreamTransfering即将接收流数据,用户需要在此事件中对e.Bucket初始化。
OnStreamTransfered流数据处理,用户需要在此事件中对e.Bucket手动释放。 当流数据传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。

四、创建

4.1 TcpTouchRpcClient

基本创建如下,支持创建TcpClient的所有配置。

TcpTouchRpcClient client = new TcpTouchRpcClient();
client.Setup(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.SetVerifyToken("TouchRpc"));
client.Connect();

4.2 HttpTouchRpcClient

基本创建如下,支持创建TcpClient的所有配置。

HttpTouchRpcClient client = new HttpTouchRpcClient();
client.Setup(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.SetVerifyToken("TouchRpc"));
client.Connect();

4.3 UdpTouchRpc

基本创建如下,支持@的所有配置。

UdpTouchRpc client = new UdpTouchRpc();
client.Setup(new TouchSocketConfig()
.SetBindIPHost(7794)
.SetRemoteIPHost("127.0.0.1:7789"));//设置目标地址。
client.Start();

4.4 WSTouchRpcClient

 WSTouchRpcClient client = new WSTouchRpcClient();
client.Setup(new TouchSocketConfig()
.SetRemoteIPHost("ws://127.0.0.1:5000/wstouchrpc"));
client.ConnectAsync();
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createtouchrpcservice/index.html b/handbook/build/docs/createtouchrpcservice/index.html new file mode 100644 index 000000000..c29cc0bbf --- /dev/null +++ b/handbook/build/docs/createtouchrpcservice/index.html @@ -0,0 +1,17 @@ + + + + + +创建TouchRpc服务器 | TouchSocket + + + + +
+

创建TouchRpc服务器

一、说明

TouchRpc的服务器有多种形式的host,每种服务器的创建都大同小异,且功能基本一致。

二、服务器架构

TouchRpc服务器的架构与其所属的基础协议架构一致,例如,在基于tcp协议时,其架构就和tcp服务器一致。在收到新客户端连接时,会创建一个TcpTouchRpcSocketClient的类实例,与客户端TcpTouchRpcClient一一对应,后续的数据通信均由此实例负责。

三、可配置项

可配置项

SetVerifyTimeout

设置验证超时时间,默认3000ms。(仅TcpTouchRpc可用) 。

SetVerifyToken

设置验证口令。

SetHeartbeatFrequency

设置心跳。默认为间隔2000ms,连续3次无响应即视为断开。

SetSerializationSelector

设置序列化选择器。

SetResponseType

设置允许的响应类型

SetRootPath

设置根路径

四、支持插件接口

声明自定义实例类,然后实现ITouchRpcPlugin接口,即可实现下列事务的触发。 +或者继承自TouchRpcPluginBase类,重写相应方法即可。

插件方法功能
OnHandshaking客户端在验证连接。默认情况下,框架会首先验证连接Token是否正确,如果不正确则直接拒绝。不会有任何投递。用户也可以使用Metadata进行动态验证。
OnHandshaked客户端完成连接验证
OnFileTransfering在文件传输即将进行时触发。
OnFileTransfered当文件传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。
OnLoadingStream在远程请求加载流时触发。
OnReceivedProtocolData收到协议数据
OnRemoteAccessing在远程操作访问之前。
OnRemoteAccessed在远程操作访问之后。
OnRouting当需要转发路由包时。一般所有的客户端之间的数据传输,都需要经过该函数的运行。
OnStreamTransfering即将接收流数据,用户需要在此事件中对e.Bucket初始化。
OnStreamTransfered流数据处理,用户需要在此事件中对e.Bucket手动释放。 当流数据传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。

五、创建服务器

5.1 基于Tcp协议

这是基于Tcp协议TouchRpc。在可配置TouchRpc的基础之上,还可以配置与TcpService可配置项相关的配置。

var service = new TcpTouchRpcService();
var config = new TouchSocketConfig()//配置
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
a.AddFileLogger();
})
.SetVerifyToken("TouchRpc");//设定连接口令,作用类似账号密码

service.Setup(config)
.Start();

service.Logger.Info($"{service.GetType().Name}已启动");

5.2 基于Http协议

这是基于Http升级协议。在该解析器中,配置设置HttpService一致。

var service = new HttpTouchRpcService();
TouchSocketConfig config = new TouchSocketConfig()//配置
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
a.AddFileLogger();
})
.SetVerifyToken("TouchRpc");

service.Setup(config)
.Start();

service.Logger.Info($"{service.GetType().Name}已启动");

5.3 基于Udp协议

这是基于UDP协议解析器。在该解析器中,配置设置与UdpSession一致。因为udp是无连接的,所以不需要SetVerifyToken。

var service = new UdpTouchRpc();
TouchSocketConfig config = new TouchSocketConfig()//配置
.SetBindIPHost(new IPHost(7789))
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
a.AddFileLogger();
});

service.Setup(config)
.Start();

service.Logger.Info($"{service.GetType().Name}已启动");

5.4 基于AspNetCore的Websocket协议

具体步骤

  1. nuget 安装TouchSocket.AspNetCore或者TouchSocketPro.AspNetCore
  2. IServiceCollection添加AddWSTouchRpc,并进行相关配置(不用配置端口,会和asp使用同一端口)。
  3. IApplicationBuilder必须先使用UseWebSockets。
  4. IApplicationBuilder调用UseWSTouchRpc,并传入url设置。

在ConfigureServices时,添加AddWSTouchRpc,并且配置相关项。

public void ConfigureServices(IServiceCollection services)
{
//向Asp服务中添加IWSTouchRpcService
services.AddWSTouchRpc(new TouchSocketConfig()
.UseAspNetCoreContainer(services));//设置IOC容器

services.AddControllers();

services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "API Demo", Version = "v1" });
});
}

启用中间件

首先必须启用WebSocket。其次使用UseWSTouchRpc即可。

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

// Swagger
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "API Demo v1");
});


app.UseWebSockets();//必须先使用WebSocket
app.UseWSTouchRpc("/wstouchrpc");//该操作不会影响原有的WebSocket,只要url不同即可。

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createudpsession/index.html b/handbook/build/docs/createudpsession/index.html new file mode 100644 index 000000000..f254b2386 --- /dev/null +++ b/handbook/build/docs/createudpsession/index.html @@ -0,0 +1,16 @@ + + + + + +创建UdpSession | TouchSocket + + + + +
+

创建UdpSession

一、说明

UDP组件是基于UDP协议的最基础组件,其功能简单,易用。它既能充当服务器,又能够作为客户端。

二、产品特点

  • 简单易用。
  • 多线程。
  • 内存池
  • 高性能

三、产品应用场景

  • UDP基础使用场景:可跨平台、跨语言使用。

四、支持插件接口

声明自定义实例类,然后实现IUdpSessionPlugin接口,即可实现下列事务的触发。或者继承自UdpSessionPluginBase类,重写相应方法即可。

插件方法功能
OnReceivedData在收到数据时触发

四、使用UdpSession

UdpSession udpSession = new UdpSession();
udpSession.Received += (remote, byteBlock,requestInfo) =>
{
udpSession.Send(remote, byteBlock);
Console.WriteLine($"收到:{Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len)}");
};
udpSession.Setup(new TouchSocketConfig()
.SetBindIPHost(new IPHost(7789)))
.Start();
Console.WriteLine("等待接收");

注意
  1. 即使不监听地址,Setup和Start都是必须要的。
  2. 当udp作为客户端时,Config如果不设置SetBindIPHost,将不会接收,如果不知道绑定那个端口,可以直接绑定0端口,这样,就会使用系统空闲的一个端口了。
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createwebsocketclient/index.html b/handbook/build/docs/createwebsocketclient/index.html new file mode 100644 index 000000000..49923081c --- /dev/null +++ b/handbook/build/docs/createwebsocketclient/index.html @@ -0,0 +1,18 @@ + + + + + +创建WebSocket客户端 | TouchSocket + + + + +
+

创建WebSocket客户端

说明

支持Ssl的WebSocket客户端。

可配置项

继承HttpClient。

支持插件接口

支持ITcpPlugin、IWebSocketPlugin

创建WS客户端

WebSocketClient myWSClient = new WebSocketClient();
//myWSClient.Received += this.MyWSClient_Received;
//myWSClient.Handshaked += this.MyWSClient_Handshaked;

myWSClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost(this.textBox3.Text)
.ConfigureContainer(a =>
{
a.SetSingletonLogger(new LoggerGroup(new EasyLogger(this.ShowMsg), new FileLogger()));
}));
myWSClient.Connect();

myWSClient.Logger.Message("连接成功");

创建WSs客户端

*当需要连接到由证书机构颁发的网址(例如:小程序__物联网__等)时,仅需要设置url即可。*

wss://127.0.0.1:7789/ws

当连接自定义证书的Ssl:wss://127.0.0.1:7789/ws

WebSocketClient myWSClient = new WebSocketClient();

myWSClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost(new IPHost("wss://127.0.0.1:7789/ws"))
.SetClientSslOption(
new ClientSslOption()
{
ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") },
SslProtocols = SslProtocols.Tls12,
TargetHost = "127.0.0.1",
CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; }
}))
.Connect();

Console.WriteLine("连接成功");
while (true)
{
myWSClient.SendWithWS(Console.ReadLine());
}

注意:当使用域名连接时,TargetHost为域名,例如连接到IPHost("ws://baidu.com")时,TargetHost应当填写:baidu.com

发送数据

将client对象转为HttpClient,即可使用扩展方法,进行发送。

作为一条消息发送

将一个数据分包发送 +例如:发送的数据为{0,1,2,3,4,5,6,7,8,9},当设置packageSize为5时,会先发送{0,1,2,3,4}作为头包,然后发送{5,6,7,8,9}的后继包。

接收数据

订阅Received事件实现,或使用插件实现。

client.Received += (c, e) =>
{
switch (e.Opcode)
{
case WSDataType.Cont:
break;
case WSDataType.Text:
break;
case WSDataType.Binary:
break;
case WSDataType.Close:
break;
case WSDataType.Ping:
break;
case WSDataType.Pong:
break;
default:
break;
}
};

附加插件实现 +该操作和服务器一致。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/createwebsocketservice/index.html b/handbook/build/docs/createwebsocketservice/index.html new file mode 100644 index 000000000..98f6a845b --- /dev/null +++ b/handbook/build/docs/createwebsocketservice/index.html @@ -0,0 +1,22 @@ + + + + + +创建WebSocket服务器 | TouchSocket + + + + +
+

创建WebSocket服务器

一、说明

WebSocket是基于Http协议的升级协议,所以应当挂载在http服务器执行。

二、可配置项

继承HttpService

三、支持插件接口

支持ITcpPlugin、IHttpPlugin、IWebSocketPlugin

IWebSocketPlugin

OnHandshaking表示在即将握手连接时。
OnHandshaked表示完成握手后。
OnHandleWSDataFrame当收到WS数据时。

四、创建WebSocket服务

4.1 简单通过插件创建

通过插件创建的话,只能指定一个特殊url路由。如果想获得连接前的Http请求,也必须再添加一个实现IWebSocketPlugin接口的插件,然后从OnHandshaking方法中捕获。

var service = new HttpService();
service.Setup(new TouchSocketConfig()//加载配置
.UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.SetSingletonLogger<ConsoleLogger>();
})
.ConfigurePlugins(a =>
{
a.Add<WebSocketServerPlugin>()//添加WebSocket功能
.SetWSUrl("/ws")
.SetCallback(WSCallback);//WSCallback回调函数是在WS收到数据时触发回调的。
a.Add<MyWebSocketPlugin>();//MyWebSocketPlugin是继承自WebSocketPluginBase的插件。
}))
.Start();

Console.WriteLine("Http服务器已启动");
Console.WriteLine("ws://127.0.0.1:7789/ws");

4.2 通过WebApi创建

通过WebApi的方式会更加灵活,也能很方便的获得Http相关参数。还能实现多个Url的连接路由。 +实现步骤:

  1. 必须启用插件
  2. 必须配置ConfigureRpcStore,和注册MyServer
  3. 必须添加WebApiParserPlugin
var service = new HttpService();
service.Setup(new TouchSocketConfig()//加载配置
.UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.SetSingletonLogger<ConsoleLogger>();
})
.ConfigureRpcStore(a=>
{
a.RegisterServer<MyServer>();
})
.ConfigurePlugins(a =>
{
a.Add<WebApiParserPlugin>();
}))
.Start();

Console.WriteLine("服务器已启动,可使用下列地址连接");
Console.WriteLine("ws://127.0.0.1:7789/MyServer/ConnectWS");
public class MyServer : RpcServer
{
private readonly ILog m_logger;

public MyServer(ILog logger)
{
this.m_logger = logger;
}

[Router("/[api]/[action]")]
[WebApi(HttpMethodType.GET, MethodFlags = MethodFlags.IncludeCallContext)]
public void ConnectWS(IWebApiCallContext callContext)
{
if (callContext.Caller is HttpSocketClient socketClient)
{
if (socketClient.SwitchProtocolToWebSocket(callContext.Context))
{
m_logger.Message("WS通过WebApi连接");
}
}
}
}

创建基于Ssl的WebSocket服务

创建WSs服务器时,其他配置不变,只需要在config中配置SslOption代码即可。 +在RRQMBox中,放置了一个自制Ssl证书,密码为“RRQMSocket”以供测试。使用配置非常方便。

var config = new TouchSocketConfig();
config.UsePlugin()
.SetReceiveType(ReceiveType.Auto)
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.SetServiceSslOption(new ServiceSslOption() //Ssl配置,当为null的时候,相当于创建了ws服务器,当赋值的时候,相当于wss服务器。
{
Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"),
SslProtocols = SslProtocols.Tls12
});

接收消息

【回调接收】 +在添加WebSocketServerPlugin插件后,可以调用SetCallback函数,然后设置一个回调函数(如下所示),然后该函数在服务器收到信息时,会触发(并发触发)。

static void WSCallback(ITcpClientBase client, WSDataFrameEventArgs e)
{
switch (e.DataFrame.Opcode)
{
case WSDataType.Cont:
Console.WriteLine($"收到中间数据,长度为:{e.DataFrame.PayloadLength}");
break;
case WSDataType.Text:
Console.WriteLine(e.DataFrame.ToText());
break;
case WSDataType.Binary:
if (e.DataFrame.FIN)
{
Console.WriteLine($"收到二进制数据,长度为:{e.DataFrame.PayloadLength}");
}
else
{
Console.WriteLine($"收到未结束的二进制数据,长度为:{e.DataFrame.PayloadLength}");
}
break;
case WSDataType.Close:
{
Console.WriteLine("远程请求断开");
client.Close("断开");
}

break;
case WSDataType.Ping:
break;
case WSDataType.Pong:
break;
default:
break;
}
}

【继承源插件接收】 +实际上WebSocketServerPlugin是可以被继承的,然后重写OnHandleWSDataFrame函数,但尽量不要覆盖基类方法,不然插件其他将不会触发。

class MyWebSocketServerPlugin: WebSocketServerPlugin
{
protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e)
{
base.OnHandleWSDataFrame(client, e);
}
}

【插件接口接收】 +WS服务器,虽然是Http的插件,但是也能触发插件接口。适用于WS的插件接口是IWebSocketPlugin(或者从WebSocketPluginBase继承),声明任意类,实现该接口即可。

class MyWebSocketServerPlugin: WebSocketPluginBase
{
protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e)
{
//此处的父类方法可以直接覆盖。
base.OnHandleWSDataFrame(client, e);
}
}

回复、响应数据

在以上接收、或直接从HttpService获取Clients,将client对象转为HttpSocketClient,即可使用扩展方法,进行发送。

不要直接Send,7.x版本直接Send可以,但8.0以后,Send只会以TCP数据回应。

作为一条消息发送

服务器广播发送

//广播给所有人
if (client is HttpSocketClient socketClient && socketClient.Service is HttpService service)
{
var clients = service.GetClients();
foreach (var item in clients)
{
item.SendWithWS(e.DataFrame.ToText());
}
}

将一个数据分包发送 +例如:发送的数据为{0,1,2,3,4,5,6,7,8,9},当设置packageSize为5时,会先发送{0,1,2,3,4}作为头包,然后发送{5,6,7,8,9}的后继包。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/custombetweenanddatahandlingadapter/index.html b/handbook/build/docs/custombetweenanddatahandlingadapter/index.html new file mode 100644 index 000000000..d74d55951 --- /dev/null +++ b/handbook/build/docs/custombetweenanddatahandlingadapter/index.html @@ -0,0 +1,17 @@ + + + + + +模板解析“区间数据”数据适配器 | TouchSocket + + + + +
+

模板解析“区间数据”数据适配器

一、说明

区间适配器,一般用于字符串类的消息,类似“Hello##”,该数据,以开头,以##结尾。当然,区间适配器也能用于二进制数据,但是会有概率发生标识重复的情况。所以,用于二进制时,应当设置较复杂的区间标识。

该适配器与[终止因子分割适配器](../8.2 Tcp适配器/d.终止因子分割数据处理适配器.mdx)相比,可以设置开头的字符区间。

二、特点

  1. 可以自由适配很多的字符串数据协议。
  2. 可以随意定制数据协议。
  3. 可以与任意语言、框架对接数据。

三、使用

客户端与服务器均适用。下列以服务器为例。

步骤

  1. 声明新建类,实现IBetweenAndRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。
  2. 声明新建类,继承CustomBetweenAndDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。
  3. TouchSocketConfig配置中设置。
  4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。

【MyBetweenAndRequestInfo】 +首先,新建MyBetweenAndRequestInfo类,然后实现IBetweenAndRequestInfo接口。

/// <summary>
/// 以**12##12##,Min=5为例。
/// </summary>
class MyBetweenAndRequestInfo : IBetweenAndRequestInfo
{
public void OnParsingBody(byte[] body)
{
//这里的Body应该为12##12
}

public bool OnParsingEndCode(byte[] endCode)
{
return true;//该返回值决定,是否执行Receive
}

public bool OnParsingStartCode(byte[] startCode)
{
return true;
}
}

新建MyCustomBetweenAndDataHandlingAdapter继承CustomBetweenAndDataHandlingAdapter,然后对StartCode、EndCode作出赋值,以此表明起始字符与结束字符的值。

class MyCustomBetweenAndDataHandlingAdapter : CustomBetweenAndDataHandlingAdapter<MyBetweenAndRequestInfo>
{
public MyCustomBetweenAndDataHandlingAdapter()
{
this.MinSize = 5;//表示,实际数据体不会小于5,例如“**12##12##”数据,解析后会解析成“12##12”
}

public override byte[] StartCode => Encoding.UTF8.GetBytes("**");//可以为0长度字节,意味着没有起始标识。

public override byte[] EndCode => Encoding.UTF8.GetBytes("##");//必须为有效值。

protected override MyBetweenAndRequestInfo GetInstance()
{
return new MyBetweenAndRequestInfo();
}
}

【接收】

TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型
if (requestInfo is MyBetweenAndRequestInfo myRequestInfo)
{
//此处可以处理MyBigFixedHeaderRequestInfo的相关信息了。
}

};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(() => { return new MyCustomBetweenAndDataHandlingAdapter(); }))//配置适配器
.Start();//启动
提示

上述创建的适配器客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/customdatahandlingadapter/index.html b/handbook/build/docs/customdatahandlingadapter/index.html new file mode 100644 index 000000000..1a84bbe77 --- /dev/null +++ b/handbook/build/docs/customdatahandlingadapter/index.html @@ -0,0 +1,16 @@ + + + + + +用户自定义适配器 | TouchSocket + + + + +
+

用户自定义适配器

一、说明

和原始适配器相比,用户自定义适配器(CustomDataHandlingAdapter)简单很多。因为他只需要考虑接下来如何处理即可。

二、运行逻辑

返回指令类型:

  • FilterResult.Cache:将ByteBlock中的,从ByteBlock.Pos到结束的所有数据进行缓存,用于和下次接收数据做拼接。
  • FilterResult.Success:完成本次数据解析,向Received投递IRequestInfo对象。在返回之前,请一定确保已经修改ByteBlock.Pos属性。不然会发生无限循环的危险情况。
  • FilterResult.GoOn:将ByteBlock.Pos至结束的数据重新投递,所以在返回之前,请一定确保已经修改ByteBlock.Pos属性,至少已经递增一位。不然会发生无限循环的危险情况。
注意

返回Success或者GoOn指令时,请一定确保已经修改ByteBlock.Pos属性,至少已经递增一位。不然会发生无限循环的危险情况。

三、特点

  1. 更加自由度的操作数据。
  2. 能够简单的缓存不能解析的数据。

四、使用

还是以下列数据为例:

步骤

  1. 声明新建类,实现IRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。
  2. 声明新建类,继承CustomDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。
  3. TouchSocketConfig配置中设置。
  4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。

【定义适配器】

internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter<MyRequestInfo>
{

/// <summary>
/// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。
/// <para>当不满足解析条件时,请返回<see cref="FilterResult.Cache"/>,此时会保存<see cref="ByteBlock.CanReadLen"/>的数据</para>
/// <para>当数据部分异常时,请移动<see cref="ByteBlock.Pos"/>到指定位置,然后返回<see cref="FilterResult.GoOn"/></para>
/// <para>当完全满足解析条件时,请返回<see cref="FilterResult.Success"/>最后将<see cref="ByteBlock.Pos"/>移至指定位置。</para>
/// </summary>
/// <param name="byteBlock">字节块</param>
/// <param name="beCached">是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。</param>
/// <param name="request">对象。</param>
/// <param name="tempCapacity">缓存容量指导,指示当需要缓存时,应该申请多大的内存。</param>
/// <returns></returns>
protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref MyRequestInfo request, ref int tempCapacity)
{
//以下解析思路为一次性解析,不考虑缓存的临时对象。

if (byteBlock.CanReadLen < 3)
{
return FilterResult.Cache;//当头部都无法解析时,直接缓存
}

int pos = byteBlock.Pos;//记录初始游标位置,防止本次无法解析时,回退游标。

MyRequestInfo myRequestInfo = new MyRequestInfo();

//此操作实际上有两个作用,
//1.填充header
//2.将byteBlock.Pos递增3的长度。
byteBlock.Read(out byte[] header, 3);//填充header

//因为第一个字节表示所有长度,而DataType、OrderType已经包含在了header里面。
//所有只需呀再读取header[0]-2个长度即可。
byte bodyLength = (byte)(header[0] - 2);

if (bodyLength > byteBlock.CanReadLen)
{
//body数据不足。
byteBlock.Pos = pos;//回退游标
return FilterResult.Cache;
}
else
{
//此操作实际上有两个作用,
//1.填充body
//2.将byteBlock.Pos递增bodyLength的长度。
byteBlock.Read(out byte[] body, bodyLength);

myRequestInfo.Header = header;
myRequestInfo.DataType = header[1];
myRequestInfo.OrderType = header[2];
myRequestInfo.Body = body;
request = myRequestInfo;//赋值ref
return FilterResult.Success;//返回成功
}
}
}

internal class MyRequestInfo : IRequestInfo
{
/// <summary>
/// 自定义属性,Body
/// </summary>
public byte[] Body { get; internal set; }

/// <summary>
/// 自定义属性,Header
/// </summary>
public byte[] Header { get; internal set; }

/// <summary>
/// 自定义属性,DataType
/// </summary>
public byte DataType { get; internal set; }

/// <summary>
/// 自定义属性,OrderType
/// </summary>
public byte OrderType { get; internal set; }
}

【接收】

TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型
if (requestInfo is MyRequestInfo myRequestInfo)
{
//此处可以处理MyRequestInfo的相关信息了。
string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);
}

};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(() => { return new MyCustomDataHandlingAdapter(); }))//配置适配器
.Start();//启动
提示

上述创建的适配器客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/customfixedheaderdatahandlingadapter/index.html b/handbook/build/docs/customfixedheaderdatahandlingadapter/index.html new file mode 100644 index 000000000..6d487d83f --- /dev/null +++ b/handbook/build/docs/customfixedheaderdatahandlingadapter/index.html @@ -0,0 +1,16 @@ + + + + + +模板解析“固定包头”数据适配器 | TouchSocket + + + + +
+

模板解析“固定包头”数据适配器

一、说明

和用户自定义适配器相比,使用模板解析将会更加简单流程。例如在上节所说的数据格式,前三个字节是固定长度的,为3,而后续长度则由第一个字节计算可得,所以我们把类似这样的数据格式,叫做“固定包头”数据,那么,他就可以使用固定包头数据解析模板。

二、特点

  1. 可以自由适配99%的数据协议(例如:modbus,电力控制协议等)。
  2. 可以随意定制数据协议。
  3. 可以与任意语言、框架对接数据。

三、使用

客户端与服务器均适用。下列以服务器为例。

步骤

  1. 声明新建类,实现IFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。
  2. 声明新建类,继承CustomFixedHeaderDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。
  3. TouchSocketConfig配置中设置。
  4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。

【MyFixedHeaderRequestInfo】

首先,新建MyFixedHeaderRequestInfo类,然后实现IFixedHeaderRequestInfo用户自定义固定包头接口。

然后在OnParsingHeader函数执行结束时,对实现的BodyLength属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。

public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo
{
private int bodyLength;
/// <summary>
/// 接口实现,标识数据长度
/// </summary>
public int BodyLength
{
get { return bodyLength; }
}

private byte dataType;
/// <summary>
/// 自定义属性,标识数据类型
/// </summary>
public byte DataType
{
get { return dataType; }
}

private byte orderType;
/// <summary>
/// 自定义属性,标识指令类型
/// </summary>
public byte OrderType
{
get { return orderType; }
}

private byte[] body;
/// <summary>
/// 自定义属性,标识实际数据
/// </summary>
public byte[] Body
{
get { return body; }
}


public bool OnParsingBody(byte[] body)
{
if (body.Length == this.bodyLength)
{
this.body = body;
return true;
}
return false;
}


public bool OnParsingHeader(byte[] header)
{
//在该示例中,第一个字节表示后续的所有数据长度,但是header设置的是3,所以后续还应当接收length-2个长度。
this.bodyLength = header[0]-2;
this.dataType = header[1];
this.orderType = header[2];
return true;
}
}

新建MyFixedHeaderCustomDataHandlingAdapter继承CustomFixedHeaderDataHandlingAdapter,然后对HeaderLength作出赋值,以此表明固定包头的长度是多少。

public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyFixedHeaderRequestInfo>
{
/// <summary>
/// 接口实现,指示固定包头长度
/// </summary>
public override int HeaderLength => 3;

/// <summary>
/// 获取新实例
/// </summary>
/// <returns></returns>
protected override MyFixedHeaderRequestInfo GetInstance()
{
return new MyFixedHeaderRequestInfo();
}
}

【接收】

TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型
if (requestInfo is MyFixedHeaderRequestInfo myRequestInfo)
{
//此处可以处理MyFixedHeaderRequestInfo的相关信息了。
string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);
}

};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(() => { return new MyFixedHeaderCustomDataHandlingAdapter(); }))//配置适配器
.Start();//启动
提示

上述示例的数据是经典的固定包头格式,具有Header+Body的明显分割点。但有时候,也有一些数据有好几段,例如:具有Crc校验的数据,也就是Header+Body+Crc的格式,这时候,我们可以把Body+Crc看做一段数据,然后从Header解析BodyLength以后,加上Crc的长度。最后会在OnParsingBody时,将Body和Crc一起投递,届时做好数据分割即可。

提示

上述创建的适配器客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/customunfixedheaderdatahandlingadapter/index.html b/handbook/build/docs/customunfixedheaderdatahandlingadapter/index.html new file mode 100644 index 000000000..4b9282c1d --- /dev/null +++ b/handbook/build/docs/customunfixedheaderdatahandlingadapter/index.html @@ -0,0 +1,18 @@ + + + + + +模板解析“非固定包头”数据适配器 | TouchSocket + + + + +
+

模板解析“非固定包头”数据适配器

一、说明

有时候,我们需要解析的数据的包头是不定的,例如:HTTP数据格式,其数据头和数据体由“\r\n”隔开,而数据头又因为请求者的请求信息的不同,头部数据量不固定,而数据体的长度,也是由数据头的ContentLength的值显式指定的,所以,可以考虑使用CustomUnfixedHeaderDataHandlingAdapter解析。

二、特点

  1. 可以自由适配所有的数据协议。
  2. 可以随意定制数据协议。
  3. 可以与任意语言、框架对接数据。

三、使用

客户端与服务器均适用。下列以服务器为例。

步骤

  1. 声明新建类,实现IFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。
  2. 声明新建类,继承CustomUnfixedHeaderDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。
  3. TouchSocketConfig配置中设置。
  4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。

【MyUnfixedHeaderRequestInfo】 +首先,新建MyFixedHeaderRequestInfo类,然后实现IUnfixedHeaderRequestInfo用户自定义固定包头接口。 +然后在OnParsingHeader函数执行结束时,对实现的BodyLength属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。

public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo
{
private int bodyLength;
/// <summary>
/// 接口实现,标识数据长度
/// </summary>
public int BodyLength
{
get { return bodyLength; }
}


private byte[] body;
/// <summary>
/// 自定义属性,标识实际数据
/// </summary>
public byte[] Body
{
get { return body; }
}


public bool OnParsingBody(byte[] body)
{
if (body.Length == this.bodyLength)
{
this.body = body;
return true;
}
return false;
}


public bool OnParsingHeader(ByteBlock byteBlock)
{
//此处逻辑和固定包头模板基本一致。也需要对BodyLength作出赋值。
//但是不同固定包头的是,需要自己移动已读的游标。并且返回正确的值。

//下列通过假逻辑实现Http协议的解析。

//从现有的可读数据中,读取“\r\n\r\n”,以此来分割http的headers和body。
int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, Encoding.UTF8.GetBytes("\r\n\r\n"));
if (index > 0)
{
//索引到了“\r\n\r\n”,以此推断出,在当前缓存区中,由byteBlock.Pos至index的数据即为headers。
int headerLength = index - byteBlock.Pos;
string headers = Encoding.UTF8.GetString(byteBlock.Buffer, byteBlock.Pos,headerLength);//解码headers
byteBlock.Pos += headerLength;//然后将缓存区的游标移至headers结束的位置。

//最后通过headers,解析出后续的body的长度,然后在此处赋值。
this.bodyLength = 0;//此处的0是占位值。
return true;
}
else
{
//没索引到“\r\n\r\n”,以此推断出,在当前缓存区中,header的接收尚未完成,
//所以返回false,并且不需要修改游标。
return false;
}
}
}


新建MyCustomUnfixedHeaderDataHandlingAdapter继承CustomUnfixedHeaderDataHandlingAdapter

public class MyCustomUnfixedHeaderDataHandlingAdapter : CustomUnfixedHeaderDataHandlingAdapter<MyUnfixedHeaderRequestInfo>
{
protected override MyUnfixedHeaderRequestInfo GetInstance()
{
return new MyUnfixedHeaderRequestInfo();
}
}

【接收】

TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型
if (requestInfo is MyUnfixedHeaderRequestInfo myRequestInfo)
{
//此处可以处理MyUnfixedHeaderRequestInfo的相关信息了。
string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length);
}

};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(() => { return new MyCustomUnfixedHeaderDataHandlingAdapter(); }))//配置适配器
.Start();//启动
提示

上述创建的适配器客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/dataadaptertester/index.html b/handbook/build/docs/dataadaptertester/index.html new file mode 100644 index 000000000..3414c4d8a --- /dev/null +++ b/handbook/build/docs/dataadaptertester/index.html @@ -0,0 +1,18 @@ + + + + + +适配器完整性、性能测试 | TouchSocket + + + + +
+

适配器完整性、性能测试

一、说明

适配器测试是测试适配器在正常情况下,极端工作的一种测试方式。能够在前期,解决100%的算法问题。也能在极端配置下,模拟极端工作环境,能够简单,直观的展示出适配器的稳定性和工作性能。

1.1 测试原理

假设发送数据为{0,1,2,3,4},连续发送10次。 +当bufferLength=1时,会先接收一个字节,然后适配器判断无法解析,然后缓存,然后再接收下一个字节,直到成功解析一个完整数据包。该模式解决的就是大家所说的分包,也就是能很好的模拟网络很差的环境。 +当bufferLength>5时,假如为8,则会先接收{0,1,2,3,4,0,1,2},然后适配器成功判断解析前五字节,然后缓存后三字节,然后再接收下一个续包,直到解析结束。

1.2 测试事项

  1. bufferLength应该多次设置,且最好不要整除于发送数据的长度,这样避免巧合发生,测不出极端问题。
  2. Run的次数应该多设,模拟高频情况。

二、Tcp适配器

Tcp适配器的工作环境,只需考虑单线程即可。因为是客户端与适配器是一一对应的。

下列以 固定包头数据处理适配器 为例

//Tcp适配器测试
//bufferLength的作用是模拟tcp接收缓存区,例如:

//发送数据为{0,1,2,3,4}时
//当bufferLength=1时,会先接收一个字节,然后适配器判断无法解析,然后缓存,然后再接收下一个字节,直到成功解析。
//该模式能很好的模拟网络很差的环境。
//当bufferLength=8时,会先接收{0,1,2,3,4,0,1,2},然后适配器判断解析前五字节,然后缓存后三字节,然后再接收下一个续包,直到解析结束

for (int bufferLength = 1; bufferLength < 1024 * 10; bufferLength += 1024)
{
bool isSuccess = true;
var data = new byte[] { 0, 1, 2, 3, 4 };
DataAdapterTester tester = DataAdapterTester.CreateTester(new FixedHeaderPackageAdapter()
, bufferLength, (byteBlock, requestInfo) =>
{
//此处就是接收,如果是自定义适配器,可以将requestInfo强制转换为实际对象,然后判断数据的确定性
if (byteBlock.Len!=5||(!byteBlock.ToArray().SequenceEqual(data)))
{
isSuccess = false;
}
});

//data是发送的数据,因为此处使用的是固定包头适配器,
//发送前适配器会自动添加包头,所以,此处只发送数据即可。
//如果测试的是自定义适配器,发送前没有封装的话,就需要自行构建发送数据。
//随后的两个参数,10,10是测试次数,和期望次数,一般这两个值是相等的。
//意为:本次数据将循环发送10次,且会接收10次。不然此处会一直阻塞。
//最后一个参数是测试的最大超时时间。

var time = tester.Run(data, 10, 10, 1000 * 10);
Thread.Sleep(1000);
Console.WriteLine($"测试结束,状态:{isSuccess},用时:{time}");
}
Console.WriteLine("测试结束");

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/dataforwarding/index.html b/handbook/build/docs/dataforwarding/index.html new file mode 100644 index 000000000..1edd58195 --- /dev/null +++ b/handbook/build/docs/dataforwarding/index.html @@ -0,0 +1,16 @@ + + + + + +数据转发项目 | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/datahandleadapter/index.html b/handbook/build/docs/datahandleadapter/index.html new file mode 100644 index 000000000..8936b556e --- /dev/null +++ b/handbook/build/docs/datahandleadapter/index.html @@ -0,0 +1,20 @@ + + + + + +原始自定义适配器 | TouchSocket + + + + +
+

原始自定义适配器

说明

自定义适配器可从两个方面入手。

  1. 则是直接从DataHandlingAdapter继承,此时可以接触到最原始的TCP数据,可以自定实现数据的继续投递方式。但一般实现算法比较困难,因为所考虑的情况比较多。
  2. 则是从CustomDataHandlingAdapter(用户快捷自定义适配器)继承,此时数据的投递必须通过IRequestInfo,ByteBlock将为null。所需考虑的情况比较单一,对于数据的处理也比较简单。

原始DataHandlingAdapter

自己实现适配器,然后使其工作。例如:假设如下数据格式,第一个字节表示整个数据长度(包括数据类型和指令类型),第二字节表示数据类型,第三字节表示指令类型,后续字节表示其他数据。

其次,希望在发送时,只传入数据类型,指令类型和其他数据,而数据长度则由适配器自行封装。最后,希望在接收端每次能接收到一个完整的数据。

实现

首先,创建类,继承自DataHandlingAdapter,然后实现对应属性,及方法。

class MyDataHandleAdapter : DataHandlingAdapter
{
public override bool CanSplicingSend => false;

public override bool CanSendRequestInfo => false;

protected override void PreviewReceived(ByteBlock byteBlock)
{

}

protected override void PreviewSend(byte[] buffer, int offset, int length)
{

}

protected override void PreviewSend(IRequestInfo requestInfo)
{

}

protected override void PreviewSend(IList<ArraySegment<byte>> transferBytes)
{

}

protected override void Reset()
{

}
}

【封装发送数据长度】 +封装发送数据时,比较简单,示例如下:

protected override void PreviewSend(byte[] buffer, int offset, int length)
{
int dataLen = length - offset;//先获取需要发送的实际数据长度
if (dataLen > byte.MaxValue)//超长判断
{
throw new OverlengthException("发送数据太长。");
}

//从内存池申请内存块,因为此处数据绝不超过255,所以避免内存池碎片化,每次申请64K
//ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。
using (ByteBlock byteBlock = new ByteBlock(64 * 1024))
{
byteBlock.Write((byte)dataLen);//先写长度
byteBlock.Write(buffer, offset, length);//再写数据
this.GoSend(byteBlock.Buffer, 0, byteBlock.Len);
}
}

【解析接收数据】 +从原生适配器解封数据,需要考虑的情况比较多。在本示例中,需要考虑以下情况:

  1. 一次刚好接收一个数据。
  2. 一次刚好接收了多个数据。
  3. 一次接收了多个数据,但最后一个数据不完整。
  4. 一次未接收完一个数据。

综上,情况比较复杂,所以就必须自己做接收数据的缓存容器。

/// <summary>
/// 临时包,此包仅当前实例储存
/// </summary>
private ByteBlock tempByteBlock;

/// <summary>
/// 包剩余长度
/// </summary>
private byte surPlusLength;
protected override void PreviewReceived(ByteBlock byteBlock)
{
byte[] buffer = byteBlock.Buffer;
int r = byteBlock.Len;
if (this.tempByteBlock == null)//如果没有临时包,则直接分包。
{
SplitPackage(buffer, 0, r);
}
else
{
if (surPlusLength == r)//接收长度正好等于剩余长度,组合完数据以后直接处理数据。
{
this.tempByteBlock.Write(buffer, 0, surPlusLength);
PreviewHandle(this.tempByteBlock);
this.tempByteBlock = null;
surPlusLength = 0;
}
else if (surPlusLength < r)//接收长度大于剩余长度,先组合包,然后处理包,然后将剩下的分包。
{
this.tempByteBlock.Write(buffer, 0, surPlusLength);
PreviewHandle(this.tempByteBlock);
this.tempByteBlock = null;
SplitPackage(buffer, surPlusLength, r);
}
else//接收长度小于剩余长度,无法处理包,所以必须先组合包,然后等下次接收。
{
this.tempByteBlock.Write(buffer, 0, r);
surPlusLength -= (byte)r;
}
}
}
/// <summary>
/// 分解包
/// </summary>
/// <param name="dataBuffer"></param>
/// <param name="index"></param>
/// <param name="r"></param>
private void SplitPackage(byte[] dataBuffer, int index, int r)
{
while (index < r)
{
byte length = dataBuffer[index];
int recedSurPlusLength = r - index - 1;
if (recedSurPlusLength >= length)
{
ByteBlock byteBlock = new ByteBlock(length);
byteBlock.Write(dataBuffer, index + 1, length);
PreviewHandle(byteBlock);
surPlusLength = 0;
}
else//半包
{
this.tempByteBlock = new ByteBlock(length);
surPlusLength = (byte)(length - recedSurPlusLength);
this.tempByteBlock.Write(dataBuffer, index + 1, recedSurPlusLength);
}
index += length + 1;
}
}
/// <summary>
/// 处理数据
/// </summary>
/// <param name="byteBlock"></param>
private void PreviewHandle(ByteBlock byteBlock)
{
try
{
this.GoReceived(byteBlock, null);
}
finally
{
byteBlock.Dispose();//在框架里面将内存块释放
}
}

使用自定义适配器

自定义适配器的使用和预设的适配器一样。不过在该案例中,发送数据时,应当传入三个有效值,分别为数据类型指令类型其他数据

封装函数及分片发送意义

在上述案例中,发送数据时应当传入数据类型指令类型其他数据三个有效值,而在RRQM中,发送函数仅有Send(和重载),这无疑需要我们自己封装其他方法。 +假设以下情况需要实现:

数据类型有两种,分别为Up(1),Down(0)。指令类型有两种,分别为Go(1)、Hold(0)。数据类型和指令类型可以任意组合,且均可携带其他数据。

面对上述情况,我们可以封装以下函数使用:

public class MySocketClient : SimpleSocketClient
{
public void Up_Go_Send(byte[] data)
{
ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[].
byteBlock.Write((byte)1);
byteBlock.Write((byte)1);
byteBlock.Write(data);
try
{
this.Send(byteBlock);
}
finally
{
byteBlock.Dispose();
}
}
public void Down_Go_Send(byte[] data)
{
ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[].
byteBlock.Write((byte)0);
byteBlock.Write((byte)1);
byteBlock.Write(data);
try
{
this.Send(byteBlock);
}
finally
{
byteBlock.Dispose();
}
}
public void Up_Hold_Send(byte[] data)
{
ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[].
byteBlock.Write((byte)1);
byteBlock.Write((byte)0);
byteBlock.Write(data);
try
{
this.Send(byteBlock);
}
finally
{
byteBlock.Dispose();
}
}
public void Down_Hold_Send(byte[] data)
{
ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[].
byteBlock.Write((byte)0);
byteBlock.Write((byte)0);
byteBlock.Write(data);
try
{
this.Send(byteBlock);
}
finally
{
byteBlock.Dispose();
}
}
}

为什么要分片发送??

在示例代码中不难看出,封装的函数将发送数据进行了Write操作(相当于Copy),这无疑是消耗性能的。只是在该案例中,复制的数据最大为255,感觉优化效果甚微,倘若我们需要发送的数据是1Mb,那就相当于在封装数据时,因为前两个字节的存在而复制1Mb的数据(冤死了),然后在适配器中还需要因为数据包头,再复制一次。

优化。。。 +所以我们在封装时,可以使用分片发送,但是同时也需要适配器支持。不然内部会出错。

protected override void PreviewSend(IList<ArraySegment<byte>> transferBytes)
{
int dataLen = 0;
foreach (var item in transferBytes)
{
dataLen += item.Count;
}
if (dataLen > byte.MaxValue)//超长判断
{
throw new OverlengthException("发送数据太长。");
}

//从内存池申请内存块,因为此处数据绝不超过255,所以避免内存池碎片化,每次申请64K
//ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。

using (ByteBlock byteBlock = new ByteBlock(64 * 1024))
{
byteBlock.Write((byte)dataLen);//先写长度
foreach (var item in transferBytes)
{
byteBlock.Write(item.Array, item.Offset, item.Count);//依次写入
}
this.GoSend(byteBlock.Buffer, 0, byteBlock.Len);
}
}

重新封装函数。。。

public void Up_Go_SplicingSend(byte[] data)
{
List<TransferByte> transferBytes = new List<TransferByte>();
transferBytes.Add(new TransferByte(new byte[] { 1}));
transferBytes.Add(new TransferByte(new byte[] { 1}));
transferBytes.Add(new TransferByte(data));
this.Send(transferBytes);
}
public void Down_Go_SplicingSend(byte[] data)
{
List<TransferByte> transferBytes = new List<TransferByte>();
transferBytes.Add(new TransferByte(new byte[] { 0 }));
transferBytes.Add(new TransferByte(new byte[] { 1 }));
transferBytes.Add(new TransferByte(data));
this.Send(transferBytes);
}
public void Up_Hold_SplicingSend(byte[] data)
{
List<TransferByte> transferBytes = new List<TransferByte>();
transferBytes.Add(new TransferByte(new byte[] { 1 }));
transferBytes.Add(new TransferByte(new byte[] { 0 }));
transferBytes.Add(new TransferByte(data));
this.Send(transferBytes);
}
public void Down_Hold_SplicingSend(byte[] data)
{
List<TransferByte> transferBytes = new List<TransferByte>();
transferBytes.Add(new TransferByte(new byte[] { 0 }));
transferBytes.Add(new TransferByte(new byte[] { 0 }));
transferBytes.Add(new TransferByte(data));
this.Send(transferBytes);
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/datasecurity/index.html b/handbook/build/docs/datasecurity/index.html new file mode 100644 index 000000000..96377eb56 --- /dev/null +++ b/handbook/build/docs/datasecurity/index.html @@ -0,0 +1,17 @@ + + + + + +数据加密 | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/dependencyproperty/index.html b/handbook/build/docs/dependencyproperty/index.html new file mode 100644 index 000000000..fd0a2cc38 --- /dev/null +++ b/handbook/build/docs/dependencyproperty/index.html @@ -0,0 +1,18 @@ + + + + + +依赖属性 | TouchSocket + + + + +
+

依赖属性

一、说明

用过WPF的小伙伴一定对依赖属性不陌生。所以TouchSocket模仿其结构,创建了适用于网络框架的依赖属性。

二、什么是依赖属性?

我们知道常规属性,就是拥有get,set访问器的字段,叫做属性。

class MyClass
{
public int MyProperty { get; set; }
}

而依赖属性,则是具有注入特征的属性。它可以像普通属性一样,声明在类内部(示例1)。也可以声明在任何地方(示例2)。

【示例1】

  1. 继承DependencyObject
  2. 按如下格式生成属性项(propdp代码块可快速实现)
class MyClass: DependencyObject
{
/// <summary>
/// 属性项
/// </summary>
public int MyProperty
{
get { return GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}

/// <summary>
/// 依赖项
/// </summary>
public static readonly DependencyProperty<int> MyPropertyProperty =
DependencyProperty<int>.Register("MyProperty", typeof(MyClass), 10);

}

【示例2】 +假设以下情况: +对于TouchSocket的IClient接口对象(已经实现IDependencyObject),希望创建一个int类型的,名为MyProperty的依赖项属性。

那么,可以用下列代码实现

public static class DependencyExtensions
{
/// <summary>
/// 依赖项
/// </summary>
public static readonly DependencyProperty<int> MyPropertyProperty =
DependencyProperty<int>.Register("MyProperty", typeof(MyClass), 10);

/// <summary>
/// 设置MyProperty
/// </summary>
/// <typeparam name="TClient"></typeparam>
/// <param name="client"></param>
/// <param name="value"></param>
/// <returns></returns>
public static TClient SetMyProperty<TClient>(this TClient client, int value) where TClient : IClient
{
client.SetValue(MyPropertyProperty, value);
return client;
}

/// <summary>
/// 获取MyProperty
/// </summary>
/// <typeparam name="TClient"></typeparam>
/// <param name="client"></param>
/// <returns></returns>
public static int GetMyProperty<TClient>(this TClient client) where TClient : IClient
{
return client.GetValue(MyPropertyProperty);
}
}
TcpClient tcpClient = new TcpClient();
tcpClient.SetMyProperty(100);
int MyProperty = tcpClient.GetMyProperty();

三、优缺点

优点:

  1. 可以不声明在类内部。这意味着可以从外部注入。
  2. 不需要初始赋值,也就意味着创建大量对象时,可以不需要占用太多内存。

缺点:

  1. 对于值类型,涉及拆装箱操作,对性能有一定性能影响(不是几百万操作,可以忽略)。
注意

当一个属性被频繁(千万级别)使用时,不建议使用依赖属性。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/donate/index.html b/handbook/build/docs/donate/index.html new file mode 100644 index 000000000..3494d1e0b --- /dev/null +++ b/handbook/build/docs/donate/index.html @@ -0,0 +1,16 @@ + + + + + +支持作者 | TouchSocket + + + + +
+

支持作者

赞助TouchSocket项目

您的支持就是我不懈努力的动力。

爱心赞助名单(以下排名只按照打赏时间顺序)

  1. Bobo Joker(200¥)
  2. UnitySir(66¥)
  3. Coffee(100¥)
  4. Ninety(50¥)
  5. *琼(100¥)
  6. **安(5¥)
  7. **文(200+200¥)
  8. tonychen899(50¥)
  9. *平(50¥)
  10. 杜(400+100¥)
  11. 施*双(666¥)
  12. *童(20¥)
  13. Tom (88¥)
  14. *强(200¥)
  15. *潮(10+20+1+2¥)
  16. *星(20¥)
  17. 舔狗反咬事件(66¥)
  18. 美少女酱(30¥)
  19. 流水游鱼(9.99¥)
  20. 华丽谢幕(33+20¥)
  21. 阁主悦澜殇(50+50¥)
  22. 烈日(20+20¥)
  23. Silent(50¥)
  24. 月华散(50¥)
  25. 黄*德(PayPal:1000NT$)
  26. 一头大狮子(20¥)
  27. 蒋*秋(188¥)
  28. **发(100+100¥)
  29. 梦想遥不可及(128+98¥)
  30. 可爱又善良的我(100¥)
  31. *君(6.6¥)
  32. *于(30¥)
  33. J*n(100¥)
  34. D*Y(20¥)
  35. *人(50¥)
  36. *光(66¥)
  37. Estel(100¥)
  38. 1(200¥)
  39. **阳(100¥)
  40. chenqiang(6.6¥)
  41. Azure(50¥)
  42. 广东-小白(1.5¥)

一起喝酒?

打赏支付.png

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/engineertoolbox/index.html b/handbook/build/docs/engineertoolbox/index.html new file mode 100644 index 000000000..78c00809f --- /dev/null +++ b/handbook/build/docs/engineertoolbox/index.html @@ -0,0 +1,18 @@ + + + + + +工程师软件工具箱 | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/enterprise/index.html b/handbook/build/docs/enterprise/index.html new file mode 100644 index 000000000..5a66a1624 --- /dev/null +++ b/handbook/build/docs/enterprise/index.html @@ -0,0 +1,16 @@ + + + + + +企业版相关 | TouchSocket + + + + +
+

企业版相关

一、说明

TouchSocketPro是TouchSocket系的加强版本。其基础功能完全包含TouchSocket,除此之外,还有一些附加功能,这需要付费购买密钥,然后才能使用。具体详细区别如下表格所示。

同时TouchSocketPro还提供企业定制服务及必要的远程协助,具体收费可以咨询作者若汝棋茗,联系方式:QQ:505554090。

二、TouchSocket与TouchSocketPro

2.1 Tcp组件

2.2 NAT组件

2.3 UDP组件

  • 所有功能

2.4 JsonRpc

  • 自定义解析
  • 其余功能

2.5 WebApi

  • 所有功能

2.6 XmlRpc

  • 所有功能

2.7 TouchRpc(tcp、udp、http、websocket)

2.8 Http组件

  • 超大文件传输
  • 多通道文件续传
  • 静态网页展示
  • 文件传输限速

WebSocket

  • 全部功能
提示

上述的功能中,所有带有 的标识,均为TouchSocketPro包含的内容。其余功能TouchSocket也均支持。

三、能提供的个性服务

3.1 数据处理适配器的重写

在TouchSocketPro中,可以通过适配器对数据进行预处理和对象解析,目前TouchSocketPro拥有的适配器仅有固定包头固定长度终止分割Json字符串解析Http对象解析五种适配器。但是往往这些适配器不是我们想要的,例如:串口信号、AGV数据格式等。那么我们可以为您提供解析数据格式(对象)的服务。

3.2 增加或限制某个功能

程序库为的是能提供基础服务,所以某个功能的出现,均是为了具备更好的普适性,但是有时候也会与您的需求背道而驰,那么我们也可以为您定制某个功能(或禁用某个功能)。

四、TouchSocketPro

类型个人独立授权个人企业授权企业授权
功能全部功能全部功能全部功能
使用期限永久永久永久
授权归属个人个人企业
协助服务全部现有功能协助
个性化功能扩展支持支持支持
激活方式密钥激活密钥激活密钥激活和源码引用
后续升级Nuget升级Nuget升级Nuget升级或随时索要最新源码
源代码开放不开放不开放开放
用于盈利允许允许允许
个性化功能扩展支持支持支持
开具发票原则上不开具开具开具
赠品送您1束玫瑰送您2束玫瑰送您3束玫瑰,和一个自定义适配器,或复杂度相同的个性化服务。
价格298¥已停售998¥

4.1 个人独立授权

授权归属于购买者个人所有,规定购买者可将所购产品只能应用于所属个人的任何软件(产品)上,可以以此盈利,但必须遵守个人使用协议

4.2 个人企业授权

授权归属于购买者个人所有,规定购买者可将所购产品应用于购买者服务(工作)的企业的任何软件(产品)上,但授权期限与购买者服务(工作)期限一致,一旦购买者离职(或不再服务于企业),授权将在30个工作日后失效。同时,购买者在将所购产品应用于企业时,有必要告知义务,在离职(或不再服务于企业)时,也应当再次告知企业详情。

(个人企业版在2023.1.1日后不再售卖。已售卖的个人企业版原始功能不变。或者联系作者,可免费升级至企业版)

4.3 企业授权

  • 当授权归属于企业所有时,永久授权。且仅企业享有授权,所有职员均无授权。
  • 当授权归属个人所有时,永久授权。且保留一次企业冠名权益,现有授权自动降为“个人企业授权”条款。。

五、密钥使用

首先请确保所有的项目完全卸载删除TouchSocket,并且在需要的项目中安装了TouchSocketPro。

当购买密钥后,您会获得类似“D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1”这样的密钥。然后在程序初始化(例如Main函数)时。使用以下代码即可。

 Enterprise.Default.LicenceKey = "密钥";

AspNetCore中使用时,建议自定义服务注入的方式实现。步骤如下:

  1. 新建项目,引用Microsoft.Extensions.DependencyInjectionTouchSocketPro.AspNetCore
  2. 新建静态类ServiceCollectionExtension,创建IServiceCollection的扩展方法。
  3. 在IServiceCollection的扩展方法中,注入密钥。
  4. 在AspNetCore引用新建的项目。
  5. 在服务中注入。

部分代码示例如下:

public static class ServiceCollectionExtension
{
public static void AddLicence(this IServiceCollection service)
{
Enterprise.Default.LicenceKey = "D1D1D1D1D1D1D1";
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddLicence();
}

六、限时测试

为方便大家测试,TouchSocketPro提供限时1小时的测试功能,当时间结束时企业版功能关闭,重启进程即可再次试用1小时,以此往复。

调用ForTest时,会抛出可控异常。如果坚持使用企业版,使用Try拦截即可。

try
{
Enterprise.ForTest();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

七、购买通道

购买可通过以下方式。购买前请先联系作者若汝棋茗。联系QQ:505554090。

扫描下列微信码,或者点击淘宝链接

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/eventbus/index.html b/handbook/build/docs/eventbus/index.html new file mode 100644 index 000000000..9c9a1934b --- /dev/null +++ b/handbook/build/docs/eventbus/index.html @@ -0,0 +1,17 @@ + + + + + +EventBus | TouchSocket + + + + +
+

EventBus

说明

EventBus功能是企业版专属功能,其职能类似MQTT的发布订阅模式,也类似RabbitMQ的Sub模式。如果没有使用密钥,可以试用参考。

创建服务器

服务器的创建就是TouchRpc服务器。除udp协议外,tcp、http、websocket协议的版本均支持该功能。

下列以TcpTouchRpcService为例。

TcpTouchRpcService tcpRpcService = new TcpTouchRpcService();

var config = new RRQMConfig();
config.SetListenIPHosts(new IPHost[] { new RRQMSocket.IPHost(7789) });
tcpRpcService
.Setup(config)
.Start();

服务器发布一个事件。 +第一个参数为事件名,第二个为访问权限。

tcpRpcService.PublishEvent("Hello", AccessType.Owner | AccessType.Service | AccessType.Everyone);

创建客户端

客户端订阅该事件。

TcpTouchRpcClient tcpRpcClient = new TcpTouchRpcClient();
tcpRpcClient
.Setup("127.0.0.1:7789")
.Connect();

tcpRpcClient.SubscribeEvent<string>("Hello", SubscribeEvent);

其中SubscribeEvent是接收委托。此处用方法转换接收。其目的为,当服务器触发该方法时,就会分发到此处。

 private void SubscribeEvent(EventSender eventSender, string arg)
{
this.ShowMsg($"从{eventSender.RaiseSourceType}收到通知事件{eventSender.EventName},信息:{arg}");
}

服务器触发

第一个参数是事件名,第二个是事件参数。可以是任意类型,但是目前仅支持一个参数。

tcpRpcService.RaiseEvent("Hello", "Hi");

其他

实际上在TouchRpc架构中。TouchServiceTouchSocketClientTouchClient三者均已实现IEventObject接口,这意味均可以发布、取消发布、订阅、取消订阅、触发等操作(会验证操作权限)。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/fastbinaryformatter/index.html b/handbook/build/docs/fastbinaryformatter/index.html new file mode 100644 index 000000000..cb901907c --- /dev/null +++ b/handbook/build/docs/fastbinaryformatter/index.html @@ -0,0 +1,16 @@ + + + + + +高性能二进制序列化 | TouchSocket + + + + +
+

高性能二进制序列化

一、说明

该序列化以二进制方式进行序列化,不要求序列化与反序列化类型相同,使用体验和兼容性与json相似。支持基础类型自定义实体类结构体元组数组字典List等。

二、序列化、反序列化

var obj = "TouchSocket";
var data = SerializeConvert.FastBinarySerialize(obj);
var newobj = SerializeConvert.FastBinaryDeserialize<string>(data);

三、自定义转换器

自定义转化器的使用,可以解决所有类型的序列化,但是这需要自己编写一些代码。具体操作如下:

  1. 声明转换器。
/// <summary>
/// 继承<see cref="FastBinaryConverter{T}"/>或者实现<see cref="IFastBinaryConverter"/>
/// </summary>
class StudentFastBinaryConverter : FastBinaryConverter<Student>
{
protected override Student Read(byte[] buffer, int offset, int len)
{
var byteBlock = new ValueByteBlock(buffer);
byteBlock.Pos = offset;
var obj = new Student();
obj.P1 = byteBlock.ReadInt32();
obj.P2 = byteBlock.ReadString();
return obj;
}

protected override int Write(ByteBlock byteBlock, Student obj)
{
//此处可以直接嵌套Json序列化,但是为演示效果,下列将依然使用二进制方式
int pos = byteBlock.Pos;
byteBlock.Write(obj.P1);
byteBlock.Write(obj.P2);
return byteBlock.Pos - pos;//返回的即是obj所有的字节长度
}
}
  1. 附加转换器
[FastConverter(typeof(StudentFastBinaryConverter))]
class Student
{
public int P1 { get; set; }
public string P2 { get; set; }
}
tip

当类型已经定义,无法通过特性添加转换器时,可以通过FastBinaryFormatter.AddFastBinaryConverter(typeof(Student),new StudentFastBinaryConverter());直接添加。

四、性能测试

4.1 简单测试

待测试类型

[Serializable]
public class MyPackPerson
{
public int Age { get; set; }
public string Name { get; set; }
}

结果

以下测试是执行10000次序列化和反序列的结果。

4.2 复杂类型测试

待测试类

 [Serializable]
public class Student
{
public int P1 { get; set; }
public string P2 { get; set; }
public long P3 { get; set; }
public byte P4 { get; set; }
public DateTime P5 { get; set; }
public double P6 { get; set; }
public byte[] P7 { get; set; }

public List<int> List1 { get; set; }
public List<string> List2 { get; set; }
public List<byte[]> List3 { get; set; }

public Dictionary<int, int> Dic1 { get; set; }
public Dictionary<int, string> Dic2 { get; set; }
public Dictionary<string, string> Dic3 { get; set; }
public Dictionary<int, Arg> Dic4 { get; set; }
}

[Serializable]
public class Arg
{
public Arg(int myProperty)
{
this.MyProperty = myProperty;
}

public Arg()
{
Person person = new Person();
person.Name = "张三";
person.Age = 18;
}

public int MyProperty { get; set; }
}
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

赋值

Student student = new Student();
student.P1 = 10;
student.P2 = "若汝棋茗";
student.P3 = 100;
student.P4 = 0;
student.P5 = DateTime.Now;
student.P6 = 10;
student.P7 = new byte[1024 * 64];

Random random = new Random();
random.NextBytes(student.P7);

student.List1 = new List<int>();
student.List1.Add(1);
student.List1.Add(2);
student.List1.Add(3);

student.List2 = new List<string>();
student.List2.Add("1");
student.List2.Add("2");
student.List2.Add("3");

student.List3 = new List<byte[]>();
student.List3.Add(new byte[1024]);
student.List3.Add(new byte[1024]);
student.List3.Add(new byte[1024]);

student.Dic1 = new Dictionary<int, int>();
student.Dic1.Add(1, 1);
student.Dic1.Add(2, 2);
student.Dic1.Add(3, 3);

student.Dic2 = new Dictionary<int, string>();
student.Dic2.Add(1, "1");
student.Dic2.Add(2, "2");
student.Dic2.Add(3, "3");

student.Dic3 = new Dictionary<string, string>();
student.Dic3.Add("1", "1");
student.Dic3.Add("2", "2");
student.Dic3.Add("3", "3");

student.Dic4 = new Dictionary<int, Arg>();
student.Dic4.Add(1, new Arg(1));
student.Dic4.Add(2, new Arg(2));
student.Dic4.Add(3, new Arg(3));

结果

Fast的效率比System自带的,快了近7倍,比System.Text.Json快了4倍多,比NewtonsoftJson快了近30倍。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/filepool/index.html b/handbook/build/docs/filepool/index.html new file mode 100644 index 000000000..003b4351c --- /dev/null +++ b/handbook/build/docs/filepool/index.html @@ -0,0 +1,16 @@ + + + + + +文件流池 | TouchSocket + + + + +
+

文件流池

一、说明

文件在读,或写的时候,一直都是独占状态。这个问题在不同进程中,似乎是合理的,但是如果在相同进程里,就会显得很呆。例如:我们在下载文件的时候,希望能同一时间多个读取同一个文件。且能有一个闭环的管理。那么,使用FilePool,就显得非常必要了。

二、使用读

从FilePool.GetReader的静态函数中,获取一个线程安全的文件读取访问器,该访问器具有读,和相关的操作属性。在每次读取后,Position会递增。

使用完成后,可以随时释放。

int len = 0;
byte[] buffer = new byte[1024 * 1024];

using (var reader = FilePool.GetReader(path))
{
while (true)
{
int r = reader.Read(buffer, 0, buffer.Length);
if (r == 0)
{
break;
}
len += r;
}
}

Console.WriteLine(len);

三、使用写

从FilePool.GetWriter的静态函数中,获取一个文件写入访问器线程安全,该访问器,具有写,和相关的操作属性。在每次写入后,Position会递增。

使用完成后,可以随时释放。

注意默认调用Dispose后,文件会根据创建类型是否为单一访问而决定是否立即释放。

byte[] buffer = new byte[1024];

using (var writer = FilePool.GetWriter(path,true))
{
writer.Position = num * package;
int surLen = package;
while (surLen > 0)
{
int r = Math.Min(surLen, buffer.Length);
writer.Write(buffer, 0, r);
surLen -= r;
}
}
Console.WriteLine("完成");

四、手动释放文件资源

当某个文件没有及时释放,或者由于不可知异常而没有释放时,可以调用FilePool.TryReleaseFile减少引用,并尝试释放资源。

减少引用的意思是,当某个文件,被创建多个访问器时,会递增其引用数,当引用数不为0时,是不会释放的。所以当调用FilePool.TryReleaseFile时,首先会减少引用,然后才会判断是否可以释放。

当需要强制释放某个文件时,可以采取下列措施。

while (FilePool.TryReleaseFile(fileName, 0).ResultCode!= ResultCode.Success)
{

}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/filesynchronization/index.html b/handbook/build/docs/filesynchronization/index.html new file mode 100644 index 000000000..e0e5b707e --- /dev/null +++ b/handbook/build/docs/filesynchronization/index.html @@ -0,0 +1,16 @@ + + + + + +文件同步系统 | TouchSocket + + + + +
+

文件同步系统

定制方

网友“陶”

说明

应该网友要求,需要开发一个服务器,一个客户端,客户端的职能就是同步本地文件服务器。有点类似OneDrive

技术点

  • 数据同步:设置配置数据、项目文件数据等。
  • 文件:断点续传、换网续传。
  • 登录:登录授权。登录验证。

效果

image.png

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/fixedheaderpackageadapter/index.html b/handbook/build/docs/fixedheaderpackageadapter/index.html new file mode 100644 index 000000000..ba06f00e1 --- /dev/null +++ b/handbook/build/docs/fixedheaderpackageadapter/index.html @@ -0,0 +1,16 @@ + + + + + +固定包头数据处理适配器 | TouchSocket + + + + +
+

固定包头数据处理适配器

一、说明

固定包头数据处理适配器是处理粘包、分包问题的最有力、最可靠、最高效、最稳定的一种方案,它基本上适用于所有场景。即使跨语言使用,也只需要在其他语言中设计相同算法就可以。

二、特点

  1. 最有力的解决粘包。分包问题。
  2. 是自定义协议的不二选择。
  3. 支持指定包头长度,Byte、Ushort、Int三种类型作为包头。
  4. 最好在客户端与服务器均使用TouchSocket组件时使用。不然就需要非TouchSocket的一方适配包头算法。

三、协议算法

  • Byte包头算法:以第一个字节作为后续整个数据的长度,整个数据长度区间为[0,255]
  • Ushort包头算法:前2个字节,且为默认端序(小端)的排列,作为后续整个数据的长度,整个数据长度区间为[0,65535]
  • Int包头算法(默认配置):前4个字节,且为默认端序(小端)排列,作为后续整个数据的长度,整个数据长度区间为[0,2^31]

四、使用

客户端与服务器均适用。下列以服务器为例。

步骤

  1. TouchSocketConfig配置中设置(可以同时指定HeaderType等属性)
  2. 通过Received(事件、方法、插件)中的ByteBlock读取数据。
TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(() => { return new FixedHeaderPackageAdapter() { FixedHeaderType= FixedHeaderType.Int }; }))//配置适配器
.Start();//启动
注意

接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。

提示

该适配器,客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/fixedsizepackageadapter/index.html b/handbook/build/docs/fixedsizepackageadapter/index.html new file mode 100644 index 000000000..441a0b674 --- /dev/null +++ b/handbook/build/docs/fixedsizepackageadapter/index.html @@ -0,0 +1,16 @@ + + + + + +固定长度数据处理适配器 | TouchSocket + + + + +
+

固定长度数据处理适配器

一、说明

固定长度数据处理适配器是将发送的数据通过分割、填补的操作,以达到每次发送、接收的数据都是固定的长度来处理粘包、分包问题。这种方案一般适用于机械臂,机器人控制等场景。

二、特点

  1. 无论何时,发送与接收的数据长度永远为设定值。
  2. 算法简单,可以比较轻松的实现跨语言、跨框架。
  3. 一般适用于业务数据固定场景,

三、使用

客户端与服务器均适用。下列以服务器为例。

步骤

  1. TouchSocketConfig配置中设置,同时指定数据的长度。
  2. 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。
TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(()=> { return new FixedSizePackageAdapter(10); }))//配置适配器,固定数据长度为10字节。
.Start();//启动
注意

接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。

提示

该适配器,客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/fpsgame/index.html b/handbook/build/docs/fpsgame/index.html new file mode 100644 index 000000000..6be3d8ad4 --- /dev/null +++ b/handbook/build/docs/fpsgame/index.html @@ -0,0 +1,16 @@ + + + + + +FPS实时游戏 | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/generateproxy/index.html b/handbook/build/docs/generateproxy/index.html new file mode 100644 index 000000000..3e4511348 --- /dev/null +++ b/handbook/build/docs/generateproxy/index.html @@ -0,0 +1,25 @@ + + + + + +生成、获取代理 | TouchSocket + + + + +
+

生成、获取代理

一、说明

1.1 为什么要生成代理?

使用rpc的原则就是像使用本地方法一样,让开发者感觉不到任何的不同。所以就必须把服务代理到本地,常见的方式有三种,动态代理接口静态织入静态编译。三种方式殊途同归,最终都是构建本地数据结构,然后和远程通信。三种方式各有优缺,具体如下:

优缺点动态代理接口静态织入静态编译
优点动态构建类,灵活、适应性强。静态代码生成,自定义类参数自动生成,修改较灵活,调用效率高自定义类参数自动生成,密封性强,安全性高,调用效率高。
缺点调用效率较低,自定义类参数须自行构建,实现须IL支持,对调用平台有要求,例如:IOS不允许动态类生成,则不可使用。项目代码管理难统一,强迫症猝死服务一旦有破坏性升级,则必须重新替换dll,灵活性几乎为0。

1.2 为什么不直接支持接口代理调用?

【原因一】 +支持out和ref参数,在使用代理时,效率不高。

【原因二】 +需要在参数支持调用上下文,所以无法直接用接口调用。

【原因三】 +支持单次调用的调用配置(例如超时时间,取消调用,序列化方式等)

【原因四】 +引用问题,当在服务接口中,使用了其他的项目的数据结构的话,在接口调用项目上也需要引用该项目。太麻烦。

1.3 TouchRpc源文件代理相比接口代理,有什么优缺点?

源文件代理相比接口代理,几乎没什么缺点。有人会觉得接口代理更整洁、方便?实际上源文件代理只会更整洁、方便。

假设一个场景,你需要开发服务器和客户端,这时,你需要做:

  1. 先单独定义一个接口项目
  2. 再定义一个实现项目
  3. 编译接口项目
  4. 引用到客户端

上述步骤中,还不包括,接口项目和实现项目需要引入其他引用的情况,也不包括,接口中包含了其他项目的自定义数据结构。如果包含了的话,客户端还需要引入其他项目。

而且,还需要考虑接口项目的编译目标平台和其他编译参数。最难受的是,如果这些工作,是你和同事合作的话,那可能就是出个bug,同事传你一个dll v1.0版本,再有问题,v1.1修复版,等等。

而最要命的,当属程序集数据泄露。设想一下,如果某个同事在写数据库操作的项目时,把连接信息直接放在了代码里(或某个逻辑),本身如果这个项目只在服务器应用,也没有关系,但是因为你懒,你在接口中使用了该项目的一个数据结构,这就使得你不得不把这个项目一同交给调用方的同事,但你对这些毫无察觉。嗷嚎,黑用户一反编译,直接帮你把数据整理了。

但是如果用生成的源代码,那上述的可怕问题根本不用考虑。其次,会更整洁,更方便。

假设相同场景,你需要开发服务器和客户端,这时,你需要做:

  1. 先定义一个服务项目(可以写接口,也能写逻辑,当然也可以分成两个项目)
  2. 编译项目,然后导出代理源代码。
  3. 引用到客户端
  • 不需要考虑数据结构引用问题,因为代理会转写。
  • 不需要考虑编译参数问题,因为客户端拿到的也是源码。
  • 不需要再让同事一次次发你dll,只需要,他启动服务,你更新引用就ok。
  • 不需要怕程序集数据泄露,因为一切都是转写的,而且只转写应用的、公共的部分。

二、从服务端获取代理

2.1 生成代理

在开发过程中,如果服务器和客户端,都是我们自己开发的话(在同一个电脑),就可以使用本地代理生成。

调用下列代码,会将已注册的所有服务,导出代理为字符串。

RpcStore是实例,或者是IRpcParser的属性

string code=RpcStore.GetProxyCodes("MyNameSpace"));

【示例1】 +将代理字符串,写成.cs文件,然后通过链接的形式,将代码添加到客户端项目。

服务器代码,在服务器执行后,会在运行路径下,生成一个WhisperServers.cs的文件。

var service = new TcpTouchRpcService();
var config = new TouchSocketConfig()//配置
.SetListenIPHosts(new IPHost[] { new IPHost(port) })
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
a.AddFileLogger();
})
.ConfigureRpcStore(a =>
{
a.RegisterServer<MyRpcServer>();//注册服务

#if DEBUG
File.WriteAllText("../../../WhisperServers.cs", a.GetProxyCodes("WhisperServers",new Type[] { typeof(TouchRpcAttribute) }));
#endif
})
.SetVerifyToken("TouchRpc");

service.Setup(config)
.Start();

然后打开需要引入的客户端解决方案。选择需要添加代理的项目,依次执行:

右击项目=》添加=》现有项

然后选择服务器生成的.cs文件,选择“添加”的下拉框,选择“添加为连接”。

最后确认文件被正确添加为链接。

这样,每次当服务有更新的时候,只需要启动一下服务器,代理就会自动刷新。

实际上在RpcStore完成服务注册解析器添加以后,调用GetProxyInfo,输入代理类型、即可获得代理信息,然后再通过CodeGenerator.ConvertToCode方法,转换为可以直接编译的代码。 +此时,你可以复制、或者直接把代理代码写成源代码(cs文件)。 +然后你可以把这个代码引入到客户端

//或者直接本地导出代理文件。
ServerCellCode[] codes = rpcStore.GetProxyInfo(RpcStore.ProxyAttributeMap.Values.ToArray());
string codeString = CodeGenerator.ConvertToCode("RRQMProxy", codes);

亦或者,为防止篡改生成的代码,不想把代理代码直接投入使用,那可以考虑将代码单独编译成dll,然后将编译的程序集加载到客户端。

提示

上述行为,均是导出所有已注册的服务,当需要在同一个服务端,生成多个不同代理的源码时,可通过CodeGenerator静态类的相关方法直接生成。例如:

string codes=CodeGenerator.GetProxyCodes("Namespace",new Type[]{typeof(RpcServer) },new Type[] { typeof(TouchRpcAttribute)});

2.2 代理类型添加

通过之前的学习,大家可能大概明白了,在RRQMRPC中,客户端与服务器在进行交互时,所需的数据结构不要求是同一类型,仅是数据类型结构相同即可。所以在声明了服务以后,服务中所包含的自定义类型,会被复刻成结构相同的类型,但是这也仅仅局限于参数与服务相同程序集的时候。如果服务中引入了其他程序集的数据结构,则不会复刻。所以在客户端调用时,需要引入同一程序集。

但是,往往在服务中,会引入其他程序集,例如,我们习惯在项目中建立一个Models程序集,用于存放所有的实体模型,那是不是意味着客户端也必须引入这个程序集才能调用呢?没别的方法了?? +有,且不只有一种

2.2.1 添加代理类型

在服务注册之前,任意时刻,可调用CodeGenerator.AddProxyType静态方法,添加代理类型,同时可传入一个bool值,表明是否深度搜索,比如,假如RpcArgsClassLib.ProxyClass1中还有其他类型,则参数为True时,依然会代理。

RPCService rpcService = new RPCService();
CodeGenerator.AddProxyType<RpcArgsClassLib.ProxyClass1>();
CodeGenerator.AddProxyType<RpcArgsClassLib.ProxyClass2>(deepSearch:true);

2.2.2 标记自定义类

在需要代理的类上面声明RpcProxy标签,然后也可以重新指定代理类名。

[RpcProxy("MyArgs")]
public class Args
{
}

三、客户端源代码生成代理

前一种方式已经算是几近完美的代理生成方案,但是有时候,当大家协作时,喜欢全部自己敲写。

例如:

对于下列服务,有时候就是喜欢自己写个接口,然后直接调用。

public class MyRpcServer : RpcServer
{
[TouchRpc]
public bool Login(string account, string password)
{
if (account == "123" && password == "abc")
{
return true;
}

return false;
}
}
public interface IMyRpcServer
{
public bool Login(string account, string password);
}

以往来说,实现这种方式的绝大多数,大概是使用IL动态构建一个类,然后动态实现接口代理,伪代码如下:

IMyRpcServer myRpcServer=ProxyGenerator.CreateProxy<IMyRpcServer>();

但是现在,时代变了,我们有了源代码生成,那么事情将变得无比简单。

同样,我们需要设置接口,如下:

/// <summary>
/// GeneratorRpcProxy的标识,表明这个接口应该被生成其他源代码。
/// ConsoleApp2.MyRpcServer参数是整个rpc调用的前缀,即:除方法名的所有,包括服务的类名。
/// </summary>
[GeneratorRpcProxy("ConsoleApp2.MyRpcServer")]
interface IMyRpcServer
{
[Description("这是登录方法")]//该作用是生成注释
[GeneratorRpcMethod]//表面该方法应该被代理,也可以通过参数,直接设置调用键
public bool Login(string account, string password);
}

这时候,神奇的一幕发生了,凡是实现IRpcClient的接口的实例,都增加了扩展方法。而这功能,和服务器生成的扩展Rpc方法的功能是一致的。

提示

大家可能会疑问,源代码生成代理,和服务端生成代理,有什么区别?或者说有什么优点? +实际上没有区别,也没有优点。之所以设计这个,是因为之前有人提过需求,想要完全分离前、后端。即:后端写好服务后,前端自由定义服务接口,和调用参数,仅此而已。

所以,生成代理的方式,按照大家的习惯需求选择就可以。

源代码生成代理示例代码

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/heartbeat/index.html b/handbook/build/docs/heartbeat/index.html new file mode 100644 index 000000000..eb696b443 --- /dev/null +++ b/handbook/build/docs/heartbeat/index.html @@ -0,0 +1,16 @@ + + + + + +心跳设计 | TouchSocket + + + + +
+

心跳设计

一、说明

1.1 为什么要设置心跳?

心跳机制一般是客户端服务器定时发送一个特定的数据包,让服务器知道自己还在线,以确保连接的有效性的机制。 网络中的接收和发送数据都是使用操作系统中的 SOCKET 进行实现。 但是如果此 套接字 已经断开,那发送数据和接收数据的时候就一定会有问题。 可是如何判断这个套接字是否还可以使用呢? 这个就需要在系统中创建心跳机制。

其实TCP中已经为我们实现了一个内置心跳机制(SetKeepAliveValue)。但是该机制受限于操作系统,而且很容易误报。所以很少被大家使用。

大家使用最多的,就是自己设计数据包,然后预留心跳格式,当对方收到心跳包时,直接返回响应包即可。

那么,按这个思路,让我们使用优雅的实现吧。

二、设计数据格式

使用心跳之前,必须要明确数据格式,绝对不能混淆业务数据。一般在适配Plc等现成模块时,他们是有固定的数据格式,这时候你可以参阅数据处理适配器,快速的解析数据。

但是在本文中,并没有规定的格式,所以我们需要先设计一种简单高效的数据格式。

如下:

数据长度数据类型载荷数据
2字节(Ushort)1字节(Byte)n字节(<65535)

2.1 解析数据格式

下列代码主要实现对上述数据格式的解析

internal class MyFixedHeaderDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyRequestInfo>
{
public override int HeaderLength => 3;

public override bool CanSendRequestInfo => false;

protected override MyRequestInfo GetInstance()
{
return new MyRequestInfo();
}

protected override void PreviewSend(IRequestInfo requestInfo)
{
throw new NotImplementedException();
}
}

internal class MyRequestInfo : IFixedHeaderRequestInfo
{
public DataType DataType { get; set; }
public byte[] Data { get; set; }

public int BodyLength { get; private set; }

public bool OnParsingBody(byte[] body)
{
if (body.Length == this.BodyLength)
{
this.Data = body;
return true;
}
return false;
}

public bool OnParsingHeader(byte[] header)
{
if (header.Length == 3)
{
this.BodyLength = TouchSocketBitConverter.Default.ToUInt16(header, 0) - 1;
this.DataType = (DataType)header[2];
return true;
}
return false;
}

public void Package(ByteBlock byteBlock)
{
byteBlock.Write((ushort)((this.Data == null ? 0 : this.Data.Length) + 1));
byteBlock.Write((byte)this.DataType);
if (Data != null)
{
byteBlock.Write(Data);
}
}

public byte[] PackageAsBytes()
{
using ByteBlock byteBlock = new ByteBlock();
this.Package(byteBlock);
return byteBlock.ToArray();
}

public override string ToString()
{
return $"数据类型={this.DataType},数据={(this.Data == null ? "null" : Encoding.UTF8.GetString(this.Data))}";
}
}

internal enum DataType : byte
{
Ping,
Pong,
Data
}

三、创建扩展类

下列代码可选,主要实现对Client增加Ping的扩展方法。方便调用。

/// <summary>
/// 一个心跳计数器扩展。
/// </summary>
internal static class DependencyExtensions
{
public static readonly DependencyProperty<Timer> HeartbeatTimerProperty =
DependencyProperty<Timer>.Register("HeartbeatTimer", typeof(DependencyExtensions), null);

public static bool Ping<TClient>(this TClient client) where TClient : ITcpClientBase
{
try
{
client.Send(new MyRequestInfo() { DataType = DataType.Ping }.PackageAsBytes());
return true;
}
catch (Exception ex)
{
client.Logger.Exception(ex);
}

return false;
}

public static bool Pong<TClient>(this TClient client) where TClient : ITcpClientBase
{
try
{
client.Send(new MyRequestInfo() { DataType = DataType.Pong }.PackageAsBytes());
return true;
}
catch (Exception ex)
{
client.Logger.Exception(ex);
}

return false;
}
}

四、创建心跳插件类

下列代码主要实现心跳插件的功能。默认每五秒自动触发一次。且接收方收到Ping后,直接会回复Pong。

internal class HeartbeatAndReceivePlugin : TcpPluginBase
{
private readonly int m_timeTick;
private readonly ILog logger;

[DependencyInject(1000 * 5)]
public HeartbeatAndReceivePlugin(int timeTick, ILog logger)
{
this.m_timeTick = timeTick;
this.logger = logger;
}

protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e)
{
if (client is ISocketClient)
{
return;//此处可判断,如果为服务器,则不用使用心跳。
}

if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer)
{
timer.Dispose();
}

client.SetValue(DependencyExtensions.HeartbeatTimerProperty, new Timer((o) =>
{
client.Ping();
}, null, 0, m_timeTick));

base.OnConnected(client, e);
}

protected override void OnDisconnected(ITcpClientBase client, ClientDisconnectedEventArgs e)
{
base.OnDisconnected(client, e);
if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer)
{
timer.Dispose();
client.SetValue(DependencyExtensions.HeartbeatTimerProperty, null);
}
}

protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e)
{
if (e.RequestInfo is MyRequestInfo myRequest)
{
this.logger.Info(myRequest.ToString());
if (myRequest.DataType == DataType.Ping)
{
client.Pong();
}
}
base.OnReceivedData(client, e);
}
}

五、测试、启动

/// <summary>
/// 示例心跳。
/// 博客地址<see href="https://blog.csdn.net/qq_40374647/article/details/125598921"/>
/// </summary>
/// <param name="args"></param>
private static void Main(string[] args)
{
ConsoleAction consoleAction = new ConsoleAction();

//服务器
TcpService service = new TcpService();
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.UsePlugin()
.SetDataHandlingAdapter(()=>new MyFixedHeaderDataHandlingAdapter())
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
})
.ConfigurePlugins(a =>
{
a.Add<HeartbeatAndReceivePlugin>();
}))
.Start();//启动
service.Logger.Info("服务器成功启动");

//客户端
TcpClient tcpClient = new TcpClient();
tcpClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.UsePlugin()
.SetDataHandlingAdapter(() => new MyFixedHeaderDataHandlingAdapter())
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
})
.ConfigurePlugins(a =>
{
a.Add<HeartbeatAndReceivePlugin>();
}));
tcpClient.Connect();
tcpClient.Logger.Info("客户端成功连接");

consoleAction.OnException += ConsoleAction_OnException;
consoleAction.Add("1", "发送心跳", () =>
{
tcpClient.Ping();
});
consoleAction.Add("2", "发送数据", () =>
{
tcpClient.Send(new MyRequestInfo()
{
DataType = DataType.Data,
Data = Encoding.UTF8.GetBytes(Console.ReadLine())
}
.PackageAsBytes());
});
consoleAction.ShowAll();
while (true)
{
consoleAction.Run(Console.ReadLine());
}
}

private static void ConsoleAction_OnException(Exception obj)
{
Console.WriteLine(obj);
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/httpfiletransfer/index.html b/handbook/build/docs/httpfiletransfer/index.html new file mode 100644 index 000000000..d76f416d4 --- /dev/null +++ b/handbook/build/docs/httpfiletransfer/index.html @@ -0,0 +1,16 @@ + + + + + +文件传输 | TouchSocket + + + + +
+

文件传输

一、说明

该Http服务器及客户端,仅仅是轻量级的Http工具,不具备广泛的兼容性,所以请慎重使用。

二、服务器响应文件

该操作支持大型文件,也支持断点续传、支持迅雷加速等。

internal class MyHttpPlug : HttpPluginBase
{
protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e)
{
if (e.Context.Request.UrlEquals("/file"))
{
e.Context.Response
.SetStatus()//必须要有状态
.FromFile(@"D:\System\Windows.iso", e.Context.Request);//直接回应文件。
}
base.OnGet(client, e);
}
}

三、服务器接收上传文件

该操作目前仅支持小文件上传,实测100Mb没问题。

internal class MyHttpPlug : HttpPluginBase
{
protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e)
{
if (e.Context.Request.UrlEquals("/uploadfile"))
{
try
{
if (e.Context.Request.ContentLen>1024*1024*100)//全部数据体超过100Mb则直接拒绝接收。
{
e.Context.Response
.SetStatus("403", "数据过大")
.Answer();
return;
}
//此操作会先接收全部数据,然后再分割数据。
//所以上传文件不宜过大,不然会内存溢出。
var multifileCollection = e.Context.Request.GetMultifileCollection();

foreach (var item in multifileCollection)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append($"文件名={item.FileName}\t");
stringBuilder.Append($"数据长度={item.Length}");
client.Logger.Info(stringBuilder.ToString());
}

e.Context.Response
.SetStatus()
.FromText("Ok")
.Answer();
}
catch (Exception ex)
{
client.Logger.Exception(ex);
}
}
base.OnPost(client, e);
}
}

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/httpstaticpageplugin/index.html b/handbook/build/docs/httpstaticpageplugin/index.html new file mode 100644 index 000000000..8db9f510f --- /dev/null +++ b/handbook/build/docs/httpstaticpageplugin/index.html @@ -0,0 +1,16 @@ + + + + + +静态页面插件 | TouchSocket + + + + +
+

静态页面插件

静态网页托管插件仅服务器支持

HttpStaticPagePlugin静态网页托管插件,是用于Http的内容响应。

var service = new HttpService();

var config = new TouchSocketConfig();
config.UsePlugin()
.SetReceiveType(ReceiveType.Auto)
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigurePlugins(a =>
{
a.Add<HttpStaticPagePlugin>().AddFolder("../../../../../api");//添加静态页面文件夹
});

service.Setup(config).Start();
Console.WriteLine("Http服务器已启动");
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/ilog/index.html b/handbook/build/docs/ilog/index.html new file mode 100644 index 000000000..5a9b6a40e --- /dev/null +++ b/handbook/build/docs/ilog/index.html @@ -0,0 +1,19 @@ + + + + + +日志记录器 | TouchSocket + + + + +
+

日志记录器

一、日志记录接口(ILog)

继承ILog接口,然后实现以下方法。即可实现内部的日志记录。 +当用户自行输出日志时,可自行实现过程。

class MyLogger : ILog
{
public LogType LogType { get; set; } = LogType.Debug | LogType.Error;

public void Log(LogType logType, object source, string message, Exception exception)
{
//此处就是日志实际输出的位置。
}
}
注意

LogType 表示当前日志的可输出类型,并非输出级别,所以当需要输出多种类型时,请进行位域操作。

二、控制台日志记录器(ConsoleLogger)

在使用控制台日志记录器时,会按照以下格式输出。 +image.png

三、文件日志记录器(FileLogger)

在使用文件日志记录器时,先会在指定目录下创建“logs”目录,然后按日期生成“.log”文件。 +image.png

四、日志组记录器(LoggerGroup)

使用日志组记录器时,可以同时记录多个日志,例如:下列示例就同时在控制台和文件记录日志。

LoggerGroup logger = new LoggerGroup(new ConsoleLogger(),new FileLogger());

五、日志扩展

引入命名空间。可快捷记录日志。

LoggerGroup logger = new LoggerGroup(new ConsoleLogger(),new FileLogger());
logger.Info("Message");
logger.Warning("Warning");
logger.Error("Error");
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/independentusedatahandlingadapter/index.html b/handbook/build/docs/independentusedatahandlingadapter/index.html new file mode 100644 index 000000000..25c0d0829 --- /dev/null +++ b/handbook/build/docs/independentusedatahandlingadapter/index.html @@ -0,0 +1,16 @@ + + + + + +独立使用适配器 | TouchSocket + + + + +
+

独立使用适配器

一、说明

适配器的机制,是非常好的解封包机制,那这么好的机制,我们在设计的时候,也想到了单独使用适配器的情况。例如:

  1. 对于串口通信,可以使用适配器解包。
  2. 有时候可能大家只想用原生Socket实现。那么也可以使用适配器解包,或者封包。

二、使用

FixedHeaderPackageAdapter adapter = new FixedHeaderPackageAdapter();

bool sendCallBack = false;
bool receivedCallBack = false;

byte[] sentData = null;
adapter.SendCallBack = (buffer, offset, length) =>
{
//此处会回调发送的最终调用。例如:此处使用固定包头,则发送的数据为4+n的封装。
sentData = new byte[length];
Array.Copy(buffer, offset, sentData, 0, length);
if (length == 4 + 4)
{
sendCallBack = true;
}
};

adapter.ReceivedCallBack += (byteBlock, requestInfo) =>
{
//此处会回调接收的最终触发,例如:此处使用的固定包头,会解析4+n的数据为n。

if (byteBlock.Len == 4)
{
receivedCallBack = true;
}
};

byte[] data = Encoding.UTF8.GetBytes("RRQM");

adapter.SendInput(data, 0, data.Length);//模拟输入,会在SendCallBack中输出最终要发送的数据。

using (ByteBlock block = new ByteBlock())
{
block.Write(sentData);
block.Pos = 0;
adapter.ReceivedInput(block);//模拟输出,会在ReceivedCallBack中输出最终收到的实际数据。
}
提示

上述仅仅是以固定包头适配器示例的,实际上对于其他所有的适配器均可以使用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/index.html b/handbook/build/docs/index.html new file mode 100644 index 000000000..02c64e8df --- /dev/null +++ b/handbook/build/docs/index.html @@ -0,0 +1,17 @@ + + + + + +说明 | TouchSocket + + + + +
+

说明

当前版本

+


公告
  1. 原 RRQM 系文档,可以加 qq 群(234762506),在群文件自行获取。

使用前必要阅读

TouchSocket 由作者若汝棋茗及其他贡献者开发,所有版权归作者若汝棋茗所有,程序集源代码在遵循 Apache License 2.0 的开源协议以及附加协议下,可免费供其他开发者二次开发或(商业)使用。

Apache License 2.0 开源协议简述

  • 永久权利
  • 一旦被授权,永久拥有。
  • 全球范围的权利
  • 在一个国家获得授权,适用于所有国家。假如你在美国,许可是从印度授权的,也没有问题。
  • 授权免费,且无版税
  • 前期,后期均无任何费用。
  • 授权无排他性
  • 任何人都可以获得授权
  • 授权不可撤消
  • 一旦获得授权,没有任何人可以取消。比如,你基于该产品代码开发了衍生产品,你不用担心会在某一天被禁止使用该代码。

附加协议

个人使用须知:

  • 不得将程序集用作违法犯罪活动。
  • 不得将程序集单独包装售卖,申请专利等。
  • 不得擦除程序集所有有关作者的信息。

以上内容必须全部符合,个人使用授权才成立。

二次开发须知:

  • 不得将程序集用作违法犯罪活动。
  • 不得将程序集单独包装售卖,申请专利等。
  • 不得擦除程序集所有有关作者的信息。
  • 二次开发完成后的作品必须附带源作品所有作者信息,包括但不限于作者名、Gitee、Github 地址等。
  • 完成后的作品(仅 TouchSocket 部分)必须将发布时最新源代码提交一份给本作者,QQ 邮箱:505554090@qq.com

以上内容必须全部符合,二次开发授权才成立。

盈利性(商业)用途使用须知:

  • 不得将程序集用作违法犯罪活动。
  • 不得将程序集单独包装售卖,申请专利等。
  • 不得擦除程序集所有有关作者的信息,并必须于用户可见界面(如关于)中提名。

以上内容必须全部符合,使用授权才成立。

TouchSocketPro 商用许可

TouchSocketPro 是 TouchSocket 的企业版,其 99%功能与 TouchSocket 一致。所有版权归作者若汝棋茗所有。

TouchSocketPro 功能部分遵循:

  • 限时(1h)免费测试,测试期间可参与商业使用。
  • 付费使用,购买后还须遵循相关使用协议,详情咨询若汝棋茗。

TouchSocketPro 程序集源代码不公开开源,需要付费购买。

免责申明

在使用 TouchSocketTouchSocketPro 之前请进行缜密的测试。在使用期间,由本程序集造成或间接造成的所有损失,均自己承担,与本程序集无关。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/ioc/index.html b/handbook/build/docs/ioc/index.html new file mode 100644 index 000000000..e9037d00f --- /dev/null +++ b/handbook/build/docs/ioc/index.html @@ -0,0 +1,16 @@ + + + + + +依赖注入容器 | TouchSocket + + + + +
+

依赖注入容器

一、说明

所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。通俗来讲,就是把有依赖关系的类放到容器中,然后在我们需要这些类时,容器自动解析出这些类的实例。依赖注入最大的好处时实现类的解耦,利于程序拓展、单元测试、自动化模拟测试等。依赖注入的英文为:Dependency Injection,简称 DI。(说明来自网络)

TouchSocket内置了Container容器。只需要引入TouchSocket.Core即可使用。

二、特点

  • 支持构造函数、属性、方法三种注入方式,可以选择其中部分生效。
  • 支持 Singleton、Scoped、Transient三种生命周期。
  • 支持单接口,多实现注入。
  • 支持当获取类型是可实例类型时,即使不注册,也能成功构造。
  • 支持默认参数注入。
  • 支持构建参数注入。
  • 支持标签参数注入。
  • 支持泛型注入。
  • 支持Object注入。

三、注入方式

对于一个类,默认情况下,会支持构造函数、属性、方法三种注入方式。但是,当明确知道该类型仅会使用其中部分方式注入时,可以设置注入类型,以此节约性能。

/// <summary>
/// 让MyClass仅支持构造函数和属性注入
/// </summary>
[DependencyType(DependencyType.Constructor | DependencyType.Property)]
class MyClass
{

}

3.1 构造函数注入

其中MyLog1,MyLog2虽然没有注册,但是因为是实例,所以依然可以成功构造。

[Fact]
public void CtorShouldBeOk()
{
Container container = new Container();
container.RegisterTransient<ILog, MyLog3>();

var log3 = container.Resolve<ILog>() as MyLog3;

Assert.NotNull(log3.MyLog1);
Assert.NotNull(log3.MyLog2);
}
public class MyLog3 : ILog
{
public MyLog3(MyLog1 myLog1, MyLog2 myLog2)
{
this.MyLog1 = myLog1;
this.MyLog2 = myLog2;
}

public MyLog1 MyLog1 { get; }
public MyLog2 MyLog2 { get; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

3.2 属性注入

使用DependencyParamterInject,或者DependencyInject标记属性,即可注入。

示例中使用的是单接口多实现,所以使用DependencyParamterInject标记。

[Fact]
public void PropertyShouldBeOk()
{
Container container = new Container();
container.RegisterTransient<ILog, MyLog1>("MyLog1");
container.RegisterTransient<ILog, MyLog2>("MyLog2");
container.RegisterTransient<ILog, MyLog3>("MyLog3");
container.RegisterTransient<ILog, MyLog5>();

var log5 = container.Resolve<ILog>() as MyLog5;

Assert.NotNull(log5.MyLog1);
Assert.NotNull(log5.MyLog2);
Assert.True(log5.MyLog1.GetType() == typeof(MyLog1));
Assert.True(log5.MyLog2.GetType() == typeof(MyLog2));
}

public class MyLog5 : ILog
{
[DependencyParamterInject("MyLog1")]
public ILog MyLog1 { get; set; }

[DependencyParamterInject("MyLog2")]
public ILog MyLog2 { get; set; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

3.2 方法注入

使用DependencyInject标记属性,即可对方法注入。

同时,示例中演示了默认参数设定。在初始化MyLog6后,A=10,B="TouchSocket"。

同时,还能嵌套MyLog1和MyLog4的同一接口的不同实现,和实现的默认参数构造。

[Fact]
public void MethodShouldBeOk()
{
Container container = new Container();
container.RegisterTransient<ILog, MyLog1>("MyLog1");
container.RegisterTransient<ILog, MyLog2>("MyLog2");
container.RegisterTransient<ILog, MyLog3>("MyLog3");
container.RegisterTransient<ILog, MyLog4>("MyLog4");
container.RegisterTransient<ILog, MyLog6>("MyLog5");
container.RegisterTransient<ILog, MyLog6>();

var log6 = container.Resolve<ILog>() as MyLog6;

Assert.NotNull(log6.MyLog1);
Assert.NotNull(log6.MyLog4);
Assert.True(log6.MyLog1.GetType() == typeof(MyLog1));
Assert.True(log6.MyLog4.GetType() == typeof(MyLog4));
Assert.True(((MyLog4)log6.MyLog4).A == 20);
Assert.True(((MyLog4)log6.MyLog4).B == "IOU");
}
public class MyLog6 : ILog
{
[DependencyInject(10, "TouchSocket")]
public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)
{
this.A = a;
this.B = b;
this.MyLog1 = myLog1;
this.MyLog4 = myLog4;
}

public int A { get; set; }
public string B { get; set; }
public ILog MyLog1 { get; set; }
public ILog MyLog4 { get; set; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

Object注入

[Fact]
public void ObjectSingletonShouldBeOk()
{
Container container = new Container();
container.RegisterSingleton<ILog, MyLog1>();
container.RegisterSingleton<ILog, MyLog10>("10");

var log10 = container.Resolve<ILog>("10") as MyLog10;
Assert.NotNull(log10);
Assert.NotNull(log10.MyLog1);
Assert.True(log10.MyLog1.GetType() == typeof(MyLog1));
}
public class MyLog10 : ILog
{
[DependencyParamterInject(typeof(ILog))]
public object MyLog1 { get; set; }


public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

四、生命周期

生命周期是对注入构造的实例的有效性而言的。TouchSocket支持三种生命周期。

  • Singleton:单例注入,当注入,并且实例化以后,全局唯一实例。
  • Transient:瞬时注入,每次获取的实例都是新实例。
  • Scoped:区域单例注入,当在一个IScopedContainer时,实例唯一。

对于前两种,熟悉IOC的同学,相信都知道到。那接下来就演示一下Scoped。

实际上使用Scoped时,得先明确区域,也就是创建一个IScopedContainer的区域容器(类似Aps.net的IServiceProvider)。然后后续实例从IScopedContainer获得即可。

[Fact]
public void ScopedShouldBeOk()
{
Container container = new Container();
container.RegisterScoped<ILog, MyLog1>();

var log1 = container.Resolve<ILog>();
var log2 = container.Resolve<ILog>();
Assert.NotNull(log1);
Assert.False(log1 == log2);

IScopedContainer scopedContainer = container.Resolve<IScopedContainer>();
log1 = scopedContainer.Resolve<ILog>();
log2 = scopedContainer.Resolve<ILog>();
Assert.NotNull(log1);
Assert.True(log1 == log2);
}

所有模型定义

public interface IGeneric<T1, T2>
{
}

public class Generic<T1, T2> : IGeneric<T1, T2>
{

}



public class MyLog1 : ILog
{
public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}
public class MyLog2 : ILog
{
public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

public class MyLog3 : ILog
{
public MyLog3(MyLog1 myLog1, MyLog2 myLog2)
{
this.MyLog1 = myLog1;
this.MyLog2 = myLog2;
}

public MyLog1 MyLog1 { get; }
public MyLog2 MyLog2 { get; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

public class MyLog4 : ILog
{
[DependencyInject(10, "TouchSocket")]
public MyLog4(int a, string b, MyLog1 myLog1, MyLog2 myLog2)
{
this.A = a;
this.B = b;
this.MyLog1 = myLog1;
this.MyLog2 = myLog2;
}

public int A { get; }
public string B { get; }
public MyLog1 MyLog1 { get; }
public MyLog2 MyLog2 { get; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

public class MyLog5 : ILog
{
[DependencyParamterInject("MyLog1")]
public ILog MyLog1 { get; set; }

[DependencyParamterInject("MyLog2")]
public ILog MyLog2 { get; set; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

public class MyLog6 : ILog
{
[DependencyInject(10, "TouchSocket")]
public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)
{
this.A = a;
this.B = b;
this.MyLog1 = myLog1;
this.MyLog4 = myLog4;
}

public int A { get; set; }
public string B { get; set; }
public ILog MyLog1 { get; set; }
public ILog MyLog4 { get; set; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

public class MyLog7 : ILog
{
public MyLog7(IGeneric<ILog, MyLog2> generic)
{
this.Generic = generic;
}

public IGeneric<ILog, MyLog2> Generic { get; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

[DependencyType(DependencyType.Constructor)]
public class MyLog8 : ILog
{
[DependencyInject(10, "RRQM")]
public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)
{
this.A = a;
this.B = b;
this.MyLog1 = myLog1;
this.MyLog4 = myLog4;
}

public int A { get; set; }
public string B { get; set; }
public ILog MyLog1 { get; set; }
public ILog MyLog4 { get; set; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}

[DependencyType(DependencyType.Constructor | DependencyType.Method)]
public class MyLog9 : ILog
{
[DependencyInject(10, "RRQM")]
public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)
{
this.A = a;
this.B = b;
this.MyLog1 = myLog1;
this.MyLog4 = myLog4;
}

public int A { get; set; }
public string B { get; set; }
public ILog MyLog1 { get; set; }
public ILog MyLog4 { get; set; }

public void Debug(LogType logType, object source, string message, Exception exception)
{

}

public void Debug(LogType logType, object source, string message)
{

}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/ipackage/index.html b/handbook/build/docs/ipackage/index.html new file mode 100644 index 000000000..82929ee71 --- /dev/null +++ b/handbook/build/docs/ipackage/index.html @@ -0,0 +1,16 @@ + + + + + +包序列化模式 | TouchSocket + + + + +
+

包序列化模式

一、说明

包序列化模式是为了解决极限序列化的问题。常规序列化的瓶颈,主要是反射、表达式树、创建对象等几个方面,这几个问题在运行时阶段,都没有一个好的解决方案。目前在net6以后,微软大力支持源代码生成,这使得这类问题得到了很大程度的解决。但是对于老项目,或者无法使用net6和vs2022以上的项目,是无法使用的。所以,这时候包序列化模式就显得非常需要了。

二、特点

【优点】

  1. 简单、可靠、高效
  2. 可以支持所有类型(需要自己编写代码)
  3. 数据量最少(从理论来说这是占数据量最轻量的设计)

【缺点】

  1. 要求序列化端和反序列化端必须保持一致,可以存在数据差异,但是不能出现数据断层。

三、使用

【实体类】

class MyClass : IPackage
{
public int P1 { get; set; }
public string P2 { get; set; }
public char P3 { get; set; }
public double P4 { get; set; }
public List<int> P5 { get; set; }
public Dictionary<int, MyClassModel> P6 { get; set; }
public void Package(ByteBlock byteBlock)
{
//基础类型直接写入。
byteBlock.Write(P1);
byteBlock.Write(P2);
byteBlock.Write(P3);
byteBlock.Write(P4);

//集合类型,可以先判断是否为null
byteBlock.WriteIsNull(P5);
if (P5 != null)
{
//如果不为null
//就先写入集合长度
//然后遍历将每个项写入
byteBlock.Write(P5.Count);
foreach (var item in P5)
{
byteBlock.Write(item);
}
}

//字典类型,可以先判断是否为null
byteBlock.WriteIsNull(P6);
if (P6 != null)
{
//如果不为null
//就先写入字典长度
//然后遍历将每个项,按键、值写入
byteBlock.Write(P6.Count);
foreach (var item in P6)
{
byteBlock.Write(item.Key);
byteBlock.WritePackage(item.Value);//因为值MyClassModel实现了IPackage,所以可以直接写入
}
}
}

public void Unpackage(ByteBlock byteBlock)
{
//基础类型按序读取。
this.P1 = byteBlock.ReadInt32();
this.P2 = byteBlock.ReadString();
this.P3 = byteBlock.ReadChar();
this.P4 = byteBlock.ReadDouble();

var isNull = byteBlock.ReadIsNull();
if (!isNull)
{
int count = byteBlock.ReadInt32();
var list = new List<int>(count);
for (int i = 0; i < count; i++)
{
list.Add(byteBlock.ReadInt32());
}
this.P5 = list;
}


isNull = byteBlock.ReadIsNull();//复用前面的变量,省的重新声明
if (!isNull)
{
int count = byteBlock.ReadInt32();
var dic = new Dictionary<int, MyClassModel>(count);
for (int i = 0; i < count; i++)
{
dic.Add(byteBlock.ReadInt32(), byteBlock.ReadPackage<MyClassModel>());
}
this.P6 = dic;
}
}
}

class MyClassModel : PackageBase
{
public DateTime P1 { get; set; }
public override void Package(ByteBlock byteBlock)
{
byteBlock.Write(P1);
}

public override void Unpackage(ByteBlock byteBlock)
{
this.P1 = byteBlock.ReadDateTime();
}
}

【打包和解包】

var myClass = new MyClass();
myClass.P1 = 1;
myClass.P2 = "若汝棋茗";
myClass.P3 = 'a';
myClass.P4= 3;

myClass.P5=new List<int> { 1, 2, 3 };

myClass.P6= new Dictionary<int, MyClassModel>()
{
{ 1,new MyClassModel(){ P1=DateTime.Now} },
{ 2,new MyClassModel(){ P1=DateTime.Now} }
};

using (ByteBlock byteBlock=new ByteBlock())
{
myClass.Package(byteBlock);//打包,相当于序列化

byteBlock.Seek(0);//将流位置重置为0

var myNewClass = new MyClass();
myNewClass.Unpackage(byteBlock);//解包,相当于反序列化
}

四、性能评测

基准测试表明:

包序列化模式和使用源代码生成方式工作的MemoryPack几乎一样。比json方式快了10倍多,比微软的json快了近4倍。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/jsonrpcdescription/index.html b/handbook/build/docs/jsonrpcdescription/index.html new file mode 100644 index 000000000..d7e5e8e29 --- /dev/null +++ b/handbook/build/docs/jsonrpcdescription/index.html @@ -0,0 +1,16 @@ + + + + + +产品及架构介绍 | TouchSocket + + + + +
+

产品及架构介绍

一、说明

JsonRpc是通用的RPC规范,与编程语言无关、操作系统无关。详细说明请参阅JsonRpc 2.0 官方文档,在TouchSocket中封装了前后端,使其使用更加方便、高效。

目前支持Tcp、Http、Websocket三种协议调用。

二、特点:

  • 异常反馈
  • 插件支持。
  • 支持自定义类型。
  • 支持类型嵌套。
  • 支持js、Android等调用。
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/jsonrpcservice/index.html b/handbook/build/docs/jsonrpcservice/index.html new file mode 100644 index 000000000..6f6c874f6 --- /dev/null +++ b/handbook/build/docs/jsonrpcservice/index.html @@ -0,0 +1,17 @@ + + + + + +定义、发布、启动服务 | TouchSocket + + + + +
+

定义、发布、启动服务

一、定义服务

服务器端中新建一个类,继承于RpcServer类(或实现IRpcServer),然后在该类中写公共方法,并用JsonRpc属性标签标记,如果方法有重载,需要重新指定函数键

  • 支持代理生成注释
public class JsonRpcServer : RpcServer
{
[JsonRpc]
public string TestJsonRpc(string str)
{
return "TouchSocket" + str;
}

/// <summary>
/// 当标记为true时直接使用方法名称
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
[JsonRpc(true)]
public string TestJsonRpc1(string str)
{
return "TouchSocket" + str;
}

/// <summary>
/// 使用调用上下文。
/// 可以从上下文获取调用的SocketClient。从而获得IP和Port等相关信息。
/// </summary>
/// <param name="callContext"></param>
/// <param name="str"></param>
/// <returns></returns>
[JsonRpc(MethodFlags = MethodFlags.IncludeCallContext)]
public string TestGetContext(ICallContext callContext, string str)
{
if (callContext.Caller is HttpSocketClient)
{
Console.WriteLine("HTTP请求");
var client = callContext.Caller as HttpSocketClient;
var ip = client.IP;
var port = client.Port;
Console.WriteLine($"HTTP请求{ip}:{port}");

}

if (callContext.Caller is SocketClient)
{
Console.WriteLine("Tcp请求");
var client = callContext.Caller as SocketClient;
var ip = client.IP;
var port = client.Port;

client.Send(Encoding.UTF8.GetBytes("Hello Word"));
Console.WriteLine($"Tcp请求{ip}:{port}");

}
return "TouchSocket" + str;
}

[JsonRpc]
public JObject TestJObject(JObject obj)
{
return obj;
}
}

二、使用Tcp创建服务解析器

服务解析器是实际的服务接收、触发、调用、反馈的实际载体,通俗来说就是通信服务器

JsonRpcParserPlugin插件添加在TcpService服务器时,会使用TCP协议。此时的调用,会根据适配器类型,决定是否需要有调用结束标识,一般以\r\n结尾。

TcpService service = new TcpService();
service.Setup(new TouchSocketConfig()
.UsePlugin()
.ConfigureRpcStore(a =>
{
a.RegisterServer<JsonRpcServer>();//配置RpcStore必须在最前面。
})
.ConfigurePlugins(a =>
{
a.Add<JsonRpcParserPlugin>();//tcp中路由路径无效
})
.SetDataHandlingAdapter(() =>
{
return new NormalDataHandlingAdapter();
//return new TerminatorPackageAdapter("\r\n");使用该适配器时,调用方必须在最后追加相应的结束调用符。
})
.SetListenIPHosts(new IPHost[] { new IPHost(7705) }))
.Start();

三、使用Http或Websocket创建服务解析器

JsonRpcParserPlugin插件添加在HttpService服务器时,会使用Http、Websocket协议。

创建后,如果想使用Http调用,只需要以Post方式,将调用Json字符串路由到设定路由地址即可(下文示例“/jsonRpc”)。 +如果想使用Websocket调用,只需要以文本形式,传递到服务器即可。服务器会判定:如果内容中包含“jsonrpc”则认定为调用,会做调用处理。

HttpService service = new HttpService();

service.Setup(new TouchSocketConfig()
.UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7706) })
.ConfigureRpcStore(a =>//Rpc的配置必须在插件之前。
{
a.RegisterServer<JsonRpcServer>();
})
.ConfigurePlugins(a =>
{
a.Add<WebSocketServerPlugin>()
.SetWSUrl("/ws");//启用websocket,使用/ws路由连接。

a.Add<JsonRpcParserPlugin>()
.SetJsonRpcUrl("/jsonRpc");
}))
.Start();
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/jsonserialize/index.html b/handbook/build/docs/jsonserialize/index.html new file mode 100644 index 000000000..4345a8a46 --- /dev/null +++ b/handbook/build/docs/jsonserialize/index.html @@ -0,0 +1,21 @@ + + + + + +Json序列化 | TouchSocket + + + + +
+

Json序列化

一、说明

在TouchSocket中,内置了Json序列化与反序列化。

string jsonstr=SerializeConvert.ToJson(new object());//序列化
object obj=SerializeConvert.FromJson<object>(jsonstr);//反序列化

二、动态调整的Json策略

默认情况下: +在net45和netstandard2.0平台时,序列化方式是由JsonFast(群友老江)提供的单文件json序列化。该json工具能够序列化大多数数据结构,且性能和Newtonsoft.Json不相上下(见下测试)。 +在netcoreapp3.1及以上平台时,序列化方式使用System.Text.Json。

但是 +当应用中加载了Newtonsoft.Json的程序集后,所有的平台的序列化,均会使用Newtonsoft.Json。可通过**SerializeConvert.NewtonsoftJsonIsSupported**静态属性获取当前是否支持Newtonsoft.Json。

也可以手动加载Newtonsoft.Json(一般在Unity3d中需要手动加载)。

bool IsSupported=SerializeConvert.LoadNewtonsoftJson(typeof(JsonConvert));//返回值指示是否成功加载

当加载了Newtonsoft.Json的程序集,但是不想使用该工具序列化时,可将**SerializeConvert.NewtonsoftJsonFirst**静态属性设为false。

三、JsonFast性能

【简单数据对象】

public class SimpleObject 
{
public int Age { get; set; }
public string Name { get; set; }
}
[Benchmark]
public void JsonFast_SimpleObject()
{
var v = new SimpleObject { Age = 40, Name = "John" };
for (int i = 0; i < Count; i++)
{
var str = JsonFastConverter.JsonTo(v);
var val = JsonFastConverter.JsonFrom<SimpleObject>(str);
}
}

下图为1w次的序列化与反序列化。JsonFast的效率甚至还稍高一些。 +image.png

【复杂对象】

public class ComplexObject
{
public Dictionary<int, int> Dic1 { get; set; }
public Dictionary<int, string> Dic2 { get; set; }
public Dictionary<string, string> Dic3 { get; set; }
public Dictionary<int, Arg> Dic4 { get; set; }
public List<int> List1 { get; set; }
public List<string> List2 { get; set; }
public List<byte[]> List3 { get; set; }
public int P1 { get; set; }
public string P2 { get; set; }
public long P3 { get; set; }
public byte P4 { get; set; }
public DateTime P5 { get; set; }
public double P6 { get; set; }
public byte[] P7 { get; set; }
}

public class Arg
{
public Arg()
{
}

public Arg(int myProperty)
{
MyProperty = myProperty;
}

public int MyProperty { get; set; }
}

初始化

private ComplexObject GetComplexObject()
{
ComplexObject complexObject = new ComplexObject();
complexObject.P1 = 10;
complexObject.P2 = "天下无敌";
complexObject.P3 = 100;
complexObject.P4 = 0;
complexObject.P5 = DateTime.Now;
complexObject.P6 = 10;
complexObject.P7 = new byte[1024 * 64];

Random random = new Random();
random.NextBytes(complexObject.P7);

complexObject.List1 = new List<int>();
complexObject.List1.Add(1);
complexObject.List1.Add(2);
complexObject.List1.Add(3);

complexObject.List2 = new List<string>();
complexObject.List2.Add("1");
complexObject.List2.Add("2");
complexObject.List2.Add("3");

complexObject.List3 = new List<byte[]>();
complexObject.List3.Add(new byte[1024]);
complexObject.List3.Add(new byte[1024]);
complexObject.List3.Add(new byte[1024]);

complexObject.Dic1 = new Dictionary<int, int>();
complexObject.Dic1.Add(1, 1);
complexObject.Dic1.Add(2, 2);
complexObject.Dic1.Add(3, 3);

complexObject.Dic2 = new Dictionary<int, string>();
complexObject.Dic2.Add(1, "1");
complexObject.Dic2.Add(2, "2");
complexObject.Dic2.Add(3, "3");

complexObject.Dic3 = new Dictionary<string, string>();
complexObject.Dic3.Add("1", "1");
complexObject.Dic3.Add("2", "2");
complexObject.Dic3.Add("3", "3");

complexObject.Dic4 = new Dictionary<int, Arg>();
complexObject.Dic4.Add(1, new Arg(1));
complexObject.Dic4.Add(2, new Arg(2));
complexObject.Dic4.Add(3, new Arg(3));
return complexObject;
}
[Benchmark]
public void JsonFast_ComplexObject()
{
var v = GetComplexObject();
for (int i = 0; i < Count; i++)
{
var str = JsonFastConverter.JsonTo(v);
var val = JsonFastConverter.JsonFrom<ComplexObject>(str);
}
}

下图为100次序列化与反序列化,JsonFast性能稍弱,但是基本满足要求。 +image.png

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/multithreadingfiletransfer/index.html b/handbook/build/docs/multithreadingfiletransfer/index.html new file mode 100644 index 000000000..143cc060c --- /dev/null +++ b/handbook/build/docs/multithreadingfiletransfer/index.html @@ -0,0 +1,17 @@ + + + + + +多线程文件传输 | TouchSocket + + + + +
+

多线程文件传输

一、说明

多线程文件传输,顾名思义,就是多个连接链路,共同传输一个文件。

多线程传输的优点是什么?和常规文件传输相比,场景有哪些不同?

首先,常规文件传输是基于单个连接链路的,所以,单个连接的传输速率上限,就是常规传输的上限。一般来说,局域网当中,单个连接即可占满所有带宽,所以这时候多线程传输和常规传输并无差别。但是,在云服务器,或者在有流量均衡算法的网络中,每个连接的最大速率不是带宽的最大速率,那么这时候,两个差距是比较大的。

例如,我自己租的一个单核云服务器,它的单个连接速率只有1Mb,但是弹性带宽却有10Mb。宏观表象就是,一个客户端连接时,可以用1Mb带宽,两个客户端连接时,就可以用2Mb。那么这时候,多线程传输就显得格外重要了。

其次,多线程传输是无状态的,所以对于断线重连,换网重连等操作,是完全无感的。

二、使用

因为是多链路传输,所以,就必须建立多个客户端的连接到服务器。这里使用已经封装好的通信模型ClientFactory。

ClientFactory的通信模型使用的是一个主通信端+多个传输客户端。

对于客户端的配置,请详细参考创建TouchRpc客户端

private TcpTouchRpcClientFactory CreateClientFactory()
{
TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory()
{
MinCount = 5,
MaxCount = 10,
OnGetMainConfig = () =>//配置主通信
{
return new TouchSocketConfig()
.SetRemoteIPHost("tcp://127.0.0.1:7789");
},
OnGetTransferConfig = () => //配置辅助通信
{
return new TouchSocketConfig()
.SetRemoteIPHost("tcp://127.0.0.1:7789");
}
};

return clientFactory;
}

【拉取文件】

TcpTouchRpcClientFactory clientFactory = CreateClientFactory();
var resultCon = clientFactory.CheckStatus();//检验主通信器连接状态。默认如果没有连接,则会建立。
if (resultCon.IsSuccess())
{
var fileOperator = new MultithreadingFileOperator()
{
ResourcePath = path,//请求资源路径
SavePath = savePath,//本地保存路径
};
//此处相当于Timer,每秒获取传输的速度和进度
LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) =>
{
if (fileOperator.IsEnd)
{
loop.SafeDispose();
}

Console.WriteLine($"速度:{fileOperator.Speed()},进度:{fileOperator.Progress}");
});
_=loopAction.RunAsync();

Result result= await clientFactory.PullFileAsync(fileOperator);
if (result.IsSuccess())
{
MessageBox.Show(result.ToString());
}
}
else
{
MessageBox.Show(resultCon.ToString());
}

【推送文件】

TcpTouchRpcClientFactory clientFactory = CreateClientFactory();
var resultCon = clientFactory.CheckStatus();//检验主通信器连接状态。默认如果没有连接,则会建立。
if (resultCon.IsSuccess())
{
var fileOperator = new MultithreadingFileOperator()
{
ResourcePath = path,
SavePath = savePath,
};

//此处相当于Timer,每秒获取传输的速度和进度
LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) =>
{
if (fileOperator.IsEnd)
{
loop.SafeDispose();
}

Console.WriteLine($"速度:{fileOperator.Speed()},进度:{fileOperator.Progress}");
});
_=loopAction.RunAsync();

Result result=await clientFactory.PushFileAsync(fileOperator);
if (result.IsSuccess())
{
MessageBox.Show(result.ToString());
}
}
else
{
MessageBox.Show(resultCon.ToString());
}

三、客户端之间传输文件

该功能也支持客户端之间互相传输。使用方法基本一致,需要额外指定目标Id,以及获取传输的Id集合即可。

多线程的客户端之间传输文件,不像其他操作类型那么简单。因为除了需要指定目的Id外,还需要指定获取目标Id的,传输客户端的Id集合,不然,获取数据的时候,仍然会是单线程工作的。

此外,服务器也需要同意路由

internal class MyTouchRpcPlugin : TouchRpcPluginBase
{
protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)
{
if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile)
{
e.IsPermitOperation = true;
}
base.OnRouting(client, e);
}
}

【获取目标传输客户端的Id集合】 +在TcpTouchRpcClientFactory属性中,有个OnFindTransferIds。通过实现该属性,使其能够获取到对应客户端的传输客户端Id集合(下列代码为模拟值,要具体实现该功能,还得自行实现)。

TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory()
{
MinCount = 5,
MaxCount = 10,
OnGetMainConfig = () =>//配置主通信
{
return new TouchSocketConfig()
.SetRemoteIPHost("tcp://127.0.0.1:7789")
.SetVerifyToken("FileService");
},
OnGetTransferConfig = () => //配置辅助通信
{
return new TouchSocketConfig()
.SetRemoteIPHost("tcp://127.0.0.1:7789")
.SetVerifyToken("FileService");
}
,
OnFindTransferIds = (client,targetId) =>
{
//此处的操作不唯一,可能需要rpc实现。
//其目的比较简单,就是获取到targetId对应的主客户端的所有传输客户端的Id集合。
//这样就实现了多个客户端向多个客户端传输文件的目的。

return new string[] { targetId};//此处为模拟结果。
}
};
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/natservice/index.html b/handbook/build/docs/natservice/index.html new file mode 100644 index 000000000..258fb8958 --- /dev/null +++ b/handbook/build/docs/natservice/index.html @@ -0,0 +1,16 @@ + + + + + +Tcp端口转发 | TouchSocket + + + + +
+

Tcp端口转发

一、说明

NATService是具有转发功能的TCP服务器。他的职能是将收到的TCP数据转发到多个目标服务器。也能将多个目标服务器的数据转发到连接客户端。

二、常见使用场景

  • 调试场景:在生产环境中,想要调试客户端,要么中断服务器,要么就将实际数据转发到NAT,然后在不影响实际场景的情况下进行调试。
  • 内网穿透场景:一般tcp都会使用转发式的内网穿透。

三、创建NATService

static void Main(string[] args)
{
MyNATService service = new MyNATService();
var config = new TouchSocketConfig();
config.SetListenIPHosts(new IPHost[] { new IPHost(7788) });

service.Setup(config);
service.Start();

Console.WriteLine("转发服务器已启动。已将7788端口转发到127.0.0.1:7789与127.0.0.1:7790地址");
}
提示

NATService支持客户端适配器和Ssl。也支持转发适配器和Ssl。

 class MyNATService : NATService
{
protected override void OnConnected(NATSocketClient socketClient, RRQMEventArgs e)
{
base.OnConnected(socketClient, e);

try
{
//此处模拟的是只要连接到NAT服务器,就转发。
//实际上,这个方法可以随时调用。
socketClient.AddTargetClient(new TouchSocketConfig().SetRemoteIPHost("127.0.0.1:7789"));
socketClient.AddTargetClient(new TouchSocketConfig().SetRemoteIPHost("127.0.0.1:7790"));
}
catch (Exception ex)
{
socketClient.Logger.Exception(ex);
}
}

protected override void OnTargetClientDisconnected(NATSocketClient socketClient, ITcpClient tcpClient, ClientDisconnectedEventArgs e)
{
socketClient.Logger.Message($"{socketClient.IP}:{socketClient.Port}的转发客户端{tcpClient.IP}:{tcpClient.Port}已经断开连接。");
base.OnTargetClientDisconnected(socketClient, tcpClient, e);
}

protected override byte[] OnNATReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
{
//服务器收到的数据
return base.OnNATReceived(socketClient, byteBlock, requestInfo);
}

protected override byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ByteBlock byteBlock, IRequestInfo requestInfo)
{
//连接的客户端收到的数据
return base.OnTargetClientReceived(socketClient, tcpClient, byteBlock, requestInfo);
}
}


四、转发断线重连

try
{
//此处模拟的是只要连接到NAT服务器,就转发。
//实际上,这个方法可以随时调用。
socketClient.AddTargetClient(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.ConfigurePlugins(a=>
{
//在企业版中,使用以下任意方式,可实现转发客户端的断线重连。
a.Add<PollingKeepAlivePlugin<TcpClient>>()
.SetTick(1000);//每秒检查
//a.UseReconnection();
}));
}
catch (Exception ex)
{
socketClient.Logger.Exception(ex);
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/normaldatahandlingadapter/index.html b/handbook/build/docs/normaldatahandlingadapter/index.html new file mode 100644 index 000000000..98b7cb3a5 --- /dev/null +++ b/handbook/build/docs/normaldatahandlingadapter/index.html @@ -0,0 +1,16 @@ + + + + + +a.正常数据处理适配器 | TouchSocket + + + + +
+

a.正常数据处理适配器

一、说明

正常数据处理适配器就是处理普通的TCP报文,内部不进行任何数据处理,这也就意味着它并不能解决粘、分包的问题,它只是能够将数据进行接收和处理而已。

二、特点

  1. 能够接收所有TCP报文,与语言、框架无关。
  2. 相当于加强版的Socket,但是数据发送与接收是完全一致的。

三、使用

步骤

  1. TouchSocketConfig配置中设置
  2. 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。
TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(()=> { return new NormalDataHandlingAdapter(); }))//配置适配器
.Start();//启动
提示

该适配器,客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/othercore/index.html b/handbook/build/docs/othercore/index.html new file mode 100644 index 000000000..c0e1bca1f --- /dev/null +++ b/handbook/build/docs/othercore/index.html @@ -0,0 +1,19 @@ + + + + + +其他相关功能类 | TouchSocket + + + + +
+

其他相关功能类

一、Crc计算

TouchSocket从网上搜集了Crc1-23的计算方法。并封装在了Crc类中。 +以最常用的Crc16为例。

byte[] data = new byte[10];
byte[] result = Crc.Crc16(data, 0, data.Length);

二、时间测量器(TimeMeasurer)

功能:封装的Stopwatch,测量运行Action的时间。

TimeSpan timeSpan = TimeMeasurer.Run(() =>
{
Thread.Sleep(1000);
});

三、MD5计算

string str = MD5.GetMD5Hash("TouchSocket");
bool b = MD5.VerifyMD5Hash("TouchSocket",str);

四、16进制相关

【将16进制的字符转换为数组】

 public static byte[] ByHexStringToBytes(this string hexString, string splite = default)

【将16进制的字符转换为int32】

 public static int ByHexStringToInt32(this string hexString)

五、雪花ID生成

雪花ID,会生成long类型的不重复ID。

SnowflakeIDGenerator generator = new SnowflakeIDGenerator(4);
long id=generator.NextID();

六、数据压缩

内部封装了Gzip的压缩。使用静态方法即可完成。


byte[] data = new byte[1024];
new Random().NextBytes(data);

using (ByteBlock byteBlock=new ByteBlock())
{
GZip.Compress(byteBlock,data,0,data.Length);//压缩
var decompressData2 = GZip.Decompress(byteBlock.ToArray());//解压
}


压缩接口 +内部还定义了一个IDataCompressor的压缩接口。目的是为了向成熟框架传递压缩方法(例如TcpClient)。 +默认配备了一个GZipDataCompressor。可以直接使用。当然大家可以自由扩展其他压缩方法。

class MyDataCompressor : IDataCompressor
{
public byte[] Compress(ArraySegment<byte> data)
{
//此处实现压缩
throw new NotImplementedException();
}

public byte[] Decompress(ArraySegment<byte> data)
{
//此处实现压缩
throw new NotImplementedException();
}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/pipelinedatahandlingadapter/index.html b/handbook/build/docs/pipelinedatahandlingadapter/index.html new file mode 100644 index 000000000..b803dd281 --- /dev/null +++ b/handbook/build/docs/pipelinedatahandlingadapter/index.html @@ -0,0 +1,16 @@ + + + + + +Pipeline数据适配器 | TouchSocket + + + + +
+

Pipeline数据适配器

一、说明

Pipeline适配器,是结合IOCP与管道模型结合的产物。功能类似于NetworkStream,但与之不同的是,Pipeline每当有数据到达时,会先触发一个事件(OnReveived),然后用户在事件中可无限制的Read或Write数据。如果本次接收完成,可退出接收。当下一段数据抵达时,会再次通知接收。

二、使用

下列示例代码实现,当读到换行时,结束本次接收。

TcpService service = new TcpService();

service.Received += (client, byteBlock, requestInfo) =>
{
if (requestInfo is Pipeline pipeline)//实际上Pipeline继承自Stream
{
pipeline.ReadTimeout = 1000 * 60;//设置读取超时时间为60秒。
StreamReader streamReader = new StreamReader(pipeline);//所以可以直接用StreamReader构造
string ss = streamReader.ReadLine();//会一直等换行,直到等到换行,才继续向下执行
Console.WriteLine(ss);
}
//当Pipeline退出该事件方法时,会被自动释放,下次会投递新的Pipeline实例。
// 如果里面还有未Read完的数据,下次会继续投递,如果想直接丢弃,则在此处直接调用Disopose即可。

};

//声明配置
var config = new TouchSocketConfig();
config.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetDataHandlingAdapter(() => new PipelineDataHandlingAdapter());//配置适配器为Pipeline

//载入配置
service.Setup(config);

//启动
service.Start();

提示

上述创建的适配器客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/pluginsmanager/index.html b/handbook/build/docs/pluginsmanager/index.html new file mode 100644 index 000000000..cb3104629 --- /dev/null +++ b/handbook/build/docs/pluginsmanager/index.html @@ -0,0 +1,20 @@ + + + + + +插件系统 | TouchSocket + + + + +
+

插件系统

说明

  • 插件是对TouchSocket产品的横向扩展。

产品特点

  • 简单易用。
  • 易扩展。

产品应用场景

  • TCP基础使用场景。
  • 自定义协议解析场景。

插件特性

【多线程并发】 +插件的所有触发,均是同一实例,所以在服务器运行时,几乎都是并发触发的,所有应当考虑并发问题。

【插件先行】 +当启用插件时,插件的触发仅次于方法重写,而优于事件。

【执行顺序】 +每个插件都有一个Order属性,该属性表示该插件的执行顺序,数值小,越提前执行(Order在Add之前生效,后续修改无效)。

【中断传递】 +当某个插件在响应时,如果设置e.Handled=true,则该数据将不会再触发后续的插件、事件、重写方法。

用户自定义插件

用户通过实现框架预设的插件接口,即可接收相应的触发。每个组件都有详细的插件支持说明。

例如:ITcpPluginITokenPluginIProtocolPlugin等。

系统自定义插件

当各位朋友使用TouchSocket封装自己的dll时,可能需要一些定义插件。那么这个需求TouchSocket也能满足大家。

例如:实现基于TCP的特殊信息自定义插件,当收到字母‘A’时,希望触发实现IAPlugin接口插件的GoToA方法。

具体操作如下:

  1. 声明IAPlugin接口,继承IPlugin
  2. 声明GoToA接口方法(该方法必须两个参数,第一参数无要求,一般为触发主体,第二参数必须继承TouchSocketEventArgs)。
  3. 在合适时候,判断当前配置是否支持插件,然后使用服务器或客户端的PluginsManager属性调用Raise方法,此处的泛型(IAPlugin)必须为接口类型。
public interface IAPlugin : IPlugin
{
void GoToA(ITcpClientBase client,TouchSocketEventArgs e);
}
public class MyTClient : TcpClient
{
protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
{
if (this.UsePlugin)
{
if (byteBlock.ToString()=="A")
{
this.PluginsManager.Raise<IAPlugin>("GoToA",this,new TouchSocketEventArgs());
}
}
}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/reconnection/index.html b/handbook/build/docs/reconnection/index.html new file mode 100644 index 000000000..ebdc3678c --- /dev/null +++ b/handbook/build/docs/reconnection/index.html @@ -0,0 +1,16 @@ + + + + + +断线重连 | TouchSocket + + + + +
+

断线重连

一、说明

所谓断线重连,即tcp客户端在断开服务器后,主动发起的再次连接请求。

二、使用Reconnection插件

使用断线重连非常简单,仅一行代码完成。

.UsePlugin()
.ConfigurePlugins(a=>
{
a.UseReconnection(5, true, 1000);//如需永远尝试连接,tryCount设置为-1即可。
});
注意

断线重连,必须满足以下几个要求:

  1. 必须完成第一次连接
  2. 必须是被动断开,如果是客户端主动调用Close、Disconnect等方法主动断开的话,不会生效。
  3. 必须有显式的断开信息,也就是说,直接拔网线的话,不会立即生效,会等tcp保活到期后再生效。

三、使用PollingKeepAlive插件

企业版使用断线重连,在兼容上述方法的同时,还支持一种无人值守的连接方式,即轮询式连接,使用也非常简单,仅一行代码完成。

.UsePlugin()
.ConfigurePlugins(a=>
{
a.Add<PollingKeepAlivePlugin<TcpClient>>()
.SetTick(1000);//每秒检查
});
注意

PollingKeepAlive断线重连,必须满足以下几个要求:

  1. 不要和UseReconnection一同使用
  2. 必须有显式的断开信息,也就是说,直接拔网线的话,不会立即生效,会等tcp保活到期后再生效。
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/remotefilecontrol/index.html b/handbook/build/docs/remotefilecontrol/index.html new file mode 100644 index 000000000..27cc2e0a7 --- /dev/null +++ b/handbook/build/docs/remotefilecontrol/index.html @@ -0,0 +1,16 @@ + + + + + +远程文件操作 | TouchSocket + + + + +
+

远程文件操作

一、说明

支持直接访问远程文件、文件夹的快捷操作。

二、支持的操作

以下内容,所有TouchRpc均支持(包括基于udp协议的)。

操作文件文件夹
获取信息支持:获取文件名称,大小,修改时间等。支持:获取文件夹名称,大小,子文件夹,文件名称、修改时间等。
创建不支持文件的直接创建。支持
删除支持支持
复制支持支持
移动支持支持

三、代码示例

以获取文件夹信息为例:

client为TouchRpc的终端。可以是逻辑客户端,也可以是逻辑服务器所包含的SocketClient

//client必选先建立连接(udp协议的除外)
//Metadata可以向对方传递更多的有用信息。
//5000是超时时间,单位毫秒。
//CancellationToken包含一个可取消令箭
RemoteDirectoryInfoResult rootDirectoryInfoResult = client.GetDirectoryInfo(dirPath,new Metadata(),5000,new CancellationToken());

其余操作基本一致。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/remotemonitoring/index.html b/handbook/build/docs/remotemonitoring/index.html new file mode 100644 index 000000000..cec55642c --- /dev/null +++ b/handbook/build/docs/remotemonitoring/index.html @@ -0,0 +1,21 @@ + + + + + +远程监测、控制项目 | TouchSocket + + + + +
+

远程监测、控制项目

定制方

网友

说明

应该网友要求,基本完成了预定的所有功能,包括远程更新、远程屏幕监测、屏幕操作、远程文件资源管理器、远程控制台、远程注册表操作、远程文件操作(删除、复制、重命名、压缩)、等等。

技术点

  • 整体界面:应定制方要求,界面使用原始控件。
  • 各种远程操作:均采用的是RRQM通信框架。

效果

【客户端——被控制端】

客户端是个winform的无界面程序。

image.png

【服务器——管理端】 +1.gif +2.gif +3.gif +4.gif +5.gif

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/remotestreamaccess/index.html b/handbook/build/docs/remotestreamaccess/index.html new file mode 100644 index 000000000..fc0f64f88 --- /dev/null +++ b/handbook/build/docs/remotestreamaccess/index.html @@ -0,0 +1,20 @@ + + + + + +b.远程流访问 | TouchSocket + + + + +
+

b.远程流访问

一、说明

可以在通信对方,创建一个Stream,然后映射到本地,由本地直接进行读、写等操作。

二、场景

当远程主机拥有一个超大流数据(可能是文件,或者其他)时,本地只想访问其部分数据的话,就可以使用该功能。 +例如,假设C服务器有个10Gb的文件。A客户端需要其10000-20000字节之间的数据,那你此时可以使用该功能,直接进行读取。

三、代码示例

下列以客户端作为请求端,以服务器作为响应端。实际上服务器也可以做请求端。

【请求端】 +任意TouchRpc终端(除udp协议)均可以调用LoadRemoteStream创建一个流数据映射。 +同时可以传递一个元数据组。用于载入自定义消息。

RemoteStream remoteStream = client.LoadRemoteStream(new Metadata().AddOrUpdate("1", "1"));

【响应端】 +响应端定义一个插件,重写OnLoadingStream,然后实现需要载入的具体流信息。示例中是以MemoryStream作为流主体。

class MyTcpTouchRpcPlugin : TouchRpcPluginBase
{
protected override void OnLoadingStream(ITouchRpc client, LoadingStreamEventArgs e)
{
if (e.Metadata["1"]=="1")
{
e.Stream = new MemoryStream();
}
base.OnLoadingStream(client, e);
}
}

四、读写

当RemoteStream被成功创建以后,即可直接Read、Write。因为RemoteStream继承自Stream。

var client = GetClient();
RemoteStream remoteStream = client.LoadRemoteStream(new Metadata().AddOrUpdate("1", "1"));

byte[] data = new byte[] { 0, 1, 2, 3, 4 };
remoteStream.Write(data);
Assert.True(remoteStream.Length==5);
Assert.True(remoteStream.Position==5);

remoteStream.Position = 0;
byte[] buffer=new byte[5];
remoteStream.Read(buffer);
Assert.True(buffer.SequenceEqual(data));
Assert.True(remoteStream.Position == 5);
Assert.True(remoteStream.Length == 5);

remoteStream.SafeDispose();

五、释放

断开连接,或者请求方主动调用Dispose时,响应方的Stream均会被实际的Dispose掉。

六、性能

图中示例为直接读取一个Window.iso文件所示。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/resetid/index.html b/handbook/build/docs/resetid/index.html new file mode 100644 index 000000000..c2a9907ca --- /dev/null +++ b/handbook/build/docs/resetid/index.html @@ -0,0 +1,16 @@ + + + + + +服务器重置ID | TouchSocket + + + + +
+

服务器重置ID

一、说明

每个客户端在连接时,服务器都会为连接的客户端新分配一个唯一的ID。也就是说,在服务器中ID与SocketClient实例就是一一对应的。

二、配置初始ID策略

默认情况下服务器都会根据历史连接数量,为连接的客户端新分配ID。也就是说,第一个连接的,其ID就是1,以此类推。

当然我们可以自由的定义ID策略,只需要在Config配置中,配置SetGetDefaultNewID,自定义新ID来源即可。要求不和现连接的客户端ID重复。

下列示例,就是使用Guid作为初始ID。

.SetGetDefaultNewID(()=> { return new Guid().ToString(); })

三、创建能代表连接的ID

上述这种ID规范,是与连接信息没有任何关联的,这也就意味着,这种方式是无法关联SocketClient的。

但往往,有时候,我们希望,SocketClient的ID,能一定程度的代表一些信息。例如:以客户端的IP和端口,作为唯一ID。

那这时候,服务器可以订阅Connecting,然后,为新连接的SocketClient,设置与之有关联信息的ID。

m_service.Connecting = (client, e) => 
{
e.ID = $"{client.IP}:{client.Port}";
};//有客户端正在连接
提示

上述行为通过插件实现可能更加优雅。

四、即时修改ID

上述修改ID的方式,应该还不足以应对所有情况。有时候我们希望,在该连接完成,且经过某种验证之后再设置新的ID,那么我们可以通过ResetID的方法,来实现需求。

4.1 通过Service直接修改

service.ResetID("oldId","newId");

4.2 通过SocketClient修改

socketClient.ResetID("newId");
备注

上述的ID标识,仅仅是服务器(TcpService)和辅助客户端(SocketClient)之间的关联。与客户端(TcpClient)是没有任何关系的。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/rpcactionfilter/index.html b/handbook/build/docs/rpcactionfilter/index.html new file mode 100644 index 000000000..a3ffc87d7 --- /dev/null +++ b/handbook/build/docs/rpcactionfilter/index.html @@ -0,0 +1,16 @@ + + + + + +Rpc服务AOP | TouchSocket + + + + +
+

Rpc服务AOP

一、说明

RPC服务在被调用是,可以使用实现IRpcActionFilter特性(Attribute),进行相关AOP操作。

二、声明特性

public class MyRpcActionFilterAttribute : RpcActionFilterAttribute
{
public override void Executing(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult)
{
//invokeResult = new InvokeResult()
//{
// Status = InvokeStatus.UnEnable,
// Message = "不允许执行",
// Result = default
//};
if (callContext.Caller is TcpTouchRpcSocketClient client)
{
client.Logger.Info($"即将执行RPC-{callContext.MethodInstance.Name}");
}
base.Executing(callContext, parameters, ref invokeResult);
}

public override void Executed(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult)
{
if (callContext.Caller is TcpTouchRpcSocketClient client)
{
client.Logger.Info($"执行RPC-{callContext.MethodInstance.Name}完成,状态={invokeResult.Status}");
}
base.Executed(callContext, parameters, ref invokeResult);
}

public override void ExecutException(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception)
{
if (callContext.Caller is TcpTouchRpcSocketClient client)
{
client.Logger.Info($"执行RPC-{callContext.MethodInstance.Name}异常,信息={invokeResult.Message}");
}

base.ExecutException(callContext, parameters, ref invokeResult, exception);
}
}
提示

每个方法都有详细的注释,仔细查看可能会事半功倍。

三、使用

 [Description("性能测试")]
[TouchRpc]
[MyRpcActionFilter]
public int Performance(int a)
{
return a;
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/rpcallcontext/index.html b/handbook/build/docs/rpcallcontext/index.html new file mode 100644 index 000000000..3b0b32040 --- /dev/null +++ b/handbook/build/docs/rpcallcontext/index.html @@ -0,0 +1,16 @@ + + + + + +调用上下文 | TouchSocket + + + + +
+

调用上下文

一、说明

RPC服务是无状态的,即只知道当前服务被调用,但无法得知是被谁调用,这个问题给日志记录、RPC回调等带来了很多麻烦事。但是,Touch的Rpc支持调用上下文获取。在上下文中可以获得调用者(ICaller)信息等。

二、通过标签参数获取

步骤:

  1. Rpc标签需要传入MethodFlags.IncludeCallContext参数。
  2. 定义的服务的第一个参数必须是ICallContext或其派生类。
  3. 最后获得其Caller属性即可得到调用者。
public class MyRpcServer : RpcServer
{
[Description("登录")]
[TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]//使用调用上才文
public bool Login(ICallContext callContext,string account,string password)
{
if (callContext.Caller is TcpTouchRpcSocketClient)
{
Console.WriteLine("TcpTouchRpc请求");
}
if (account=="123"&&password=="abc")
{
return true;
}

return false;
}
}

三、通过瞬时生命周期获取

步骤:

  1. 继承TransientRpcServer或者实现ITransientRpcServer接口。
public class MyRpcServer : TransientRpcServer
{
[Description("登录")]
[TouchRpc]
public bool Login(string account,string password)
{
if ( this.CallContext.Caller is TcpTouchRpcSocketClient)
{
Console.WriteLine("TcpTouchRpc请求");
}
if (account=="123"&&password=="abc")
{
return true;
}

return false;
}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/rpcoption/index.html b/handbook/build/docs/rpcoption/index.html new file mode 100644 index 000000000..61aacd2d7 --- /dev/null +++ b/handbook/build/docs/rpcoption/index.html @@ -0,0 +1,16 @@ + + + + + +调用配置 | TouchSocket + + + + +
+

调用配置

一、调用反馈类型

RPC在调用时,的调用状态有三种状态可选,分别为:OnlySendWaitSendWaitInvoke。区别是:

OnlySendWaitSendWaitInvoke
仅发送RPC请求,在TCP底层协议下,能保证发送成功,但是不反馈服务器任何状态,也不会取得返回值异常等信息。在UDP底层协议下,不保证发送成功,仅仅是具有请求动作而已。发送RPC请求,并且等待收到状态返回,能保证RPC请求顺利到达服务,但是不能得知RPC服务是否成功执行,也不会取得返回值异常等信息发送RPC请求,且返回所有信息,包括是否成功调用,执行后的返回值异常等信息。

1.1 使用

同样的,在InvokeOption中可以直接赋值使用。

InvokeOption invokeOption = new InvokeOption();
invokeOption.FeedbackType = FeedbackType.WaitInvoke;
//invokeOption.FeedbackType = FeedbackType.OnlySend;
//invokeOption.FeedbackType = FeedbackType.WaitSend;
string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

注意:假如IInvokeOption使用的是InvokeOption的话,在new的时候,应该对其他参数也进行设置(因为它是结构体)。

二、调用超时设置

调用RPC,不能无限制等待,必须要有计时器,或者任务取消的功能。

2.1 计时器设置

直接对InvokeOptionTimeout 属性赋值即可,单位为毫秒

InvokeOption invokeOption = new InvokeOption();
invokeOption.Timeout = 1000 * 10;//10秒后无反应,则抛出RRQMTimeoutException异常
string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

2.2 任务取消

在RPC调用时,计时器是一个好的选择,但是还不够完美,有时候我们希望能手动终结某个调用任务。这时候,计时器就不堪重任,需要能主动取消任务的功能。熟悉.net的小伙伴都知道,CancellationToken是具备这个功能的。同样的,只需要对InvokeOptionCancellationToken 赋值即可。

InvokeOption invokeOption = new InvokeOption();
CancellationTokenSource tokenSource = new CancellationTokenSource();
invokeOption.CancellationToken = tokenSource.Token;
//tokenSource.Cancel();//调用时取消任务
string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

2.3 服务任务取消

实际上7.2的取消任务,仅仅能实现让客户端取消请求,但是服务器并不知道,如果想让服务器也感知任务消息,就必须依托于调用上下文。

此处的取消,有可能是调用者主动取消。也有可能是调用者已经掉线。

public class ElapsedTimeRpcServer : ServerProvider
{
[Description("测试可取消的调用")]
[RRQMRPC(MethodFlags.IncludeCallContext)]
public bool DelayInvoke(ICallContext serverCallContext,int tick)//同步服务
{
for (int i = 0; i < tick; i++)
{
Thread.Sleep(100);
if (serverCallContext.TokenSource.IsCancellationRequested)
{
Console.WriteLine("客户端已经取消该任务!");
return false;//实际上在取消时,客户端得不到该值
}
}
return true;
}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/rpcstream/index.html b/handbook/build/docs/rpcstream/index.html new file mode 100644 index 000000000..f03e8fd21 --- /dev/null +++ b/handbook/build/docs/rpcstream/index.html @@ -0,0 +1,16 @@ + + + + + +Rpc大数据流式传输 | TouchSocket + + + + +
+

Rpc大数据流式传输

一、说明

在RPC中,并没有对传输的数据做限制,但是因为RPC默认使用的固定包头适配器中,默认设置的可传递数据为10Mb,所以在RPC中,用户可一次性传递的数据包大约为9.9Mb。所以,如果用户传递超出阈值的数据,适配器则会触发异常,而无法接收。但在实际上RPC的使用中,大数据的传输也是很重要的一个环节,所以RRQM已经做了大数据的传输思路建议,希望能有效解决大家的麻烦。

二、设置适配器参数(推荐指数:⭐)

操作原理:在固定包头适配器中,默认限制了单次可发送数据包的最大值,所以可以修改此值实现目的。

该方法简单粗暴,能够解决一定程度的大数据问题,但并不建议这么做。

注意:客户端必须同样设置。

TouchSocketConfig config = new TouchSocketConfig()//配置
.SetMaxPackageSize(1024 * 1024 * 10)

三、RPC嵌套Channel(推荐指数:⭐⭐⭐⭐⭐)

操作原理:先利用RPC让客户端与服务器约定特定的Channel,然后后续数据通过Channel传递,最后由RPC返回结果。

3.1 请求流数据

【Service端】

/// <summary>
/// "测试ServiceToClient创建通道,从而实现流数据的传输"
/// </summary>
/// <param name="callContext"></param>
/// <param name="channelID"></param>
[Description("测试ServiceToClient创建通道,从而实现流数据的传输")]
[TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]
public int RpcPullChannel(ICallContext callContext, int channelID)
{
int size = 0;
int package = 1024 * 1024;
if (callContext.Caller is TcpTouchRpcSocketClient socketClient)
{
if (socketClient.TrySubscribeChannel(channelID, out Channel channel))
{
for (int i = 0; i < 1024; i++)
{
size += package;
channel.Write(new byte[package]);
}
channel.Complete();//必须调用指令函数,如Complete,Cancel,Dispose
}
}
return size;
}

【Client端】

ChannelStatus status = ChannelStatus.Default;
int size = 0;
Channel channel = client.CreateChannel();//创建通道
Task task = Task.Run(() =>//这里必须用异步
{
using (channel)
{
while (channel.MoveNext())
{
byte[] data = channel.GetCurrent();
size += data.Length;
}
status = channel.Status;
}
});
int result = client.RpcPullChannel(channel.ID);//RpcPullChannel是代理方法,此处会阻塞至服务器全部发送完成。
await task;//等待异步接收完成
Console.WriteLine($"状态:{status},size={size}");

3.2 推送流数据

【Service端】

/// <summary>
/// "测试推送"
/// </summary>
/// <param name="callContext"></param>
/// <param name="channelID"></param>
[Description("测试ServiceToClient创建通道,从而实现流数据的传输")]
[TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]
public int RpcPushChannel(ICallContext callContext, int channelID)
{
int size = 0;

if (callContext.Caller is TcpTouchRpcSocketClient socketClient)
{
if (socketClient.TrySubscribeChannel(channelID, out Channel channel))
{
while (channel.MoveNext())
{
size += channel.GetCurrent().Length;
}
}
}
return size;
}

【Client端】

ChannelStatus status = ChannelStatus.Default;
int size = 0;
int package = 1024 * 1024;
Channel channel = client.CreateChannel();//创建通道
Task task = Task.Run(() =>//这里必须用异步
{
for (int i = 0; i < 1024; i++)
{
size += package;
channel.Write(new byte[package]);
}
channel.Complete();//必须调用指令函数,如Complete,Cancel,Dispose
});
int result = client.RpcPushChannel(channel.ID);//RpcPushChannel是代理方法,此处会阻塞至服务器全部完成。
await task;//等待异步接收完成
Console.WriteLine($"状态:{status},result={result}");
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/serializationselector/index.html b/handbook/build/docs/serializationselector/index.html new file mode 100644 index 000000000..5f25d23fc --- /dev/null +++ b/handbook/build/docs/serializationselector/index.html @@ -0,0 +1,17 @@ + + + + + +序列化选择器 | TouchSocket + + + + +
+

序列化选择器

一、说明

从下图(图片来源网络)可以看出,序列化是RPC中至关重要的一个环节,可以说,序列化的优劣,会很大程度的影响RPC调用性能。

二、支持的序列化

在TouchRpc中,内置了四种序列化方式,分别为FastBinaryJsonXmlSystemBinary。这四种方式的特点,就是其序列化的特点。

FastBinaryJsonXmlSystemBinary
特点序列化方式速度快,数据量小,但是兼容的数据格式也比较有限。仅支持基础类型、自定义实体类、数组、List、字典兼容性好,可读性强,但是受字符串影响,性能不出众,且数据量受限制兼容性一般,可读性强,同样受字符串影响,性能不出众,且数据量受限制序列化速度快。但是兼容性低。且要求类必须一致,不然需要重新指定图根。

三、使用预设序列化

在TouchRpc中,选择序列化是非常简单的,且序列化方式完全由调用端决定。 +在实际的调用中,通过InvokeOption的参数指定。

实际上,只需要传入相关参数即可。

InvokeOption invokeOption = new InvokeOption() //InvokeOption是结构体,所以成员必须全部初始化。
{
FeedbackType = FeedbackType.WaitInvoke,
Timeout = 1000 * 10
};
;
invokeOption.SerializationType = SerializationType.FastBinary;
//invokeOption.SerializationType = Serialization.SerializationType.Json;
//invokeOption.SerializationType = Serialization.SerializationType.Xml;
string returnString = client.Invoke<string>("TestOne", invokeOption, "10");

四、自定义序列化

4.1 定义自定义序列化器

想要实现自定义序列化,必须通过重写序列化选择器,实现SerializeParameterDeserializeParameter函数。

下列代码将以MemoryPack序列化作为示例,并且保留了预设序列化。

public class MemoryPackSerializationSelector:DefaultSerializationSelector
{
public override byte[] SerializeParameter(SerializationType serializationType, object parameter)
{
if ((byte)serializationType == 4)
{
return MemoryPackSerializer.Serialize(parameter.GetType(),parameter);
}
return base.SerializeParameter(serializationType, parameter);
}

public override object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType)
{
if ((byte)serializationType == 4)
{
if (parameterBytes==null)
{
return default;
}
return MemoryPackSerializer.Deserialize(parameterType,parameterBytes);
}
return base.DeserializeParameter(serializationType, parameterBytes, parameterType);
}
}

4.2 使用

必须在服务器客户端Config配置中设置解析器。

var config = new TouchSocketConfig()//配置
.SetSerializationSelector(new MemoryPackSerializationSelector());

然后,因为赋值时是SerializationType的枚举类型,所以执行强制类型转换即可。

InvokeOption invokeOption = new InvokeOption()
{
FeedbackType = FeedbackType.WaitInvoke,
SerializationType = (SerializationType)4,
Timeout = 1000 * 10
};

var msg = client.Login(new LoginModel() { Account = "Account", Password = "Password" }, invokeOption);
提示

因为使用的是MemoryPack序列化,所以最好将Rpc的所有参数声明在单独的程序集中。这样客户端与服务器项目都可以直接引用。

序列化选择器示例代码

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/smallfiletransfer/index.html b/handbook/build/docs/smallfiletransfer/index.html new file mode 100644 index 000000000..7cff5d27b --- /dev/null +++ b/handbook/build/docs/smallfiletransfer/index.html @@ -0,0 +1,17 @@ + + + + + +小文件传输 | TouchSocket + + + + +
+

小文件传输

一、说明

小文件传输是指,当传输文件小于设定大小(默认1024*1024字节)时的传输。

为什么要设立小文件传输?与常规文件传输相比,优点在哪里? +常规传输,建立一个传输通道,大约需要传输两端,往返通信4-6次。这在本地局域网中,显得无所谓。但是在互联网环境中,一次ping延迟平均50ms,那么建立一个传输,就大约需要200-300ms。这也就意味着,即使一个文件只有一字节,也需要这些时间。所以,这明显是不合理的。所以TouchRpc又新增了小文件传输,只要文件在1Mb以内,仅往返1次,就可以完成传输。

当然,对于小文件的最高效传输方式依然是先压缩,后传输的方式。

二、使用

【拉取文件】

  1. 直接调用PullSmallFile或者PullSmallFileAsync,获取到实际的文件数据。
  2. 通过Save方法,将数据写入文件。也可以自行保存。
var result = await this.fileClient.PullSmallFileAsync(path);//拉取文件
var saveResult = result.Save(savePath);//将拉取的数据进行保存。

【推送文件】

  1. 直接调用PushSmallFile或者PushSmallFileAsync。
  2. 返回值即表示是否成功。
var result = await this.fileClient.PushSmallFileAsync(savePath, fileInfo);
if (result.IsSuccess())
{
}

其他可选参数可以自己定义。

三、客户端之间传输

该功能也支持客户端之间互相传输。使用方法基本一致,需要额外指定目标Id即可。

此外,服务器也需要同意路由

internal class MyTouchRpcPlugin : TouchRpcPluginBase
{
protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)
{
if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile)
{
e.IsPermitOperation = true;
}
base.OnRouting(client, e);
}
}

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/startguide/index.html b/handbook/build/docs/startguide/index.html new file mode 100644 index 000000000..01ace3e2d --- /dev/null +++ b/handbook/build/docs/startguide/index.html @@ -0,0 +1,16 @@ + + + + + +入门指南 | TouchSocket + + + + +
+

入门指南

一、说明

TouchSocket(Pro)是基于.Net发布的程序集,所以它可以被用于对应.Net版本的C#、F#、VB.net等语言项目。它不区分您的项目是控制台、Winform、Wpf、或者是Aspnetcore,它统统都支持。

下面我们将以最简单的C# 控制台程序作为入门,让您最直观的感受ToucSocket的强大。

二、创建项目

由于TouchSocket(Pro)是基于net45、netstandard2.0、netcoreapp3.1三个平台作为常期支持平台,net7.0作为最新发布平台的程序,所以您可以用vs2010及以上的任意版本创建项目。

下面我们将以vs2022作为示例:

说明

如果您选择vs code等其他的编译工具,那么我相信您已不是新手。那么您只需要安装TouchSocket(Pro)的最新nuget包即可。

2.1 创建新项目

2.2 选择项目类型

2.3 配置项目名称和路径

2.4 选择Net版本

三、安装

3.1 Nuget安装

右击项目=》点击“管理Nuget程序包”。

点击“浏览”,然后在搜索框输入TouchSocket,然后在搜索结果中选择。最后点击安装。

3.2 PackageReference

单击项目,打开项目编辑,然后在空白根内部引用。

<ItemGroup>
<PackageReference Include="TouchSocket" Version="1.2.3"/>
</ItemGroup>
提示

Version="1.2.3"可能不是最新的版本,请前往Nuget官网查看。

3.3 Dll直接引用

Nuget官网中,选择需要的,然后选择“Download package”,即可下载一个后缀为.nupkg文件。

提示

如果下载速度较慢,可以考虑使用迅雷等工具加速。

将下载的后缀为.nupkg的文件,通过压缩工具解压。得到如下目录结构。

然后进入“lib”的文件夹。选择对应平台。

提示

一般来说,所有基于.NET Framework的项目,都最好引用net45的库。然后其他版本的,选择最近的,较低的库即可。在本示例中,选择netcoreapp3.1的库。

把下列文件引用到项目即可。

四、结束

恭喜你,到这里,你就完成了入门的教学,你可能会好奇,做了这么多,还是什么都没有做啊。这是因为TouchSocket并不是一个单功能的,而是一个多功能程序库。所以,你必须在其他模块中查看你所需要的内容。

祝你好运!!!

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/stategridtransmission/index.html b/handbook/build/docs/stategridtransmission/index.html new file mode 100644 index 000000000..de31a4e58 --- /dev/null +++ b/handbook/build/docs/stategridtransmission/index.html @@ -0,0 +1,18 @@ + + + + + +国网输电i1标准版 | TouchSocket + + + + +
+

国网输电i1标准版

说明

本代码仅适用以下协议。 +协议中,由Packet_Length表示序号7-11的长度。也就是Packet_Length=N+2+2+1+1。 +但是在设计时,会将序号1-10,视为固定包头。序号11-13为Body。

版权

该代码所有版权归若汝棋茗所有,使用时请务必注明。

协议类型

代码

using TouchSocket.Core;
using TouchSocket.Sockets;

namespace AdapterConsoleApp
{
/// <summary>
/// 国网输电i1标准版
/// </summary>
internal class SGCCCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<SGCCRequestInfo>
{
public override int HeaderLength => 30;

public override bool CanSendRequestInfo => false;

protected override SGCCRequestInfo GetInstance()
{
return new SGCCRequestInfo();
}

protected override void PreviewSend(IRequestInfo requestInfo)
{
throw new System.NotImplementedException();
}
}

public class SGCCRequestInfo : IFixedHeaderRequestInfo
{
private byte[] m_sync;
private int m_bodyLength;
private byte[] m_cMDID;
private byte[] m_sample;
private byte[] m_cRC16;

public int BodyLength { get => m_bodyLength; }

/// <summary>
/// 报文头:5AA5
/// </summary>
public byte[] Sync { get => m_sync; set => m_sync = value; }

/// <summary>
/// 报文长度
/// </summary>
public ushort PacketLength { get => (ushort)(this.m_bodyLength - 3); }

/// <summary>
/// 状态监测装置ID(17位编码)
/// </summary>
public byte[] CMDID { get => m_cMDID; set => m_cMDID = value; }

/// <summary>
/// 帧类型—参考附表C8-1相关含义
/// </summary>
public byte FrameType { get; set; }

/// <summary>
/// 报文类型—参考附表C8-2相关含义
/// </summary>
public byte PacketType { get; set; }

/// <summary>
/// 帧序列号(无符号整数)
/// </summary>
public byte FrameNo { get; set; }

/// <summary>
/// 通道号—表示采集装置上的摄像机编号。如:一个装连接⒉部摄像机,则分别标号为1、2
/// </summary>
public byte ChannelNo { get; set; }

/// <summary>
/// 预置位号—即云台摄像所设置的预置位号,不带云台摄像机,预置位号为255
/// </summary>
public byte PresettingNo { get; set; }

/// <summary>
/// 总包数(无符号整数,取值范围:大于等于0)
/// </summary>
public ushort PacketNo { get; set; }

/// <summary>
/// 子包包号(无符号整数,取值范围:大于等于0>
/// </summary>
public ushort SubpacketNo { get; set; }

/// <summary>
/// 数据区
/// </summary>
public byte[] Sample { get => m_sample; set => m_sample = value; }

/// <summary>
/// 校验位
/// </summary>
public byte[] CRC16 { get => m_cRC16; }

/// <summary>
/// 报文尾:0x96
/// </summary>
public byte End { get; set; }

public bool OnParsingHeader(byte[] header)
{
if (header.Length == 30)
{
using (ByteBlock byteBlock = new ByteBlock(header))
{
byteBlock.Pos = 0;
byteBlock.Read(out m_sync, 2);

byte[] lenBuffer;
byteBlock.Read(out lenBuffer, 2);

this.m_bodyLength = TouchSocketBitConverter.LittleEndian.ToUInt16(lenBuffer, 0) + 3 - 6;//先把crc校验和end都获取。
byteBlock.Read(out m_cMDID, 17);
this.FrameType = (byte)byteBlock.ReadByte();
this.PacketType = (byte)byteBlock.ReadByte();
this.FrameNo = (byte)byteBlock.ReadByte();
this.ChannelNo = (byte)byteBlock.ReadByte();
this.PresettingNo = (byte)byteBlock.ReadByte();
this.PacketNo = byteBlock.ReadUInt16();
this.SubpacketNo = byteBlock.ReadUInt16();

return true;
}
}
return false;
}

public bool OnParsingBody(byte[] body)
{
if (body.Length == this.BodyLength && body[^1] == 150)
{
using (ByteBlock byteBlock = new ByteBlock(body))
{
byteBlock.Read(out this.m_sample, this.m_bodyLength - 3);
byteBlock.Read(out this.m_cRC16, 2);
this.End = (byte)byteBlock.ReadByte();
}
return true;
}
return false;
}
}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/streamtransfer/index.html b/handbook/build/docs/streamtransfer/index.html new file mode 100644 index 000000000..77ddd8c74 --- /dev/null +++ b/handbook/build/docs/streamtransfer/index.html @@ -0,0 +1,16 @@ + + + + + +Stream传输 | TouchSocket + + + + +
+

Stream传输

一、说明

Stream的直接发送,单个TCP连接上可以同时进行多个传输。客户端与服务器之间可以任意相互发送。

二、特性

  1. 实时检测速度,进度等信息。
  2. 从Stream.Position开始,直到Read结束。

三、示例

下列以服务器作为Stream的接收方。客户端为发送方。

【服务器】

TcpTouceRpcService service = CreateTcpTouceRpcService();

service.StreamTransfering += (socketClient, e) =>
{
e.Bucket = new MemoryStream();//此处用MemoryStream作为接收容器,也可以使用FileStream。
e.AddOperation(Operation.Permit);//允许接收该流
Metadata metadata = e.Metadata;//获取元数据
StreamOperator streamOperator = e.StreamOperator;//获取操作器,可用于取消任务,获取进度等。

//Console.WriteLine("设置最大传输速度为1024byte");
//streamOperator.SetMaxSpeed(1024);

//Console.WriteLine("5秒后设置为5Mb");
//RRQMCore.Run.EasyAction.DelayRun(5, () =>
//{
// streamOperator.SetMaxSpeed(1024 * 1024 * 5);
//});

Task.Run(async () =>
{
while (streamOperator.Result.ResultCode == ResultCode.Default)
{
Console.WriteLine($"速度={streamOperator.Speed()},进度={streamOperator.Progress}");

await Task.Delay(1000);
}

Console.WriteLine($"从循环传输结束,状态={streamOperator.Result}");
});
Console.WriteLine("开始接收流数据");
};

service.StreamTransfered += (socketClient, e) =>
{
//此处不管传输成功与否,都会执行,具体状态通过e.Status判断。
if (e.Result.ResultCode == ResultCode.Success)
{

}
e.Bucket.Dispose();//必须手动释放流数据。
Console.WriteLine($"从ReceivedStream传输结束,状态={e.Result}");
};

【客户端】

TcpTouchRpcClient client = CreateTcpTouchRpcClient();

byte[] data = new byte[1024 * 1024 * 50];
new Random().NextBytes(data);
MemoryStream stream = new MemoryStream(data);
stream.Position = 0;

Console.WriteLine($"即将发送流数据,长度为:{stream.Length}");

StreamOperator streamOperator = new StreamOperator();
streamOperator.PackageSize = 1024 * 64;//分包长度
//streamOperator.SetMaxSpeed(1024 * 1024 * 5);//最大传输值

//streamOperator.Cancel();//随时取消传输

LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (a) =>
{
if (streamOperator.Result.ResultCode != ResultCode.Default)
{
a.Dispose();
}
Console.WriteLine($"速度:{streamOperator.Speed()},进度:{streamOperator.Progress}");
});
loopAction.RunAsync();

Metadata metadata = new Metadata();//将键值对的元数据传到接收端
metadata.Add("1", "1");
metadata.Add("2", "2");

//该方法会阻塞,直到结束
Result result = client.SendStream(stream, streamOperator, metadata);
Console.WriteLine(result);

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/tcpcommandlineplugin/index.html b/handbook/build/docs/tcpcommandlineplugin/index.html new file mode 100644 index 000000000..13eaf7b14 --- /dev/null +++ b/handbook/build/docs/tcpcommandlineplugin/index.html @@ -0,0 +1,16 @@ + + + + + +命令行执行插件 | TouchSocket + + + + +
+

命令行执行插件

一、说明

TcpCommandLinePlugin命令行执行插件,是用于TCP的快捷事务实现。该类是抽象类,必须通过继承,在继承类中,声明的具的公共的且名称以Command结尾的方法,均可被快捷执行。

二、创建快捷执行插件

/// <summary>
/// 命令执行插件。方法必须以Command结尾。
/// </summary>
class MyCommandLinePlugin : TcpCommandLinePlugin
{
private readonly ILog logger;

public MyCommandLinePlugin(ILog logger) : base(logger)
{
this.ReturnException = true;//表示执行异常的时候,是否返回异常信息
this.logger = logger;
}

/// <summary>
/// 加法
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public int AddCommand(int a, int b)
{
this.logger.Info($"执行{nameof(AddCommand)}");
return a + b;
}

/// <summary>
/// 乘法,并且获取调用者信息
/// </summary>
/// <param name=""></param>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public int MULCommand(ISocketClient socketClient,int a, int b)
{
this.logger.Info($"{socketClient.IP}:{socketClient.Port}执行{nameof(MULCommand)}");
return a * b;
}

/// <summary>
/// 测试异常
/// </summary>
/// <exception cref="Exception"></exception>
public void ExcCommand()
{
throw new Exception("我异常了");
}
}

三、创建服务器

TcpService service = new TcpService();

var config = new TouchSocketConfig();
config.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) }) //同时监听两个地址
.SetDataHandlingAdapter(() =>
{
//return new TerminatorPackageAdapter(1024, "\r\n");//命令行中使用\r\n结尾
return new NormalDataHandlingAdapter();//亦或者省略\r\n,但此时调用方不能高速调用,会粘包
})
.UsePlugin()
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
})
.ConfigurePlugins(a =>
{
a.Add<MyCommandLinePlugin>();
});

//载入配置
service.Setup(config);

//启动
service.Start();

service.Logger.Info("服务器成功启动。");
service.Logger.Info("使用:“Add 10 20”测试");
service.Logger.Info("使用:“MUL 10 20”测试");
service.Logger.Info("使用:“Exc”测试异常");

四、调用

上述快捷执行插件,即可被普通tcp客户端,或cmd/telnet等便捷调用。

调用数据格式:

Add 10 20 /r/n /r/n非必须,但是当适配器选为终止字符分割适配器时,则必须。不然,则不可连续调用,会粘包。

提示

调用的参数也支持自定义实体类,届时蚕食使用Json数据格式即可。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/tcpother/index.html b/handbook/build/docs/tcpother/index.html new file mode 100644 index 000000000..4e3efc30e --- /dev/null +++ b/handbook/build/docs/tcpother/index.html @@ -0,0 +1,16 @@ + + + + + +其他场景应用 | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/terminatorpackageadapter/index.html b/handbook/build/docs/terminatorpackageadapter/index.html new file mode 100644 index 000000000..8258f59fe --- /dev/null +++ b/handbook/build/docs/terminatorpackageadapter/index.html @@ -0,0 +1,16 @@ + + + + + +终止因子分割数据处理适配器 | TouchSocket + + + + +
+

终止因子分割数据处理适配器

一、说明

终止因子数据处理适配器是通过特殊字符或数值的方式,来达到处理粘包、分包的目的。可随意设置分割因子的值,以及编码方式。不仅如此,还有异常数据设置,在达到设定值时,如果还没有发现分割因子,则抛弃数据。其稳定性仅次于固定包头,且使用场景也比较广泛。

二、特点

  1. 最适用于字符串类(Json,Xml等)的信息交互。
  2. 算法简单,非常容易实现跨语言、跨框架。
  3. 发送普通流数据时,有很小的概率发生提前终止的情况(可设置复杂终止因子来解决)。

三、使用

客户端与服务器均适用。下列以服务器为例。

步骤

  1. TouchSocketConfig配置中设置,同时指定数据的长度。
  2. 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。
TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost(7790) })
.SetDataHandlingAdapter(()=> { return new TerminatorPackageAdapter("\r\n"); }))//配置终止字符适配器,以\r\n结尾。
.Start();//启动
提示

默认情况下终止因子不会保留在数据中,用户可通过ReserveTerminatorCode属性,设为true,来保留终止因子。

注意

接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。

提示

该适配器,客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/tlvdatahandlingadapter/index.html b/handbook/build/docs/tlvdatahandlingadapter/index.html new file mode 100644 index 000000000..30bd30553 --- /dev/null +++ b/handbook/build/docs/tlvdatahandlingadapter/index.html @@ -0,0 +1,20 @@ + + + + + +三元组编码(TLV)适配器 | TouchSocket + + + + +
+

三元组编码(TLV)适配器

一、说明

TLV适配器,定义了一种简单高效的三元组编码,简称TLV编码。它是由数据的类型Tag(T),数据的长度Length(L),数据的值Value(V)构成的一组数据报文。TLV是基于二进制编码的,将数据以(T -L- V)的形式编码为字节数组,即TLV是字节流的数据传输协议。它规定了一帧数据的首个字节或几个字节来表示数据类型,紧接着一个或几个字节表示数据长度,最后是数据的内容。

数据协议如下:

Tag

  • 标识数据的类型。
  • 占2字节
  • 大端序无符号整型。
  • 0-9保留系统使用。[10,65535]客户端自行定义。
  • 已用Tag:0表示Close,载荷Value为关闭消息。
  • 已用Tag:1表示Ping,无载荷,对方收到后必须无条件返回Pong。
  • 已用Tag:2表示Pong,无载荷。

Length

  • 标识后续Value的长度。
  • 按LengtType的指定,可以用1字节、2字节、4字节来表示长度,分别对应255、65535、2147483647字节的对应值。
  • 1字节时,不区分端序。
  • 2字节时,大端序无符号整型。
  • 4字节时,大端序有符号整型。
  • 默认使用2字节的Ushort类型。

Value

载荷数据。可以为任意类型。

二、使用

【适配器使用】 +设置的FixedHeaderType类型后,实际的支持最大数据还受SetMaxPackageSize影响。默认为1024102410字节。

.SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//如果使用TLVPlugin插件,此步骤可省略。

【插件】

只需要添加TLVPlugin插件即可。客户端亦然。

使用插件,相当于自动设置适配器,并且主动回应Ping。

var config = new TouchSocketConfig();

config.UsePlugin()
.SetMaxPackageSize(1024 * 1024 * 10)
//.SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//如果使用TLVPlugin插件,此步骤可省略。
.ConfigurePlugins(a =>
{
a.Add<TLVPlugin>()//使用插件,相当于自动设置适配器,并且主动回应Ping。
.SetLengthType(FixedHeaderType.Int);//设置支持的最大数据类型,该值还受SetMaxPackageSize影响。
});

三、保活机制

  • TLV数据协议中,定义了Tag=1时为ping,Tag=2时为Pong。所以可以依靠这套机制,进行保活。
  • 实际上,在插件中,已经做了Ping,Pong的处理。客户端可以直接调用。
  • 该操作,服务器也可以直接ping客户端。
bool result=this.m_client.Ping();//返回值为true时,对端一定在线。此方法服务器也可以主动ping客户端。

自动ping

利用PollingKeepAlivePlugin插件自动Ping。

四、构建数据

如果对方是其他语言,请使用约定的方式发送数据。 +如果是CSharp的话,构建数据非常简单。 +构建数据时,可用TLVDataFrame构建。或者其值类型构建,此处推荐ValueTLVDataFrame +【直接构造】

ValueTLVDataFrame requestInfo = new ValueTLVDataFrame(10, new byte[] { 0, 1, 2, 3 });

【追加型构建】

 ValueTLVDataFrame requestInfo = new ValueTLVDataFrame();
requestInfo.AppendValue(new byte[] { 0, 1, 2, 3 });
requestInfo.AppendValue(new byte[] { 4, 5, 6, 7 });

五、发送数据

构建完数据后,直接发送。

client.Send(new ValueTLVDataFrame(10,Encoding.UTF8.GetBytes("rrqm")));//推荐写法,如果使用自己Build,则需要明确指出FixedHeaderType的值。
提示

上述创建的适配器客户端与服务器均适用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/touchrpcbase/index.html b/handbook/build/docs/touchrpcbase/index.html new file mode 100644 index 000000000..368c8b9cb --- /dev/null +++ b/handbook/build/docs/touchrpcbase/index.html @@ -0,0 +1,18 @@ + + + + + +基础功能 | TouchSocket + + + + +
+

基础功能

一、连接验证

连接验证可以初步保证连接客户端的安全性。框架内部默认使用一个string类型的Token作为验证凭证。当然也允许服务器进行其他验证。具体如下:

1.1 Token验证

在服务器或客户端的配置上,设置VerifyToken,即可实现字符串Token验证。

var config = new TouchSocketConfig()//配置
.SetVerifyToken("TouchRpc");

1.2 动态验证

使用插件,重写OnHandshaking相关。然后可以自行判断一些信息,比如:IP地址、元数据等。

internal class MyTouchRpcPlugin : TouchRpcPluginBase
{
protected override void OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e)
{
if (e.Metadata["a"] != "a")
{
e.IsPermitOperation = false;//不允许连接
e.Message = "元数据不对";//同时返回消息
e.Handled= true;//表示该消息已在此处处理。
return;
}
if (e.Token == "123")
{
e.IsPermitOperation = true;
e.Handled = true;
return;
}
base.OnHandshaking(client, e);
}
}

二、ID同步

在TouchRpc中,存在于服务器的辅助客户端(SocketClient),与远程客户端(Client)是一一对应关系,其ID也完全一致。所以在任意一方修改ID(调用ResetID),都会同时修改远程ID。所以合理使用该操作,可以完成复用ID(重置ID)的需求。

三、协议扩展

协议扩展功能,就是对现有的TouchRpc进行自定义的扩展协议。其目的就是为了应对更加复杂,高要求的需求。

例1:当需要广播消息时,可能大家都会想到使用rpc直接进行广播。但是如此一来,每广播一个客户端,就需要序列化一次。因为数据都是一样的,所以多次序列化显得非常没有必要。那么这时候,可以自定义协议,然后先序列化,然后直接广播数据。

自定义协议效率如何呢? +自定义协议的效率是非常高的,99%接近于底层协议(可能是tcp、udp、websocket)效率。

3.1 使用

使用起来是非常简单的,每个TouchRpc客户端或者TouchRpc服务端,都实现了Send方法接口。 +第一个参数为short类型,使用者可以约定任意数值不要使用小于0的,因为框架内部在使用)。

接收方在OnReceivedProtocolData函数中,已经包含了协议参数,所以直接自行筛选即可。

internal class MyTouchRpcPlugin : TouchRpcPluginBase
{
protected override void OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e)
{
if (e.Protocol == 10)
{
//判断完协议以后,从e.ByteBlock可以拿到实际的数据
//但是需要注意的是,真实数据会整体向右偏移2个字节。
string msg = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 2, e.ByteBlock.Len - 2);
}
base.OnReceivedProtocolData(client, e);
}
}
注意

从ProtocolDataEventArgs解析的ByteBlock,其真实数据会整体向右偏移2个字节。因为前两个字节是ushort的Protocol。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/touchrpcdescription/index.html b/handbook/build/docs/touchrpcdescription/index.html new file mode 100644 index 000000000..858cc8b07 --- /dev/null +++ b/handbook/build/docs/touchrpcdescription/index.html @@ -0,0 +1,18 @@ + + + + + +产品及架构介绍 | TouchSocket + + + + +
+

产品及架构介绍

一、说明

TouchRpc是一个简单易用,便捷高效,且易于扩展的自定义数据格式可靠执行传输协议

【协议格式】

| 2字节 | n字节 |

协议格式非常简单。 +前两个字节为默认端序的小端,int16有符号类型。其中小于0的协议一般不要占用,因为框架在使用。 +后续字节则为本次协议的载荷数据。

细心的小伙伴可能会问,这个数据协议没有分包标识啊,也就是无法分辨一个数据包是不是完整的。这是因为TouchRpc支持多种协议运行,可能在一些协议上,就已经涵盖了分包机制,所以为避免过度封装,所以TouchRpc并未制定分包。所以TouchRpc在不同协议工作时,可能实际的数据格式也不相同。

例如:在Tcp工作时,其分包算法使用的是固定包头。在websocket工作时,使用的就是其自身的分包算法。

可能好多人会疑惑,TouchRpc和tcp、udp有什么关系?或者说,类似tcp,本身就是可靠传输协议了,那TouchRpc的可靠又体现在什么地方呢?

1.1 TouchRpc和Tcp、Udp有什么关系?

TouchRpc像http和websocket一样,也是封装的应用层协议。它可以基于最基本的tcp或udp工作,也能基于http和websocket工作。所以,可以认为TouchRpc是更为高级的应用层协议。

1.2 Tcp本身就是可靠传输协议了,那TouchRpc的可靠又体现在什么地方呢?

首先呢,我们得明确,tcp的可靠,是在保持连接的时候,才可靠。当突然断网时,这种可靠将被打破。其次这种可靠是单项的,举例来说,发送方只是负责将数据发给接收方,至于接收方处理了没有,或者处理结果如何,都是未知的。那么这时候聪明的小伙伴就会想到让接收方回复一个状态不就行了?是的,这就是TouchRpc工作的场景之一了。

当然,TouchRpc的功能远非上述的两个场景,详细概览如下:

二、特点

2.1 基础功能

  • 支持连接验证,也支持动态信息验证。
  • 支持ID同步,每个客户端连接到服务器后,自身ID会与服务器ID同步,且支持重置。
  • 支持ssl加密。
  • 支持协议扩展

2.2 Rpc功能

  • 支持常规rpc操作。
  • 支持代理代码生成。
  • 支持自定义类型的参数。
  • 支持out、ref关键字参数。
  • 支持服务器主动Call客户端和客户端之间互Call。
  • 支持调用上下文,可进行服务AOP。
  • 支持异步调用。
  • 支持调用超时、调用中断。
  • 支持全异常反馈,被调用方发生的一切异常,都会传递到调用方。
  • 支持.NET二进制序列化、Json序列化、xml序列化、Fast序列化,以及自定义序列化扩展。
  • 高性能调用,在保证送达但不返回的情况下,10w次调用用时0.8s,在返回的情况下,用时3.9s。

2.3 文件传输

  • 支持任意大小的文件传输。
  • 支持断点续传。
  • 支持传输限速。
  • 支持服务器主动向客户端请求、发送文件。
  • 支持客户端之间互相请求、发送文件。
  • 支持小文件快速传输。
  • 支持超大文件多链路、多线程传输。

2.4 远程操作

  • 支持创建文件夹。
  • 支持文件的删除、移动、重命名等操作。
  • 支持服务器对客户端的主动操作。
  • 支持客户端之间的操作。

2.5 流数据方面

  • 支持发送任意类型的Stream。
  • 支持将远程的流数据映射到本地,然后直接Read或Write。
  • 支持实施传输压缩。

2.6 Channel数据

  • 支持独立通道数据,可进行数据隔离。
  • 支持服务器到客户端,客户端到客户端的操作。

2.7 EventBus

  • 支持事件的创建、订阅、取消、触发等。
  • 支持触发权限。
  • 支持事件广播。

2.8 Redis

  • 支持string为键的任意类型的数据。
  • 支持服务器向客户端存储。
  • 支持存储持久化。

三、场景

什么情况下使用TouchRpc比较好呢?首先,你得先了解RPC,了解完后,因为TouchRpc无法跨语言,所以,建议以下场景使用TouchRpc比较稳妥。

  1. 不需要跨语言的终端,例如:Unity游戏,Winform、WPF、MAUI等软件。
  2. 服务器之间集群。
  3. 扩展微服务,此时可以使用反向RPC实现。

实际上TouchRpc有四个版本,分别为:

类型特性
Tcp版基于TCP协议,连接性能最好,执行效率最高,支持TouchRpc所有功能。
Udp版基于UDP Package协议,无连接,执行效率高,仅支持TouchRpc的Rpc功能。
Http版基于Http握手连接,数据交互仍然使用TCP。连接性能一般,但兼容性强,支持JsonRpc,WebApi,XmlRpc,WebSocket等一系列Http组件,且执行效率和TCP版一样高,支持TouchRpc所有功能。
WebSocket版该版本是仅适用于Asp.Net Core的版本,特点就是和Asp.Net Core共用端口。但是执行数据使用的是WebSocket,所有效率只有Tcp版的80%。支持TouchRpc所有功能
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/touchsocketbitconverter/index.html b/handbook/build/docs/touchsocketbitconverter/index.html new file mode 100644 index 000000000..f32874726 --- /dev/null +++ b/handbook/build/docs/touchsocketbitconverter/index.html @@ -0,0 +1,16 @@ + + + + + +大小端转换器 | TouchSocket + + + + +
+

大小端转换器

一、说明

大小端在计算机业界,Endian表示数据在存储器中的存放顺序。

  • 大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
  • 小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

二、绝对大端

byte[] data= TouchSocketBitConverter.BigEndian.GetBytes(10);
//结果 {0,0,0,10}

三、绝对小端

byte[] data= TouchSocketBitConverter.LittleEndian.GetBytes(10);
//结果 {10,0,0,0}

四、默认端

TouchSocket系全采用默认“小端”模式。可通过DefaultEndianType属性,修改为大端。

TouchSocketBitConverter.DefaultEndianType = EndianType.Big;
byte[] data= TouchSocketBitConverter.Default.GetBytes(10);
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/transferfile/index.html b/handbook/build/docs/transferfile/index.html new file mode 100644 index 000000000..836f44a1d --- /dev/null +++ b/handbook/build/docs/transferfile/index.html @@ -0,0 +1,24 @@ + + + + + +传输文件 | TouchSocket + + + + +
+

传输文件

演示: 可以看到,下图正在上传一个Window的系统镜像文件,大约4.2Gb,传输速度已达到800Mb/s,GC基本上没有释放,性能非常强悍(中间有稍微停顿,因为程序在获取文件MD5值)。

产品应用场景

  • 常规C/S应用使用场景:开发使用非常方便,连接验证,数据业务,文件传输等一系列功能完全集成。
  • Unity游戏场景:性能卓越,功能丰富,使用方便。

服务架构

  • 其传输架构是基于Channel工作的。所以当在同一时间,可进行多个传输并行,且数据互不影响。
  • 在文件传输时,每个连接端和服务器均是平等权利的,所以RRQM将其命名为对点。任意两个对点之间均可Pull(拉取或下载)或Push(推送或上传)文件,例如下图中,Client1、SocketClient1、Client2、SocketClient2四个互相为对点,均可自由传输文件。

一、说明

文件传输是每个框架都需要的功能,也是检验一个框架性能的非常重要的指标。

TouchRpc开辟了对点文件传输。即,当客户端连接服务器以后,两者可以任意,随时的互相发送文件。不仅如此,即使是客户端之间,可以发送文件。

下列示例仅演示由TcpTouchRpcClientTcpTouchRpcService(实际上是TcpTouchRpcSocketClient)的操作。

对点之间可以任意pull(拉取)、push(推送)文件。接收对点可以订阅FileTransferingFileTransfered事件,来获取相关信息,发起对点直接通过传输控制器或返回值获取传输信息。

值得注意的是,FileTransfered事件的触发并不意味着完成传输,具体结果还要通过Result属性值进行判断。

二、Pull文件

TcpTouchRpcClientTcpTouchRpcService发起Pull请求时,相当于由客户端从服务器下载文件。

响应流程:

  1. 发起Pull请求。
  2. 接收对点(即此处的服务器)触发FileTransfering事件。
  3. 返回文件信息,然后检验是否续传等,然后开始接收。
  4. 接收完成或异常。
  5. 接收对点触发FileTransfered事件。
  6. 发起对点函数返回,控制器状态改变。

具体请求:

请求参数参数属性请求参数属性描述

| FileOperator:FileOperator是本次传输的请求操作器,主要用于获取传输进度、速度、状态以及取消传输等操作。接收方的控制器从FileTransfering事件的参数e中获得。

| ResourcePath | ResourcePath属性为请求文件在接收对点的路径,当该值为相对路径时,会与接收对点的RootPath组合路径。当为绝对路径时,则会直接访问路径文件(此时如果不在对点设置条件,则有可能会有文件安全隐患,设置详情链接。 | +| | SavePath | SavePath属性是发起对点本地的保存路径。 | +| | Flags | 可通过叠加位域的形式,尝试断点续传。 | +| | CompletedLength | 已完成流长度。 | +| | Speed 函数 | 从上次获取到此次获得的速度。一般请每秒钟调用一次获取速度值。 | +| | Progress | 传输进度,范围0-1。 | +| | Result | 获取传输状态以及状态信息。当ResultCode为Default时,意味着传输正在进行。 | +| | Token | CancellationToken类型的可取消令箭。 | +| | Metadata | string类型的键值对,用于和接收方交互数据。 |

示例代码:

【服务器】

var service = new TouchSocketConfig()//配置
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.UsePlugin()
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
a.AddFileLogger();
})
.ConfigurePlugins(a =>
{
a.Add<MyPlugin>();
})
.SetVerifyToken("File")//连接验证口令。
.BuildWithTcpTouchRpcService();//此处build相当于new TcpTouchRpcService,然后Setup,然后Start。
service.Logger.Info("服务器成功启动");
class MyPlugin : TouchRpcPluginBase<TcpTouchRpcSocketClient>
{
protected override void OnFileTransfering(TcpTouchRpcSocketClient client, FileOperationEventArgs e)
{
e.IsPermitOperation = true;//运行操作

//有可能是上传,也有可能是下载
client.Logger.Info($"有客户端请求传输文件,ID={client.ID},请求类型={e.TransferType},请求文件名={e.ResourcePath}");
}

protected override void OnFileTransfered(TcpTouchRpcSocketClient client, FileTransferStatusEventArgs e)
{
//传输结束,但是不一定成功,需要从e.Result判断状态。
client.Logger.Info($"客户端传输文件结束,ID={client.ID},请求类型={e.TransferType},文件名={e.ResourcePath},请求状态={e.Result}");
}

protected override void OnHandshaked(TcpTouchRpcSocketClient client, VerifyOptionEventArgs e)
{
client.Logger.Info($"有客户端成功验证,ID={client.ID}");
}

protected override void OnDisconnected(TcpTouchRpcSocketClient client, ClientDisconnectedEventArgs e)
{
client.Logger.Info($"有客户端断开,ID={client.ID}");
base.OnDisconnected(client, e);
}
}

【客户端】

TcpTouchRpcClient client = new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.SetVerifyToken("File")
.UsePlugin()
.ConfigureContainer(a =>
{
a.AddConsoleLogger();
a.AddFileLogger();
})
.ConfigurePlugins(a =>
{
a.UseTouchRpcHeartbeat<TcpTouchRpcClient>();
})
.BuildWithTcpTouchRpcClient();

client.Logger.Info("连接成功");

Metadata metadata = new Metadata();//传递到服务器的元数据
metadata.Add("1", "1");
metadata.Add("2", "2");

FileOperator fileOperator = new FileOperator()//实例化本次传输的控制器,用于获取传输进度、速度、状态等。
{
Flags = TransferFlags.BreakpointResume,//尝试断点续传,使用断点续传时,会验证MD5值
SavePath = $@"Windows.iso",//保存路径
ResourcePath = @"D:\System\Windows.iso",//请求路径
Metadata= metadata//传递到服务器的元数据
};

fileOperator.Timeout = TimeSpan.FromSeconds(60);//当传输大文件,且启用断点续传时,服务器可能会先计算MD5,而延时响应,所以需要设置超时时间。

//此处的作用相当于Timer,定时每秒输出当前的传输进度和速度。
LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
{
if (fileOperator.Result.ResultCode != ResultCode.Default)
{
loop.Dispose();
}

client.Logger.Info($"进度:{fileOperator.Progress},速度:{fileOperator.Speed()}");
});

loopAction.RunAsync();



//此方法会阻塞,直到传输结束,也可以使用PullFileAsync
IResult result = client.PullFile(fileOperator);

client.Logger.Info(result.ToString());

三、Push文件

Push和Pull操作一致,仅需要在最后调用PushFile即可。

四、客户端之间传输文件

该功能支持客户端之间传输文件,使用方法基本一致,只需要额外增加目标Id即可。

此外,服务器也需要同意路由。需要注意的是,使用该方式文件传输时,还会发起通道路由,所以,需要允许的路由应该还额外增加通道类型

internal class MyTouchRpcPlugin : TouchRpcPluginBase
{
protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e)
{
if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile||e.RouterType== RouteType.CreateChannel)
{
e.IsPermitOperation = true;
}
base.OnRouting(client, e);
}
}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/udpbroadcast/index.html b/handbook/build/docs/udpbroadcast/index.html new file mode 100644 index 000000000..18812f0cb --- /dev/null +++ b/handbook/build/docs/udpbroadcast/index.html @@ -0,0 +1,16 @@ + + + + + +组播、广播 | TouchSocket + + + + +
+

组播、广播

一、说明

  • 广播BroadCast:主机之间“一对所有”的通讯模式,广播者可以向网络中所有主机发送信息。广播禁止在Internet宽带网上传输(广播风暴)。
  • 多播MultiCast:主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据。

二、组播使用

组播使用非常简单,

  1. 配置中启用广播UseBroadcast重要
  2. 在UdpSession启动后。调用JoinMulticastGroup即可加入组播。调用DropMulticastGroup,退出组播。

2.1 创建组播服务器

//创建udpService
UdpSession udpService = new UdpSession();
udpService.Received = (remote, byteBlock, requestInfo) =>
{
Console.WriteLine(byteBlock.ToString());
};
udpService.Setup(new TouchSocketConfig()
.SetBindIPHost(new IPHost(7789))
.UseBroadcast()
.SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))
.Start();

//加入组播组
udpService.JoinMulticastGroup(IPAddress.Parse("224.5.6.7"));

2.2 发送组播数据

UdpSession udpClient = new UdpSession();
udpClient.Setup(new TouchSocketConfig()
.SetBindIPHost(new IPHost(7788))
.SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))
.Start();

udpClient.Send(new IPEndPoint(IPAddress.Parse("224.5.6.7"), 7789), Encoding.UTF8.GetBytes("我是组播"));

三、广播

广播使用非常简单,

  1. 配置中启用广播UseBroadcast重要

3.1 创建广播服务器

广播接收时,是不需要加入组播组的。

//创建udpService
UdpSession udpService = new UdpSession();
udpService.Received = (remote, byteBlock, requestInfo) =>
{
Console.WriteLine(byteBlock.ToString());
};
udpService.Setup(new TouchSocketConfig()
.SetBindIPHost(new IPHost(7789))
.UseBroadcast()
.SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))
.Start();

3.2 发送广播数据

UdpSession udpClient = new UdpSession();
udpClient.Setup(new TouchSocketConfig()
.UseBroadcast()//该配置在发送广播时是必须的
.SetBindIPHost(new IPHost(7788))
.SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))
.Start();

udpClient.Send(new IPEndPoint(IPAddress.Parse("255.255.255.255"), 7789), Encoding.UTF8.GetBytes("我是广播"));
注意

在发送广播数据时,发送端配置UseBroadcast是必须的。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/udpdatahandlingadapter/index.html b/handbook/build/docs/udpdatahandlingadapter/index.html new file mode 100644 index 000000000..471686a6a --- /dev/null +++ b/handbook/build/docs/udpdatahandlingadapter/index.html @@ -0,0 +1,16 @@ + + + + + +原始自定义适配器 | TouchSocket + + + + +
+

原始自定义适配器

说明

Udp的适配器,主要承担组包和解析数据。其基本逻辑和Tcp相似。但是需要注意的是,Udp适配器是多线程操作。在解析数据时,应当充分考虑并发问题。

class MyUdpAdatper : UdpDataHandlingAdapter
{
public override bool CanSplicingSend => false;

protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock)
{

}

protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length, bool isAsync)
{

}

protected override void PreviewSend(EndPoint endPoint, IList<TransferByte> transferBytes, bool isAsync)
{

}

protected override void Reset()
{

}
}

单元测试

使用UdpDataAdapterTester即可测试。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/udptransmitbigdata/index.html b/handbook/build/docs/udptransmitbigdata/index.html new file mode 100644 index 000000000..57fcc24a8 --- /dev/null +++ b/handbook/build/docs/udptransmitbigdata/index.html @@ -0,0 +1,16 @@ + + + + + +传输大于64K的数据 | TouchSocket + + + + +
+

传输大于64K的数据

一、说明

UDP由于自身限制,每次发送的数据包最大约64K,但是在局域网内,有时候希望传输更大的数据。所以必须有策略发送。

TouchSocket可通过简单设置,实现该功能。

二、使用

只需要在配置中,设置其适配器为UdpPackageAdapter类型即可(默认为NormalUdpDataHandlingAdapter)。同时可以根据传输数据的大小,修改相关属性,如:MTUTimeout等。

UdpSession udpSession = new UdpSession();
udpSession.Received += (endpoint, byteBlock, requestInfo) =>
{

};

udpSession.Setup(new TouchSocketConfig()
.SetBindIPHost(new IPHost($"127.0.0.1:7789"))
.SetUdpDataHandlingAdapter(()=> new UdpPackageAdapter()));//加载配置
udpSession.Start();//启动
注意

此模式下,发送端与接收端均必须为TouchSocket(或实现相同算法),且为相同设置。

三、原理

在发送时,会将要发送的数据分割成MTU长度的数据。然后为其编号,然后发送,最后由接收方重组。

3.1 数据格式

ID:由雪花算法生成,在并发请求时1毫秒中有400w分之一的概率发生ID重复。但基本可以忽略不计。

Bit说明76543210
协议名
byte1PackageID为long类型,占用8字节,标识数据包唯一性。
byte2
byte3
byte4
byte5
byte6
byte7
byte8SN为Ushort占2字节,标识帧序
byte9
byte10flag,占1字节,最高位标识是否为结束,其他位保留。1
byte?有效载荷数据
byte^2当不为终结帧时,此处仍然为载荷数据。当是终结帧时,倒数两个字节为Crc16校验。
byte^1
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/upgrade/index.html b/handbook/build/docs/upgrade/index.html new file mode 100644 index 000000000..71b1b969a --- /dev/null +++ b/handbook/build/docs/upgrade/index.html @@ -0,0 +1,41 @@ + + + + + +历史更新 | TouchSocket + + + + +
+

历史更新

TouchSocket 框架升级/发版规则

升级前重点关注可能造成【破坏性】的标签类型

版本号规则:主版本号.次版本号.修订版本号

  • 只要【确认】为框架 bug,则当天修复,当天发版,修订版本号 加 1
  • 如果 .csproj 文件有变更,则当天发版,修订版本号 加 1
  • 其余情况,每年发布一个 主版本

v1.2.1

更新日期:2023.2.2

更新描述:兼容性更新。

  •   TouchRpc支持命名元组。
  •   TouchRpc在调用WaitSend下失败的bug。
  •   TouchRpc在Handshaked时,调用Rpc超时bug。
  •   序列化、反射在unity中使用il2cpp编译的bug。
  •   ByteBlock对于int,long等数据,写入和读取的时候支持大小端指定。
  •   IServicePlugin插件,用于显示通知服务器的启动状态。
  •   将BytePool由静态调整为实例,且由其Default实例作为默认。

v1.1.0

更新日期:2023.1.13

更新描述:小版本升级,可能会有不兼容。请按下列提示修改。

  •   TouchRpc系文件传输时,文件夹不存在的提示。
  •   WaitingClient,当客户端断开连接时,可选是否抛出异常。
  •   Fast序列化时。可选序列化只读属性。
  •   多个不稳定Bug。
  •   Tcp客户端新增Disconnecting事件。在主动Close时生效。
  •   多个事件类名称修改,请按照提示修改即可。
  •   多个无用方法参数。

v1.0.0

更新日期:2023.1.1

更新描述:大版本升级,请详细阅读下列更新日志。

  •   将最高版本升级为NET7。
  •   Tcp系异步发送效率。
  •   TouchRpc系Channel的稳健性。
  •   多个不稳定Bug。
  •   ValueByteBlock,在简单代码块里面能有效减少创建的类。
  •   MemoryCache类,其功能类似微软官方。但是支持全部泛型。
  •   IPackage系。该系列能以超高效率的进行二进制序列化。
  •   SingleTimer类,不可重入的Timer。
  •   Jsonrpc支持自定义适配器解析(EE)
  •   严重TouchRpc系OnRouting通知,所有的客户端之间的通信,都必须经过OnRouting的筛查。
  •   TouchRpc系小文件传输,在文件小于1Mb时,其传输效率是常规传输的10倍以上。
  •   TouchRpc系超大文件多链路传输,支持多个客户端协同传输同一个文件,这在互联网环境中,效率比常规传输提高类3-5倍。
  •   TouchRpc系Redis组件,能实现双端共同存储。
  •   严重精简所有命名空间,删除所有三级命名空间。例如:TouchSocket.Core.ByteManager精简为TouchSocket.Core。
  •   严重删除Newtonsoft.Json的源代码嵌入。全局的Json会根据环境动态调整,详情见Json工具
  •   严重框架默认日志由ConsoleLogger,替换为EmptyLogger(不输出任何东西)。
  •   严重Tcp全系,在连接时,ID的初始值使用long类型从0递增。
  •   严重Tcp服务器,将定时清理无数据交互的选项替换为UseCheckClear插件。并且默认没有启用,需要手动加入。
  •   Tcp系适配器,取消部分参数。
  •   DataLock改名为DataSecurity。
  •   EasyAction改名EasyTask。
  •   IMessage改名IMessageObject。
  •   TokenInstance改名MessageInstance。
  •   TouchRpc系,精简常规文件传输操作。
  •   严重TouchRpc系,所有插件通知参数,默认都设为不允许操作,需要手动设置e.IsPermitOperation=true。
  •   Newtonsoft.Json的源代码嵌入。全局的Json会根据环境动态调整,详情见Json工具

更新示例指南

(1)适配器参数报错:直接删除isAsync参数,以及isAsync为True的所有逻辑。 +image.png +(2)依赖属性的声明报错:增加泛型约束即可,详情查看依赖属性 +image.png +(3)服务端定时清理警告:在配置插件中使用UseCheckClear,并且进行相关配置。 +image.png +image.png


版本号: 0.7.0

更新日期:2022.9.21 +更新描述:兼容性更新,增强型更新。RPC内容需要客户端与服务器同步更新。 +更新详情:

优化

  1. Fast二进制序列化,支持自定义序列化。
  2. TouchRpc全系,在文件传输等大型IO时,由于心跳失败而断开连接。
  3. 优化AspNetCore的IContainer。
  4. TcpCommandLinePlugin与WSCommandLinePlugin支持获取客户端参数。

新增

  1. 插件实例会以单例注入容器。
  2. 所有适配器支持缓存超时设定。
  3. 修改所有事件为委托。
  4. 开放AspnetCore创建Tcp,Http等服务器的配置。
  5. IClient增加发送、接收的最后时间记录。
  6. Http支持多文件上传(目前仅支持小文件,具体大小以实际运行内存为准,实测100Mb没问题)。
  7. Websocket插件默认会处理Close报文。且插件支持Close。
  8. Rpc支持模板代码重写。
  9. TouchRpc支持元组。
  10. JsonRpc支持Websocket协议。

修改

  1. IScopedContainer修改为IContainerProvider

修复

  1. BytePool回收内存时不判断大小的bug。

删除

  1. 无。

版本号: 0.6.0

更新日期:2022.9.10 +更新描述:兼容性更新,增强型更新。专为Unity 3D适配。 +更新详情:

优化

  1. Gzip的压缩效率。
  2. 发送效率。

新增

  1. IDataCompressor数据传输压缩接口。
  2. RemoteStream支持数据读写压缩。
  3. WaitResultPackageBase类,专属非序列化的数据格式化。
  4. DelaySender延迟缓存发送

修改

修复

  1. Rpc注册服务为单例时,实际上是瞬时服务的bug。

删除

  1. 独立线程发送。

版本号: 0.5.0

更新日期:2022.9.1 +更新描述:兼容性更新,增强型更新。 +更新详情:

优化

  1. 全局资源的获取逻辑。

新增

  1. Container增加卸载注册功能。
  2. FilePool新增FileStorageStream的获取。
  3. http客户端(及websocket)支持代理和验证代理。
  4. TouchRpc全系新增远程文件操作
  5. TouchRpc(除udp)新增远程流访问

修改

修复

  1. 修复Http客户端请求重复Header时的bug。

删除

  1. TouchRpc全系的事件操作,推荐直接插件的方式,或者使用TouchRpcActionPlugin然后添加委托。

更新示例 +TouchRpc的相关事件均已使用插件代替。所以请使用插件实现操作。如果需要事件等功能的话,可以用TouchRpcActionPlugin的插件实现。例如:

.UsePlugin()
.ConfigurePlugins(a=>
{
a.Add<TouchRpcActionPlugin<TcpTouchRpcClient>>()//此处的逻辑可用插件替代完成。
.SetFileTransfering((client, e) =>
{
//有可能是上传,也有可能是下载
client.Logger.Info($"服务器请求传输文件,ID={client.ID},请求类型={e.TransferType},文件名={e.FileInfo.FileName}");
})
.SetFileTransfered((client, e) =>
{
//传输结束,但是不一定成功,需要从e.Result判断状态。
client.Logger.Info($"服务器传输文件结束,ID={client.ID},请求类型={e.TransferType},文件名={e.FileInfo.FileName},请求状态={e.Result}");
});
})

版本号: 0.4.5

更新日期:2022.8.25 +更新描述:兼容性更新,增强型更新。 +更新详情:

优化

  1. FileLogger的写入逻辑,大大地提升了写入效率。

新增

  1. Pipeline适配器
  2. TLV适配器
  3. WaitingClient支持按条件等待返回。
  4. 日志系统可以筛选日志的输出类型
  5. Rpc系统,可以使用单例、瞬时生命周期的服务。
  6. Rpc系统,可定义持久化模型。
  7. Rpc在使用瞬时生命周期的服务时,可以直接获取调用上下文。
  8. XmlRpc增加调用上下文。

修改

  1. 日志系统。
  2. Rpc的调用上下文均采用接口,例如:JsonRpc改为IJsonRpcCallContext,WebApi为IWebApiCallContext。
  3. IRpcActionFilter的参数列表。

修复

  1. UdpSession资源不释放的Bug。

删除

  1. 冗余元素。

版本号: 0.3.5

更新日期:2022.8.12 +更新描述:兼容性更新,增强型更新。 +更新详情:

优化

  1. 各类客户端发送逻辑。
  2. Method类的调用逻辑。

新增

  1. 适配器可以设定发送IRequestInfo对象。
  2. 插件新增UseWebSocket的快捷方式。
  3. ReconnectionPlugin插件可以获得重连次数的重载设置。
  4. 【企业版】TcpService的服务注入。
  5. 【企业版】HttpService的服务注入。
  6. 【企业版】IOC容器的共享使用。

修改

  1. 各类发送逻辑,以最小化发送方法为基础,其余方法改为扩展方法。
  2. 相关接口的实现。
  3. 由网友修改GetInfo

修复

  1. Container获取泛型失败bug。
  2. BetweenAnd适配器适配器部分bug。
  3. Router标签无法路由的bug。
  4. 修复TouchRpc推送文件状态不正确bug
  5. 修复独立线程在断线重连后发送bug。

删除

  1. 冗余的发送方法,不影响上版本任何使用。

版本号: 0.2.4

更新日期:2022.7.28 +更新描述:兼容性更新。 +更新详情:

优化

  1. 优化IOC容器。
  2. 优化Metadata的写入方式。
  3. FileLogger,当日志文件达到1Mb时,会再新增文件序号。

新增

  1. Mapper类,支持简单类型映射
  2. Tcp服务器、客户端、udp等增加端口复用配置。
  3. 【企业版】轮询式断线重连。
  4. 【企业版】NATService转发客户端重连。

修改

  1. RRQM二进制序列化,改名为Fast。
  2. TouchRpcClient连接时的Metadata,改为由Config配置注入。
  3. FilePool,取消延迟释放机制。

修复

  1. 修复WebSocket连接问题

删除

  1. 客户端直接调用的短线重连方式。仅保留在Config注入的功能。

版本号: 0.1.0

更新日期:2022.7.16 +更新描述:初始化版本发布。由RRQMSocket迁移而来。

迁移指南:

1.所有类的命名空间修改,此处如果类型名未修改的话,可由vs智能提示解决。

2.类型名称修改

原类型名称新类型名称
RRQMBitConverterTouchSocketBitConverter
RRQMConfigTouchSocketConfig
RRQMConverterTouchSocketConverter
RRQMDependencyObjectDependencyObject
MsgEventArgsMsgEventArgs
RRQMEventAgrsTouchSocketEventArgs
IServerProviderIRpcServer
ServerProviderRpcServer
RRQMOverlengthExceptionOverlengthException

3.使用逻辑修改

1)原RRQMConfig设置Logger的方法,改为容器注入: +image.png +断线重连逻辑 +image.png +RpcStore使用变更 +如果是仅有一个Rpc解析器,那么可以直接删除RpcStore的声明,从而使用对应的解析器实例,直接注册服务。然后可以通过其属性RpcStore,获取到具体的RpcStore实例。

如果是有多个解析器,那么,首先可以使用任意一个解析器的RpcStore属性实例,作为主RpcStore,然后添加其他解析器。当然也可以直接new RpcStore,然后统一管理解析器。其中构造函数中的Container容器,可以直接new Container(),但是更建议使用和解析器相同的容器,这样注入的服务会变得全局可用。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/waitingclient/index.html b/handbook/build/docs/waitingclient/index.html new file mode 100644 index 000000000..85830850e --- /dev/null +++ b/handbook/build/docs/waitingclient/index.html @@ -0,0 +1,16 @@ + + + + + +同步请求 | TouchSocket + + + + +
+

同步请求

一、说明

有很多小伙伴一直有一些需求:

  1. 客户端发送一个数据,然后等待服务器回应。
  2. 服务器向客户端发送一个数据,然后等待客户端回应。

那针对这些需求,可以使用WaitingClient。其内部实现了IWaitSender接口,能够在发送完成后,等待返回。

二、创建及使用

2.1 以TcpClient为例

TcpClient m_tcpClient = new TcpClient();
var config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:7789"));

//载入配置
m_tcpClient.Setup(config);
m_tcpClient.Connect();

//调用GetWaitingClient获取到IWaitingClient的对象。
var waitClient = m_tcpClient.GetWaitingClient(new WaitingOptions()
{
AdapterFilter = AdapterFilter.AllAdapter,//表示发送和接收的数据都会经过适配器
BreakTrigger = true,//表示当连接断开时,会立即触发
ThrowBreakException = true//表示当连接断开时,是否触发异常
});

//然后使用SendThenReturn。
byte[] returnData = waitClient.SendThenReturn(Encoding.UTF8.GetBytes("RRQM"));
m_tcpClient.Logger.Info($"收到回应消息:{Encoding.UTF8.GetString(returnData)}");

//同时,如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时,可以使用SendThenResponse.
ResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes("RRQM"));
IRequestInfo requestInfo = responsedData.RequestInfo;//同步收到的RequestInfo

2.2 以TcpService为例

var service = new TcpService();
service.Received = (client, byteBlock, requestInfo) =>
{
//调用GetWaitingClient获取到IWaitingClient的对象。
var waitClient = client.GetWaitingClient(new WaitingOptions()
{
AdapterFilter = AdapterFilter.AllAdapter,//表示发送和接收的数据都会经过适配器
BreakTrigger = true,//表示当连接断开时,会立即触发
ThrowBreakException = true//表示当连接断开时,是否触发异常
});

//然后使用SendThenReturn。
byte[] returnData = waitClient.SendThenReturn(Encoding.UTF8.GetBytes("RRQM"));
client.Logger.Info($"收到回应消息:{Encoding.UTF8.GetString(returnData)}");

//同时,如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时,可以使用SendThenResponse.
ResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes("RRQM"));
IRequestInfo responseRequestInfo = responsedData.RequestInfo;//同步收到的RequestInfo
};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.ConfigureContainer(a =>//容器的配置顺序应该在最前面
{
a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用)
})
.ConfigurePlugins(a =>
{
//a.Add();//此处可以添加插件
}))
.Start();//启动
提示

实际上上述行为,只要实现IClient, IDefaultSender, ISend三个接口的类均可以使用。

注意事项
  1. 发送完数据,在等待时,如果收到其他返回数据,则可能得到错误结果。
  2. 发送采用Lock锁,一个事务没结束,另一个请求也发不出去。
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/webapidescription/index.html b/handbook/build/docs/webapidescription/index.html new file mode 100644 index 000000000..ad569ba20 --- /dev/null +++ b/handbook/build/docs/webapidescription/index.html @@ -0,0 +1,16 @@ + + + + + +产品及架构介绍 | TouchSocket + + + + +
+

产品及架构介绍

一、说明

WebApi是通用的RPC调用,与编程语言无关,与操作系统无关。其路由机制模仿AspNetCore,可实现很多路由机制。但是因为http兼容性错综复杂,所以目前TouchSocket的WebApi仅支持GETPOST函数。使用体验接近于AspNetCore。

二、特点

  • 高性能,100个客户端,10w次调用,仅用时17s。
  • 全异常反馈
  • 支持大部分路由规则。
  • 支持js、Android等调用。
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/webapiservice/index.html b/handbook/build/docs/webapiservice/index.html new file mode 100644 index 000000000..bc974f606 --- /dev/null +++ b/handbook/build/docs/webapiservice/index.html @@ -0,0 +1,16 @@ + + + + + +定义、发布、启动服务 | TouchSocket + + + + +
+

定义、发布、启动服务

定义服务

服务器端中新建一个类,继承于RpcServer类(或实现IRpcServer),然后在该类中写公共方法,并用WebApi属性标签标记,如果方法有重载,需要重新指定函数键

  • 支持代理生成注释
public class ApiServer : RpcServer
{
[Router("[api]/[action]ab")]//此路由会以"/Server/Sumab"实现
[WebApi(HttpMethodType.GET)]
public int Sum(int a, int b)
{
return a + b;
}

[WebApi(HttpMethodType.POST)]
public int TestPost(MyClass myClass)
{
return myClass.A + myClass.B;
}

/// <summary>
/// 使用调用上下文,响应文件下载。
/// </summary>
/// <param name="callContext"></param>
[WebApi(HttpMethodType.GET, MethodFlags = MethodFlags.IncludeCallContext)]
public Task<string> DownloadFile(IWebApiCallContext callContext, string id)
{
if (id == "rrqm")
{
callContext.HttpContext.Response.FromFile(@"D:\System\Windows.iso", callContext.HttpContext.Request);
return Task.FromResult("ok");
}
return Task.FromResult("id不正确。");
}
}

public class MyClass
{
public int A { get; set; }
public int B { get; set; }
}

创建简单服务器

 HttpService service = new HttpService();
service.Setup(new TouchSocketConfig()
.UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.SetSingletonLogger<ConsoleLogger>();//注册一个日志
})
.ConfigureRpcStore(a =>
{
a.RegisterServer<ApiServer>();//注册服务
})
.ConfigurePlugins(a =>
{
a.Add<WebApiParserPlugin>();//添加支持WebApi的插件。此处可能需要using TouchSocket.Core.Plugins;
}))
.Start();

Console.WriteLine("以下连接用于测试webApi");
Console.WriteLine($"使用:http://127.0.0.1:7789/ApiServer/Sum?a=10&b=20");

Console.ReadKey();
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/webdataforwarding/index.html b/handbook/build/docs/webdataforwarding/index.html new file mode 100644 index 000000000..6acab4ede --- /dev/null +++ b/handbook/build/docs/webdataforwarding/index.html @@ -0,0 +1,16 @@ + + + + + +Web数据转发Winform项目 | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/websocketdescription/index.html b/handbook/build/docs/websocketdescription/index.html new file mode 100644 index 000000000..5600a1fa0 --- /dev/null +++ b/handbook/build/docs/websocketdescription/index.html @@ -0,0 +1,16 @@ + + + + + +产品及架构介绍 | TouchSocket + + + + +
+

产品及架构介绍

产品介绍

  • WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

产品特点

  • 简单易用。
  • 多线程。
  • 内存池
  • 高性能
  • 多种数据接收模式(IOCP,BIO,Select)。
  • 多地址监听(可以一次性监听多个IP及端口)

产品应用场景

  • WebSocket基础使用场景:可跨平台、跨语言使用。
  • 自定义协议解析场景:可解析任意数据格式的WebSocket数据报文。

服务器架构

服务器运行挂载在HttpService上,所以架构和HttpService一致。

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/wpfuifiletransfer/index.html b/handbook/build/docs/wpfuifiletransfer/index.html new file mode 100644 index 000000000..aca7487dd --- /dev/null +++ b/handbook/build/docs/wpfuifiletransfer/index.html @@ -0,0 +1,19 @@ + + + + + +WPF界面、文件传输项目 | TouchSocket + + + + +
+

WPF界面、文件传输项目

定制方 +凯**有限公司 +说明 +应该公司要求,开发以WPF为技术框架的桌面项目管理应用,其界面类似QQ(此处因为涉及UI版权,不展示实际效果)。并且以RRQMSocket为通信基础,解决项目文件的上传和下载。实际的解决了在2G网,甚至更差的网络环境下的大文件传输。

技术点

  • 整体界面:圆角窗体、窗体阴影、最小化嵌入、拖拽效果等。
  • 项目树视图:样式、搜索、定向搜索、搜索项定位、树视图连线。
  • 数据同步:设置配置数据、项目文件数据等。
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/wscommandlineplugin/index.html b/handbook/build/docs/wscommandlineplugin/index.html new file mode 100644 index 000000000..811178712 --- /dev/null +++ b/handbook/build/docs/wscommandlineplugin/index.html @@ -0,0 +1,17 @@ + + + + + +WSCommandLinePlugin | TouchSocket + + + + +
+

WSCommandLinePlugin

命令行执行插件客户端、服务器均支持

WSCommandLinePlugin命令行执行插件,是用于WebSocket的快捷事务实现,让WS在Text文本中,用最简单的文字消息即可完成相关事务的执行。该类是抽象类,必须通过继承,在继承类中,声明的具的公共的且名称以Command结尾的方法,均可被快捷执行。

例如:下列插件,即可被普通WS客户端,或服务器便捷调用。

调用数据格式: +Add 10 20支持Json数据格式

var service = new HttpService();

var config = new TouchSocketConfig();
config.UsePlugin()
.SetReceiveType(ReceiveType.Auto)
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a=>
{
a.SetSingletonLogger<ConsoleLogger>();
})
.ConfigurePlugins(a=>
{
a.Add<WebSocketServerPlugin>();//添加WebSocket功能
a.Add<MyWSCommandLinePlugin>();//添加WS命令行事务。
});

service.Setup(config)
.Start();
service.Logger.Message("Http服务器已启动");
service.Logger.Message("WS访问:ws://127.0.0.1:7789/ws");
/// <summary>
/// 命令行插件。
/// 声明的方法必须以"Command"结尾,支持json字符串,参数之间空格隔开。
/// </summary>
class MyWSCommandLinePlugin : WSCommandLinePlugin
{
public int AddCommand(int a, int b)
{
return a + b;
}

public SumClass SumCommand(SumClass sumClass)
{
sumClass.Sum = sumClass.A + sumClass.B;
return sumClass;
}
}
class SumClass
{
public int A { get; set; }
public int B { get; set; }
public int Sum { get; set; }

}
+ + + + \ No newline at end of file diff --git a/handbook/build/docs/wsjsonrpc/index.html b/handbook/build/docs/wsjsonrpc/index.html new file mode 100644 index 000000000..bf63cee17 --- /dev/null +++ b/handbook/build/docs/wsjsonrpc/index.html @@ -0,0 +1,16 @@ + + + + + +基于WS的JsonRpc | TouchSocket + + + + + + + + + \ No newline at end of file diff --git a/handbook/build/docs/xmlrpcdescription/index.html b/handbook/build/docs/xmlrpcdescription/index.html new file mode 100644 index 000000000..2fa039443 --- /dev/null +++ b/handbook/build/docs/xmlrpcdescription/index.html @@ -0,0 +1,16 @@ + + + + + +产品及架构介绍 | TouchSocket + + + + +
+

产品及架构介绍

XmlRpc是通用的工作在Internet上的RPC。一个XML-RPC消息就是一个请求体为xml的http-post请求,被调用的方法在服务器端执行并将执行结果以xml格式编码后返回。这与编程语言无关,与操作系统无关。在RRQM中封装了前后端,使其使用更加方便、高效。

特点:

  • 异常反馈
  • 支持自定义类型。
  • 支持类型嵌套。
  • 支持Web等调用。

示例代码

XmlRpc示例

+ + + + \ No newline at end of file diff --git a/handbook/build/docs/xmlrpcservice/index.html b/handbook/build/docs/xmlrpcservice/index.html new file mode 100644 index 000000000..e392d7a51 --- /dev/null +++ b/handbook/build/docs/xmlrpcservice/index.html @@ -0,0 +1,16 @@ + + + + + +定义、发布、启动服务 | TouchSocket + + + + +
+

定义、发布、启动服务

定义服务

服务器端中新建一个类,继承于ServerProvider类(或实现IServerProvider),然后在该类中写公共方法,并用XmlRpc属性标签标记,如果方法有重载,需要重新指定函数键

  • 支持代理生成注释
public class Server : ServerProvider
{
[XmlRpc]
public int Sum(int a, int b)
{
return a + b;
}

[XmlRpc]
public int TestClass(MyClass myClass)
{
return myClass.A + myClass.B;
}
}

public class MyClass
{
public int A { get; set; }
public int B { get; set; }
}

创建服务解析器

服务解析器是实际的服务接收、触发、调用、反馈的实际载体,通俗来说就是通信服务器

static IRpcParser CreateXmlRpcRpcParser()
{
HttpService service = new HttpService();

service.Setup(new RRQMConfig().UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7706) }))
.Start();

return service.AddPlugin<XmlRpcParserPlugin>()
.SetProxyToken("RPC")
.SetXmlRpcUrl("/xmlRpc");
}

注册、发布服务

添加解析器(添加时需要以键、值方式添加,方便后续查找),然后注册服务即可。

static void Main(string[] args)
{
RpcService rpcService = new RpcService();

//添加解析器,解析器根据传输协议,序列化方式的不同,调用RPC服务
rpcService.AddRpcParser("xmlRpcParser ", CreateXmlRpcRpcParser());

//注册当前程序集的所有服务
rpcService.RegisterAllServer();

//分享代理,代理文件可通过RRQMTool远程获取。
rpcService.ShareProxy(new IPHost(8848));

//或者直接本地导出代理文件。
//RpcProxyInfo proxyInfo = rpcService.GetProxyInfo(RpcType.RRQMRPC, "RPC");
//string codeString = CodeGenerator.ConvertToCode("RRQMProxy", proxyInfo.Codes);

Console.WriteLine("服务器已启动");
Console.ReadKey();

}
+ + + + \ No newline at end of file diff --git a/handbook/build/img/TouchSocketlogo.png b/handbook/build/img/TouchSocketlogo.png new file mode 100644 index 000000000..d4199b5c3 Binary files /dev/null and b/handbook/build/img/TouchSocketlogo.png differ diff --git a/handbook/build/img/chinadotnet.png b/handbook/build/img/chinadotnet.png new file mode 100644 index 000000000..cbe49d197 Binary files /dev/null and b/handbook/build/img/chinadotnet.png differ diff --git a/handbook/build/img/docs/consoleaction-1.gif b/handbook/build/img/docs/consoleaction-1.gif new file mode 100644 index 000000000..3e24d573d Binary files /dev/null and b/handbook/build/img/docs/consoleaction-1.gif differ diff --git a/handbook/build/img/docs/createhttpservice-1.png b/handbook/build/img/docs/createhttpservice-1.png new file mode 100644 index 000000000..c6a6e3c54 Binary files /dev/null and b/handbook/build/img/docs/createhttpservice-1.png differ diff --git a/handbook/build/img/docs/createtcpservice-1.png b/handbook/build/img/docs/createtcpservice-1.png new file mode 100644 index 000000000..dc7300f00 Binary files /dev/null and b/handbook/build/img/docs/createtcpservice-1.png differ diff --git a/handbook/build/img/docs/createtcpservice-2.png b/handbook/build/img/docs/createtcpservice-2.png new file mode 100644 index 000000000..7f3fcc503 Binary files /dev/null and b/handbook/build/img/docs/createtcpservice-2.png differ diff --git a/handbook/build/img/docs/customdatahandlingadapter-1.png b/handbook/build/img/docs/customdatahandlingadapter-1.png new file mode 100644 index 000000000..b1d189ed0 Binary files /dev/null and b/handbook/build/img/docs/customdatahandlingadapter-1.png differ diff --git a/handbook/build/img/docs/dataforwarding-1.png b/handbook/build/img/docs/dataforwarding-1.png new file mode 100644 index 000000000..b59df3df8 Binary files /dev/null and b/handbook/build/img/docs/dataforwarding-1.png differ diff --git a/handbook/build/img/docs/datahandleadapter-1.png b/handbook/build/img/docs/datahandleadapter-1.png new file mode 100644 index 000000000..253449fb4 Binary files /dev/null and b/handbook/build/img/docs/datahandleadapter-1.png differ diff --git a/handbook/build/img/docs/donate-1.png b/handbook/build/img/docs/donate-1.png new file mode 100644 index 000000000..da3686d2e Binary files /dev/null and b/handbook/build/img/docs/donate-1.png differ diff --git a/handbook/build/img/docs/engineertoolbox-1.jpg b/handbook/build/img/docs/engineertoolbox-1.jpg new file mode 100644 index 000000000..e716e8475 Binary files /dev/null and b/handbook/build/img/docs/engineertoolbox-1.jpg differ diff --git a/handbook/build/img/docs/engineertoolbox-2.jpg b/handbook/build/img/docs/engineertoolbox-2.jpg new file mode 100644 index 000000000..3253d4595 Binary files /dev/null and b/handbook/build/img/docs/engineertoolbox-2.jpg differ diff --git a/handbook/build/img/docs/engineertoolbox-3.jpg b/handbook/build/img/docs/engineertoolbox-3.jpg new file mode 100644 index 000000000..4f79f1092 Binary files /dev/null and b/handbook/build/img/docs/engineertoolbox-3.jpg differ diff --git a/handbook/build/img/docs/enterprise-1.jpg b/handbook/build/img/docs/enterprise-1.jpg new file mode 100644 index 000000000..1973cf479 Binary files /dev/null and b/handbook/build/img/docs/enterprise-1.jpg differ diff --git a/handbook/build/img/docs/enterprise-1.png b/handbook/build/img/docs/enterprise-1.png new file mode 100644 index 000000000..7be60d7b9 Binary files /dev/null and b/handbook/build/img/docs/enterprise-1.png differ diff --git a/handbook/build/img/docs/fastbinaryformatter-1.png b/handbook/build/img/docs/fastbinaryformatter-1.png new file mode 100644 index 000000000..c967c17da Binary files /dev/null and b/handbook/build/img/docs/fastbinaryformatter-1.png differ diff --git a/handbook/build/img/docs/fastbinaryformatter-2.png b/handbook/build/img/docs/fastbinaryformatter-2.png new file mode 100644 index 000000000..fe7a8322d Binary files /dev/null and b/handbook/build/img/docs/fastbinaryformatter-2.png differ diff --git a/handbook/build/img/docs/filesynchronization-1.png b/handbook/build/img/docs/filesynchronization-1.png new file mode 100644 index 000000000..afbb6d214 Binary files /dev/null and b/handbook/build/img/docs/filesynchronization-1.png differ diff --git a/handbook/build/img/docs/generateproxy-1.png b/handbook/build/img/docs/generateproxy-1.png new file mode 100644 index 000000000..d35238bc9 Binary files /dev/null and b/handbook/build/img/docs/generateproxy-1.png differ diff --git a/handbook/build/img/docs/ilog-1.png b/handbook/build/img/docs/ilog-1.png new file mode 100644 index 000000000..bb07cacb3 Binary files /dev/null and b/handbook/build/img/docs/ilog-1.png differ diff --git a/handbook/build/img/docs/ilog-2.png b/handbook/build/img/docs/ilog-2.png new file mode 100644 index 000000000..324b73cd6 Binary files /dev/null and b/handbook/build/img/docs/ilog-2.png differ diff --git a/handbook/build/img/docs/ipackage-1.jpg b/handbook/build/img/docs/ipackage-1.jpg new file mode 100644 index 000000000..19e5e98e2 Binary files /dev/null and b/handbook/build/img/docs/ipackage-1.jpg differ diff --git a/handbook/build/img/docs/ipackage-1.png b/handbook/build/img/docs/ipackage-1.png new file mode 100644 index 000000000..a732995a2 Binary files /dev/null and b/handbook/build/img/docs/ipackage-1.png differ diff --git a/handbook/build/img/docs/jsonserialize-1.png b/handbook/build/img/docs/jsonserialize-1.png new file mode 100644 index 000000000..9a107177c Binary files /dev/null and b/handbook/build/img/docs/jsonserialize-1.png differ diff --git a/handbook/build/img/docs/jsonserialize-2.png b/handbook/build/img/docs/jsonserialize-2.png new file mode 100644 index 000000000..0565b38db Binary files /dev/null and b/handbook/build/img/docs/jsonserialize-2.png differ diff --git a/handbook/build/img/docs/remotemonitoring-1.png b/handbook/build/img/docs/remotemonitoring-1.png new file mode 100644 index 000000000..3cce7ebe6 Binary files /dev/null and b/handbook/build/img/docs/remotemonitoring-1.png differ diff --git a/handbook/build/img/docs/remotemonitoring-2.gif b/handbook/build/img/docs/remotemonitoring-2.gif new file mode 100644 index 000000000..097618946 Binary files /dev/null and b/handbook/build/img/docs/remotemonitoring-2.gif differ diff --git a/handbook/build/img/docs/remotemonitoring-3.gif b/handbook/build/img/docs/remotemonitoring-3.gif new file mode 100644 index 000000000..c8d786049 Binary files /dev/null and b/handbook/build/img/docs/remotemonitoring-3.gif differ diff --git a/handbook/build/img/docs/remotemonitoring-4.gif b/handbook/build/img/docs/remotemonitoring-4.gif new file mode 100644 index 000000000..055f89d54 Binary files /dev/null and b/handbook/build/img/docs/remotemonitoring-4.gif differ diff --git a/handbook/build/img/docs/remotemonitoring-5.gif b/handbook/build/img/docs/remotemonitoring-5.gif new file mode 100644 index 000000000..e11b88e2d Binary files /dev/null and b/handbook/build/img/docs/remotemonitoring-5.gif differ diff --git a/handbook/build/img/docs/remotemonitoring-6.gif b/handbook/build/img/docs/remotemonitoring-6.gif new file mode 100644 index 000000000..2af03f1c2 Binary files /dev/null and b/handbook/build/img/docs/remotemonitoring-6.gif differ diff --git a/handbook/build/img/docs/remotestreamaccess-1.gif b/handbook/build/img/docs/remotestreamaccess-1.gif new file mode 100644 index 000000000..b7d8db21c Binary files /dev/null and b/handbook/build/img/docs/remotestreamaccess-1.gif differ diff --git a/handbook/build/img/docs/serializationselector-1.png b/handbook/build/img/docs/serializationselector-1.png new file mode 100644 index 000000000..e6ac69c3d Binary files /dev/null and b/handbook/build/img/docs/serializationselector-1.png differ diff --git a/handbook/build/img/docs/startguide-1.png b/handbook/build/img/docs/startguide-1.png new file mode 100644 index 000000000..7d3ad3a60 Binary files /dev/null and b/handbook/build/img/docs/startguide-1.png differ diff --git a/handbook/build/img/docs/startguide-10.png b/handbook/build/img/docs/startguide-10.png new file mode 100644 index 000000000..2227e02e6 Binary files /dev/null and b/handbook/build/img/docs/startguide-10.png differ diff --git a/handbook/build/img/docs/startguide-11.png b/handbook/build/img/docs/startguide-11.png new file mode 100644 index 000000000..368c2094b Binary files /dev/null and b/handbook/build/img/docs/startguide-11.png differ diff --git a/handbook/build/img/docs/startguide-12.png b/handbook/build/img/docs/startguide-12.png new file mode 100644 index 000000000..f805b6454 Binary files /dev/null and b/handbook/build/img/docs/startguide-12.png differ diff --git a/handbook/build/img/docs/startguide-2.png b/handbook/build/img/docs/startguide-2.png new file mode 100644 index 000000000..bdf0131ac Binary files /dev/null and b/handbook/build/img/docs/startguide-2.png differ diff --git a/handbook/build/img/docs/startguide-3.png b/handbook/build/img/docs/startguide-3.png new file mode 100644 index 000000000..24240cda9 Binary files /dev/null and b/handbook/build/img/docs/startguide-3.png differ diff --git a/handbook/build/img/docs/startguide-4.png b/handbook/build/img/docs/startguide-4.png new file mode 100644 index 000000000..221ba949a Binary files /dev/null and b/handbook/build/img/docs/startguide-4.png differ diff --git a/handbook/build/img/docs/startguide-5.png b/handbook/build/img/docs/startguide-5.png new file mode 100644 index 000000000..6a81f5305 Binary files /dev/null and b/handbook/build/img/docs/startguide-5.png differ diff --git a/handbook/build/img/docs/startguide-6.png b/handbook/build/img/docs/startguide-6.png new file mode 100644 index 000000000..3a85f739f Binary files /dev/null and b/handbook/build/img/docs/startguide-6.png differ diff --git a/handbook/build/img/docs/startguide-7.png b/handbook/build/img/docs/startguide-7.png new file mode 100644 index 000000000..bd0c1b668 Binary files /dev/null and b/handbook/build/img/docs/startguide-7.png differ diff --git a/handbook/build/img/docs/startguide-8.png b/handbook/build/img/docs/startguide-8.png new file mode 100644 index 000000000..f2f2f7395 Binary files /dev/null and b/handbook/build/img/docs/startguide-8.png differ diff --git a/handbook/build/img/docs/startguide-9.png b/handbook/build/img/docs/startguide-9.png new file mode 100644 index 000000000..6b4cb70b5 Binary files /dev/null and b/handbook/build/img/docs/startguide-9.png differ diff --git a/handbook/build/img/docs/upgrade-1.png b/handbook/build/img/docs/upgrade-1.png new file mode 100644 index 000000000..7ed97fbed Binary files /dev/null and b/handbook/build/img/docs/upgrade-1.png differ diff --git a/handbook/build/img/docs/upgrade-2.png b/handbook/build/img/docs/upgrade-2.png new file mode 100644 index 000000000..e887f5c39 Binary files /dev/null and b/handbook/build/img/docs/upgrade-2.png differ diff --git a/handbook/build/img/docs/upgrade-3.png b/handbook/build/img/docs/upgrade-3.png new file mode 100644 index 000000000..f6bf023c8 Binary files /dev/null and b/handbook/build/img/docs/upgrade-3.png differ diff --git a/handbook/build/img/docs/upgrade-4.png b/handbook/build/img/docs/upgrade-4.png new file mode 100644 index 000000000..4f4b108f6 Binary files /dev/null and b/handbook/build/img/docs/upgrade-4.png differ diff --git a/handbook/build/img/docs/upgrade-5.png b/handbook/build/img/docs/upgrade-5.png new file mode 100644 index 000000000..dd2298cd5 Binary files /dev/null and b/handbook/build/img/docs/upgrade-5.png differ diff --git a/handbook/build/img/docs/upgrade-6.png b/handbook/build/img/docs/upgrade-6.png new file mode 100644 index 000000000..c79cd6e7b Binary files /dev/null and b/handbook/build/img/docs/upgrade-6.png differ diff --git a/handbook/build/img/docs/webdataforwarding-1.gif b/handbook/build/img/docs/webdataforwarding-1.gif new file mode 100644 index 000000000..55d9ca5ca Binary files /dev/null and b/handbook/build/img/docs/webdataforwarding-1.gif differ diff --git a/handbook/build/img/favicon.ico b/handbook/build/img/favicon.ico new file mode 100644 index 000000000..404af9424 Binary files /dev/null and b/handbook/build/img/favicon.ico differ diff --git a/handbook/build/index.html b/handbook/build/index.html new file mode 100644 index 000000000..4a456aa5a --- /dev/null +++ b/handbook/build/index.html @@ -0,0 +1,16 @@ + + + + + +TouchSocket说明文档。 TouchSocket | TouchSocket + + + + +
+
TouchSocket
一款简单易用的基础网络通讯组件库。
两岸猿声啼不住,轻舟已过万重山。
  • Apache-2.0 宽松开源协议,商业免费授权
  • 支持 .NET Framework 4.5及以上, .NET Core3.1及以上,.NET Standard2.0及以上
  • 无依赖
  • 极速上手,极简使用
受支持平台:
TcpService service = new TcpService();
service.Connecting = (client, e) => { };//有客户端正在连接
service.Connected = (client, e) => { };//有客户端成功连接
service.Disconnected = (client, e) => { };//有客户端断开连接
service.Received = (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
client.Logger.Info($"已从{client.ID}接收到信息:{mes}");
};

service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.ConfigureContainer(a =>//容器的配置顺序应该在最前面
{
a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用)
})
.ConfigurePlugins(a =>
{
//a.Add();//此处可以添加插件
}))
.Start();//启动

开源免费/商业免费授权

⭐️ Apache-2.0 开源协议,代码在 Gitee/Github 平台托管 ⭐️

1000 +
Stars
400 +
Forks
106,125
Downloads
+ + + + \ No newline at end of file diff --git a/handbook/build/search-index.json b/handbook/build/search-index.json new file mode 100644 index 000000000..466341676 --- /dev/null +++ b/handbook/build/search-index.json @@ -0,0 +1 @@ +[{"documents":[{"i":1,"t":"说明","u":"/touchsocket/docs/","b":["文档"]},{"i":21,"t":"应用信使","u":"/touchsocket/docs/appmessenger","b":["文档","05、Core"]},{"i":26,"t":"介绍及使用","u":"/touchsocket/docs/adapterdescription","b":["文档","08、数据处理适配器"]},{"i":51,"t":"模板解析“大数据固定包头”数据适配器","u":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":58,"t":"发现、调用服务","u":"/touchsocket/docs/callxmlrpc","b":["文档","14、XmlRpc组件件"]},{"i":67,"t":"发现、调用服务","u":"/touchsocket/docs/callwebapi","b":["文档","12、WebApi组件"]},{"i":76,"t":"发现、调用服务","u":"/touchsocket/docs/calljsonrpc","b":["文档","13、JsonRpc组件"]},{"i":87,"t":"控制台行为","u":"/touchsocket/docs/consoleaction","b":["文档","05、Core"]},{"i":93,"t":"商业合作","u":"/touchsocket/docs/cooperation","b":["文档","03、支持作者及商业运营","3.3 商业项目"]},{"i":95,"t":"创建HttpClient","u":"/touchsocket/docs/createhttpclient","b":["文档","09、Http组件"]},{"i":108,"t":"创建HttpService","u":"/touchsocket/docs/createhttpservice","b":["文档","09、Http组件"]},{"i":123,"t":"创建rpc服务","u":"/touchsocket/docs/createandcallrpc","b":["文档","11、TouchRpc组件","11.5 Rpc功能"]},{"i":147,"t":"内存池","u":"/touchsocket/docs/bytepool","b":["文档","05、Core"]},{"i":160,"t":"创建TouchRpc客户端","u":"/touchsocket/docs/createtouchrpcclient","b":["文档","11、TouchRpc组件"]},{"i":176,"t":"创建TcpClient","u":"/touchsocket/docs/createtcpclient","b":["文档","06、Tcp组件"]},{"i":197,"t":"创建UdpSession","u":"/touchsocket/docs/createudpsession","b":["文档","07、Udp组件"]},{"i":208,"t":"创建TcpService","u":"/touchsocket/docs/createtcpservice","b":["文档","06、Tcp组件"]},{"i":244,"t":"创建TouchRpc服务器","u":"/touchsocket/docs/createtouchrpcservice","b":["文档","11、TouchRpc组件"]},{"i":262,"t":"说明","u":"/touchsocket/docs/adapterdemodescription","b":["文档","08、数据处理适配器","8.4 适配器案例赏析"]},{"i":266,"t":"模板解析“区间数据”数据适配器","u":"/touchsocket/docs/custombetweenanddatahandlingadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":273,"t":"创建WebSocket服务器","u":"/touchsocket/docs/createwebsocketservice","b":["文档","10、WebSocket组件"]},{"i":293,"t":"用户自定义适配器","u":"/touchsocket/docs/customdatahandlingadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":302,"t":"模板解析“固定包头”数据适配器","u":"/touchsocket/docs/customfixedheaderdatahandlingadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":309,"t":"创建WebSocket客户端","u":"/touchsocket/docs/createwebsocketclient","b":["文档","10、WebSocket组件"]},{"i":324,"t":"数据转发项目","u":"/touchsocket/docs/dataforwarding","b":["文档","03、支持作者及商业运营","3.3 商业项目"]},{"i":332,"t":"适配器完整性、性能测试","u":"/touchsocket/docs/dataadaptertester","b":["文档","08、数据处理适配器"]},{"i":341,"t":"模板解析“非固定包头”数据适配器","u":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":348,"t":"数据加密","u":"/touchsocket/docs/datasecurity","b":["文档","05、Core"]},{"i":351,"t":"工程师软件工具箱","u":"/touchsocket/docs/engineertoolbox","b":["文档","03、支持作者及商业运营","3.4 使用者项目"]},{"i":355,"t":"原始自定义适配器","u":"/touchsocket/docs/datahandleadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":366,"t":"支持作者","u":"/touchsocket/docs/donate","b":["文档","03、支持作者及商业运营"]},{"i":372,"t":"依赖属性","u":"/touchsocket/docs/dependencyproperty","b":["文档","05、Core"]},{"i":379,"t":"文件同步系统","u":"/touchsocket/docs/filesynchronization","b":["文档","03、支持作者及商业运营","3.3 商业项目"]},{"i":387,"t":"EventBus","u":"/touchsocket/docs/eventbus","b":["文档","11、TouchRpc组件"]},{"i":398,"t":"固定包头数据处理适配器","u":"/touchsocket/docs/fixedheaderpackageadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":407,"t":"文件流池","u":"/touchsocket/docs/filepool","b":["文档","05、Core"]},{"i":416,"t":"固定长度数据处理适配器","u":"/touchsocket/docs/fixedsizepackageadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":423,"t":"FPS实时游戏","u":"/touchsocket/docs/fpsgame","b":["文档","03、支持作者及商业运营","3.4 使用者项目"]},{"i":425,"t":"高性能二进制序列化","u":"/touchsocket/docs/fastbinaryformatter","b":["文档","05、Core"]},{"i":437,"t":"生成、获取代理","u":"/touchsocket/docs/generateproxy","b":["文档","11、TouchRpc组件","11.5 Rpc功能"]},{"i":456,"t":"静态页面插件","u":"/touchsocket/docs/httpstaticpageplugin","b":["文档","09、Http组件"]},{"i":459,"t":"文件传输","u":"/touchsocket/docs/httpfiletransfer","b":["文档","09、Http组件"]},{"i":466,"t":"独立使用适配器","u":"/touchsocket/docs/independentusedatahandlingadapter","b":["文档","08、数据处理适配器"]},{"i":471,"t":"日志记录器","u":"/touchsocket/docs/ilog","b":["文档","05、Core"]},{"i":482,"t":"心跳设计","u":"/touchsocket/docs/heartbeat","b":["文档","06、Tcp组件"]},{"i":496,"t":"产品及架构介绍","u":"/touchsocket/docs/jsonrpcdescription","b":["文档","13、JsonRpc组件"]},{"i":501,"t":"包序列化模式","u":"/touchsocket/docs/ipackage","b":["文档","05、Core"]},{"i":510,"t":"定义、发布、启动服务","u":"/touchsocket/docs/jsonrpcservice","b":["文档","13、JsonRpc组件"]},{"i":517,"t":"Json序列化","u":"/touchsocket/docs/jsonserialize","b":["文档","05、Core"]},{"i":524,"t":"多线程文件传输","u":"/touchsocket/docs/multithreadingfiletransfer","b":["文档","11、TouchRpc组件","11.6 文件传输"]},{"i":531,"t":"Tcp端口转发","u":"/touchsocket/docs/natservice","b":["文档","06、Tcp组件"]},{"i":540,"t":"依赖注入容器","u":"/touchsocket/docs/ioc","b":["文档","05、Core"]},{"i":557,"t":"Pipeline数据适配器","u":"/touchsocket/docs/pipelinedatahandlingadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":562,"t":"插件系统","u":"/touchsocket/docs/pluginsmanager","b":["文档","05、Core"]},{"i":575,"t":"远程文件操作","u":"/touchsocket/docs/remotefilecontrol","b":["文档","11、TouchRpc组件"]},{"i":582,"t":"远程监测、控制项目","u":"/touchsocket/docs/remotemonitoring","b":["文档","03、支持作者及商业运营","3.3 商业项目"]},{"i":591,"t":"断线重连","u":"/touchsocket/docs/reconnection","b":["文档","06、Tcp组件"]},{"i":598,"t":"其他相关功能类","u":"/touchsocket/docs/othercore","b":["文档","05、Core"]},{"i":611,"t":"服务器重置ID","u":"/touchsocket/docs/resetid","b":["文档","06、Tcp组件"]},{"i":624,"t":"b.远程流访问","u":"/touchsocket/docs/remotestreamaccess","b":["文档","11、TouchRpc组件"]},{"i":637,"t":"调用上下文","u":"/touchsocket/docs/rpcallcontext","b":["文档","11、TouchRpc组件","11.5 Rpc功能"]},{"i":644,"t":"Rpc服务AOP","u":"/touchsocket/docs/rpcactionfilter","b":["文档","11、TouchRpc组件","11.5 Rpc功能"]},{"i":651,"t":"调用配置","u":"/touchsocket/docs/rpcoption","b":["文档","11、TouchRpc组件","11.5 Rpc功能"]},{"i":664,"t":"Rpc大数据流式传输","u":"/touchsocket/docs/rpcstream","b":["文档","11、TouchRpc组件","11.5 Rpc功能"]},{"i":675,"t":"序列化选择器","u":"/touchsocket/docs/serializationselector","b":["文档","11、TouchRpc组件","11.5 Rpc功能"]},{"i":687,"t":"小文件传输","u":"/touchsocket/docs/smallfiletransfer","b":["文档","11、TouchRpc组件","11.6 文件传输"]},{"i":695,"t":"国网输电i1标准版","u":"/touchsocket/docs/stategridtransmission","b":["文档","08、数据处理适配器","8.4 适配器案例赏析"]},{"i":703,"t":"入门指南","u":"/touchsocket/docs/startguide","b":["文档"]},{"i":721,"t":"Stream传输","u":"/touchsocket/docs/streamtransfer","b":["文档","11、TouchRpc组件"]},{"i":728,"t":"其他场景应用","u":"/touchsocket/docs/tcpother","b":["文档","06、Tcp组件"]},{"i":730,"t":"命令行执行插件","u":"/touchsocket/docs/tcpcommandlineplugin","b":["文档","06、Tcp组件"]},{"i":739,"t":"终止因子分割数据处理适配器","u":"/touchsocket/docs/terminatorpackageadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":746,"t":"三元组编码(TLV)适配器","u":"/touchsocket/docs/tlvdatahandlingadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]},{"i":759,"t":"大小端转换器","u":"/touchsocket/docs/touchsocketbitconverter","b":["文档","05、Core"]},{"i":768,"t":"基础功能","u":"/touchsocket/docs/touchrpcbase","b":["文档","11、TouchRpc组件"]},{"i":781,"t":"产品及架构介绍","u":"/touchsocket/docs/touchrpcdescription","b":["文档","11、TouchRpc组件"]},{"i":807,"t":"原始自定义适配器","u":"/touchsocket/docs/udpdatahandlingadapter","b":["文档","08、数据处理适配器","8.3 Udp适配器"]},{"i":812,"t":"传输大于64K的数据","u":"/touchsocket/docs/udptransmitbigdata","b":["文档","07、Udp组件"]},{"i":821,"t":"传输文件","u":"/touchsocket/docs/transferfile","b":["文档","11、TouchRpc组件","11.6 文件传输"]},{"i":837,"t":"组播、广播","u":"/touchsocket/docs/udpbroadcast","b":["文档","07、Udp组件"]},{"i":852,"t":"同步请求","u":"/touchsocket/docs/waitingclient","b":["文档","06、Tcp组件"]},{"i":860,"t":"产品及架构介绍","u":"/touchsocket/docs/webapidescription","b":["文档","12、WebApi组件"]},{"i":865,"t":"历史更新","u":"/touchsocket/docs/upgrade","b":["文档"]},{"i":892,"t":"定义、发布、启动服务","u":"/touchsocket/docs/webapiservice","b":["文档","12、WebApi组件"]},{"i":897,"t":"Web数据转发Winform项目","u":"/touchsocket/docs/webdataforwarding","b":["文档","03、支持作者及商业运营","3.3 商业项目"]},{"i":905,"t":"WPF界面、文件传输项目","u":"/touchsocket/docs/wpfuifiletransfer","b":["文档","03、支持作者及商业运营","3.3 商业项目"]},{"i":907,"t":"产品及架构介绍","u":"/touchsocket/docs/websocketdescription","b":["文档","10、WebSocket组件"]},{"i":916,"t":"产品及架构介绍","u":"/touchsocket/docs/xmlrpcdescription","b":["文档","14、XmlRpc组件件"]},{"i":922,"t":"基于WS的JsonRpc","u":"/touchsocket/docs/wsjsonrpc","b":["文档","10、WebSocket组件"]},{"i":923,"t":"WSCommandLinePlugin","u":"/touchsocket/docs/wscommandlineplugin","b":["文档","10、WebSocket组件"]},{"i":926,"t":"定义、发布、启动服务","u":"/touchsocket/docs/xmlrpcservice","b":["文档","14、XmlRpc组件件"]},{"i":933,"t":"企业版相关","u":"/touchsocket/docs/enterprise","b":["文档","03、支持作者及商业运营"]},{"i":974,"t":"a.正常数据处理适配器","u":"/touchsocket/docs/normaldatahandlingadapter","b":["文档","08、数据处理适配器","8.2 Tcp适配器"]}],"index":{"version":"2.3.9","fields":["t"],"fieldVectors":[["t/1",[0,4.974]],["t/21",[1,4.18,2,4.769]],["t/26",[3,3.079,4,4.18]],["t/51",[5,1.79,6,1.79,7,2.136,8,2.13,9,1.672,10,1.79,11,1.062]],["t/58",[12,3.271,13,2.822,14,2.389]],["t/67",[12,3.271,13,2.822,14,2.389]],["t/76",[12,3.271,13,2.822,14,2.389]],["t/87",[15,4.769,16,4.769]],["t/93",[17,4.769,18,4.769]],["t/95",[19,2.526,20,4.769]],["t/108",[19,2.526,21,4.769]],["t/123",[14,2.389,19,2.179,22,3.271]],["t/147",[23,4.769,24,4.18]],["t/160",[19,2.179,25,3.606,26,3.606]],["t/176",[19,2.526,27,4.769]],["t/197",[19,2.526,28,4.769]],["t/208",[19,2.526,29,4.769]],["t/244",[19,2.179,25,3.606,30,3.271]],["t/262",[0,4.974]],["t/266",[5,2.139,6,2.139,8,2.444,11,1.268,31,2.912]],["t/273",[19,2.179,30,3.271,32,3.606]],["t/293",[11,1.792,33,4.113,34,3.271]],["t/302",[5,2.139,6,2.139,8,1.613,9,1.998,10,2.139,11,1.268]],["t/309",[19,2.179,26,3.606,32,3.606]],["t/324",[8,2.278,35,3.271,36,3.021]],["t/332",[11,1.575,37,3.616,38,3.616,39,3.616]],["t/341",[5,1.949,6,1.949,8,1.47,9,1.82,10,1.949,11,1.156,40,2.654]],["t/348",[8,2.642,41,4.769]],["t/351",[42,4.113,43,4.113,44,4.113]],["t/355",[11,1.792,34,3.271,45,3.606]],["t/366",[46,4.769,47,4.769]],["t/372",[48,4.18,49,4.769]],["t/379",[50,3.021,51,3.606,52,3.606]],["t/387",[53,5.674]],["t/398",[9,2.481,10,2.656,11,1.575,54,2.656]],["t/407",[24,3.606,50,3.021,55,3.606]],["t/416",[9,2.481,11,1.575,54,2.656,56,3.616]],["t/423",[57,4.113,58,4.113,59,4.113]],["t/425",[60,4.113,61,4.113,62,3.021]],["t/437",[63,4.113,64,4.113,65,4.113]],["t/456",[66,4.113,67,4.113,68,3.271]],["t/459",[69,4.168]],["t/466",[4,3.606,11,1.792,70,4.113]],["t/471",[71,4.769,72,4.769]],["t/482",[73,4.769,74,4.769]],["t/496",[3,2.656,75,2.822,76,2.822]],["t/501",[62,3.021,77,4.113,78,4.113]],["t/510",[14,2.1,79,2.876,80,2.876,81,2.876]],["t/517",[62,3.503,82,4.769]],["t/524",[69,3.503,83,4.769]],["t/531",[35,3.271,84,4.113,85,4.113]],["t/540",[48,3.606,86,4.113,87,4.113]],["t/557",[8,2.278,11,1.792,88,4.113]],["t/562",[52,4.18,68,3.793]],["t/575",[50,3.021,89,3.271,90,4.113]],["t/582",[36,2.656,89,2.876,91,3.616,92,3.616]],["t/591",[93,4.113,94,4.113,95,4.113]],["t/598",[96,3.17,97,3.17,98,3.17,99,3.616]],["t/611",[30,3.271,100,4.113,101,4.113]],["t/624",[55,3.17,89,2.876,102,3.616,103,3.616]],["t/637",[13,3.272,104,4.769]],["t/644",[14,2.389,22,3.271,105,4.113]],["t/651",[13,3.272,106,4.769]],["t/664",[7,2.828,22,2.565,107,3.226,108,3.226,109,2.369]],["t/675",[62,3.503,110,4.769]],["t/687",[69,4.168]],["t/695",[111,3.226,112,3.226,113,3.226,114,3.226,115,3.226]],["t/703",[116,4.769,117,4.769]],["t/721",[109,3.503,118,4.769]],["t/728",[1,3.606,96,3.606,119,4.113]],["t/730",[68,3.271,120,4.113,121,4.113]],["t/739",[11,1.405,54,2.369,122,3.226,123,3.226,124,3.226]],["t/746",[11,1.575,125,3.616,126,3.616,127,3.616]],["t/759",[128,4.113,129,4.113,130,4.113]],["t/768",[98,4.18,131,4.769]],["t/781",[3,2.656,75,2.822,76,2.822]],["t/807",[11,1.792,34,3.271,45,3.606]],["t/812",[8,2.003,109,2.656,132,3.616,133,3.616]],["t/821",[50,3.503,109,3.503]],["t/837",[134,4.113,135,4.113,136,4.113]],["t/852",[51,4.18,137,4.769]],["t/860",[3,2.656,75,2.822,76,2.822]],["t/865",[138,4.769,139,4.769]],["t/892",[14,2.1,79,2.876,80,2.876,81,2.876]],["t/897",[8,1.787,35,2.565,36,2.369,140,3.226,141,3.226]],["t/905",[36,2.656,69,2.656,142,3.616,143,3.616]],["t/907",[3,2.656,75,2.822,76,2.822]],["t/916",[3,2.656,75,2.822,76,2.822]],["t/922",[144,4.113,145,4.113,146,4.113]],["t/923",[147,5.674]],["t/926",[14,2.1,79,2.876,80,2.876,81,2.876]],["t/933",[97,3.606,148,4.113,149,4.113]],["t/974",[11,1.792,54,3.021,150,4.113]]],"invertedIndex":[["64k",{"_index":133,"t":{"812":{"position":[[4,3]]}}}],["aop",{"_index":105,"t":{"644":{"position":[[5,3]]}}}],["b",{"_index":102,"t":{"624":{"position":[[0,1]]}}}],["eventbu",{"_index":53,"t":{"387":{"position":[[0,8]]}}}],["fp",{"_index":57,"t":{"423":{"position":[[0,3]]}}}],["httpclient",{"_index":20,"t":{"95":{"position":[[2,10]]}}}],["httpservic",{"_index":21,"t":{"108":{"position":[[2,11]]}}}],["i1",{"_index":114,"t":{"695":{"position":[[4,2]]}}}],["id",{"_index":101,"t":{"611":{"position":[[5,2]]}}}],["json",{"_index":82,"t":{"517":{"position":[[0,4]]}}}],["jsonrpc",{"_index":146,"t":{"922":{"position":[[5,7]]}}}],["pipelin",{"_index":88,"t":{"557":{"position":[[0,8]]}}}],["rpc",{"_index":22,"t":{"123":{"position":[[2,3]]},"644":{"position":[[0,3]]},"664":{"position":[[0,3]]}}}],["stream",{"_index":118,"t":{"721":{"position":[[0,6]]}}}],["tcp",{"_index":84,"t":{"531":{"position":[[0,3]]}}}],["tcpclient",{"_index":27,"t":{"176":{"position":[[2,9]]}}}],["tcpservic",{"_index":29,"t":{"208":{"position":[[2,10]]}}}],["tlv",{"_index":127,"t":{"746":{"position":[[6,3]]}}}],["touchrpc",{"_index":25,"t":{"160":{"position":[[2,8]]},"244":{"position":[[2,8]]}}}],["udpsess",{"_index":28,"t":{"197":{"position":[[2,10]]}}}],["web",{"_index":140,"t":{"897":{"position":[[0,3]]}}}],["websocket",{"_index":32,"t":{"273":{"position":[[2,9]]},"309":{"position":[[2,9]]}}}],["winform",{"_index":141,"t":{"897":{"position":[[7,7]]}}}],["wpf",{"_index":142,"t":{"905":{"position":[[0,3]]}}}],["ws",{"_index":145,"t":{"922":{"position":[[2,2]]}}}],["wscommandlineplugin",{"_index":147,"t":{"923":{"position":[[0,19]]}}}],["三元组",{"_index":125,"t":{"746":{"position":[[0,3]]}}}],["上下文",{"_index":104,"t":{"637":{"position":[[2,3]]}}}],["二进制",{"_index":61,"t":{"425":{"position":[[3,3]]}}}],["产品",{"_index":75,"t":{"496":{"position":[[0,2]]},"781":{"position":[[0,2]]},"860":{"position":[[0,2]]},"907":{"position":[[0,2]]},"916":{"position":[[0,2]]}}}],["介绍",{"_index":3,"t":{"26":{"position":[[0,2]]},"496":{"position":[[5,2]]},"781":{"position":[[5,2]]},"860":{"position":[[5,2]]},"907":{"position":[[5,2]]},"916":{"position":[[5,2]]}}}],["代理",{"_index":65,"t":{"437":{"position":[[5,2]]}}}],["企业",{"_index":148,"t":{"933":{"position":[[0,2]]}}}],["传输",{"_index":109,"t":{"664":{"position":[[8,2]]},"721":{"position":[[6,2]]},"812":{"position":[[0,2]]},"821":{"position":[[0,2]]}}}],["作者",{"_index":47,"t":{"366":{"position":[[2,2]]}}}],["使用",{"_index":4,"t":{"26":{"position":[[3,2]]},"466":{"position":[[2,2]]}}}],["依赖",{"_index":48,"t":{"372":{"position":[[0,2]]},"540":{"position":[[0,2]]}}}],["信使",{"_index":2,"t":{"21":{"position":[[2,2]]}}}],["入门",{"_index":116,"t":{"703":{"position":[[0,2]]}}}],["其他",{"_index":96,"t":{"598":{"position":[[0,2]]},"728":{"position":[[0,2]]}}}],["内存",{"_index":23,"t":{"147":{"position":[[0,2]]}}}],["分割",{"_index":124,"t":{"739":{"position":[[4,2]]}}}],["创建",{"_index":19,"t":{"95":{"position":[[0,2]]},"108":{"position":[[0,2]]},"123":{"position":[[0,2]]},"160":{"position":[[0,2]]},"176":{"position":[[0,2]]},"197":{"position":[[0,2]]},"208":{"position":[[0,2]]},"244":{"position":[[0,2]]},"273":{"position":[[0,2]]},"309":{"position":[[0,2]]}}}],["功能",{"_index":98,"t":{"598":{"position":[[4,2]]},"768":{"position":[[2,2]]}}}],["加密",{"_index":41,"t":{"348":{"position":[[2,2]]}}}],["包",{"_index":77,"t":{"501":{"position":[[0,1]]}}}],["包头",{"_index":10,"t":{"51":{"position":[[10,2]]},"302":{"position":[[7,2]]},"341":{"position":[[8,2]]},"398":{"position":[[2,2]]}}}],["区间",{"_index":31,"t":{"266":{"position":[[5,2]]}}}],["历史",{"_index":138,"t":{"865":{"position":[[0,2]]}}}],["原始",{"_index":45,"t":{"355":{"position":[[0,2]]},"807":{"position":[[0,2]]}}}],["发布",{"_index":80,"t":{"510":{"position":[[3,2]]},"892":{"position":[[3,2]]},"926":{"position":[[3,2]]}}}],["发现",{"_index":12,"t":{"58":{"position":[[0,2]]},"67":{"position":[[0,2]]},"76":{"position":[[0,2]]}}}],["合作",{"_index":18,"t":{"93":{"position":[[2,2]]}}}],["同步",{"_index":51,"t":{"379":{"position":[[2,2]]},"852":{"position":[[0,2]]}}}],["启动",{"_index":81,"t":{"510":{"position":[[6,2]]},"892":{"position":[[6,2]]},"926":{"position":[[6,2]]}}}],["命令行",{"_index":120,"t":{"730":{"position":[[0,3]]}}}],["商业",{"_index":17,"t":{"93":{"position":[[0,2]]}}}],["因子",{"_index":123,"t":{"739":{"position":[[2,2]]}}}],["固定",{"_index":9,"t":{"51":{"position":[[8,2]]},"302":{"position":[[5,2]]},"341":{"position":[[6,2]]},"398":{"position":[[0,2]]},"416":{"position":[[0,2]]}}}],["国",{"_index":111,"t":{"695":{"position":[[0,1]]}}}],["场景",{"_index":119,"t":{"728":{"position":[[2,2]]}}}],["基于",{"_index":144,"t":{"922":{"position":[[0,2]]}}}],["基础",{"_index":131,"t":{"768":{"position":[[0,2]]}}}],["多线程",{"_index":83,"t":{"524":{"position":[[0,3]]}}}],["大",{"_index":7,"t":{"51":{"position":[[5,1]]},"664":{"position":[[3,1]]}}}],["大于",{"_index":132,"t":{"812":{"position":[[2,2]]}}}],["大小",{"_index":128,"t":{"759":{"position":[[0,2]]}}}],["完整性",{"_index":37,"t":{"332":{"position":[[3,3]]}}}],["定义",{"_index":79,"t":{"510":{"position":[[0,2]]},"892":{"position":[[0,2]]},"926":{"position":[[0,2]]}}}],["实时",{"_index":58,"t":{"423":{"position":[[3,2]]}}}],["客户端",{"_index":26,"t":{"160":{"position":[[10,3]]},"309":{"position":[[11,3]]}}}],["容器",{"_index":87,"t":{"540":{"position":[[4,2]]}}}],["属性",{"_index":49,"t":{"372":{"position":[[2,2]]}}}],["工具箱",{"_index":44,"t":{"351":{"position":[[5,3]]}}}],["工程师",{"_index":42,"t":{"351":{"position":[[0,3]]}}}],["广播",{"_index":136,"t":{"837":{"position":[[3,2]]}}}],["序列化",{"_index":62,"t":{"425":{"position":[[6,3]]},"501":{"position":[[1,3]]},"517":{"position":[[4,3]]},"675":{"position":[[0,3]]}}}],["应用",{"_index":1,"t":{"21":{"position":[[0,2]]},"728":{"position":[[4,2]]}}}],["式",{"_index":108,"t":{"664":{"position":[[7,1]]}}}],["心跳",{"_index":73,"t":{"482":{"position":[[0,2]]}}}],["性能",{"_index":38,"t":{"332":{"position":[[7,2]]}}}],["执行",{"_index":121,"t":{"730":{"position":[[3,2]]}}}],["指南",{"_index":117,"t":{"703":{"position":[[2,2]]}}}],["控制",{"_index":92,"t":{"582":{"position":[[5,2]]}}}],["控制台",{"_index":15,"t":{"87":{"position":[[0,3]]}}}],["插件",{"_index":68,"t":{"456":{"position":[[4,2]]},"562":{"position":[[0,2]]},"730":{"position":[[5,2]]}}}],["播",{"_index":135,"t":{"837":{"position":[[1,1]]}}}],["操作",{"_index":90,"t":{"575":{"position":[[4,2]]}}}],["支持",{"_index":46,"t":{"366":{"position":[[0,2]]}}}],["数据",{"_index":8,"t":{"51":{"position":[[6,2],[13,2]]},"266":{"position":[[7,2],[10,2]]},"302":{"position":[[10,2]]},"324":{"position":[[0,2]]},"341":{"position":[[11,2]]},"348":{"position":[[0,2]]},"557":{"position":[[8,2]]},"812":{"position":[[8,2]]},"897":{"position":[[3,2]]}}}],["数据处理",{"_index":54,"t":{"398":{"position":[[4,4]]},"416":{"position":[[4,4]]},"739":{"position":[[6,4]]},"974":{"position":[[4,4]]}}}],["数据流",{"_index":107,"t":{"664":{"position":[[4,3]]}}}],["文件",{"_index":50,"t":{"379":{"position":[[0,2]]},"407":{"position":[[0,2]]},"575":{"position":[[2,2]]},"821":{"position":[[2,2]]}}}],["文件传输",{"_index":69,"t":{"459":{"position":[[0,4]]},"524":{"position":[[3,4]]},"687":{"position":[[1,4]]},"905":{"position":[[6,4]]}}}],["断线",{"_index":93,"t":{"591":{"position":[[0,2]]}}}],["日志",{"_index":71,"t":{"471":{"position":[[0,2]]}}}],["更新",{"_index":139,"t":{"865":{"position":[[2,2]]}}}],["服务",{"_index":14,"t":{"58":{"position":[[5,2]]},"67":{"position":[[5,2]]},"76":{"position":[[5,2]]},"123":{"position":[[5,2]]},"510":{"position":[[8,2]]},"644":{"position":[[3,2]]},"892":{"position":[[8,2]]},"926":{"position":[[8,2]]}}}],["服务器",{"_index":30,"t":{"244":{"position":[[10,3]]},"273":{"position":[[11,3]]},"611":{"position":[[0,3]]}}}],["架构",{"_index":76,"t":{"496":{"position":[[3,2]]},"781":{"position":[[3,2]]},"860":{"position":[[3,2]]},"907":{"position":[[3,2]]},"916":{"position":[[3,2]]}}}],["标准版",{"_index":115,"t":{"695":{"position":[[6,3]]}}}],["模式",{"_index":78,"t":{"501":{"position":[[4,2]]}}}],["模板",{"_index":5,"t":{"51":{"position":[[0,2]]},"266":{"position":[[0,2]]},"302":{"position":[[0,2]]},"341":{"position":[[0,2]]}}}],["正常",{"_index":150,"t":{"974":{"position":[[2,2]]}}}],["池",{"_index":24,"t":{"147":{"position":[[2,1]]},"407":{"position":[[3,1]]}}}],["注入",{"_index":86,"t":{"540":{"position":[[2,2]]}}}],["流",{"_index":55,"t":{"407":{"position":[[2,1]]},"624":{"position":[[4,1]]}}}],["测试",{"_index":39,"t":{"332":{"position":[[9,2]]}}}],["游戏",{"_index":59,"t":{"423":{"position":[[5,2]]}}}],["版",{"_index":149,"t":{"933":{"position":[[2,1]]}}}],["独立",{"_index":70,"t":{"466":{"position":[[0,2]]}}}],["生成",{"_index":63,"t":{"437":{"position":[[0,2]]}}}],["用户",{"_index":33,"t":{"293":{"position":[[0,2]]}}}],["界面",{"_index":143,"t":{"905":{"position":[[3,2]]}}}],["监测",{"_index":91,"t":{"582":{"position":[[2,2]]}}}],["相关",{"_index":97,"t":{"598":{"position":[[2,2]]},"933":{"position":[[3,2]]}}}],["端",{"_index":129,"t":{"759":{"position":[[2,1]]}}}],["端口",{"_index":85,"t":{"531":{"position":[[3,2]]}}}],["类",{"_index":99,"t":{"598":{"position":[[6,1]]}}}],["系统",{"_index":52,"t":{"379":{"position":[[4,2]]},"562":{"position":[[2,2]]}}}],["组",{"_index":134,"t":{"837":{"position":[[0,1]]}}}],["终止",{"_index":122,"t":{"739":{"position":[[0,2]]}}}],["编码",{"_index":126,"t":{"746":{"position":[[3,2]]}}}],["网",{"_index":112,"t":{"695":{"position":[[1,1]]}}}],["自定义",{"_index":34,"t":{"293":{"position":[[2,3]]},"355":{"position":[[2,3]]},"807":{"position":[[2,3]]}}}],["获取",{"_index":64,"t":{"437":{"position":[[3,2]]}}}],["行为",{"_index":16,"t":{"87":{"position":[[3,2]]}}}],["解析",{"_index":6,"t":{"51":{"position":[[2,2]]},"266":{"position":[[2,2]]},"302":{"position":[[2,2]]},"341":{"position":[[2,2]]}}}],["记录器",{"_index":72,"t":{"471":{"position":[[2,3]]}}}],["设计",{"_index":74,"t":{"482":{"position":[[2,2]]}}}],["访问",{"_index":103,"t":{"624":{"position":[[5,2]]}}}],["说明",{"_index":0,"t":{"1":{"position":[[0,2]]},"262":{"position":[[0,2]]}}}],["请求",{"_index":137,"t":{"852":{"position":[[2,2]]}}}],["调用",{"_index":13,"t":{"58":{"position":[[3,2]]},"67":{"position":[[3,2]]},"76":{"position":[[3,2]]},"637":{"position":[[0,2]]},"651":{"position":[[0,2]]}}}],["转发",{"_index":35,"t":{"324":{"position":[[2,2]]},"531":{"position":[[5,2]]},"897":{"position":[[5,2]]}}}],["转换器",{"_index":130,"t":{"759":{"position":[[3,3]]}}}],["软件",{"_index":43,"t":{"351":{"position":[[3,2]]}}}],["输电",{"_index":113,"t":{"695":{"position":[[2,2]]}}}],["远程",{"_index":89,"t":{"575":{"position":[[0,2]]},"582":{"position":[[0,2]]},"624":{"position":[[2,2]]}}}],["连",{"_index":95,"t":{"591":{"position":[[3,1]]}}}],["适配器",{"_index":11,"t":{"51":{"position":[[15,3]]},"266":{"position":[[12,3]]},"293":{"position":[[5,3]]},"302":{"position":[[12,3]]},"332":{"position":[[0,3]]},"341":{"position":[[13,3]]},"355":{"position":[[5,3]]},"398":{"position":[[8,3]]},"416":{"position":[[8,3]]},"466":{"position":[[4,3]]},"557":{"position":[[10,3]]},"739":{"position":[[10,3]]},"746":{"position":[[10,3]]},"807":{"position":[[5,3]]},"974":{"position":[[8,3]]}}}],["选择器",{"_index":110,"t":{"675":{"position":[[3,3]]}}}],["配置",{"_index":106,"t":{"651":{"position":[[2,2]]}}}],["重",{"_index":94,"t":{"591":{"position":[[2,1]]}}}],["重置",{"_index":100,"t":{"611":{"position":[[3,2]]}}}],["长度",{"_index":56,"t":{"416":{"position":[[2,2]]}}}],["静态",{"_index":66,"t":{"456":{"position":[[0,2]]}}}],["非",{"_index":40,"t":{"341":{"position":[[5,1]]}}}],["页面",{"_index":67,"t":{"456":{"position":[[2,2]]}}}],["项目",{"_index":36,"t":{"324":{"position":[[4,2]]},"582":{"position":[[7,2]]},"897":{"position":[[14,2]]},"905":{"position":[[10,2]]}}}],["高性能",{"_index":60,"t":{"425":{"position":[[0,3]]}}}]],"pipeline":["stemmer"]}},{"documents":[{"i":2,"t":"当前版本","u":"/touchsocket/docs/","h":"#当前版本","p":1},{"i":4,"t":"使用前必要阅读","u":"/touchsocket/docs/","h":"#使用前必要阅读","p":1},{"i":6,"t":"Apache License 2.0 开源协议简述","u":"/touchsocket/docs/","h":"","p":1},{"i":8,"t":"附加协议","u":"/touchsocket/docs/","h":"","p":1},{"i":9,"t":"个人使用须知:","u":"/touchsocket/docs/","h":"#个人使用须知","p":1},{"i":11,"t":"二次开发须知:","u":"/touchsocket/docs/","h":"#二次开发须知","p":1},{"i":13,"t":"盈利性(商业)用途使用须知:","u":"/touchsocket/docs/","h":"#盈利性商业用途使用须知","p":1},{"i":15,"t":"TouchSocketPro 商用许可","u":"/touchsocket/docs/","h":"#touchsocketpro-商用许可","p":1},{"i":17,"t":"TouchSocketPro 功能部分遵循:","u":"/touchsocket/docs/","h":"#touchsocketpro-功能部分遵循","p":1},{"i":19,"t":"免责申明","u":"/touchsocket/docs/","h":"","p":1},{"i":22,"t":"一、说明","u":"/touchsocket/docs/appmessenger","h":"#一说明","p":21},{"i":24,"t":"二、使用","u":"/touchsocket/docs/appmessenger","h":"#二使用","p":21},{"i":27,"t":"说明","u":"/touchsocket/docs/adapterdescription","h":"#说明","p":26},{"i":29,"t":"设计架构","u":"/touchsocket/docs/adapterdescription","h":"#设计架构","p":26},{"i":30,"t":"工作逻辑","u":"/touchsocket/docs/adapterdescription","h":"#工作逻辑","p":26},{"i":31,"t":"数据逻辑","u":"/touchsocket/docs/adapterdescription","h":"#数据逻辑","p":26},{"i":33,"t":"设计解释","u":"/touchsocket/docs/adapterdescription","h":"#设计解释","p":26},{"i":35,"t":"三、TCP使用","u":"/touchsocket/docs/adapterdescription","h":"#三tcp使用","p":26},{"i":37,"t":"3.1 在Config配置中使用","u":"/touchsocket/docs/adapterdescription","h":"#31-在config配置中使用","p":26},{"i":39,"t":"3.2 订阅Connecting相关事件","u":"/touchsocket/docs/adapterdescription","h":"#32-订阅connecting相关事件","p":26},{"i":41,"t":"3.3 使用插件,代替Connecting相关事件实现","u":"/touchsocket/docs/adapterdescription","h":"#33-使用插件代替connecting相关事件实现","p":26},{"i":43,"t":"3.4 任意时刻设置","u":"/touchsocket/docs/adapterdescription","h":"#34-任意时刻设置","p":26},{"i":45,"t":"四、UDP使用插件","u":"/touchsocket/docs/adapterdescription","h":"#四udp使用插件","p":26},{"i":47,"t":"五、限制使用","u":"/touchsocket/docs/adapterdescription","h":"#五限制使用","p":26},{"i":49,"t":"六、缓存超时(仅Tcp适配器)","u":"/touchsocket/docs/adapterdescription","h":"#六缓存超时仅tcp适配器","p":26},{"i":52,"t":"一、说明","u":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","h":"#一说明","p":51},{"i":54,"t":"二、特点","u":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","h":"#二特点","p":51},{"i":56,"t":"三、使用","u":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","h":"#三使用","p":51},{"i":59,"t":"直接调用","u":"/touchsocket/docs/callxmlrpc","h":"#直接调用","p":58},{"i":61,"t":"代理调用RPC","u":"/touchsocket/docs/callxmlrpc","h":"#代理调用rpc","p":58},{"i":63,"t":"如何生成获取代理文件?","u":"/touchsocket/docs/callxmlrpc","h":"#如何生成获取代理文件","p":58},{"i":65,"t":"调用","u":"/touchsocket/docs/callxmlrpc","h":"#调用","p":58},{"i":68,"t":"直接调用","u":"/touchsocket/docs/callwebapi","h":"#直接调用","p":67},{"i":70,"t":"代理调用RPC","u":"/touchsocket/docs/callwebapi","h":"#代理调用rpc","p":67},{"i":72,"t":"如何生成获取代理文件?","u":"/touchsocket/docs/callwebapi","h":"#如何生成获取代理文件","p":67},{"i":74,"t":"调用","u":"/touchsocket/docs/callwebapi","h":"#调用","p":67},{"i":77,"t":"一、直接调用","u":"/touchsocket/docs/calljsonrpc","h":"#一直接调用","p":76},{"i":79,"t":"二、客户端直接调用","u":"/touchsocket/docs/calljsonrpc","h":"#二客户端直接调用","p":76},{"i":81,"t":"代理调用RPC","u":"/touchsocket/docs/calljsonrpc","h":"#代理调用rpc","p":76},{"i":83,"t":"如何生成获取代理文件?","u":"/touchsocket/docs/calljsonrpc","h":"#如何生成获取代理文件","p":76},{"i":85,"t":"调用","u":"/touchsocket/docs/calljsonrpc","h":"#调用","p":76},{"i":88,"t":"一、说明","u":"/touchsocket/docs/consoleaction","h":"#一说明","p":87},{"i":90,"t":"二、使用","u":"/touchsocket/docs/consoleaction","h":"#二使用","p":87},{"i":92,"t":"三、效果图","u":"/touchsocket/docs/consoleaction","h":"#三效果图","p":87},{"i":96,"t":"说明","u":"/touchsocket/docs/createhttpclient","h":"#说明","p":95},{"i":98,"t":"可配置项","u":"/touchsocket/docs/createhttpclient","h":"#可配置项","p":95},{"i":100,"t":"支持插件接口","u":"/touchsocket/docs/createhttpclient","h":"#支持插件接口","p":95},{"i":103,"t":"创建HttpsClient","u":"/touchsocket/docs/createhttpclient","h":"#创建httpsclient","p":95},{"i":105,"t":"主要方法简介","u":"/touchsocket/docs/createhttpclient","h":"#主要方法简介","p":95},{"i":107,"t":"","u":"/touchsocket/docs/createhttpclient","h":"","p":95},{"i":109,"t":"一、说明","u":"/touchsocket/docs/createhttpservice","h":"#一说明","p":108},{"i":111,"t":"二、产品特点","u":"/touchsocket/docs/createhttpservice","h":"#二产品特点","p":108},{"i":113,"t":"三、产品应用场景","u":"/touchsocket/docs/createhttpservice","h":"#三产品应用场景","p":108},{"i":115,"t":"四、服务器架构","u":"/touchsocket/docs/createhttpservice","h":"#四服务器架构","p":108},{"i":117,"t":"五、支持插件接口","u":"/touchsocket/docs/createhttpservice","h":"#五支持插件接口","p":108},{"i":119,"t":"六、创建HttpService","u":"/touchsocket/docs/createhttpservice","h":"#六创建httpservice","p":108},{"i":121,"t":"七、创建加密Ssl的HttpsService","u":"/touchsocket/docs/createhttpservice","h":"#七创建加密ssl的httpsservice","p":108},{"i":124,"t":"一、说明","u":"/touchsocket/docs/createandcallrpc","h":"#一说明","p":123},{"i":126,"t":"二、定义服务","u":"/touchsocket/docs/createandcallrpc","h":"#二定义服务","p":123},{"i":128,"t":"三、启动Rpc服务器","u":"/touchsocket/docs/createandcallrpc","h":"#三启动rpc服务器","p":123},{"i":130,"t":"四、调用Rpc","u":"/touchsocket/docs/createandcallrpc","h":"#四调用rpc","p":123},{"i":131,"t":"4.1 直接调用","u":"/touchsocket/docs/createandcallrpc","h":"#41-直接调用","p":123},{"i":133,"t":"4.2、代理调用","u":"/touchsocket/docs/createandcallrpc","h":"#42代理调用","p":123},{"i":135,"t":"五、反向Rpc","u":"/touchsocket/docs/createandcallrpc","h":"#五反向rpc","p":123},{"i":137,"t":"5.1 定义、发布反向RPC服务","u":"/touchsocket/docs/createandcallrpc","h":"#51-定义发布反向rpc服务","p":123},{"i":139,"t":"5.2 调用反向RPC","u":"/touchsocket/docs/createandcallrpc","h":"#52-调用反向rpc","p":123},{"i":141,"t":"5.2.1 通过服务器直接获取","u":"/touchsocket/docs/createandcallrpc","h":"#521-通过服务器直接获取","p":123},{"i":143,"t":"六、客户端互Call RPC","u":"/touchsocket/docs/createandcallrpc","h":"#六客户端互call-rpc","p":123},{"i":145,"t":"6.1 互Call RPC","u":"/touchsocket/docs/createandcallrpc","h":"#61-互call-rpc","p":123},{"i":148,"t":"一、说明","u":"/touchsocket/docs/bytepool","h":"#一说明","p":147},{"i":150,"t":"二、功能","u":"/touchsocket/docs/bytepool","h":"#二功能","p":147},{"i":152,"t":"三、创建","u":"/touchsocket/docs/bytepool","h":"#三创建","p":147},{"i":154,"t":"四、使用","u":"/touchsocket/docs/bytepool","h":"#四使用","p":147},{"i":156,"t":"4.1 写入、读取数据对象","u":"/touchsocket/docs/bytepool","h":"#41-写入读取数据对象","p":147},{"i":158,"t":"4.2 多线程同步协作(Hold)","u":"/touchsocket/docs/bytepool","h":"#42-多线程同步协作hold","p":147},{"i":161,"t":"一、说明","u":"/touchsocket/docs/createtouchrpcclient","h":"#一说明","p":160},{"i":163,"t":"二、可配置项","u":"/touchsocket/docs/createtouchrpcclient","h":"#二可配置项","p":160},{"i":165,"t":"三、支持插件接口","u":"/touchsocket/docs/createtouchrpcclient","h":"#三支持插件接口","p":160},{"i":167,"t":"四、创建","u":"/touchsocket/docs/createtouchrpcclient","h":"#四创建","p":160},{"i":168,"t":"4.1 TcpTouchRpcClient","u":"/touchsocket/docs/createtouchrpcclient","h":"#41-tcptouchrpcclient","p":160},{"i":170,"t":"4.2 HttpTouchRpcClient","u":"/touchsocket/docs/createtouchrpcclient","h":"#42-httptouchrpcclient","p":160},{"i":172,"t":"4.3 UdpTouchRpc","u":"/touchsocket/docs/createtouchrpcclient","h":"#43-udptouchrpc","p":160},{"i":174,"t":"4.4 WSTouchRpcClient","u":"/touchsocket/docs/createtouchrpcclient","h":"#44-wstouchrpcclient","p":160},{"i":177,"t":"一、说明","u":"/touchsocket/docs/createtcpclient","h":"#一说明","p":176},{"i":179,"t":"二、特点","u":"/touchsocket/docs/createtcpclient","h":"#二特点","p":176},{"i":181,"t":"三、产品应用场景","u":"/touchsocket/docs/createtcpclient","h":"#三产品应用场景","p":176},{"i":183,"t":"四、可配置项","u":"/touchsocket/docs/createtcpclient","h":"#四可配置项","p":176},{"i":185,"t":"五、支持插件","u":"/touchsocket/docs/createtcpclient","h":"#五支持插件","p":176},{"i":187,"t":"六、创建TcpClient","u":"/touchsocket/docs/createtcpclient","h":"#六创建tcpclient","p":176},{"i":189,"t":"七、接收数据","u":"/touchsocket/docs/createtcpclient","h":"#七接收数据","p":176},{"i":191,"t":"7.1 Received委托处理","u":"/touchsocket/docs/createtcpclient","h":"#71-received委托处理","p":176},{"i":193,"t":"7.2 插件处理推荐","u":"/touchsocket/docs/createtcpclient","h":"#72-插件处理推荐","p":176},{"i":195,"t":"八、发送数据","u":"/touchsocket/docs/createtcpclient","h":"#八发送数据","p":176},{"i":198,"t":"一、说明","u":"/touchsocket/docs/createudpsession","h":"#一说明","p":197},{"i":200,"t":"二、产品特点","u":"/touchsocket/docs/createudpsession","h":"#二产品特点","p":197},{"i":202,"t":"三、产品应用场景","u":"/touchsocket/docs/createudpsession","h":"#三产品应用场景","p":197},{"i":204,"t":"四、支持插件接口","u":"/touchsocket/docs/createudpsession","h":"#四支持插件接口","p":197},{"i":206,"t":"四、使用UdpSession","u":"/touchsocket/docs/createudpsession","h":"#四使用udpsession","p":197},{"i":209,"t":"一、说明","u":"/touchsocket/docs/createtcpservice","h":"#一说明","p":208},{"i":211,"t":"二、特点","u":"/touchsocket/docs/createtcpservice","h":"#二特点","p":208},{"i":213,"t":"三、产品应用场景","u":"/touchsocket/docs/createtcpservice","h":"#三产品应用场景","p":208},{"i":215,"t":"四、服务器架构","u":"/touchsocket/docs/createtcpservice","h":"#四服务器架构","p":208},{"i":217,"t":"五、可配置项","u":"/touchsocket/docs/createtcpservice","h":"#五可配置项","p":208},{"i":219,"t":"六、支持插件","u":"/touchsocket/docs/createtcpservice","h":"#六支持插件","p":208},{"i":221,"t":"七、创建TcpService","u":"/touchsocket/docs/createtcpservice","h":"#七创建tcpservice","p":208},{"i":222,"t":"7.1 简单创建","u":"/touchsocket/docs/createtcpservice","h":"#71-简单创建","p":208},{"i":224,"t":"7.2 泛型创建","u":"/touchsocket/docs/createtcpservice","h":"#72-泛型创建","p":208},{"i":226,"t":"八、接收数据","u":"/touchsocket/docs/createtcpservice","h":"#八接收数据","p":208},{"i":228,"t":"8.1 Received委托处理","u":"/touchsocket/docs/createtcpservice","h":"#81-received委托处理","p":208},{"i":230,"t":"8.2 重写SocketClient处理","u":"/touchsocket/docs/createtcpservice","h":"#82-重写socketclient处理","p":208},{"i":232,"t":"8.3 插件处理 推荐","u":"/touchsocket/docs/createtcpservice","h":"#83-插件处理-推荐","p":208},{"i":234,"t":"九、AspNetCore中创建","u":"/touchsocket/docs/createtcpservice","h":"#九aspnetcore中创建","p":208},{"i":236,"t":"十、发送数据","u":"/touchsocket/docs/createtcpservice","h":"#十发送数据","p":208},{"i":238,"t":"10.1 如何获取SocketClient?","u":"/touchsocket/docs/createtcpservice","h":"#101-如何获取socketclient","p":208},{"i":240,"t":"10.2 发送","u":"/touchsocket/docs/createtcpservice","h":"#102-发送","p":208},{"i":242,"t":"10.3 通过TcpService发送","u":"/touchsocket/docs/createtcpservice","h":"#103-通过tcpservice发送","p":208},{"i":245,"t":"一、说明","u":"/touchsocket/docs/createtouchrpcservice","h":"#一说明","p":244},{"i":247,"t":"二、服务器架构","u":"/touchsocket/docs/createtouchrpcservice","h":"#二服务器架构","p":244},{"i":249,"t":"三、可配置项","u":"/touchsocket/docs/createtouchrpcservice","h":"#三可配置项","p":244},{"i":251,"t":"四、支持插件接口","u":"/touchsocket/docs/createtouchrpcservice","h":"#四支持插件接口","p":244},{"i":253,"t":"五、创建服务器","u":"/touchsocket/docs/createtouchrpcservice","h":"#五创建服务器","p":244},{"i":254,"t":"5.1 基于Tcp协议","u":"/touchsocket/docs/createtouchrpcservice","h":"#51-基于tcp协议","p":244},{"i":256,"t":"5.2 基于Http协议","u":"/touchsocket/docs/createtouchrpcservice","h":"#52-基于http协议","p":244},{"i":258,"t":"5.3 基于Udp协议","u":"/touchsocket/docs/createtouchrpcservice","h":"#53-基于udp协议","p":244},{"i":260,"t":"5.4 基于AspNetCore的Websocket协议","u":"/touchsocket/docs/createtouchrpcservice","h":"#54-基于aspnetcore的websocket协议","p":244},{"i":264,"t":"提交要求","u":"/touchsocket/docs/adapterdemodescription","h":"#提交要求","p":262},{"i":267,"t":"一、说明","u":"/touchsocket/docs/custombetweenanddatahandlingadapter","h":"#一说明","p":266},{"i":269,"t":"二、特点","u":"/touchsocket/docs/custombetweenanddatahandlingadapter","h":"#二特点","p":266},{"i":271,"t":"三、使用","u":"/touchsocket/docs/custombetweenanddatahandlingadapter","h":"#三使用","p":266},{"i":274,"t":"一、说明","u":"/touchsocket/docs/createwebsocketservice","h":"#一说明","p":273},{"i":276,"t":"二、可配置项","u":"/touchsocket/docs/createwebsocketservice","h":"#二可配置项","p":273},{"i":278,"t":"三、支持插件接口","u":"/touchsocket/docs/createwebsocketservice","h":"#三支持插件接口","p":273},{"i":280,"t":"IWebSocketPlugin","u":"/touchsocket/docs/createwebsocketservice","h":"#iwebsocketplugin","p":273},{"i":282,"t":"四、创建WebSocket服务","u":"/touchsocket/docs/createwebsocketservice","h":"#四创建websocket服务","p":273},{"i":283,"t":"4.1 简单通过插件创建","u":"/touchsocket/docs/createwebsocketservice","h":"#41-简单通过插件创建","p":273},{"i":285,"t":"4.2 通过WebApi创建","u":"/touchsocket/docs/createwebsocketservice","h":"#42-通过webapi创建","p":273},{"i":287,"t":"创建基于Ssl的WebSocket服务","u":"/touchsocket/docs/createwebsocketservice","h":"#创建基于ssl的websocket服务","p":273},{"i":289,"t":"接收消息","u":"/touchsocket/docs/createwebsocketservice","h":"#接收消息","p":273},{"i":291,"t":"回复、响应数据","u":"/touchsocket/docs/createwebsocketservice","h":"#回复响应数据","p":273},{"i":294,"t":"一、说明","u":"/touchsocket/docs/customdatahandlingadapter","h":"#一说明","p":293},{"i":296,"t":"二、运行逻辑","u":"/touchsocket/docs/customdatahandlingadapter","h":"#二运行逻辑","p":293},{"i":298,"t":"三、特点","u":"/touchsocket/docs/customdatahandlingadapter","h":"#三特点","p":293},{"i":300,"t":"四、使用","u":"/touchsocket/docs/customdatahandlingadapter","h":"#四使用","p":293},{"i":303,"t":"一、说明","u":"/touchsocket/docs/customfixedheaderdatahandlingadapter","h":"#一说明","p":302},{"i":305,"t":"二、特点","u":"/touchsocket/docs/customfixedheaderdatahandlingadapter","h":"#二特点","p":302},{"i":307,"t":"三、使用","u":"/touchsocket/docs/customfixedheaderdatahandlingadapter","h":"#三使用","p":302},{"i":310,"t":"说明","u":"/touchsocket/docs/createwebsocketclient","h":"#说明","p":309},{"i":312,"t":"可配置项","u":"/touchsocket/docs/createwebsocketclient","h":"#可配置项","p":309},{"i":314,"t":"支持插件接口","u":"/touchsocket/docs/createwebsocketclient","h":"#支持插件接口","p":309},{"i":316,"t":"创建WS客户端","u":"/touchsocket/docs/createwebsocketclient","h":"#创建ws客户端","p":309},{"i":318,"t":"创建WSs客户端","u":"/touchsocket/docs/createwebsocketclient","h":"#创建wss客户端","p":309},{"i":320,"t":"发送数据","u":"/touchsocket/docs/createwebsocketclient","h":"#发送数据","p":309},{"i":322,"t":"接收数据","u":"/touchsocket/docs/createwebsocketclient","h":"#接收数据","p":309},{"i":325,"t":"定制方","u":"/touchsocket/docs/dataforwarding","h":"#定制方","p":324},{"i":327,"t":"说明","u":"/touchsocket/docs/dataforwarding","h":"#说明","p":324},{"i":329,"t":"技术点","u":"/touchsocket/docs/dataforwarding","h":"#技术点","p":324},{"i":331,"t":"效果","u":"/touchsocket/docs/dataforwarding","h":"#效果","p":324},{"i":333,"t":"一、说明","u":"/touchsocket/docs/dataadaptertester","h":"#一说明","p":332},{"i":335,"t":"1.1 测试原理","u":"/touchsocket/docs/dataadaptertester","h":"#11-测试原理","p":332},{"i":337,"t":"1.2 测试事项","u":"/touchsocket/docs/dataadaptertester","h":"#12-测试事项","p":332},{"i":339,"t":"二、Tcp适配器","u":"/touchsocket/docs/dataadaptertester","h":"#二tcp适配器","p":332},{"i":342,"t":"一、说明","u":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","h":"#一说明","p":341},{"i":344,"t":"二、特点","u":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","h":"#二特点","p":341},{"i":346,"t":"三、使用","u":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","h":"#三使用","p":341},{"i":349,"t":"一、3DES","u":"/touchsocket/docs/datasecurity","h":"#一3des","p":348},{"i":352,"t":"说明","u":"/touchsocket/docs/engineertoolbox","h":"#说明","p":351},{"i":354,"t":"界面展示","u":"/touchsocket/docs/engineertoolbox","h":"#界面展示","p":351},{"i":356,"t":"说明","u":"/touchsocket/docs/datahandleadapter","h":"#说明","p":355},{"i":358,"t":"原始DataHandlingAdapter","u":"/touchsocket/docs/datahandleadapter","h":"#原始datahandlingadapter","p":355},{"i":360,"t":"实现","u":"/touchsocket/docs/datahandleadapter","h":"#实现","p":355},{"i":362,"t":"使用自定义适配器","u":"/touchsocket/docs/datahandleadapter","h":"#使用自定义适配器","p":355},{"i":364,"t":"封装函数及分片发送意义","u":"/touchsocket/docs/datahandleadapter","h":"#封装函数及分片发送意义","p":355},{"i":367,"t":"赞助TouchSocket项目","u":"/touchsocket/docs/donate","h":"#赞助touchsocket项目","p":366},{"i":369,"t":"爱心赞助名单(以下排名只按照打赏时间顺序)","u":"/touchsocket/docs/donate","h":"#爱心赞助名单以下排名只按照打赏时间顺序","p":366},{"i":371,"t":"一起喝酒?","u":"/touchsocket/docs/donate","h":"#一起喝酒","p":366},{"i":373,"t":"一、说明","u":"/touchsocket/docs/dependencyproperty","h":"#一说明","p":372},{"i":375,"t":"二、什么是依赖属性?","u":"/touchsocket/docs/dependencyproperty","h":"#二什么是依赖属性","p":372},{"i":377,"t":"三、优缺点","u":"/touchsocket/docs/dependencyproperty","h":"#三优缺点","p":372},{"i":380,"t":"定制方","u":"/touchsocket/docs/filesynchronization","h":"#定制方","p":379},{"i":382,"t":"说明","u":"/touchsocket/docs/filesynchronization","h":"#说明","p":379},{"i":384,"t":"技术点","u":"/touchsocket/docs/filesynchronization","h":"#技术点","p":379},{"i":386,"t":"效果","u":"/touchsocket/docs/filesynchronization","h":"#效果","p":379},{"i":388,"t":"说明","u":"/touchsocket/docs/eventbus","h":"#说明","p":387},{"i":390,"t":"创建服务器","u":"/touchsocket/docs/eventbus","h":"#创建服务器","p":387},{"i":392,"t":"创建客户端","u":"/touchsocket/docs/eventbus","h":"#创建客户端","p":387},{"i":394,"t":"服务器触发","u":"/touchsocket/docs/eventbus","h":"#服务器触发","p":387},{"i":396,"t":"其他","u":"/touchsocket/docs/eventbus","h":"#其他","p":387},{"i":399,"t":"一、说明","u":"/touchsocket/docs/fixedheaderpackageadapter","h":"#一说明","p":398},{"i":401,"t":"二、特点","u":"/touchsocket/docs/fixedheaderpackageadapter","h":"#二特点","p":398},{"i":403,"t":"三、协议算法","u":"/touchsocket/docs/fixedheaderpackageadapter","h":"#三协议算法","p":398},{"i":405,"t":"四、使用","u":"/touchsocket/docs/fixedheaderpackageadapter","h":"#四使用","p":398},{"i":408,"t":"一、说明","u":"/touchsocket/docs/filepool","h":"#一说明","p":407},{"i":410,"t":"二、使用读","u":"/touchsocket/docs/filepool","h":"#二使用读","p":407},{"i":412,"t":"三、使用写","u":"/touchsocket/docs/filepool","h":"#三使用写","p":407},{"i":414,"t":"四、手动释放文件资源","u":"/touchsocket/docs/filepool","h":"#四手动释放文件资源","p":407},{"i":417,"t":"一、说明","u":"/touchsocket/docs/fixedsizepackageadapter","h":"#一说明","p":416},{"i":419,"t":"二、特点","u":"/touchsocket/docs/fixedsizepackageadapter","h":"#二特点","p":416},{"i":421,"t":"三、使用","u":"/touchsocket/docs/fixedsizepackageadapter","h":"#三使用","p":416},{"i":426,"t":"一、说明","u":"/touchsocket/docs/fastbinaryformatter","h":"#一说明","p":425},{"i":428,"t":"二、序列化、反序列化","u":"/touchsocket/docs/fastbinaryformatter","h":"#二序列化反序列化","p":425},{"i":430,"t":"三、自定义转换器","u":"/touchsocket/docs/fastbinaryformatter","h":"#三自定义转换器","p":425},{"i":432,"t":"四、性能测试","u":"/touchsocket/docs/fastbinaryformatter","h":"#四性能测试","p":425},{"i":433,"t":"4.1 简单测试","u":"/touchsocket/docs/fastbinaryformatter","h":"#41-简单测试","p":425},{"i":435,"t":"4.2 复杂类型测试","u":"/touchsocket/docs/fastbinaryformatter","h":"#42-复杂类型测试","p":425},{"i":438,"t":"一、说明","u":"/touchsocket/docs/generateproxy","h":"#一说明","p":437},{"i":439,"t":"1.1 为什么要生成代理?","u":"/touchsocket/docs/generateproxy","h":"#11-为什么要生成代理","p":437},{"i":441,"t":"1.2 为什么不直接支持接口代理调用?","u":"/touchsocket/docs/generateproxy","h":"#12-为什么不直接支持接口代理调用","p":437},{"i":443,"t":"1.3 TouchRpc源文件代理相比接口代理,有什么优缺点?","u":"/touchsocket/docs/generateproxy","h":"#13-touchrpc源文件代理相比接口代理有什么优缺点","p":437},{"i":445,"t":"二、从服务端获取代理","u":"/touchsocket/docs/generateproxy","h":"#二从服务端获取代理","p":437},{"i":446,"t":"2.1 生成代理","u":"/touchsocket/docs/generateproxy","h":"#21-生成代理","p":437},{"i":448,"t":"2.2 代理类型添加","u":"/touchsocket/docs/generateproxy","h":"#22-代理类型添加","p":437},{"i":450,"t":"2.2.1 添加代理类型","u":"/touchsocket/docs/generateproxy","h":"#221-添加代理类型","p":437},{"i":452,"t":"2.2.2 标记自定义类","u":"/touchsocket/docs/generateproxy","h":"#222-标记自定义类","p":437},{"i":454,"t":"三、客户端源代码生成代理 企业版","u":"/touchsocket/docs/generateproxy","h":"#三客户端源代码生成代理-企业版","p":437},{"i":457,"t":"静态网页托管插件仅服务器支持","u":"/touchsocket/docs/httpstaticpageplugin","h":"#静态网页托管插件仅服务器支持","p":456},{"i":460,"t":"一、说明","u":"/touchsocket/docs/httpfiletransfer","h":"#一说明","p":459},{"i":462,"t":"二、服务器响应文件","u":"/touchsocket/docs/httpfiletransfer","h":"#二服务器响应文件","p":459},{"i":464,"t":"三、服务器接收上传文件","u":"/touchsocket/docs/httpfiletransfer","h":"#三服务器接收上传文件","p":459},{"i":467,"t":"一、说明","u":"/touchsocket/docs/independentusedatahandlingadapter","h":"#一说明","p":466},{"i":469,"t":"二、使用","u":"/touchsocket/docs/independentusedatahandlingadapter","h":"#二使用","p":466},{"i":472,"t":"一、日志记录接口(ILog)","u":"/touchsocket/docs/ilog","h":"#一日志记录接口ilog","p":471},{"i":474,"t":"二、控制台日志记录器(ConsoleLogger)","u":"/touchsocket/docs/ilog","h":"#二控制台日志记录器consolelogger","p":471},{"i":476,"t":"三、文件日志记录器(FileLogger)","u":"/touchsocket/docs/ilog","h":"#三文件日志记录器filelogger","p":471},{"i":478,"t":"四、日志组记录器(LoggerGroup)","u":"/touchsocket/docs/ilog","h":"#四日志组记录器loggergroup","p":471},{"i":480,"t":"五、日志扩展","u":"/touchsocket/docs/ilog","h":"#五日志扩展","p":471},{"i":483,"t":"一、说明","u":"/touchsocket/docs/heartbeat","h":"#一说明","p":482},{"i":484,"t":"1.1 为什么要设置心跳?","u":"/touchsocket/docs/heartbeat","h":"#11-为什么要设置心跳","p":482},{"i":486,"t":"二、设计数据格式","u":"/touchsocket/docs/heartbeat","h":"#二设计数据格式","p":482},{"i":488,"t":"2.1 解析数据格式","u":"/touchsocket/docs/heartbeat","h":"#21-解析数据格式","p":482},{"i":490,"t":"三、创建扩展类","u":"/touchsocket/docs/heartbeat","h":"#三创建扩展类","p":482},{"i":492,"t":"四、创建心跳插件类","u":"/touchsocket/docs/heartbeat","h":"#四创建心跳插件类","p":482},{"i":494,"t":"五、测试、启动","u":"/touchsocket/docs/heartbeat","h":"#五测试启动","p":482},{"i":497,"t":"一、说明","u":"/touchsocket/docs/jsonrpcdescription","h":"#一说明","p":496},{"i":499,"t":"二、特点:","u":"/touchsocket/docs/jsonrpcdescription","h":"#二特点","p":496},{"i":502,"t":"一、说明","u":"/touchsocket/docs/ipackage","h":"#一说明","p":501},{"i":504,"t":"二、特点","u":"/touchsocket/docs/ipackage","h":"#二特点","p":501},{"i":506,"t":"三、使用","u":"/touchsocket/docs/ipackage","h":"#三使用","p":501},{"i":508,"t":"四、性能评测","u":"/touchsocket/docs/ipackage","h":"#四性能评测","p":501},{"i":511,"t":"一、定义服务","u":"/touchsocket/docs/jsonrpcservice","h":"#一定义服务","p":510},{"i":513,"t":"二、使用Tcp创建服务解析器","u":"/touchsocket/docs/jsonrpcservice","h":"#二使用tcp创建服务解析器","p":510},{"i":515,"t":"三、使用Http或Websocket创建服务解析器","u":"/touchsocket/docs/jsonrpcservice","h":"#三使用http或websocket创建服务解析器","p":510},{"i":518,"t":"一、说明","u":"/touchsocket/docs/jsonserialize","h":"#一说明","p":517},{"i":520,"t":"二、动态调整的Json策略","u":"/touchsocket/docs/jsonserialize","h":"#二动态调整的json策略","p":517},{"i":522,"t":"三、JsonFast性能","u":"/touchsocket/docs/jsonserialize","h":"#三jsonfast性能","p":517},{"i":525,"t":"一、说明 企业版","u":"/touchsocket/docs/multithreadingfiletransfer","h":"#一说明-企业版","p":524},{"i":527,"t":"二、使用","u":"/touchsocket/docs/multithreadingfiletransfer","h":"#二使用","p":524},{"i":529,"t":"三、客户端之间传输文件","u":"/touchsocket/docs/multithreadingfiletransfer","h":"#三客户端之间传输文件","p":524},{"i":532,"t":"一、说明","u":"/touchsocket/docs/natservice","h":"#一说明","p":531},{"i":534,"t":"二、常见使用场景","u":"/touchsocket/docs/natservice","h":"#二常见使用场景","p":531},{"i":536,"t":"三、创建NATService","u":"/touchsocket/docs/natservice","h":"#三创建natservice","p":531},{"i":538,"t":"四、转发断线重连 企业版","u":"/touchsocket/docs/natservice","h":"#四转发断线重连-企业版","p":531},{"i":541,"t":"一、说明","u":"/touchsocket/docs/ioc","h":"#一说明","p":540},{"i":543,"t":"二、特点","u":"/touchsocket/docs/ioc","h":"#二特点","p":540},{"i":545,"t":"三、注入方式","u":"/touchsocket/docs/ioc","h":"#三注入方式","p":540},{"i":547,"t":"3.1 构造函数注入","u":"/touchsocket/docs/ioc","h":"#31-构造函数注入","p":540},{"i":549,"t":"3.2 属性注入","u":"/touchsocket/docs/ioc","h":"#32-属性注入","p":540},{"i":551,"t":"3.2 方法注入","u":"/touchsocket/docs/ioc","h":"#32-方法注入","p":540},{"i":553,"t":"四、生命周期","u":"/touchsocket/docs/ioc","h":"#四生命周期","p":540},{"i":555,"t":"所有模型定义","u":"/touchsocket/docs/ioc","h":"#所有模型定义","p":540},{"i":558,"t":"一、说明","u":"/touchsocket/docs/pipelinedatahandlingadapter","h":"#一说明","p":557},{"i":560,"t":"二、使用","u":"/touchsocket/docs/pipelinedatahandlingadapter","h":"#二使用","p":557},{"i":563,"t":"说明","u":"/touchsocket/docs/pluginsmanager","h":"#说明","p":562},{"i":565,"t":"产品特点","u":"/touchsocket/docs/pluginsmanager","h":"#产品特点","p":562},{"i":567,"t":"产品应用场景","u":"/touchsocket/docs/pluginsmanager","h":"#产品应用场景","p":562},{"i":569,"t":"插件特性","u":"/touchsocket/docs/pluginsmanager","h":"#插件特性","p":562},{"i":571,"t":"用户自定义插件","u":"/touchsocket/docs/pluginsmanager","h":"#用户自定义插件","p":562},{"i":573,"t":"系统自定义插件","u":"/touchsocket/docs/pluginsmanager","h":"#系统自定义插件","p":562},{"i":576,"t":"一、说明 企业版","u":"/touchsocket/docs/remotefilecontrol","h":"#一说明-企业版","p":575},{"i":578,"t":"二、支持的操作","u":"/touchsocket/docs/remotefilecontrol","h":"#二支持的操作","p":575},{"i":580,"t":"三、代码示例","u":"/touchsocket/docs/remotefilecontrol","h":"#三代码示例","p":575},{"i":583,"t":"定制方","u":"/touchsocket/docs/remotemonitoring","h":"#定制方","p":582},{"i":585,"t":"说明","u":"/touchsocket/docs/remotemonitoring","h":"#说明","p":582},{"i":587,"t":"技术点","u":"/touchsocket/docs/remotemonitoring","h":"#技术点","p":582},{"i":589,"t":"效果","u":"/touchsocket/docs/remotemonitoring","h":"#效果","p":582},{"i":592,"t":"一、说明","u":"/touchsocket/docs/reconnection","h":"#一说明","p":591},{"i":594,"t":"二、使用Reconnection插件","u":"/touchsocket/docs/reconnection","h":"#二使用reconnection插件","p":591},{"i":596,"t":"三、使用PollingKeepAlive插件 企业版","u":"/touchsocket/docs/reconnection","h":"#三使用pollingkeepalive插件-企业版","p":591},{"i":599,"t":"一、Crc计算","u":"/touchsocket/docs/othercore","h":"#一crc计算","p":598},{"i":601,"t":"二、时间测量器(TimeMeasurer)","u":"/touchsocket/docs/othercore","h":"#二时间测量器timemeasurer","p":598},{"i":603,"t":"三、MD5计算","u":"/touchsocket/docs/othercore","h":"#三md5计算","p":598},{"i":605,"t":"四、16进制相关","u":"/touchsocket/docs/othercore","h":"#四16进制相关","p":598},{"i":607,"t":"五、雪花ID生成","u":"/touchsocket/docs/othercore","h":"#五雪花id生成","p":598},{"i":609,"t":"六、数据压缩","u":"/touchsocket/docs/othercore","h":"#六数据压缩","p":598},{"i":612,"t":"一、说明","u":"/touchsocket/docs/resetid","h":"#一说明","p":611},{"i":614,"t":"二、配置初始ID策略","u":"/touchsocket/docs/resetid","h":"#二配置初始id策略","p":611},{"i":616,"t":"三、创建能代表连接的ID","u":"/touchsocket/docs/resetid","h":"#三创建能代表连接的id","p":611},{"i":618,"t":"四、即时修改ID","u":"/touchsocket/docs/resetid","h":"#四即时修改id","p":611},{"i":620,"t":"4.1 通过Service直接修改","u":"/touchsocket/docs/resetid","h":"#41-通过service直接修改","p":611},{"i":622,"t":"4.2 通过SocketClient修改","u":"/touchsocket/docs/resetid","h":"#42-通过socketclient修改","p":611},{"i":625,"t":"一、说明 企业版","u":"/touchsocket/docs/remotestreamaccess","h":"#一说明-企业版","p":624},{"i":627,"t":"二、场景","u":"/touchsocket/docs/remotestreamaccess","h":"#二场景","p":624},{"i":629,"t":"三、代码示例","u":"/touchsocket/docs/remotestreamaccess","h":"#三代码示例","p":624},{"i":631,"t":"四、读写","u":"/touchsocket/docs/remotestreamaccess","h":"#四读写","p":624},{"i":633,"t":"五、释放","u":"/touchsocket/docs/remotestreamaccess","h":"#五释放","p":624},{"i":635,"t":"六、性能","u":"/touchsocket/docs/remotestreamaccess","h":"#六性能","p":624},{"i":638,"t":"一、说明","u":"/touchsocket/docs/rpcallcontext","h":"#一说明","p":637},{"i":640,"t":"二、通过标签参数获取","u":"/touchsocket/docs/rpcallcontext","h":"#二通过标签参数获取","p":637},{"i":642,"t":"三、通过瞬时生命周期获取","u":"/touchsocket/docs/rpcallcontext","h":"#三通过瞬时生命周期获取","p":637},{"i":645,"t":"一、说明","u":"/touchsocket/docs/rpcactionfilter","h":"#一说明","p":644},{"i":647,"t":"二、声明特性","u":"/touchsocket/docs/rpcactionfilter","h":"#二声明特性","p":644},{"i":649,"t":"三、使用","u":"/touchsocket/docs/rpcactionfilter","h":"#三使用","p":644},{"i":652,"t":"一、调用反馈类型","u":"/touchsocket/docs/rpcoption","h":"#一调用反馈类型","p":651},{"i":654,"t":"1.1 使用","u":"/touchsocket/docs/rpcoption","h":"#11-使用","p":651},{"i":656,"t":"二、调用超时设置","u":"/touchsocket/docs/rpcoption","h":"#二调用超时设置","p":651},{"i":658,"t":"2.1 计时器设置","u":"/touchsocket/docs/rpcoption","h":"#21-计时器设置","p":651},{"i":660,"t":"2.2 任务取消","u":"/touchsocket/docs/rpcoption","h":"#22-任务取消","p":651},{"i":662,"t":"2.3 服务任务取消","u":"/touchsocket/docs/rpcoption","h":"#23-服务任务取消","p":651},{"i":665,"t":"一、说明","u":"/touchsocket/docs/rpcstream","h":"#一说明","p":664},{"i":667,"t":"二、设置适配器参数(推荐指数:⭐)","u":"/touchsocket/docs/rpcstream","h":"#二设置适配器参数推荐指数","p":664},{"i":669,"t":"三、RPC嵌套Channel(推荐指数:⭐⭐⭐⭐⭐)","u":"/touchsocket/docs/rpcstream","h":"#三rpc嵌套channel推荐指数","p":664},{"i":671,"t":"3.1 请求流数据","u":"/touchsocket/docs/rpcstream","h":"#31-请求流数据","p":664},{"i":673,"t":"3.2 推送流数据","u":"/touchsocket/docs/rpcstream","h":"#32-推送流数据","p":664},{"i":676,"t":"一、说明","u":"/touchsocket/docs/serializationselector","h":"#一说明","p":675},{"i":678,"t":"二、支持的序列化","u":"/touchsocket/docs/serializationselector","h":"#二支持的序列化","p":675},{"i":680,"t":"三、使用预设序列化","u":"/touchsocket/docs/serializationselector","h":"#三使用预设序列化","p":675},{"i":682,"t":"四、自定义序列化","u":"/touchsocket/docs/serializationselector","h":"#四自定义序列化","p":675},{"i":683,"t":"4.1 定义自定义序列化器","u":"/touchsocket/docs/serializationselector","h":"#41-定义自定义序列化器","p":675},{"i":685,"t":"4.2 使用","u":"/touchsocket/docs/serializationselector","h":"#42-使用","p":675},{"i":688,"t":"一、说明","u":"/touchsocket/docs/smallfiletransfer","h":"#一说明","p":687},{"i":690,"t":"二、使用","u":"/touchsocket/docs/smallfiletransfer","h":"#二使用","p":687},{"i":692,"t":"三、客户端之间传输","u":"/touchsocket/docs/smallfiletransfer","h":"#三客户端之间传输","p":687},{"i":694,"t":"","u":"/touchsocket/docs/smallfiletransfer","h":"","p":687},{"i":696,"t":"说明","u":"/touchsocket/docs/stategridtransmission","h":"#说明","p":695},{"i":698,"t":"版权","u":"/touchsocket/docs/stategridtransmission","h":"#版权","p":695},{"i":700,"t":"协议类型","u":"/touchsocket/docs/stategridtransmission","h":"#协议类型","p":695},{"i":701,"t":"代码","u":"/touchsocket/docs/stategridtransmission","h":"#代码","p":695},{"i":704,"t":"一、说明","u":"/touchsocket/docs/startguide","h":"#一说明","p":703},{"i":706,"t":"二、创建项目","u":"/touchsocket/docs/startguide","h":"#二创建项目","p":703},{"i":708,"t":"2.1 创建新项目","u":"/touchsocket/docs/startguide","h":"#21-创建新项目","p":703},{"i":709,"t":"2.2 选择项目类型","u":"/touchsocket/docs/startguide","h":"#22-选择项目类型","p":703},{"i":710,"t":"2.3 配置项目名称和路径","u":"/touchsocket/docs/startguide","h":"#23-配置项目名称和路径","p":703},{"i":711,"t":"2.4 选择Net版本","u":"/touchsocket/docs/startguide","h":"#24-选择net版本","p":703},{"i":712,"t":"三、安装","u":"/touchsocket/docs/startguide","h":"#三安装","p":703},{"i":713,"t":"3.1 Nuget安装","u":"/touchsocket/docs/startguide","h":"#31-nuget安装","p":703},{"i":715,"t":"3.2 PackageReference","u":"/touchsocket/docs/startguide","h":"#32-packagereference","p":703},{"i":717,"t":"3.3 Dll直接引用","u":"/touchsocket/docs/startguide","h":"#33-dll直接引用","p":703},{"i":719,"t":"四、结束","u":"/touchsocket/docs/startguide","h":"#四结束","p":703},{"i":722,"t":"一、说明","u":"/touchsocket/docs/streamtransfer","h":"#一说明","p":721},{"i":724,"t":"二、特性","u":"/touchsocket/docs/streamtransfer","h":"#二特性","p":721},{"i":726,"t":"三、示例","u":"/touchsocket/docs/streamtransfer","h":"#三示例","p":721},{"i":731,"t":"一、说明","u":"/touchsocket/docs/tcpcommandlineplugin","h":"#一说明","p":730},{"i":733,"t":"二、创建快捷执行插件","u":"/touchsocket/docs/tcpcommandlineplugin","h":"#二创建快捷执行插件","p":730},{"i":735,"t":"三、创建服务器","u":"/touchsocket/docs/tcpcommandlineplugin","h":"#三创建服务器","p":730},{"i":737,"t":"四、调用","u":"/touchsocket/docs/tcpcommandlineplugin","h":"#四调用","p":730},{"i":740,"t":"一、说明","u":"/touchsocket/docs/terminatorpackageadapter","h":"#一说明","p":739},{"i":742,"t":"二、特点","u":"/touchsocket/docs/terminatorpackageadapter","h":"#二特点","p":739},{"i":744,"t":"三、使用","u":"/touchsocket/docs/terminatorpackageadapter","h":"#三使用","p":739},{"i":747,"t":"一、说明 企业版","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#一说明-企业版","p":746},{"i":749,"t":"二、使用","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#二使用","p":746},{"i":751,"t":"三、保活机制","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#三保活机制","p":746},{"i":753,"t":"自动ping","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#自动ping","p":746},{"i":755,"t":"四、构建数据","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#四构建数据","p":746},{"i":757,"t":"五、发送数据","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#五发送数据","p":746},{"i":760,"t":"一、说明","u":"/touchsocket/docs/touchsocketbitconverter","h":"#一说明","p":759},{"i":762,"t":"二、绝对大端","u":"/touchsocket/docs/touchsocketbitconverter","h":"#二绝对大端","p":759},{"i":764,"t":"三、绝对小端","u":"/touchsocket/docs/touchsocketbitconverter","h":"#三绝对小端","p":759},{"i":766,"t":"四、默认端","u":"/touchsocket/docs/touchsocketbitconverter","h":"#四默认端","p":759},{"i":769,"t":"一、连接验证","u":"/touchsocket/docs/touchrpcbase","h":"#一连接验证","p":768},{"i":771,"t":"1.1 Token验证","u":"/touchsocket/docs/touchrpcbase","h":"#11-token验证","p":768},{"i":773,"t":"1.2 动态验证","u":"/touchsocket/docs/touchrpcbase","h":"#12-动态验证","p":768},{"i":775,"t":"二、ID同步","u":"/touchsocket/docs/touchrpcbase","h":"#二id同步","p":768},{"i":777,"t":"三、协议扩展","u":"/touchsocket/docs/touchrpcbase","h":"#三协议扩展","p":768},{"i":779,"t":"3.1 使用","u":"/touchsocket/docs/touchrpcbase","h":"#31-使用","p":768},{"i":782,"t":"一、说明","u":"/touchsocket/docs/touchrpcdescription","h":"#一说明","p":781},{"i":784,"t":"1.1 TouchRpc和Tcp、Udp有什么关系?","u":"/touchsocket/docs/touchrpcdescription","h":"#11-touchrpc和tcpudp有什么关系","p":781},{"i":786,"t":"1.2 Tcp本身就是可靠传输协议了,那TouchRpc的可靠又体现在什么地方呢?","u":"/touchsocket/docs/touchrpcdescription","h":"#12-tcp本身就是可靠传输协议了那touchrpc的可靠又体现在什么地方呢","p":781},{"i":788,"t":"二、特点","u":"/touchsocket/docs/touchrpcdescription","h":"#二特点","p":781},{"i":789,"t":"2.1 基础功能","u":"/touchsocket/docs/touchrpcdescription","h":"#21-基础功能","p":781},{"i":791,"t":"2.2 Rpc功能","u":"/touchsocket/docs/touchrpcdescription","h":"#22-rpc功能","p":781},{"i":793,"t":"2.3 文件传输","u":"/touchsocket/docs/touchrpcdescription","h":"#23-文件传输","p":781},{"i":795,"t":"2.4 远程操作","u":"/touchsocket/docs/touchrpcdescription","h":"#24-远程操作","p":781},{"i":797,"t":"2.5 流数据方面","u":"/touchsocket/docs/touchrpcdescription","h":"#25-流数据方面","p":781},{"i":799,"t":"2.6 Channel数据","u":"/touchsocket/docs/touchrpcdescription","h":"#26-channel数据","p":781},{"i":801,"t":"2.7 EventBus","u":"/touchsocket/docs/touchrpcdescription","h":"#27-eventbus","p":781},{"i":803,"t":"2.8 Redis","u":"/touchsocket/docs/touchrpcdescription","h":"#28-redis","p":781},{"i":805,"t":"三、场景","u":"/touchsocket/docs/touchrpcdescription","h":"#三场景","p":781},{"i":808,"t":"说明","u":"/touchsocket/docs/udpdatahandlingadapter","h":"#说明","p":807},{"i":810,"t":"单元测试","u":"/touchsocket/docs/udpdatahandlingadapter","h":"#单元测试","p":807},{"i":813,"t":"一、说明","u":"/touchsocket/docs/udptransmitbigdata","h":"#一说明","p":812},{"i":815,"t":"二、使用","u":"/touchsocket/docs/udptransmitbigdata","h":"#二使用","p":812},{"i":817,"t":"三、原理","u":"/touchsocket/docs/udptransmitbigdata","h":"#三原理","p":812},{"i":819,"t":"3.1 数据格式","u":"/touchsocket/docs/udptransmitbigdata","h":"#31-数据格式","p":812},{"i":823,"t":"产品应用场景","u":"/touchsocket/docs/transferfile","h":"#产品应用场景","p":821},{"i":825,"t":"服务架构","u":"/touchsocket/docs/transferfile","h":"#服务架构","p":821},{"i":827,"t":"一、说明","u":"/touchsocket/docs/transferfile","h":"#一说明","p":821},{"i":829,"t":"二、Pull文件","u":"/touchsocket/docs/transferfile","h":"#二pull文件","p":821},{"i":831,"t":"示例代码:","u":"/touchsocket/docs/transferfile","h":"#示例代码","p":821},{"i":833,"t":"三、Push文件","u":"/touchsocket/docs/transferfile","h":"#三push文件","p":821},{"i":835,"t":"四、客户端之间传输文件","u":"/touchsocket/docs/transferfile","h":"#四客户端之间传输文件","p":821},{"i":838,"t":"一、说明","u":"/touchsocket/docs/udpbroadcast","h":"#一说明","p":837},{"i":840,"t":"二、组播使用","u":"/touchsocket/docs/udpbroadcast","h":"#二组播使用","p":837},{"i":842,"t":"2.1 创建组播服务器","u":"/touchsocket/docs/udpbroadcast","h":"#21-创建组播服务器","p":837},{"i":844,"t":"2.2 发送组播数据","u":"/touchsocket/docs/udpbroadcast","h":"#22-发送组播数据","p":837},{"i":846,"t":"三、广播","u":"/touchsocket/docs/udpbroadcast","h":"#三广播","p":837},{"i":848,"t":"3.1 创建广播服务器","u":"/touchsocket/docs/udpbroadcast","h":"#31-创建广播服务器","p":837},{"i":850,"t":"3.2 发送广播数据","u":"/touchsocket/docs/udpbroadcast","h":"#32-发送广播数据","p":837},{"i":853,"t":"一、说明","u":"/touchsocket/docs/waitingclient","h":"#一说明","p":852},{"i":855,"t":"二、创建及使用","u":"/touchsocket/docs/waitingclient","h":"#二创建及使用","p":852},{"i":856,"t":"2.1 以TcpClient为例","u":"/touchsocket/docs/waitingclient","h":"#21-以tcpclient为例","p":852},{"i":858,"t":"2.2 以TcpService为例","u":"/touchsocket/docs/waitingclient","h":"#22-以tcpservice为例","p":852},{"i":861,"t":"一、说明","u":"/touchsocket/docs/webapidescription","h":"#一说明","p":860},{"i":863,"t":"二、特点","u":"/touchsocket/docs/webapidescription","h":"#二特点","p":860},{"i":867,"t":"v1.2.1","u":"/touchsocket/docs/upgrade","h":"#v121","p":865},{"i":869,"t":"v1.1.0","u":"/touchsocket/docs/upgrade","h":"#v110","p":865},{"i":871,"t":"v1.0.0","u":"/touchsocket/docs/upgrade","h":"#v100","p":865},{"i":873,"t":"版本号: 0.7.0","u":"/touchsocket/docs/upgrade","h":"#版本号-070","p":865},{"i":875,"t":"版本号: 0.6.0","u":"/touchsocket/docs/upgrade","h":"#版本号-060","p":865},{"i":877,"t":"版本号: 0.5.0","u":"/touchsocket/docs/upgrade","h":"#版本号-050","p":865},{"i":879,"t":"版本号: 0.4.5","u":"/touchsocket/docs/upgrade","h":"#版本号-045","p":865},{"i":881,"t":"版本号: 0.3.5","u":"/touchsocket/docs/upgrade","h":"#版本号-035","p":865},{"i":883,"t":"版本号: 0.2.4","u":"/touchsocket/docs/upgrade","h":"#版本号-024","p":865},{"i":885,"t":"版本号: 0.1.0","u":"/touchsocket/docs/upgrade","h":"#版本号-010","p":865},{"i":887,"t":"1.所有类的命名空间修改,此处如果类型名未修改的话,可由vs智能提示解决。","u":"/touchsocket/docs/upgrade","h":"#1所有类的命名空间修改此处如果类型名未修改的话可由vs智能提示解决","p":865},{"i":888,"t":"2.类型名称修改","u":"/touchsocket/docs/upgrade","h":"#2类型名称修改","p":865},{"i":890,"t":"3.使用逻辑修改","u":"/touchsocket/docs/upgrade","h":"#3使用逻辑修改","p":865},{"i":893,"t":"定义服务","u":"/touchsocket/docs/webapiservice","h":"#定义服务","p":892},{"i":895,"t":"创建简单服务器","u":"/touchsocket/docs/webapiservice","h":"#创建简单服务器","p":892},{"i":898,"t":"定制方","u":"/touchsocket/docs/webdataforwarding","h":"#定制方","p":897},{"i":900,"t":"说明","u":"/touchsocket/docs/webdataforwarding","h":"#说明","p":897},{"i":902,"t":"技术点","u":"/touchsocket/docs/webdataforwarding","h":"#技术点","p":897},{"i":904,"t":"效果","u":"/touchsocket/docs/webdataforwarding","h":"#效果","p":897},{"i":908,"t":"产品介绍","u":"/touchsocket/docs/websocketdescription","h":"#产品介绍","p":907},{"i":910,"t":"产品特点","u":"/touchsocket/docs/websocketdescription","h":"#产品特点","p":907},{"i":912,"t":"产品应用场景","u":"/touchsocket/docs/websocketdescription","h":"#产品应用场景","p":907},{"i":914,"t":"服务器架构","u":"/touchsocket/docs/websocketdescription","h":"#服务器架构","p":907},{"i":918,"t":"特点:","u":"/touchsocket/docs/xmlrpcdescription","h":"#特点","p":916},{"i":920,"t":"示例代码","u":"/touchsocket/docs/xmlrpcdescription","h":"#示例代码","p":916},{"i":924,"t":"命令行执行插件客户端、服务器均支持","u":"/touchsocket/docs/wscommandlineplugin","h":"#命令行执行插件客户端服务器均支持","p":923},{"i":927,"t":"定义服务","u":"/touchsocket/docs/xmlrpcservice","h":"#定义服务","p":926},{"i":929,"t":"创建服务解析器","u":"/touchsocket/docs/xmlrpcservice","h":"#创建服务解析器","p":926},{"i":931,"t":"注册、发布服务","u":"/touchsocket/docs/xmlrpcservice","h":"#注册发布服务","p":926},{"i":934,"t":"一、说明","u":"/touchsocket/docs/enterprise","h":"#一说明","p":933},{"i":936,"t":"二、TouchSocket与TouchSocketPro","u":"/touchsocket/docs/enterprise","h":"#二touchsocket与touchsocketpro","p":933},{"i":937,"t":"2.1 Tcp组件","u":"/touchsocket/docs/enterprise","h":"#21-tcp组件","p":933},{"i":939,"t":"2.2 NAT组件","u":"/touchsocket/docs/enterprise","h":"#22-nat组件","p":933},{"i":941,"t":"2.3 UDP组件","u":"/touchsocket/docs/enterprise","h":"#23-udp组件","p":933},{"i":943,"t":"2.4 JsonRpc","u":"/touchsocket/docs/enterprise","h":"#24-jsonrpc","p":933},{"i":945,"t":"2.5 WebApi","u":"/touchsocket/docs/enterprise","h":"#25-webapi","p":933},{"i":947,"t":"2.6 XmlRpc","u":"/touchsocket/docs/enterprise","h":"#26-xmlrpc","p":933},{"i":949,"t":"2.7 TouchRpc(tcp、udp、http、websocket)","u":"/touchsocket/docs/enterprise","h":"#27-touchrpctcpudphttpwebsocket","p":933},{"i":951,"t":"2.8 Http组件","u":"/touchsocket/docs/enterprise","h":"#28-http组件","p":933},{"i":953,"t":"WebSocket","u":"/touchsocket/docs/enterprise","h":"#websocket","p":933},{"i":955,"t":"三、能提供的个性服务","u":"/touchsocket/docs/enterprise","h":"#三能提供的个性服务","p":933},{"i":956,"t":"3.1 数据处理适配器的重写","u":"/touchsocket/docs/enterprise","h":"#31-数据处理适配器的重写","p":933},{"i":958,"t":"3.2 增加或限制某个功能","u":"/touchsocket/docs/enterprise","h":"#32-增加或限制某个功能","p":933},{"i":960,"t":"四、TouchSocketPro","u":"/touchsocket/docs/enterprise","h":"#四touchsocketpro","p":933},{"i":962,"t":"4.1 个人独立授权","u":"/touchsocket/docs/enterprise","h":"#41-个人独立授权","p":933},{"i":964,"t":"4.2 个人企业授权","u":"/touchsocket/docs/enterprise","h":"#42-个人企业授权","p":933},{"i":966,"t":"4.3 企业授权","u":"/touchsocket/docs/enterprise","h":"#43-企业授权","p":933},{"i":968,"t":"五、密钥使用","u":"/touchsocket/docs/enterprise","h":"#五密钥使用","p":933},{"i":970,"t":"六、限时测试","u":"/touchsocket/docs/enterprise","h":"#六限时测试","p":933},{"i":972,"t":"七、购买通道","u":"/touchsocket/docs/enterprise","h":"#七购买通道","p":933},{"i":975,"t":"一、说明","u":"/touchsocket/docs/normaldatahandlingadapter","h":"#一说明","p":974},{"i":977,"t":"二、特点","u":"/touchsocket/docs/normaldatahandlingadapter","h":"#二特点","p":974},{"i":979,"t":"三、使用","u":"/touchsocket/docs/normaldatahandlingadapter","h":"#三使用","p":974}],"index":{"version":"2.3.9","fields":["t"],"fieldVectors":[["t/2",[0,6.684,1,6.087]],["t/4",[2,2.058,3,5.106,4,5.106,5,5.106]],["t/6",[6,3.77,7,3.77,8,1.311,9,2.487,10,3.77,11,2.487,12,3.77]],["t/8",[11,4.409,13,6.684]],["t/9",[2,2.334,14,4.931,15,4.931]],["t/11",[15,5.694,16,6.684]],["t/13",[2,1.841,15,3.89,17,4.567,18,4.567,19,4.567]],["t/15",[20,4.677,21,5.789,22,5.789]],["t/17",[20,4.125,23,3.945,24,5.106,25,5.106]],["t/19",[26,6.684,27,6.684]],["t/22",[28,2.602]],["t/24",[2,2.695,29,2.324]],["t/27",[28,2.602]],["t/29",[30,5.694,31,4.97]],["t/30",[32,6.684,33,5.4]],["t/31",[33,5.4,34,4.526]],["t/33",[30,5.694,35,6.684]],["t/35",[2,2.334,36,2.151,37,3.92]],["t/37",[2,1.665,38,1.954,39,1.619,40,4.13,41,2.725,42,3.761]],["t/39",[8,1.436,38,1.954,43,4.13,44,3.761,45,3.518,46,3.761]],["t/41",[2,1.294,38,2.42,44,2.924,45,2.735,46,2.924,47,1.864,48,3.211,49,2.924]],["t/43",[38,2.161,50,2.273,51,4.567,52,4.567,53,3.529]],["t/45",[2,2.058,47,2.964,54,2.416,55,3.945]],["t/47",[2,2.334,56,3.642,57,5.272]],["t/49",[37,2.797,58,2.877,59,4.13,60,3.761,61,3.761,62,3.192]],["t/52",[28,2.602]],["t/54",[29,2.324,63,3.571]],["t/56",[2,2.695,36,2.484]],["t/59",[64,4.526,65,3.747]],["t/61",[65,3.245,66,3.424,67,3.642]],["t/63",[66,2.701,68,3.689,69,3.281,70,3.181,71,2.94]],["t/65",[65,4.432]],["t/68",[64,4.526,65,3.747]],["t/70",[65,3.245,66,3.424,67,3.642]],["t/72",[66,2.701,68,3.689,69,3.281,70,3.181,71,2.94]],["t/74",[65,4.432]],["t/77",[64,4.526,65,3.747]],["t/79",[29,1.775,64,3.457,65,2.862,72,3.368]],["t/81",[65,3.245,66,3.424,67,3.642]],["t/83",[66,2.701,68,3.689,69,3.281,70,3.181,71,2.94]],["t/85",[65,4.432]],["t/88",[28,2.602]],["t/90",[2,2.695,29,2.324]],["t/92",[36,2.484,73,6.684]],["t/96",[28,2.602]],["t/98",[41,4.409,74,4.802]],["t/100",[75,4.032,76,4.802]],["t/103",[77,3.018,78,6.684]],["t/105",[79,5.789,80,5.272,81,5.789]],["t/107",[]],["t/109",[28,2.602]],["t/111",[29,2.012,63,3.093,82,3.642]],["t/113",[36,1.897,82,3.212,83,3.668,84,3.368]],["t/115",[31,4.304,54,2.739,85,3.302]],["t/117",[56,3.642,75,3.492,76,4.16]],["t/119",[58,4.033,77,2.614,86,5.789]],["t/121",[77,2.062,87,3.689,88,4.567,89,4.159,90,4.567]],["t/124",[28,2.602]],["t/126",[29,2.012,91,4.16,92,3.492]],["t/128",[36,1.897,67,3.212,85,2.912,93,4.65]],["t/130",[54,2.739,65,3.245,67,3.642]],["t/131",[39,2.001,50,2.541,64,3.457,65,2.862]],["t/133",[8,1.775,50,2.541,65,2.862,66,3.02]],["t/135",[56,3.642,67,3.642,94,4.931]],["t/137",[39,1.478,67,2.372,91,2.709,92,2.274,94,3.212,95,2.372,96,3.433]],["t/139",[8,1.587,65,2.56,67,2.873,94,3.89,95,2.873]],["t/141",[8,1.311,39,1.478,64,2.553,70,2.626,85,2.15,95,2.372,97,2.626]],["t/143",[58,3.181,67,2.873,72,3.012,98,4.159,99,4.159]],["t/145",[39,1.79,67,2.873,98,4.159,99,4.159,100,3.689]],["t/148",[28,2.602]],["t/150",[23,5.165,29,2.324]],["t/152",[36,2.484,77,3.018]],["t/154",[2,2.695,54,3.162]],["t/156",[39,1.79,50,2.273,101,4.567,102,4.567,103,4.567]],["t/158",[8,1.436,50,2.056,104,4.13,105,3.761,106,4.13,107,4.13]],["t/161",[28,2.602]],["t/163",[29,2.012,41,3.819,74,4.16]],["t/165",[36,2.151,75,3.492,76,4.16]],["t/167",[54,3.162,77,3.018]],["t/168",[39,2.269,50,2.881,108,5.789]],["t/170",[8,2.012,50,2.881,109,5.789]],["t/172",[38,2.739,50,2.881,110,5.789]],["t/174",[50,3.946,111,5.789]],["t/177",[28,2.602]],["t/179",[29,2.324,63,3.571]],["t/181",[36,1.897,82,3.212,83,3.668,84,3.368]],["t/183",[41,3.819,54,2.739,74,4.16]],["t/185",[47,3.361,56,3.642,75,3.492]],["t/187",[58,4.033,77,2.614,112,5.272]],["t/189",[87,5.4,113,5.694]],["t/191",[39,1.79,114,3.281,115,4.159,116,4.159,117,3.529]],["t/193",[8,1.587,47,2.651,114,3.281,117,3.529,118,3.689]],["t/195",[119,6.087,120,5.4]],["t/198",[28,2.602]],["t/200",[29,2.012,63,3.093,82,3.642]],["t/202",[36,1.897,82,3.212,83,3.668,84,3.368]],["t/204",[54,2.739,75,3.492,76,4.16]],["t/206",[2,2.334,54,2.739,121,5.789]],["t/209",[28,2.602]],["t/211",[29,2.324,63,3.571]],["t/213",[36,1.897,82,3.212,83,3.668,84,3.368]],["t/215",[31,4.304,54,2.739,85,3.302]],["t/217",[41,3.819,56,3.642,74,4.16]],["t/219",[47,3.361,58,4.033,75,3.492]],["t/221",[77,2.614,87,4.677,122,4.931]],["t/222",[39,2.001,77,2.306,114,3.668,123,4.125]],["t/224",[8,1.587,77,2.062,114,3.281,124,4.567,125,4.567]],["t/226",[113,5.694,119,6.087]],["t/228",[39,1.79,115,4.159,116,4.159,117,3.529,126,3.529]],["t/230",[8,1.587,117,3.529,126,3.529,127,4.159,128,3.89]],["t/232",[38,2.161,47,2.651,117,3.529,118,3.689,126,3.529]],["t/234",[42,4.65,77,2.306,129,5.106,130,4.65]],["t/236",[120,5.4,131,6.684]],["t/238",[39,1.79,68,3.689,70,3.181,128,3.89,132,3.89]],["t/240",[8,2.012,132,4.931,133,4.474]],["t/242",[38,2.161,97,3.181,122,3.89,132,3.89,133,3.529]],["t/245",[28,2.602]],["t/247",[29,2.012,31,4.304,85,3.302]],["t/249",[36,2.151,41,3.819,74,4.16]],["t/251",[54,2.739,75,3.492,76,4.16]],["t/253",[56,3.642,77,2.614,85,3.302]],["t/254",[11,3.012,37,3.092,39,1.79,95,2.873,134,3.529]],["t/256",[8,1.587,11,3.012,95,2.873,134,3.529,135,3.689]],["t/258",[11,3.012,38,2.161,55,3.529,95,2.873,134,3.529]],["t/260",[11,2.725,50,2.056,95,2.599,130,3.761,134,3.192,136,3.071]],["t/264",[137,6.684,138,6.684]],["t/267",[28,2.602]],["t/269",[29,2.324,63,3.571]],["t/271",[2,2.695,36,2.484]],["t/274",[28,2.602]],["t/276",[29,2.012,41,3.819,74,4.16]],["t/278",[36,2.151,75,3.492,76,4.16]],["t/280",[139,7.906]],["t/282",[54,2.416,77,2.306,92,3.08,136,3.796]],["t/283",[39,1.619,47,2.398,50,2.056,77,1.865,97,2.877,123,3.337]],["t/285",[8,1.587,50,2.273,77,2.062,97,3.181,140,4.159]],["t/287",[77,2.062,89,4.159,92,2.754,134,3.529,136,3.395]],["t/289",[141,6.087,142,6.684]],["t/291",[34,3.92,143,5.789,144,5.272]],["t/294",[28,2.602]],["t/296",[29,2.012,33,4.677,145,5.789]],["t/298",[36,2.484,63,3.571]],["t/300",[2,2.695,54,3.162]],["t/303",[28,2.602]],["t/305",[29,2.324,63,3.571]],["t/307",[2,2.695,36,2.484]],["t/310",[28,2.602]],["t/312",[41,4.409,74,4.802]],["t/314",[75,4.032,76,4.802]],["t/316",[72,3.819,77,2.614,146,5.789]],["t/318",[72,3.819,77,2.614,147,5.789]],["t/320",[120,6.387]],["t/322",[113,6.734]],["t/325",[148,5.4,149,5.4]],["t/327",[28,2.602]],["t/329",[150,5.4,151,5.4]],["t/331",[152,6.387]],["t/333",[28,2.602]],["t/335",[39,2.847,153,3.668,154,4.65]],["t/337",[8,1.775,39,2.001,153,3.668,155,5.106]],["t/339",[29,2.012,37,3.92,62,4.474]],["t/342",[28,2.602]],["t/344",[29,2.324,63,3.571]],["t/346",[2,2.695,36,2.484]],["t/349",[156,7.906]],["t/352",[28,2.602]],["t/354",[157,6.684,158,6.684]],["t/356",[28,2.602]],["t/358",[159,6.684,160,6.684]],["t/360",[49,7.2]],["t/362",[2,2.334,62,4.474,161,4.16]],["t/364",[133,3.529,162,4.567,163,4.567,164,4.567,165,4.567]],["t/367",[166,5.272,167,5.272,168,4.677]],["t/369",[166,2.924,169,3.211,170,3.211,171,3.211,172,3.211,173,3.211,174,3.211,175,2.924,176,3.211]],["t/371",[177,6.684,178,6.684]],["t/373",[28,2.602]],["t/375",[29,1.775,179,4.125,180,5.106,181,4.65]],["t/377",[36,2.484,182,6.087]],["t/380",[148,5.4,149,5.4]],["t/382",[28,2.602]],["t/384",[150,5.4,151,5.4]],["t/386",[152,6.387]],["t/388",[28,2.602]],["t/390",[77,3.018,85,3.812]],["t/392",[72,4.409,77,3.018]],["t/394",[85,3.812,183,6.684]],["t/396",[184,7.906]],["t/399",[28,2.602]],["t/401",[29,2.324,63,3.571]],["t/403",[11,3.819,36,2.151,185,5.789]],["t/405",[2,2.695,54,3.162]],["t/408",[28,2.602]],["t/410",[2,2.334,29,2.012,186,5.789]],["t/412",[2,2.334,36,2.151,187,5.789]],["t/414",[54,2.161,71,2.94,188,4.567,189,4.159,190,4.567]],["t/417",[28,2.602]],["t/419",[29,2.324,63,3.571]],["t/421",[2,2.695,36,2.484]],["t/426",[28,2.602]],["t/428",[29,1.775,191,5.613,192,5.106]],["t/430",[36,2.151,161,4.16,193,5.789]],["t/432",[54,2.739,153,4.16,194,4.677]],["t/433",[39,2.001,50,2.541,123,4.125,153,3.668]],["t/435",[8,1.587,50,2.273,153,3.281,195,4.567,196,3.181]],["t/438",[28,2.602]],["t/439",[39,2.438,66,2.443,69,2.968,197,3.518,198,3.761]],["t/441",[8,1.206,39,1.359,64,2.348,65,1.944,66,2.051,75,2.092,197,2.954,199,2.954]],["t/443",[38,1.414,39,1.171,66,2.857,179,2.414,182,2.722,199,2.546,200,2.414,201,2.989,202,2.989]],["t/445",[29,1.775,66,3.02,70,3.557,203,5.106]],["t/446",[8,1.775,39,2.001,66,3.02,69,3.668]],["t/448",[8,2.329,66,2.701,196,3.181,204,4.159]],["t/450",[8,2.162,39,1.619,66,2.443,196,2.877,204,3.761]],["t/452",[8,2.6,161,2.968,205,4.13,206,3.337]],["t/454",[36,1.401,66,2.23,69,2.709,72,2.487,207,3.77,208,2.553,209,2.709]],["t/457",[47,2.189,61,3.433,75,2.274,85,2.15,210,3.77,211,3.77,212,3.77]],["t/460",[28,2.602]],["t/462",[29,1.775,71,3.287,85,2.912,144,4.65]],["t/464",[36,1.697,71,2.94,85,2.604,141,4.159,213,4.567]],["t/467",[28,2.602]],["t/469",[2,2.695,29,2.324]],["t/472",[199,4.349,214,3.945,215,5.106,216,5.106]],["t/474",[29,1.587,214,3.529,217,4.567,218,3.89,219,4.567]],["t/476",[36,1.697,71,2.94,214,3.529,218,3.89,220,4.567]],["t/478",[54,2.161,214,3.529,218,3.89,221,3.689,222,4.567]],["t/480",[56,3.642,214,4.474,223,4.931]],["t/483",[28,2.602]],["t/484",[39,2.438,53,3.192,197,3.518,198,3.761,224,3.761]],["t/486",[29,2.012,30,4.931,225,4.931]],["t/488",[8,1.775,39,2.001,225,4.349,226,5.106]],["t/490",[36,1.897,77,2.306,206,4.125,223,4.349]],["t/492",[47,2.651,54,2.161,77,2.062,206,3.689,224,4.159]],["t/494",[56,3.642,93,5.272,153,4.16]],["t/497",[28,2.602]],["t/499",[29,2.324,63,3.571]],["t/502",[28,2.602]],["t/504",[29,2.324,63,3.571]],["t/506",[2,2.695,36,2.484]],["t/508",[54,2.739,194,4.677,227,5.789]],["t/511",[91,4.802,92,4.032]],["t/513",[2,1.665,29,1.436,37,2.797,77,1.865,92,2.491,228,3.518]],["t/515",[2,1.52,36,1.401,77,1.703,92,2.274,135,3.046,136,2.803,228,3.212]],["t/518",[28,2.602]],["t/520",[29,1.587,229,4.159,230,4.567,231,4.567,232,4.159]],["t/522",[36,2.151,194,4.677,233,5.789]],["t/525",[28,1.905,208,3.92,209,4.16]],["t/527",[2,2.695,29,2.324]],["t/529",[36,1.697,71,2.94,72,3.012,234,3.89,235,3.689]],["t/532",[28,2.602]],["t/534",[2,2.058,29,1.775,84,3.368,236,5.106]],["t/536",[36,2.151,77,2.614,237,5.789]],["t/538",[54,1.784,208,2.553,209,2.709,238,3.77,239,3.77,240,3.77,241,3.77]],["t/541",[28,2.602]],["t/543",[29,2.324,63,3.571]],["t/545",[36,2.151,242,4.677,243,5.789]],["t/547",[38,2.416,39,2.001,242,4.125,244,5.106]],["t/549",[8,1.775,38,2.416,181,4.65,242,4.125]],["t/551",[8,1.775,38,2.416,80,4.65,242,4.125]],["t/553",[54,3.162,245,6.087]],["t/555",[91,4.16,246,5.272,247,5.789]],["t/558",[28,2.602]],["t/560",[2,2.695,29,2.324]],["t/563",[28,2.602]],["t/565",[63,3.571,82,4.205]],["t/567",[82,3.642,83,4.16,84,3.819]],["t/569",[47,3.881,248,5.694]],["t/571",[47,3.361,161,4.16,249,5.789]],["t/573",[47,3.361,161,4.16,250,5.789]],["t/576",[28,1.905,208,3.92,209,4.16]],["t/578",[29,2.012,75,3.492,251,5.272]],["t/580",[36,2.151,252,4.474,253,4.474]],["t/583",[148,5.4,149,5.4]],["t/585",[28,2.602]],["t/587",[150,5.4,151,5.4]],["t/589",[152,6.387]],["t/592",[28,2.602]],["t/594",[2,2.058,29,1.775,47,2.964,254,5.106]],["t/596",[2,1.665,36,1.535,47,2.398,208,2.797,209,2.968,255,4.13]],["t/599",[256,6.684,257,6.087]],["t/601",[29,1.775,175,4.65,258,5.106,259,5.106]],["t/603",[36,2.151,257,5.272,260,5.789]],["t/605",[45,4.349,54,2.416,261,5.106,262,5.106]],["t/607",[56,3.212,69,3.668,263,5.106,264,3.945]],["t/609",[58,4.656,265,6.684]],["t/612",[28,2.602]],["t/614",[29,1.587,41,3.012,232,4.159,264,3.529,266,4.567]],["t/616",[36,1.535,77,1.865,264,3.192,267,3.761,268,4.13,269,3.761]],["t/618",[54,2.416,264,3.945,270,5.106,271,3.796]],["t/620",[39,1.619,50,2.056,64,2.797,97,2.877,271,3.071,272,4.13]],["t/622",[8,1.587,50,2.273,97,3.181,128,3.89,271,3.395]],["t/625",[28,1.905,208,3.92,209,4.16]],["t/627",[29,2.324,84,4.409]],["t/629",[36,2.151,252,4.474,253,4.474]],["t/631",[54,3.162,273,6.684]],["t/633",[56,4.205,189,6.087]],["t/635",[58,4.656,194,5.4]],["t/638",[28,2.602]],["t/640",[29,1.587,70,3.181,97,3.181,274,4.567,275,4.159]],["t/642",[36,1.697,70,3.181,97,3.181,245,4.159,276,4.567]],["t/645",[28,2.602]],["t/647",[29,2.012,248,4.931,277,5.789]],["t/649",[2,2.695,36,2.484]],["t/652",[65,3.245,196,4.033,278,5.789]],["t/654",[2,2.334,39,3.108]],["t/656",[29,1.775,53,3.945,60,4.65,65,2.862]],["t/658",[8,1.775,39,2.001,53,3.945,279,5.106]],["t/660",[8,2.525,280,4.65,281,4.65]],["t/662",[8,1.587,38,2.161,92,2.754,280,4.159,281,4.159]],["t/665",[28,2.602]],["t/667",[29,1.436,53,3.192,62,3.192,118,3.337,275,3.761,282,3.761]],["t/669",[36,1.535,67,2.599,118,3.337,282,3.761,283,4.13,284,3.761]],["t/671",[34,3.092,38,2.161,39,1.79,285,4.567,286,3.89]],["t/673",[8,1.587,34,3.092,38,2.161,286,3.89,287,4.567]],["t/676",[28,2.602]],["t/678",[29,2.012,75,3.492,191,4.474]],["t/680",[2,2.058,36,1.897,191,3.945,288,5.106]],["t/682",[54,2.739,161,4.16,191,4.474]],["t/683",[39,1.619,50,2.056,91,2.968,161,2.968,191,3.192,289,4.13]],["t/685",[2,2.334,8,2.012,50,2.881]],["t/688",[28,2.602]],["t/690",[2,2.695,29,2.324]],["t/692",[36,1.897,72,3.368,234,4.349,235,4.125]],["t/694",[]],["t/696",[28,2.602]],["t/698",[290,7.906]],["t/700",[11,4.409,196,4.656]],["t/701",[252,6.109]],["t/704",[28,2.602]],["t/706",[29,2.012,77,2.614,168,4.677]],["t/708",[8,1.587,39,1.79,77,2.062,168,3.689,291,4.567]],["t/709",[8,2.329,168,3.689,196,3.181,292,4.159]],["t/710",[8,1.587,38,2.161,41,3.012,293,4.567,294,4.567]],["t/711",[1,4.159,8,1.587,50,2.273,292,4.159,295,4.567]],["t/712",[36,2.484,296,6.087]],["t/713",[38,2.416,39,2.001,296,4.65,297,5.106]],["t/715",[8,2.012,38,2.739,298,5.789]],["t/717",[38,3.17,64,3.092,299,4.567,300,4.567]],["t/719",[54,3.162,301,6.684]],["t/722",[28,2.602]],["t/724",[29,2.324,248,5.694]],["t/726",[36,2.484,253,5.165]],["t/731",[28,2.602]],["t/733",[29,1.587,47,2.651,77,2.062,302,4.567,303,4.159]],["t/735",[36,2.151,77,2.614,85,3.302]],["t/737",[54,3.162,65,3.747]],["t/740",[28,2.602]],["t/742",[29,2.324,63,3.571]],["t/744",[2,2.695,36,2.484]],["t/747",[28,1.905,208,3.92,209,4.16]],["t/749",[2,2.695,29,2.324]],["t/751",[36,1.897,304,5.106,305,5.106,306,5.106]],["t/753",[307,6.684,308,6.684]],["t/755",[34,3.92,54,2.739,309,5.789]],["t/757",[56,4.205,120,5.4]],["t/760",[28,2.602]],["t/762",[29,1.775,310,4.65,311,5.106,312,4.349]],["t/764",[36,2.151,310,5.272,312,4.931]],["t/766",[54,2.739,312,4.931,313,5.789]],["t/769",[269,6.087,314,5.694]],["t/771",[39,2.847,314,4.349,315,5.106]],["t/773",[8,1.775,39,2.001,229,4.65,314,4.349]],["t/775",[29,2.012,105,5.272,264,4.474]],["t/777",[11,3.819,36,2.151,223,4.931]],["t/779",[2,2.334,38,2.739,39,2.269]],["t/782",[28,2.602]],["t/784",[37,2.553,39,2.274,55,2.913,179,3.046,200,3.046,316,3.77]],["t/786",[8,0.814,11,1.544,37,1.585,39,0.918,179,1.891,200,1.891,235,1.891,317,2.341,318,2.341,319,3.948,320,2.341,321,2.341,322,2.341]],["t/788",[29,2.324,63,3.571]],["t/789",[8,1.775,23,3.945,39,2.001,323,5.106]],["t/791",[8,2.525,23,3.945,67,3.212]],["t/793",[8,2.012,38,2.739,324,5.789]],["t/795",[8,1.775,50,2.541,251,4.65,325,5.106]],["t/797",[8,1.587,34,3.092,95,2.873,286,3.89,326,4.567]],["t/799",[8,1.775,34,3.457,100,4.125,284,4.65]],["t/801",[8,2.012,114,4.16,327,5.789]],["t/803",[8,2.012,126,4.474,328,5.789]],["t/805",[36,2.484,84,4.409]],["t/808",[28,2.602]],["t/810",[329,7.906]],["t/813",[28,2.602]],["t/815",[2,2.695,29,2.324]],["t/817",[36,2.484,154,6.087]],["t/819",[38,2.739,39,2.269,225,4.931]],["t/823",[82,3.642,83,4.16,84,3.819]],["t/825",[31,4.97,92,4.032]],["t/827",[28,2.602]],["t/829",[29,2.012,71,3.727,330,5.789]],["t/831",[252,5.165,253,5.165]],["t/833",[36,2.151,71,3.727,331,5.789]],["t/835",[54,2.161,71,2.94,72,3.012,234,3.89,235,3.689]],["t/838",[28,2.602]],["t/840",[2,2.058,29,1.775,221,4.125,332,4.349]],["t/842",[8,1.436,39,1.619,77,1.865,85,2.356,221,3.337,332,3.518]],["t/844",[8,2.162,34,2.797,133,3.192,221,3.337,332,3.518]],["t/846",[36,2.484,333,5.694]],["t/848",[38,2.161,39,1.79,77,2.062,85,2.604,333,3.89]],["t/850",[8,1.587,34,3.092,38,2.161,133,3.529,333,3.89]],["t/853",[28,2.602]],["t/855",[2,2.334,29,2.012,77,2.614]],["t/856",[8,1.775,39,2.001,112,4.65,334,4.65]],["t/858",[8,2.525,122,4.349,334,4.65]],["t/861",[28,2.602]],["t/863",[29,2.324,63,3.571]],["t/867",[8,2.012,39,2.269,335,4.931]],["t/869",[9,3.819,39,2.269,335,4.931]],["t/871",[9,5.23,335,4.931]],["t/873",[9,4.791,114,3.668,336,3.668]],["t/875",[9,4.791,100,4.125,336,3.668]],["t/877",[9,4.791,95,3.212,336,3.668]],["t/879",[9,3.368,50,2.541,95,3.212,336,3.668]],["t/881",[9,3.368,38,2.416,95,3.212,336,3.668]],["t/883",[8,1.775,9,3.368,50,2.541,336,3.668]],["t/885",[9,4.791,39,2.001,336,3.668]],["t/887",[39,0.828,196,1.472,206,1.707,246,1.924,271,1.571,337,2.113,338,2.113,339,2.113,340,2.113,341,2.113,342,2.113,343,2.113,344,2.113,345,2.113,346,2.113,347,2.113]],["t/888",[8,1.775,196,3.557,271,3.796,348,5.106]],["t/890",[2,2.058,33,4.125,38,2.416,271,3.796]],["t/893",[91,4.802,92,4.032]],["t/895",[77,2.614,85,3.302,123,4.677]],["t/898",[148,5.4,149,5.4]],["t/900",[28,2.602]],["t/902",[150,5.4,151,5.4]],["t/904",[152,6.387]],["t/908",[82,4.205,349,6.684]],["t/910",[63,3.571,82,4.205]],["t/912",[82,3.642,83,4.16,84,3.819]],["t/914",[31,4.97,85,3.812]],["t/918",[63,4.224]],["t/920",[252,5.165,253,5.165]],["t/924",[47,2.189,72,2.487,75,2.274,85,2.15,303,3.433,350,3.77,351,3.77]],["t/927",[91,4.802,92,4.032]],["t/929",[77,2.614,92,3.492,228,4.931]],["t/931",[92,3.492,96,5.272,352,5.789]],["t/934",[28,2.602]],["t/936",[20,4.677,29,2.012,167,5.272]],["t/937",[8,1.775,37,3.457,39,2.001,353,4.125]],["t/939",[8,2.525,353,4.125,354,5.106]],["t/941",[8,1.775,38,2.416,55,3.945,353,4.125]],["t/943",[8,2.012,50,2.881,355,5.789]],["t/945",[8,2.012,95,3.642,140,5.272]],["t/947",[8,2.012,100,4.677,356,5.789]],["t/949",[8,1.311,37,2.553,55,2.913,114,2.709,135,3.046,136,2.803,200,3.046]],["t/951",[8,1.775,126,3.945,135,4.125,353,4.125]],["t/953",[136,5.878]],["t/955",[36,1.697,92,2.754,267,4.159,357,4.567,358,4.567]],["t/956",[38,2.161,39,1.79,62,3.529,127,4.159,359,4.567]],["t/958",[8,1.436,23,3.192,38,1.954,57,3.761,360,4.13,361,4.13]],["t/960",[20,5.4,54,3.162]],["t/962",[14,3.89,39,1.79,50,2.273,362,4.567,363,3.89]],["t/964",[8,1.587,14,3.89,50,2.273,208,3.092,363,3.89]],["t/966",[38,2.416,50,2.541,208,3.457,363,4.349]],["t/968",[2,2.334,56,3.642,364,5.789]],["t/970",[58,4.033,153,4.16,365,5.789]],["t/972",[87,4.677,366,5.789,367,5.789]],["t/975",[28,2.602]],["t/977",[29,2.324,63,3.571]],["t/979",[2,2.695,36,2.484]]],"invertedIndex":[["0",{"_index":9,"t":{"6":{"position":[[17,1]]},"869":{"position":[[5,1]]},"871":{"position":[[3,1],[5,1]]},"873":{"position":[[5,1],[9,1]]},"875":{"position":[[5,1],[9,1]]},"877":{"position":[[5,1],[9,1]]},"879":{"position":[[5,1]]},"881":{"position":[[5,1]]},"883":{"position":[[5,1]]},"885":{"position":[[5,1],[9,1]]}}}],["1",{"_index":39,"t":{"37":{"position":[[2,1]]},"131":{"position":[[2,1]]},"137":{"position":[[2,1]]},"141":{"position":[[4,1]]},"145":{"position":[[2,1]]},"156":{"position":[[2,1]]},"168":{"position":[[2,1]]},"191":{"position":[[2,1]]},"222":{"position":[[2,1]]},"228":{"position":[[2,1]]},"238":{"position":[[3,1]]},"254":{"position":[[2,1]]},"283":{"position":[[2,1]]},"335":{"position":[[0,1],[2,1]]},"337":{"position":[[0,1]]},"433":{"position":[[2,1]]},"439":{"position":[[0,1],[2,1]]},"441":{"position":[[0,1]]},"443":{"position":[[0,1]]},"446":{"position":[[2,1]]},"450":{"position":[[4,1]]},"484":{"position":[[0,1],[2,1]]},"488":{"position":[[2,1]]},"547":{"position":[[2,1]]},"620":{"position":[[2,1]]},"654":{"position":[[0,1],[2,1]]},"658":{"position":[[2,1]]},"671":{"position":[[2,1]]},"683":{"position":[[2,1]]},"708":{"position":[[2,1]]},"713":{"position":[[2,1]]},"771":{"position":[[0,1],[2,1]]},"773":{"position":[[0,1]]},"779":{"position":[[2,1]]},"784":{"position":[[0,1],[2,1]]},"786":{"position":[[0,1]]},"789":{"position":[[2,1]]},"819":{"position":[[2,1]]},"842":{"position":[[2,1]]},"848":{"position":[[2,1]]},"856":{"position":[[2,1]]},"867":{"position":[[5,1]]},"869":{"position":[[3,1]]},"885":{"position":[[7,1]]},"887":{"position":[[0,1]]},"937":{"position":[[2,1]]},"956":{"position":[[2,1]]},"962":{"position":[[2,1]]}}}],["10",{"_index":132,"t":{"238":{"position":[[0,2]]},"240":{"position":[[0,2]]},"242":{"position":[[0,2]]}}}],["16",{"_index":261,"t":{"605":{"position":[[2,2]]}}}],["2",{"_index":8,"t":{"6":{"position":[[15,1]]},"39":{"position":[[2,1]]},"133":{"position":[[2,1]]},"139":{"position":[[2,1]]},"141":{"position":[[2,1]]},"158":{"position":[[2,1]]},"170":{"position":[[2,1]]},"193":{"position":[[2,1]]},"224":{"position":[[2,1]]},"230":{"position":[[2,1]]},"240":{"position":[[3,1]]},"256":{"position":[[2,1]]},"285":{"position":[[2,1]]},"337":{"position":[[2,1]]},"435":{"position":[[2,1]]},"441":{"position":[[2,1]]},"446":{"position":[[0,1]]},"448":{"position":[[0,1],[2,1]]},"450":{"position":[[0,1],[2,1]]},"452":{"position":[[0,1],[2,1],[4,1]]},"488":{"position":[[0,1]]},"549":{"position":[[2,1]]},"551":{"position":[[2,1]]},"622":{"position":[[2,1]]},"658":{"position":[[0,1]]},"660":{"position":[[0,1],[2,1]]},"662":{"position":[[0,1]]},"673":{"position":[[2,1]]},"685":{"position":[[2,1]]},"708":{"position":[[0,1]]},"709":{"position":[[0,1],[2,1]]},"710":{"position":[[0,1]]},"711":{"position":[[0,1]]},"715":{"position":[[2,1]]},"773":{"position":[[2,1]]},"786":{"position":[[2,1]]},"789":{"position":[[0,1]]},"791":{"position":[[0,1],[2,1]]},"793":{"position":[[0,1]]},"795":{"position":[[0,1]]},"797":{"position":[[0,1]]},"799":{"position":[[0,1]]},"801":{"position":[[0,1]]},"803":{"position":[[0,1]]},"842":{"position":[[0,1]]},"844":{"position":[[0,1],[2,1]]},"850":{"position":[[2,1]]},"856":{"position":[[0,1]]},"858":{"position":[[0,1],[2,1]]},"867":{"position":[[3,1]]},"883":{"position":[[7,1]]},"888":{"position":[[0,1]]},"937":{"position":[[0,1]]},"939":{"position":[[0,1],[2,1]]},"941":{"position":[[0,1]]},"943":{"position":[[0,1]]},"945":{"position":[[0,1]]},"947":{"position":[[0,1]]},"949":{"position":[[0,1]]},"951":{"position":[[0,1]]},"958":{"position":[[2,1]]},"964":{"position":[[2,1]]}}}],["3",{"_index":38,"t":{"37":{"position":[[0,1]]},"39":{"position":[[0,1]]},"41":{"position":[[0,1],[2,1]]},"43":{"position":[[0,1]]},"172":{"position":[[2,1]]},"232":{"position":[[2,1]]},"242":{"position":[[3,1]]},"258":{"position":[[2,1]]},"443":{"position":[[2,1]]},"547":{"position":[[0,1]]},"549":{"position":[[0,1]]},"551":{"position":[[0,1]]},"662":{"position":[[2,1]]},"671":{"position":[[0,1]]},"673":{"position":[[0,1]]},"710":{"position":[[2,1]]},"713":{"position":[[0,1]]},"715":{"position":[[0,1]]},"717":{"position":[[0,1],[2,1]]},"779":{"position":[[0,1]]},"793":{"position":[[2,1]]},"819":{"position":[[0,1]]},"848":{"position":[[0,1]]},"850":{"position":[[0,1]]},"881":{"position":[[7,1]]},"890":{"position":[[0,1]]},"941":{"position":[[2,1]]},"956":{"position":[[0,1]]},"958":{"position":[[0,1]]},"966":{"position":[[2,1]]}}}],["3de",{"_index":156,"t":{"349":{"position":[[2,4]]}}}],["4",{"_index":50,"t":{"43":{"position":[[2,1]]},"131":{"position":[[0,1]]},"133":{"position":[[0,1]]},"156":{"position":[[0,1]]},"158":{"position":[[0,1]]},"168":{"position":[[0,1]]},"170":{"position":[[0,1]]},"172":{"position":[[0,1]]},"174":{"position":[[0,1],[2,1]]},"260":{"position":[[2,1]]},"283":{"position":[[0,1]]},"285":{"position":[[0,1]]},"433":{"position":[[0,1]]},"435":{"position":[[0,1]]},"620":{"position":[[0,1]]},"622":{"position":[[0,1]]},"683":{"position":[[0,1]]},"685":{"position":[[0,1]]},"711":{"position":[[2,1]]},"795":{"position":[[2,1]]},"879":{"position":[[7,1]]},"883":{"position":[[9,1]]},"943":{"position":[[2,1]]},"962":{"position":[[0,1]]},"964":{"position":[[0,1]]},"966":{"position":[[0,1]]}}}],["5",{"_index":95,"t":{"137":{"position":[[0,1]]},"139":{"position":[[0,1]]},"141":{"position":[[0,1]]},"254":{"position":[[0,1]]},"256":{"position":[[0,1]]},"258":{"position":[[0,1]]},"260":{"position":[[0,1]]},"797":{"position":[[2,1]]},"877":{"position":[[7,1]]},"879":{"position":[[9,1]]},"881":{"position":[[9,1]]},"945":{"position":[[2,1]]}}}],["6",{"_index":100,"t":{"145":{"position":[[0,1]]},"799":{"position":[[2,1]]},"875":{"position":[[7,1]]},"947":{"position":[[2,1]]}}}],["7",{"_index":114,"t":{"191":{"position":[[0,1]]},"193":{"position":[[0,1]]},"222":{"position":[[0,1]]},"224":{"position":[[0,1]]},"801":{"position":[[2,1]]},"873":{"position":[[7,1]]},"949":{"position":[[2,1]]}}}],["8",{"_index":126,"t":{"228":{"position":[[0,1]]},"230":{"position":[[0,1]]},"232":{"position":[[0,1]]},"803":{"position":[[2,1]]},"951":{"position":[[2,1]]}}}],["apach",{"_index":6,"t":{"6":{"position":[[0,6]]}}}],["aspnetcor",{"_index":130,"t":{"234":{"position":[[2,10]]},"260":{"position":[[6,10]]}}}],["call",{"_index":99,"t":{"143":{"position":[[6,4]]},"145":{"position":[[5,4]]}}}],["channel",{"_index":284,"t":{"669":{"position":[[7,7]]},"799":{"position":[[4,7]]}}}],["config",{"_index":40,"t":{"37":{"position":[[5,6]]}}}],["connect",{"_index":44,"t":{"39":{"position":[[6,10]]},"41":{"position":[[11,10]]}}}],["consolelogg",{"_index":219,"t":{"474":{"position":[[11,13]]}}}],["crc",{"_index":256,"t":{"599":{"position":[[2,3]]}}}],["datahandlingadapt",{"_index":160,"t":{"358":{"position":[[2,19]]}}}],["dll",{"_index":299,"t":{"717":{"position":[[4,3]]}}}],["eventbu",{"_index":327,"t":{"801":{"position":[[4,8]]}}}],["filelogg",{"_index":220,"t":{"476":{"position":[[10,10]]}}}],["hold",{"_index":107,"t":{"158":{"position":[[12,4]]}}}],["http",{"_index":135,"t":{"256":{"position":[[6,4]]},"515":{"position":[[4,4]]},"949":{"position":[[21,4]]},"951":{"position":[[4,4]]}}}],["httpsclient",{"_index":78,"t":{"103":{"position":[[2,11]]}}}],["httpservic",{"_index":86,"t":{"119":{"position":[[4,11]]}}}],["httpsservic",{"_index":90,"t":{"121":{"position":[[10,12]]}}}],["httptouchrpcclient",{"_index":109,"t":{"170":{"position":[[4,18]]}}}],["id",{"_index":264,"t":{"607":{"position":[[4,2]]},"614":{"position":[[6,2]]},"616":{"position":[[10,2]]},"618":{"position":[[6,2]]},"775":{"position":[[2,2]]}}}],["ilog",{"_index":216,"t":{"472":{"position":[[9,4]]}}}],["iwebsocketplugin",{"_index":139,"t":{"280":{"position":[[0,16]]}}}],["json",{"_index":231,"t":{"520":{"position":[[7,4]]}}}],["jsonfast",{"_index":233,"t":{"522":{"position":[[2,8]]}}}],["jsonrpc",{"_index":355,"t":{"943":{"position":[[4,7]]}}}],["licens",{"_index":7,"t":{"6":{"position":[[7,7]]}}}],["loggergroup",{"_index":222,"t":{"478":{"position":[[9,11]]}}}],["md5",{"_index":260,"t":{"603":{"position":[[2,3]]}}}],["nat",{"_index":354,"t":{"939":{"position":[[4,3]]}}}],["natservic",{"_index":237,"t":{"536":{"position":[[4,10]]}}}],["net",{"_index":295,"t":{"711":{"position":[[6,3]]}}}],["nuget",{"_index":297,"t":{"713":{"position":[[4,5]]}}}],["packagerefer",{"_index":298,"t":{"715":{"position":[[4,16]]}}}],["ping",{"_index":308,"t":{"753":{"position":[[2,4]]}}}],["pollingkeepal",{"_index":255,"t":{"596":{"position":[[4,16]]}}}],["pull",{"_index":330,"t":{"829":{"position":[[2,4]]}}}],["push",{"_index":331,"t":{"833":{"position":[[2,4]]}}}],["receiv",{"_index":115,"t":{"191":{"position":[[4,8]]},"228":{"position":[[4,8]]}}}],["reconnect",{"_index":254,"t":{"594":{"position":[[4,12]]}}}],["redi",{"_index":328,"t":{"803":{"position":[[4,5]]}}}],["rpc",{"_index":67,"t":{"61":{"position":[[4,3]]},"70":{"position":[[4,3]]},"81":{"position":[[4,3]]},"128":{"position":[[4,3]]},"130":{"position":[[4,3]]},"135":{"position":[[4,3]]},"137":{"position":[[11,3]]},"139":{"position":[[8,3]]},"143":{"position":[[11,3]]},"145":{"position":[[10,3]]},"669":{"position":[[2,3]]},"791":{"position":[[4,3]]}}}],["servic",{"_index":272,"t":{"620":{"position":[[6,7]]}}}],["socketcli",{"_index":128,"t":{"230":{"position":[[6,12]]},"238":{"position":[[9,12]]},"622":{"position":[[6,12]]}}}],["ssl",{"_index":89,"t":{"121":{"position":[[6,3]]},"287":{"position":[[4,3]]}}}],["tcp",{"_index":37,"t":{"35":{"position":[[2,3]]},"49":{"position":[[8,3]]},"254":{"position":[[6,3]]},"339":{"position":[[2,3]]},"513":{"position":[[4,3]]},"784":{"position":[[13,3]]},"786":{"position":[[4,3]]},"937":{"position":[[4,3]]},"949":{"position":[[13,3]]}}}],["tcpclient",{"_index":112,"t":{"187":{"position":[[4,9]]},"856":{"position":[[5,9]]}}}],["tcpservic",{"_index":122,"t":{"221":{"position":[[4,10]]},"242":{"position":[[7,10]]},"858":{"position":[[5,10]]}}}],["tcptouchrpcclient",{"_index":108,"t":{"168":{"position":[[4,17]]}}}],["timemeasur",{"_index":259,"t":{"601":{"position":[[8,12]]}}}],["token",{"_index":315,"t":{"771":{"position":[[4,5]]}}}],["touchrpc",{"_index":200,"t":{"443":{"position":[[4,8]]},"784":{"position":[[4,8]]},"786":{"position":[[20,8]]},"949":{"position":[[4,8]]}}}],["touchsocket",{"_index":167,"t":{"367":{"position":[[2,11]]},"936":{"position":[[2,11]]}}}],["touchsocketpro",{"_index":20,"t":{"15":{"position":[[0,14]]},"17":{"position":[[0,14]]},"936":{"position":[[14,14]]},"960":{"position":[[2,14]]}}}],["udp",{"_index":55,"t":{"45":{"position":[[2,3]]},"258":{"position":[[6,3]]},"784":{"position":[[17,3]]},"941":{"position":[[4,3]]},"949":{"position":[[17,3]]}}}],["udpsess",{"_index":121,"t":{"206":{"position":[[4,10]]}}}],["udptouchrpc",{"_index":110,"t":{"172":{"position":[[4,11]]}}}],["v1",{"_index":335,"t":{"867":{"position":[[0,2]]},"869":{"position":[[0,2]]},"871":{"position":[[0,2]]}}}],["vs",{"_index":344,"t":{"887":{"position":[[28,2]]}}}],["webapi",{"_index":140,"t":{"285":{"position":[[6,6]]},"945":{"position":[[4,6]]}}}],["websocket",{"_index":136,"t":{"260":{"position":[[17,9]]},"282":{"position":[[4,9]]},"287":{"position":[[8,9]]},"515":{"position":[[9,9]]},"949":{"position":[[26,9]]},"953":{"position":[[0,9]]}}}],["ws",{"_index":146,"t":{"316":{"position":[[2,2]]}}}],["wss",{"_index":147,"t":{"318":{"position":[[2,3]]}}}],["wstouchrpcclient",{"_index":111,"t":{"174":{"position":[[4,16]]}}}],["xmlrpc",{"_index":356,"t":{"947":{"position":[[4,6]]}}}],["一起",{"_index":177,"t":{"371":{"position":[[0,2]]}}}],["七",{"_index":87,"t":{"121":{"position":[[0,1]]},"189":{"position":[[0,1]]},"221":{"position":[[0,1]]},"972":{"position":[[0,1]]}}}],["三",{"_index":36,"t":{"35":{"position":[[0,1]]},"56":{"position":[[0,1]]},"92":{"position":[[0,1]]},"113":{"position":[[0,1]]},"128":{"position":[[0,1]]},"152":{"position":[[0,1]]},"165":{"position":[[0,1]]},"181":{"position":[[0,1]]},"202":{"position":[[0,1]]},"213":{"position":[[0,1]]},"249":{"position":[[0,1]]},"271":{"position":[[0,1]]},"278":{"position":[[0,1]]},"298":{"position":[[0,1]]},"307":{"position":[[0,1]]},"346":{"position":[[0,1]]},"377":{"position":[[0,1]]},"403":{"position":[[0,1]]},"412":{"position":[[0,1]]},"421":{"position":[[0,1]]},"430":{"position":[[0,1]]},"454":{"position":[[0,1]]},"464":{"position":[[0,1]]},"476":{"position":[[0,1]]},"490":{"position":[[0,1]]},"506":{"position":[[0,1]]},"515":{"position":[[0,1]]},"522":{"position":[[0,1]]},"529":{"position":[[0,1]]},"536":{"position":[[0,1]]},"545":{"position":[[0,1]]},"580":{"position":[[0,1]]},"596":{"position":[[0,1]]},"603":{"position":[[0,1]]},"616":{"position":[[0,1]]},"629":{"position":[[0,1]]},"642":{"position":[[0,1]]},"649":{"position":[[0,1]]},"669":{"position":[[0,1]]},"680":{"position":[[0,1]]},"692":{"position":[[0,1]]},"712":{"position":[[0,1]]},"726":{"position":[[0,1]]},"735":{"position":[[0,1]]},"744":{"position":[[0,1]]},"751":{"position":[[0,1]]},"764":{"position":[[0,1]]},"777":{"position":[[0,1]]},"805":{"position":[[0,1]]},"817":{"position":[[0,1]]},"833":{"position":[[0,1]]},"846":{"position":[[0,1]]},"955":{"position":[[0,1]]},"979":{"position":[[0,1]]}}}],["上传",{"_index":213,"t":{"464":{"position":[[7,2]]}}}],["个人",{"_index":14,"t":{"9":{"position":[[0,2]]},"962":{"position":[[4,2]]},"964":{"position":[[4,2]]}}}],["个性",{"_index":358,"t":{"955":{"position":[[6,2]]}}}],["中",{"_index":42,"t":{"37":{"position":[[13,1]]},"234":{"position":[[12,1]]}}}],["为什么",{"_index":197,"t":{"439":{"position":[[4,3]]},"441":{"position":[[4,3]]},"484":{"position":[[4,3]]}}}],["主要",{"_index":79,"t":{"105":{"position":[[0,2]]}}}],["之间",{"_index":234,"t":{"529":{"position":[[5,2]]},"692":{"position":[[5,2]]},"835":{"position":[[5,2]]}}}],["九",{"_index":129,"t":{"234":{"position":[[0,1]]}}}],["事件",{"_index":46,"t":{"39":{"position":[[18,2]]},"41":{"position":[[23,2]]}}}],["事项",{"_index":155,"t":{"337":{"position":[[6,2]]}}}],["二",{"_index":29,"t":{"24":{"position":[[0,1]]},"54":{"position":[[0,1]]},"79":{"position":[[0,1]]},"90":{"position":[[0,1]]},"111":{"position":[[0,1]]},"126":{"position":[[0,1]]},"150":{"position":[[0,1]]},"163":{"position":[[0,1]]},"179":{"position":[[0,1]]},"200":{"position":[[0,1]]},"211":{"position":[[0,1]]},"247":{"position":[[0,1]]},"269":{"position":[[0,1]]},"276":{"position":[[0,1]]},"296":{"position":[[0,1]]},"305":{"position":[[0,1]]},"339":{"position":[[0,1]]},"344":{"position":[[0,1]]},"375":{"position":[[0,1]]},"401":{"position":[[0,1]]},"410":{"position":[[0,1]]},"419":{"position":[[0,1]]},"428":{"position":[[0,1]]},"445":{"position":[[0,1]]},"462":{"position":[[0,1]]},"469":{"position":[[0,1]]},"474":{"position":[[0,1]]},"486":{"position":[[0,1]]},"499":{"position":[[0,1]]},"504":{"position":[[0,1]]},"513":{"position":[[0,1]]},"520":{"position":[[0,1]]},"527":{"position":[[0,1]]},"534":{"position":[[0,1]]},"543":{"position":[[0,1]]},"560":{"position":[[0,1]]},"578":{"position":[[0,1]]},"594":{"position":[[0,1]]},"601":{"position":[[0,1]]},"614":{"position":[[0,1]]},"627":{"position":[[0,1]]},"640":{"position":[[0,1]]},"647":{"position":[[0,1]]},"656":{"position":[[0,1]]},"667":{"position":[[0,1]]},"678":{"position":[[0,1]]},"690":{"position":[[0,1]]},"706":{"position":[[0,1]]},"724":{"position":[[0,1]]},"733":{"position":[[0,1]]},"742":{"position":[[0,1]]},"749":{"position":[[0,1]]},"762":{"position":[[0,1]]},"775":{"position":[[0,1]]},"788":{"position":[[0,1]]},"815":{"position":[[0,1]]},"829":{"position":[[0,1]]},"840":{"position":[[0,1]]},"855":{"position":[[0,1]]},"863":{"position":[[0,1]]},"936":{"position":[[0,1]]},"977":{"position":[[0,1]]}}}],["二次开发",{"_index":16,"t":{"11":{"position":[[0,4]]}}}],["互",{"_index":98,"t":{"143":{"position":[[5,1]]},"145":{"position":[[4,1]]}}}],["五",{"_index":56,"t":{"47":{"position":[[0,1]]},"117":{"position":[[0,1]]},"135":{"position":[[0,1]]},"185":{"position":[[0,1]]},"217":{"position":[[0,1]]},"253":{"position":[[0,1]]},"480":{"position":[[0,1]]},"494":{"position":[[0,1]]},"607":{"position":[[0,1]]},"633":{"position":[[0,1]]},"757":{"position":[[0,1]]},"968":{"position":[[0,1]]}}}],["产品",{"_index":82,"t":{"111":{"position":[[2,2]]},"113":{"position":[[2,2]]},"181":{"position":[[2,2]]},"200":{"position":[[2,2]]},"202":{"position":[[2,2]]},"213":{"position":[[2,2]]},"565":{"position":[[0,2]]},"567":{"position":[[0,2]]},"823":{"position":[[0,2]]},"908":{"position":[[0,2]]},"910":{"position":[[0,2]]},"912":{"position":[[0,2]]}}}],["什么",{"_index":179,"t":{"375":{"position":[[2,2]]},"443":{"position":[[25,2]]},"784":{"position":[[21,2]]},"786":{"position":[[35,2]]}}}],["仅",{"_index":61,"t":{"49":{"position":[[7,1]]},"457":{"position":[[8,1]]}}}],["介绍",{"_index":349,"t":{"908":{"position":[[2,2]]}}}],["代替",{"_index":48,"t":{"41":{"position":[[9,2]]}}}],["代理",{"_index":66,"t":{"61":{"position":[[0,2]]},"63":{"position":[[6,2]]},"70":{"position":[[0,2]]},"72":{"position":[[6,2]]},"81":{"position":[[0,2]]},"83":{"position":[[6,2]]},"133":{"position":[[4,2]]},"439":{"position":[[10,2]]},"441":{"position":[[14,2]]},"443":{"position":[[15,2],[21,2]]},"445":{"position":[[8,2]]},"446":{"position":[[6,2]]},"448":{"position":[[4,2]]},"450":{"position":[[8,2]]},"454":{"position":[[10,2]]}}}],["代码",{"_index":252,"t":{"580":{"position":[[2,2]]},"629":{"position":[[2,2]]},"701":{"position":[[0,2]]},"831":{"position":[[2,2]]},"920":{"position":[[2,2]]}}}],["代表",{"_index":268,"t":{"616":{"position":[[5,2]]}}}],["以下",{"_index":171,"t":{"369":{"position":[[7,2]]}}}],["任务",{"_index":280,"t":{"660":{"position":[[4,2]]},"662":{"position":[[6,2]]}}}],["任意",{"_index":51,"t":{"43":{"position":[[4,2]]}}}],["企业",{"_index":208,"t":{"454":{"position":[[14,2]]},"525":{"position":[[6,2]]},"538":{"position":[[10,2]]},"576":{"position":[[6,2]]},"596":{"position":[[24,2]]},"625":{"position":[[6,2]]},"747":{"position":[[6,2]]},"964":{"position":[[6,2]]},"966":{"position":[[4,2]]}}}],["优缺点",{"_index":182,"t":{"377":{"position":[[2,3]]},"443":{"position":[[27,3]]}}}],["传输",{"_index":235,"t":{"529":{"position":[[7,2]]},"692":{"position":[[7,2]]},"786":{"position":[[13,2]]},"835":{"position":[[7,2]]}}}],["体现",{"_index":320,"t":{"786":{"position":[[32,2]]}}}],["使用",{"_index":2,"t":{"4":{"position":[[0,2]]},"9":{"position":[[2,2]]},"13":{"position":[[9,2]]},"24":{"position":[[2,2]]},"35":{"position":[[5,2]]},"37":{"position":[[14,2]]},"41":{"position":[[4,2]]},"45":{"position":[[5,2]]},"47":{"position":[[4,2]]},"56":{"position":[[2,2]]},"90":{"position":[[2,2]]},"154":{"position":[[2,2]]},"206":{"position":[[2,2]]},"271":{"position":[[2,2]]},"300":{"position":[[2,2]]},"307":{"position":[[2,2]]},"346":{"position":[[2,2]]},"362":{"position":[[0,2]]},"405":{"position":[[2,2]]},"410":{"position":[[2,2]]},"412":{"position":[[2,2]]},"421":{"position":[[2,2]]},"469":{"position":[[2,2]]},"506":{"position":[[2,2]]},"513":{"position":[[2,2]]},"515":{"position":[[2,2]]},"527":{"position":[[2,2]]},"534":{"position":[[4,2]]},"560":{"position":[[2,2]]},"594":{"position":[[2,2]]},"596":{"position":[[2,2]]},"649":{"position":[[2,2]]},"654":{"position":[[4,2]]},"680":{"position":[[2,2]]},"685":{"position":[[4,2]]},"690":{"position":[[2,2]]},"744":{"position":[[2,2]]},"749":{"position":[[2,2]]},"779":{"position":[[4,2]]},"815":{"position":[[2,2]]},"840":{"position":[[4,2]]},"855":{"position":[[5,2]]},"890":{"position":[[2,2]]},"968":{"position":[[4,2]]},"979":{"position":[[2,2]]}}}],["例",{"_index":334,"t":{"856":{"position":[[15,1]]},"858":{"position":[[16,1]]}}}],["依赖",{"_index":180,"t":{"375":{"position":[[5,2]]}}}],["保",{"_index":304,"t":{"751":{"position":[[2,1]]}}}],["修改",{"_index":271,"t":{"618":{"position":[[4,2]]},"620":{"position":[[15,2]]},"622":{"position":[[18,2]]},"887":{"position":[[10,2]]},"888":{"position":[[6,2]]},"890":{"position":[[6,2]]}}}],["免责",{"_index":26,"t":{"19":{"position":[[0,2]]}}}],["八",{"_index":119,"t":{"195":{"position":[[0,1]]},"226":{"position":[[0,1]]}}}],["六",{"_index":58,"t":{"49":{"position":[[0,1]]},"119":{"position":[[0,1]]},"143":{"position":[[0,1]]},"187":{"position":[[0,1]]},"219":{"position":[[0,1]]},"609":{"position":[[0,1]]},"635":{"position":[[0,1]]},"970":{"position":[[0,1]]}}}],["关系",{"_index":316,"t":{"784":{"position":[[23,2]]}}}],["其他",{"_index":184,"t":{"396":{"position":[[0,2]]}}}],["写",{"_index":187,"t":{"412":{"position":[[4,1]]}}}],["写入",{"_index":101,"t":{"156":{"position":[[4,2]]}}}],["函数",{"_index":163,"t":{"364":{"position":[[2,2]]}}}],["分片",{"_index":164,"t":{"364":{"position":[[5,2]]}}}],["创建",{"_index":77,"t":{"103":{"position":[[0,2]]},"119":{"position":[[2,2]]},"121":{"position":[[2,2]]},"152":{"position":[[2,2]]},"167":{"position":[[2,2]]},"187":{"position":[[2,2]]},"221":{"position":[[2,2]]},"222":{"position":[[6,2]]},"224":{"position":[[6,2]]},"234":{"position":[[13,2]]},"253":{"position":[[2,2]]},"282":{"position":[[2,2]]},"283":{"position":[[10,2]]},"285":{"position":[[12,2]]},"287":{"position":[[0,2]]},"316":{"position":[[0,2]]},"318":{"position":[[0,2]]},"390":{"position":[[0,2]]},"392":{"position":[[0,2]]},"490":{"position":[[2,2]]},"492":{"position":[[2,2]]},"513":{"position":[[7,2]]},"515":{"position":[[18,2]]},"536":{"position":[[2,2]]},"616":{"position":[[2,2]]},"706":{"position":[[2,2]]},"708":{"position":[[4,2]]},"733":{"position":[[2,2]]},"735":{"position":[[2,2]]},"842":{"position":[[4,2]]},"848":{"position":[[4,2]]},"855":{"position":[[2,2]]},"895":{"position":[[0,2]]},"929":{"position":[[0,2]]}}}],["初始",{"_index":266,"t":{"614":{"position":[[4,2]]}}}],["前",{"_index":3,"t":{"4":{"position":[[2,1]]}}}],["功能",{"_index":23,"t":{"17":{"position":[[15,2]]},"150":{"position":[[2,2]]},"789":{"position":[[6,2]]},"791":{"position":[[7,2]]},"958":{"position":[[11,2]]}}}],["加密",{"_index":88,"t":{"121":{"position":[[4,2]]}}}],["动态",{"_index":229,"t":{"520":{"position":[[2,2]]},"773":{"position":[[4,2]]}}}],["十",{"_index":131,"t":{"236":{"position":[[0,1]]}}}],["协作",{"_index":106,"t":{"158":{"position":[[9,2]]}}}],["协议",{"_index":11,"t":{"6":{"position":[[21,2]]},"8":{"position":[[2,2]]},"254":{"position":[[9,2]]},"256":{"position":[[10,2]]},"258":{"position":[[9,2]]},"260":{"position":[[26,2]]},"403":{"position":[[2,2]]},"700":{"position":[[0,2]]},"777":{"position":[[2,2]]},"786":{"position":[[15,2]]}}}],["单元测试",{"_index":329,"t":{"810":{"position":[[0,4]]}}}],["即时",{"_index":270,"t":{"618":{"position":[[2,2]]}}}],["原始",{"_index":159,"t":{"358":{"position":[[0,2]]}}}],["原理",{"_index":154,"t":{"335":{"position":[[6,2]]},"817":{"position":[[2,2]]}}}],["参数",{"_index":275,"t":{"640":{"position":[[6,2]]},"667":{"position":[[7,2]]}}}],["反",{"_index":192,"t":{"428":{"position":[[6,1]]}}}],["反向",{"_index":94,"t":{"135":{"position":[[2,2]]},"137":{"position":[[9,2]]},"139":{"position":[[6,2]]}}}],["反馈",{"_index":278,"t":{"652":{"position":[[4,2]]}}}],["发布",{"_index":96,"t":{"137":{"position":[[7,2]]},"931":{"position":[[3,2]]}}}],["发送",{"_index":133,"t":{"240":{"position":[[5,2]]},"242":{"position":[[17,2]]},"364":{"position":[[7,2]]},"844":{"position":[[4,2]]},"850":{"position":[[4,2]]}}}],["发送数据",{"_index":120,"t":{"195":{"position":[[2,4]]},"236":{"position":[[2,4]]},"320":{"position":[[0,4]]},"757":{"position":[[2,4]]}}}],["取消",{"_index":281,"t":{"660":{"position":[[6,2]]},"662":{"position":[[8,2]]}}}],["可靠",{"_index":319,"t":{"786":{"position":[[11,2],[29,2]]}}}],["同步",{"_index":105,"t":{"158":{"position":[[7,2]]},"775":{"position":[[4,2]]}}}],["名",{"_index":341,"t":{"887":{"position":[[19,1]]}}}],["名单",{"_index":170,"t":{"369":{"position":[[4,2]]}}}],["名称",{"_index":348,"t":{"888":{"position":[[4,2]]}}}],["启动",{"_index":93,"t":{"128":{"position":[[2,2]]},"494":{"position":[[5,2]]}}}],["呢",{"_index":322,"t":{"786":{"position":[[39,1]]}}}],["命令行",{"_index":350,"t":{"924":{"position":[[0,3]]}}}],["命名",{"_index":337,"t":{"887":{"position":[[6,2]]}}}],["响应",{"_index":144,"t":{"291":{"position":[[3,2]]},"462":{"position":[[5,2]]}}}],["商业",{"_index":18,"t":{"13":{"position":[[4,2]]}}}],["商用",{"_index":21,"t":{"15":{"position":[[15,2]]}}}],["喝酒",{"_index":178,"t":{"371":{"position":[[2,2]]}}}],["器",{"_index":289,"t":{"683":{"position":[[12,1]]}}}],["四",{"_index":54,"t":{"45":{"position":[[0,1]]},"115":{"position":[[0,1]]},"130":{"position":[[0,1]]},"154":{"position":[[0,1]]},"167":{"position":[[0,1]]},"183":{"position":[[0,1]]},"204":{"position":[[0,1]]},"206":{"position":[[0,1]]},"215":{"position":[[0,1]]},"251":{"position":[[0,1]]},"282":{"position":[[0,1]]},"300":{"position":[[0,1]]},"405":{"position":[[0,1]]},"414":{"position":[[0,1]]},"432":{"position":[[0,1]]},"478":{"position":[[0,1]]},"492":{"position":[[0,1]]},"508":{"position":[[0,1]]},"538":{"position":[[0,1]]},"553":{"position":[[0,1]]},"605":{"position":[[0,1]]},"618":{"position":[[0,1]]},"631":{"position":[[0,1]]},"682":{"position":[[0,1]]},"719":{"position":[[0,1]]},"737":{"position":[[0,1]]},"755":{"position":[[0,1]]},"766":{"position":[[0,1]]},"835":{"position":[[0,1]]},"960":{"position":[[0,1]]}}}],["回复",{"_index":143,"t":{"291":{"position":[[0,2]]}}}],["地方",{"_index":321,"t":{"786":{"position":[[37,2]]}}}],["场景",{"_index":84,"t":{"113":{"position":[[6,2]]},"181":{"position":[[6,2]]},"202":{"position":[[6,2]]},"213":{"position":[[6,2]]},"534":{"position":[[6,2]]},"567":{"position":[[4,2]]},"627":{"position":[[2,2]]},"805":{"position":[[2,2]]},"823":{"position":[[4,2]]},"912":{"position":[[4,2]]}}}],["均",{"_index":351,"t":{"924":{"position":[[14,1]]}}}],["型",{"_index":125,"t":{"224":{"position":[[5,1]]}}}],["基于",{"_index":134,"t":{"254":{"position":[[4,2]]},"256":{"position":[[4,2]]},"258":{"position":[[4,2]]},"260":{"position":[[4,2]]},"287":{"position":[[2,2]]}}}],["基础",{"_index":323,"t":{"789":{"position":[[4,2]]}}}],["增加",{"_index":360,"t":{"958":{"position":[[4,2]]}}}],["声明",{"_index":277,"t":{"647":{"position":[[2,2]]}}}],["处理",{"_index":117,"t":{"191":{"position":[[14,2]]},"193":{"position":[[6,2]]},"228":{"position":[[14,2]]},"230":{"position":[[18,2]]},"232":{"position":[[6,2]]}}}],["复杂",{"_index":195,"t":{"435":{"position":[[4,2]]}}}],["多线程",{"_index":104,"t":{"158":{"position":[[4,3]]}}}],["大",{"_index":311,"t":{"762":{"position":[[4,1]]}}}],["如何",{"_index":68,"t":{"63":{"position":[[0,2]]},"72":{"position":[[0,2]]},"83":{"position":[[0,2]]},"238":{"position":[[5,2]]}}}],["如果",{"_index":340,"t":{"887":{"position":[[15,2]]}}}],["委托",{"_index":116,"t":{"191":{"position":[[12,2]]},"228":{"position":[[12,2]]}}}],["安装",{"_index":296,"t":{"712":{"position":[[2,2]]},"713":{"position":[[9,2]]}}}],["定义",{"_index":91,"t":{"126":{"position":[[2,2]]},"137":{"position":[[4,2]]},"511":{"position":[[2,2]]},"555":{"position":[[4,2]]},"683":{"position":[[4,2]]},"893":{"position":[[0,2]]},"927":{"position":[[0,2]]}}}],["定制",{"_index":148,"t":{"325":{"position":[[0,2]]},"380":{"position":[[0,2]]},"583":{"position":[[0,2]]},"898":{"position":[[0,2]]}}}],["实现",{"_index":49,"t":{"41":{"position":[[25,2]]},"360":{"position":[[0,2]]}}}],["客户端",{"_index":72,"t":{"79":{"position":[[2,3]]},"143":{"position":[[2,3]]},"316":{"position":[[4,3]]},"318":{"position":[[5,3]]},"392":{"position":[[2,3]]},"454":{"position":[[2,3]]},"529":{"position":[[2,3]]},"692":{"position":[[2,3]]},"835":{"position":[[2,3]]},"924":{"position":[[7,3]]}}}],["密钥",{"_index":364,"t":{"968":{"position":[[2,2]]}}}],["对象",{"_index":103,"t":{"156":{"position":[[11,2]]}}}],["封装",{"_index":162,"t":{"364":{"position":[[0,2]]}}}],["就是",{"_index":318,"t":{"786":{"position":[[9,2]]}}}],["展示",{"_index":158,"t":{"354":{"position":[[2,2]]}}}],["属性",{"_index":181,"t":{"375":{"position":[[7,2]]},"549":{"position":[[4,2]]}}}],["嵌套",{"_index":283,"t":{"669":{"position":[[5,2]]}}}],["工作",{"_index":32,"t":{"30":{"position":[[0,2]]}}}],["常见",{"_index":236,"t":{"534":{"position":[[2,2]]}}}],["广播",{"_index":333,"t":{"846":{"position":[[2,2]]},"848":{"position":[[6,2]]},"850":{"position":[[6,2]]}}}],["序列化",{"_index":191,"t":{"428":{"position":[[2,3],[7,3]]},"678":{"position":[[5,3]]},"680":{"position":[[6,3]]},"682":{"position":[[5,3]]},"683":{"position":[[9,3]]}}}],["应用",{"_index":83,"t":{"113":{"position":[[4,2]]},"181":{"position":[[4,2]]},"202":{"position":[[4,2]]},"213":{"position":[[4,2]]},"567":{"position":[[2,2]]},"823":{"position":[[2,2]]},"912":{"position":[[2,2]]}}}],["开源",{"_index":10,"t":{"6":{"position":[[19,2]]}}}],["引用",{"_index":300,"t":{"717":{"position":[[9,2]]}}}],["当前",{"_index":0,"t":{"2":{"position":[[0,2]]}}}],["心跳",{"_index":224,"t":{"484":{"position":[[10,2]]},"492":{"position":[[4,2]]}}}],["必要",{"_index":4,"t":{"4":{"position":[[3,2]]}}}],["快捷",{"_index":302,"t":{"733":{"position":[[4,2]]}}}],["性能",{"_index":194,"t":{"432":{"position":[[2,2]]},"508":{"position":[[2,2]]},"522":{"position":[[10,2]]},"635":{"position":[[2,2]]}}}],["意义",{"_index":165,"t":{"364":{"position":[[9,2]]}}}],["所有",{"_index":246,"t":{"555":{"position":[[0,2]]},"887":{"position":[[2,2]]}}}],["手动",{"_index":188,"t":{"414":{"position":[[2,2]]}}}],["托管",{"_index":212,"t":{"457":{"position":[[4,2]]}}}],["执行",{"_index":303,"t":{"733":{"position":[[6,2]]},"924":{"position":[[3,2]]}}}],["扩展",{"_index":223,"t":{"480":{"position":[[4,2]]},"490":{"position":[[4,2]]},"777":{"position":[[4,2]]}}}],["技术",{"_index":150,"t":{"329":{"position":[[0,2]]},"384":{"position":[[0,2]]},"587":{"position":[[0,2]]},"902":{"position":[[0,2]]}}}],["指数",{"_index":282,"t":{"667":{"position":[[12,2]]},"669":{"position":[[17,2]]}}}],["按照",{"_index":173,"t":{"369":{"position":[[12,2]]}}}],["授权",{"_index":363,"t":{"962":{"position":[[8,2]]},"964":{"position":[[8,2]]},"966":{"position":[[6,2]]}}}],["排名",{"_index":172,"t":{"369":{"position":[[9,2]]}}}],["接口",{"_index":199,"t":{"441":{"position":[[12,2]]},"443":{"position":[[19,2]]},"472":{"position":[[6,2]]}}}],["接收",{"_index":141,"t":{"289":{"position":[[0,2]]},"464":{"position":[[5,2]]}}}],["接收数据",{"_index":113,"t":{"189":{"position":[[2,4]]},"226":{"position":[[2,4]]},"322":{"position":[[0,4]]}}}],["控制台",{"_index":217,"t":{"474":{"position":[[2,3]]}}}],["推荐",{"_index":118,"t":{"193":{"position":[[8,2]]},"232":{"position":[[10,2]]},"667":{"position":[[10,2]]},"669":{"position":[[15,2]]}}}],["推送",{"_index":287,"t":{"673":{"position":[[4,2]]}}}],["提交",{"_index":137,"t":{"264":{"position":[[0,2]]}}}],["提供",{"_index":357,"t":{"955":{"position":[[3,2]]}}}],["提示",{"_index":346,"t":{"887":{"position":[[32,2]]}}}],["插件",{"_index":47,"t":{"41":{"position":[[6,2]]},"45":{"position":[[7,2]]},"185":{"position":[[4,2]]},"193":{"position":[[4,2]]},"219":{"position":[[4,2]]},"232":{"position":[[4,2]]},"283":{"position":[[8,2]]},"457":{"position":[[6,2]]},"492":{"position":[[6,2]]},"569":{"position":[[0,2]]},"571":{"position":[[5,2]]},"573":{"position":[[5,2]]},"594":{"position":[[16,2]]},"596":{"position":[[20,2]]},"733":{"position":[[8,2]]},"924":{"position":[[5,2]]}}}],["插件接口",{"_index":76,"t":{"100":{"position":[[2,4]]},"117":{"position":[[4,4]]},"165":{"position":[[4,4]]},"204":{"position":[[4,4]]},"251":{"position":[[4,4]]},"278":{"position":[[4,4]]},"314":{"position":[[2,4]]}}}],["播",{"_index":332,"t":{"840":{"position":[[3,1]]},"842":{"position":[[7,1]]},"844":{"position":[[7,1]]}}}],["操作",{"_index":251,"t":{"578":{"position":[[5,2]]},"795":{"position":[[6,2]]}}}],["支持",{"_index":75,"t":{"100":{"position":[[0,2]]},"117":{"position":[[2,2]]},"165":{"position":[[2,2]]},"185":{"position":[[2,2]]},"204":{"position":[[2,2]]},"219":{"position":[[2,2]]},"251":{"position":[[2,2]]},"278":{"position":[[2,2]]},"314":{"position":[[0,2]]},"441":{"position":[[10,2]]},"457":{"position":[[12,2]]},"578":{"position":[[2,2]]},"678":{"position":[[2,2]]},"924":{"position":[[15,2]]}}}],["效果",{"_index":152,"t":{"331":{"position":[[0,2]]},"386":{"position":[[0,2]]},"589":{"position":[[0,2]]},"904":{"position":[[0,2]]}}}],["效果图",{"_index":73,"t":{"92":{"position":[[2,3]]}}}],["数据",{"_index":34,"t":{"31":{"position":[[0,2]]},"291":{"position":[[5,2]]},"671":{"position":[[7,2]]},"673":{"position":[[7,2]]},"755":{"position":[[4,2]]},"797":{"position":[[5,2]]},"799":{"position":[[11,2]]},"844":{"position":[[8,2]]},"850":{"position":[[8,2]]}}}],["数据压缩",{"_index":265,"t":{"609":{"position":[[2,4]]}}}],["数据处理",{"_index":359,"t":{"956":{"position":[[4,4]]}}}],["数据格式",{"_index":225,"t":{"486":{"position":[[4,4]]},"488":{"position":[[6,4]]},"819":{"position":[[4,4]]}}}],["文件",{"_index":71,"t":{"63":{"position":[[8,2]]},"72":{"position":[[8,2]]},"83":{"position":[[8,2]]},"414":{"position":[[6,2]]},"462":{"position":[[7,2]]},"464":{"position":[[9,2]]},"476":{"position":[[2,2]]},"529":{"position":[[9,2]]},"829":{"position":[[6,2]]},"833":{"position":[[6,2]]},"835":{"position":[[9,2]]}}}],["文件传输",{"_index":324,"t":{"793":{"position":[[4,4]]}}}],["断线",{"_index":239,"t":{"538":{"position":[[4,2]]}}}],["新",{"_index":291,"t":{"708":{"position":[[6,1]]}}}],["方",{"_index":149,"t":{"325":{"position":[[2,1]]},"380":{"position":[[2,1]]},"583":{"position":[[2,1]]},"898":{"position":[[2,1]]}}}],["方式",{"_index":243,"t":{"545":{"position":[[4,2]]}}}],["方法",{"_index":80,"t":{"105":{"position":[[2,2]]},"551":{"position":[[4,2]]}}}],["方面",{"_index":326,"t":{"797":{"position":[[7,2]]}}}],["日志",{"_index":214,"t":{"472":{"position":[[2,2]]},"474":{"position":[[5,2]]},"476":{"position":[[4,2]]},"478":{"position":[[2,2]]},"480":{"position":[[2,2]]}}}],["时刻",{"_index":52,"t":{"43":{"position":[[6,2]]}}}],["时间",{"_index":175,"t":{"369":{"position":[[16,2]]},"601":{"position":[[2,2]]}}}],["智能",{"_index":345,"t":{"887":{"position":[[30,2]]}}}],["服务",{"_index":92,"t":{"126":{"position":[[4,2]]},"137":{"position":[[14,2]]},"282":{"position":[[13,2]]},"287":{"position":[[17,2]]},"511":{"position":[[4,2]]},"513":{"position":[[9,2]]},"515":{"position":[[20,2]]},"662":{"position":[[4,2]]},"825":{"position":[[0,2]]},"893":{"position":[[2,2]]},"927":{"position":[[2,2]]},"929":{"position":[[2,2]]},"931":{"position":[[5,2]]},"955":{"position":[[8,2]]}}}],["服务器",{"_index":85,"t":{"115":{"position":[[2,3]]},"128":{"position":[[7,3]]},"141":{"position":[[8,3]]},"215":{"position":[[2,3]]},"247":{"position":[[2,3]]},"253":{"position":[[4,3]]},"390":{"position":[[2,3]]},"394":{"position":[[0,3]]},"457":{"position":[[9,3]]},"462":{"position":[[2,3]]},"464":{"position":[[2,3]]},"735":{"position":[[4,3]]},"842":{"position":[[8,3]]},"848":{"position":[[8,3]]},"895":{"position":[[4,3]]},"914":{"position":[[0,3]]},"924":{"position":[[11,3]]}}}],["服务端",{"_index":203,"t":{"445":{"position":[[3,3]]}}}],["未修改",{"_index":342,"t":{"887":{"position":[[20,3]]}}}],["本身",{"_index":317,"t":{"786":{"position":[[7,2]]}}}],["机制",{"_index":306,"t":{"751":{"position":[[4,2]]}}}],["构建",{"_index":309,"t":{"755":{"position":[[2,2]]}}}],["构造函数",{"_index":244,"t":{"547":{"position":[[4,4]]}}}],["架构",{"_index":31,"t":{"29":{"position":[[2,2]]},"115":{"position":[[5,2]]},"215":{"position":[[5,2]]},"247":{"position":[[5,2]]},"825":{"position":[[2,2]]},"914":{"position":[[3,2]]}}}],["某个",{"_index":361,"t":{"958":{"position":[[9,2]]}}}],["标签",{"_index":274,"t":{"640":{"position":[[4,2]]}}}],["标记",{"_index":205,"t":{"452":{"position":[[6,2]]}}}],["模型",{"_index":247,"t":{"555":{"position":[[2,2]]}}}],["此处",{"_index":339,"t":{"887":{"position":[[13,2]]}}}],["泛",{"_index":124,"t":{"224":{"position":[[4,1]]}}}],["注入",{"_index":242,"t":{"545":{"position":[[2,2]]},"547":{"position":[[8,2]]},"549":{"position":[[6,2]]},"551":{"position":[[6,2]]}}}],["注册",{"_index":352,"t":{"931":{"position":[[0,2]]}}}],["活",{"_index":305,"t":{"751":{"position":[[3,1]]}}}],["流",{"_index":286,"t":{"671":{"position":[[6,1]]},"673":{"position":[[6,1]]},"797":{"position":[[4,1]]}}}],["测试",{"_index":153,"t":{"335":{"position":[[4,2]]},"337":{"position":[[4,2]]},"432":{"position":[[4,2]]},"433":{"position":[[6,2]]},"435":{"position":[[8,2]]},"494":{"position":[[2,2]]},"970":{"position":[[4,2]]}}}],["测量器",{"_index":258,"t":{"601":{"position":[[4,3]]}}}],["消息",{"_index":142,"t":{"289":{"position":[[2,2]]}}}],["添加",{"_index":204,"t":{"448":{"position":[[8,2]]},"450":{"position":[[6,2]]}}}],["源代码",{"_index":207,"t":{"454":{"position":[[5,3]]}}}],["源文件",{"_index":201,"t":{"443":{"position":[[12,3]]}}}],["点",{"_index":151,"t":{"329":{"position":[[2,1]]},"384":{"position":[[2,1]]},"587":{"position":[[2,1]]},"902":{"position":[[2,1]]}}}],["爱心",{"_index":169,"t":{"369":{"position":[[0,2]]}}}],["版",{"_index":209,"t":{"454":{"position":[[16,1]]},"525":{"position":[[8,1]]},"538":{"position":[[12,1]]},"576":{"position":[[8,1]]},"596":{"position":[[26,1]]},"625":{"position":[[8,1]]},"747":{"position":[[8,1]]}}}],["版本",{"_index":1,"t":{"2":{"position":[[2,2]]},"711":{"position":[[9,2]]}}}],["版本号",{"_index":336,"t":{"873":{"position":[[0,3]]},"875":{"position":[[0,3]]},"877":{"position":[[0,3]]},"879":{"position":[[0,3]]},"881":{"position":[[0,3]]},"883":{"position":[[0,3]]},"885":{"position":[[0,3]]}}}],["版权",{"_index":290,"t":{"698":{"position":[[0,2]]}}}],["特性",{"_index":248,"t":{"569":{"position":[[2,2]]},"647":{"position":[[4,2]]},"724":{"position":[[2,2]]}}}],["特点",{"_index":63,"t":{"54":{"position":[[2,2]]},"111":{"position":[[4,2]]},"179":{"position":[[2,2]]},"200":{"position":[[4,2]]},"211":{"position":[[2,2]]},"269":{"position":[[2,2]]},"298":{"position":[[2,2]]},"305":{"position":[[2,2]]},"344":{"position":[[2,2]]},"401":{"position":[[2,2]]},"419":{"position":[[2,2]]},"499":{"position":[[2,2]]},"504":{"position":[[2,2]]},"543":{"position":[[2,2]]},"565":{"position":[[2,2]]},"742":{"position":[[2,2]]},"788":{"position":[[2,2]]},"863":{"position":[[2,2]]},"910":{"position":[[2,2]]},"918":{"position":[[0,2]]},"977":{"position":[[2,2]]}}}],["独立",{"_index":362,"t":{"962":{"position":[[6,2]]}}}],["生命周期",{"_index":245,"t":{"553":{"position":[[2,4]]},"642":{"position":[[6,4]]}}}],["生成",{"_index":69,"t":{"63":{"position":[[2,2]]},"72":{"position":[[2,2]]},"83":{"position":[[2,2]]},"439":{"position":[[8,2]]},"446":{"position":[[4,2]]},"454":{"position":[[8,2]]},"607":{"position":[[6,2]]}}}],["用户",{"_index":249,"t":{"571":{"position":[[0,2]]}}}],["用途",{"_index":19,"t":{"13":{"position":[[7,2]]}}}],["申明",{"_index":27,"t":{"19":{"position":[[2,2]]}}}],["界面",{"_index":157,"t":{"354":{"position":[[0,2]]}}}],["的话",{"_index":343,"t":{"887":{"position":[[23,2]]}}}],["盈利性",{"_index":17,"t":{"13":{"position":[[0,3]]}}}],["直接",{"_index":64,"t":{"59":{"position":[[0,2]]},"68":{"position":[[0,2]]},"77":{"position":[[2,2]]},"79":{"position":[[5,2]]},"131":{"position":[[4,2]]},"141":{"position":[[11,2]]},"441":{"position":[[8,2]]},"620":{"position":[[13,2]]},"717":{"position":[[7,2]]}}}],["相关",{"_index":45,"t":{"39":{"position":[[16,2]]},"41":{"position":[[21,2]]},"605":{"position":[[6,2]]}}}],["相比",{"_index":202,"t":{"443":{"position":[[17,2]]}}}],["瞬时",{"_index":276,"t":{"642":{"position":[[4,2]]}}}],["示例",{"_index":253,"t":{"580":{"position":[[4,2]]},"629":{"position":[[4,2]]},"726":{"position":[[2,2]]},"831":{"position":[[0,2]]},"920":{"position":[[0,2]]}}}],["空间",{"_index":338,"t":{"887":{"position":[[8,2]]}}}],["端",{"_index":312,"t":{"762":{"position":[[5,1]]},"764":{"position":[[5,1]]},"766":{"position":[[4,1]]}}}],["策略",{"_index":232,"t":{"520":{"position":[[11,2]]},"614":{"position":[[8,2]]}}}],["简介",{"_index":81,"t":{"105":{"position":[[4,2]]}}}],["简单",{"_index":123,"t":{"222":{"position":[[4,2]]},"283":{"position":[[4,2]]},"433":{"position":[[4,2]]},"895":{"position":[[2,2]]}}}],["简述",{"_index":12,"t":{"6":{"position":[[23,2]]}}}],["算法",{"_index":185,"t":{"403":{"position":[[4,2]]}}}],["类",{"_index":206,"t":{"452":{"position":[[11,1]]},"490":{"position":[[6,1]]},"492":{"position":[[8,1]]},"887":{"position":[[4,1]]}}}],["类型",{"_index":196,"t":{"435":{"position":[[6,2]]},"448":{"position":[[6,2]]},"450":{"position":[[10,2]]},"652":{"position":[[6,2]]},"700":{"position":[[2,2]]},"709":{"position":[[8,2]]},"887":{"position":[[17,2]]},"888":{"position":[[2,2]]}}}],["系统",{"_index":250,"t":{"573":{"position":[[0,2]]}}}],["组",{"_index":221,"t":{"478":{"position":[[4,1]]},"840":{"position":[[2,1]]},"842":{"position":[[6,1]]},"844":{"position":[[6,1]]}}}],["组件",{"_index":353,"t":{"937":{"position":[[7,2]]},"939":{"position":[[7,2]]},"941":{"position":[[7,2]]},"951":{"position":[[8,2]]}}}],["结束",{"_index":301,"t":{"719":{"position":[[2,2]]}}}],["绝对",{"_index":310,"t":{"762":{"position":[[2,2]]},"764":{"position":[[2,2]]}}}],["缓存",{"_index":59,"t":{"49":{"position":[[2,2]]}}}],["网页",{"_index":211,"t":{"457":{"position":[[2,2]]}}}],["能",{"_index":267,"t":{"616":{"position":[[4,1]]},"955":{"position":[[2,1]]}}}],["自动",{"_index":307,"t":{"753":{"position":[[0,2]]}}}],["自定义",{"_index":161,"t":{"362":{"position":[[2,3]]},"430":{"position":[[2,3]]},"452":{"position":[[8,3]]},"571":{"position":[[2,3]]},"573":{"position":[[2,3]]},"682":{"position":[[2,3]]},"683":{"position":[[6,3]]}}}],["获取",{"_index":70,"t":{"63":{"position":[[4,2]]},"72":{"position":[[4,2]]},"83":{"position":[[4,2]]},"141":{"position":[[13,2]]},"238":{"position":[[7,2]]},"445":{"position":[[6,2]]},"640":{"position":[[8,2]]},"642":{"position":[[10,2]]}}}],["要",{"_index":198,"t":{"439":{"position":[[7,1]]},"484":{"position":[[7,1]]}}}],["要求",{"_index":138,"t":{"264":{"position":[[2,2]]}}}],["解决",{"_index":347,"t":{"887":{"position":[[34,2]]}}}],["解析",{"_index":226,"t":{"488":{"position":[[4,2]]}}}],["解析器",{"_index":228,"t":{"513":{"position":[[11,3]]},"515":{"position":[[22,3]]},"929":{"position":[[4,3]]}}}],["解释",{"_index":35,"t":{"33":{"position":[[2,2]]}}}],["触发",{"_index":183,"t":{"394":{"position":[[3,2]]}}}],["计时器",{"_index":279,"t":{"658":{"position":[[4,3]]}}}],["计算",{"_index":257,"t":{"599":{"position":[[5,2]]},"603":{"position":[[5,2]]}}}],["订阅",{"_index":43,"t":{"39":{"position":[[4,2]]}}}],["记录",{"_index":215,"t":{"472":{"position":[[4,2]]}}}],["记录器",{"_index":218,"t":{"474":{"position":[[7,3]]},"476":{"position":[[6,3]]},"478":{"position":[[5,3]]}}}],["许可",{"_index":22,"t":{"15":{"position":[[17,2]]}}}],["设置",{"_index":53,"t":{"43":{"position":[[8,2]]},"484":{"position":[[8,2]]},"656":{"position":[[6,2]]},"658":{"position":[[7,2]]},"667":{"position":[[2,2]]}}}],["设计",{"_index":30,"t":{"29":{"position":[[0,2]]},"33":{"position":[[0,2]]},"486":{"position":[[2,2]]}}}],["评测",{"_index":227,"t":{"508":{"position":[[4,2]]}}}],["说明",{"_index":28,"t":{"22":{"position":[[2,2]]},"27":{"position":[[0,2]]},"52":{"position":[[2,2]]},"88":{"position":[[2,2]]},"96":{"position":[[0,2]]},"109":{"position":[[2,2]]},"124":{"position":[[2,2]]},"148":{"position":[[2,2]]},"161":{"position":[[2,2]]},"177":{"position":[[2,2]]},"198":{"position":[[2,2]]},"209":{"position":[[2,2]]},"245":{"position":[[2,2]]},"267":{"position":[[2,2]]},"274":{"position":[[2,2]]},"294":{"position":[[2,2]]},"303":{"position":[[2,2]]},"310":{"position":[[0,2]]},"327":{"position":[[0,2]]},"333":{"position":[[2,2]]},"342":{"position":[[2,2]]},"352":{"position":[[0,2]]},"356":{"position":[[0,2]]},"373":{"position":[[2,2]]},"382":{"position":[[0,2]]},"388":{"position":[[0,2]]},"399":{"position":[[2,2]]},"408":{"position":[[2,2]]},"417":{"position":[[2,2]]},"426":{"position":[[2,2]]},"438":{"position":[[2,2]]},"460":{"position":[[2,2]]},"467":{"position":[[2,2]]},"483":{"position":[[2,2]]},"497":{"position":[[2,2]]},"502":{"position":[[2,2]]},"518":{"position":[[2,2]]},"525":{"position":[[2,2]]},"532":{"position":[[2,2]]},"541":{"position":[[2,2]]},"558":{"position":[[2,2]]},"563":{"position":[[0,2]]},"576":{"position":[[2,2]]},"585":{"position":[[0,2]]},"592":{"position":[[2,2]]},"612":{"position":[[2,2]]},"625":{"position":[[2,2]]},"638":{"position":[[2,2]]},"645":{"position":[[2,2]]},"665":{"position":[[2,2]]},"676":{"position":[[2,2]]},"688":{"position":[[2,2]]},"696":{"position":[[0,2]]},"704":{"position":[[2,2]]},"722":{"position":[[2,2]]},"731":{"position":[[2,2]]},"740":{"position":[[2,2]]},"747":{"position":[[2,2]]},"760":{"position":[[2,2]]},"782":{"position":[[2,2]]},"808":{"position":[[0,2]]},"813":{"position":[[2,2]]},"827":{"position":[[2,2]]},"838":{"position":[[2,2]]},"853":{"position":[[2,2]]},"861":{"position":[[2,2]]},"900":{"position":[[0,2]]},"934":{"position":[[2,2]]},"975":{"position":[[2,2]]}}}],["请求",{"_index":285,"t":{"671":{"position":[[4,2]]}}}],["读",{"_index":186,"t":{"410":{"position":[[4,1]]}}}],["读写",{"_index":273,"t":{"631":{"position":[[2,2]]}}}],["读取数据",{"_index":102,"t":{"156":{"position":[[7,4]]}}}],["调整",{"_index":230,"t":{"520":{"position":[[4,2]]}}}],["调用",{"_index":65,"t":{"59":{"position":[[2,2]]},"61":{"position":[[2,2]]},"65":{"position":[[0,2]]},"68":{"position":[[2,2]]},"70":{"position":[[2,2]]},"74":{"position":[[0,2]]},"77":{"position":[[4,2]]},"79":{"position":[[7,2]]},"81":{"position":[[2,2]]},"85":{"position":[[0,2]]},"130":{"position":[[2,2]]},"131":{"position":[[6,2]]},"133":{"position":[[6,2]]},"139":{"position":[[4,2]]},"441":{"position":[[16,2]]},"652":{"position":[[2,2]]},"656":{"position":[[2,2]]},"737":{"position":[[2,2]]}}}],["购买",{"_index":366,"t":{"972":{"position":[[2,2]]}}}],["资源",{"_index":190,"t":{"414":{"position":[[8,2]]}}}],["赏",{"_index":174,"t":{"369":{"position":[[15,1]]}}}],["赞助",{"_index":166,"t":{"367":{"position":[[0,2]]},"369":{"position":[[2,2]]}}}],["超时",{"_index":60,"t":{"49":{"position":[[4,2]]},"656":{"position":[[4,2]]}}}],["路径",{"_index":294,"t":{"710":{"position":[[11,2]]}}}],["转发",{"_index":238,"t":{"538":{"position":[[2,2]]}}}],["转换器",{"_index":193,"t":{"430":{"position":[[5,3]]}}}],["运行",{"_index":145,"t":{"296":{"position":[[2,2]]}}}],["进制",{"_index":262,"t":{"605":{"position":[[4,2]]}}}],["远程",{"_index":325,"t":{"795":{"position":[[4,2]]}}}],["连",{"_index":241,"t":{"538":{"position":[[7,1]]}}}],["连接",{"_index":269,"t":{"616":{"position":[[7,2]]},"769":{"position":[[2,2]]}}}],["适配器",{"_index":62,"t":{"49":{"position":[[11,3]]},"339":{"position":[[5,3]]},"362":{"position":[[5,3]]},"667":{"position":[[4,3]]},"956":{"position":[[8,3]]}}}],["选择",{"_index":292,"t":{"709":{"position":[[4,2]]},"711":{"position":[[4,2]]}}}],["通过",{"_index":97,"t":{"141":{"position":[[6,2]]},"242":{"position":[[5,2]]},"283":{"position":[[6,2]]},"285":{"position":[[4,2]]},"620":{"position":[[4,2]]},"622":{"position":[[4,2]]},"640":{"position":[[2,2]]},"642":{"position":[[2,2]]}}}],["通道",{"_index":367,"t":{"972":{"position":[[4,2]]}}}],["逻辑",{"_index":33,"t":{"30":{"position":[[2,2]]},"31":{"position":[[2,2]]},"296":{"position":[[4,2]]},"890":{"position":[[4,2]]}}}],["遵循",{"_index":25,"t":{"17":{"position":[[19,2]]}}}],["部分",{"_index":24,"t":{"17":{"position":[[17,2]]}}}],["配置",{"_index":41,"t":{"37":{"position":[[11,2]]},"98":{"position":[[1,2]]},"163":{"position":[[3,2]]},"183":{"position":[[3,2]]},"217":{"position":[[3,2]]},"249":{"position":[[3,2]]},"276":{"position":[[3,2]]},"312":{"position":[[1,2]]},"614":{"position":[[2,2]]},"710":{"position":[[4,2]]}}}],["释放",{"_index":189,"t":{"414":{"position":[[4,2]]},"633":{"position":[[2,2]]}}}],["重",{"_index":240,"t":{"538":{"position":[[6,1]]}}}],["重写",{"_index":127,"t":{"230":{"position":[[4,2]]},"956":{"position":[[12,2]]}}}],["阅读",{"_index":5,"t":{"4":{"position":[[5,2]]}}}],["附加",{"_index":13,"t":{"8":{"position":[[0,2]]}}}],["限制",{"_index":57,"t":{"47":{"position":[[2,2]]},"958":{"position":[[7,2]]}}}],["限时",{"_index":365,"t":{"970":{"position":[[2,2]]}}}],["雪花",{"_index":263,"t":{"607":{"position":[[2,2]]}}}],["静态",{"_index":210,"t":{"457":{"position":[[0,2]]}}}],["项",{"_index":74,"t":{"98":{"position":[[3,1]]},"163":{"position":[[5,1]]},"183":{"position":[[5,1]]},"217":{"position":[[5,1]]},"249":{"position":[[5,1]]},"276":{"position":[[5,1]]},"312":{"position":[[3,1]]}}}],["项目",{"_index":168,"t":{"367":{"position":[[13,2]]},"706":{"position":[[4,2]]},"708":{"position":[[7,2]]},"709":{"position":[[6,2]]}}}],["项目名称",{"_index":293,"t":{"710":{"position":[[6,4]]}}}],["顺序",{"_index":176,"t":{"369":{"position":[[18,2]]}}}],["须知",{"_index":15,"t":{"9":{"position":[[4,2]]},"11":{"position":[[4,2]]},"13":{"position":[[11,2]]}}}],["预设",{"_index":288,"t":{"680":{"position":[[4,2]]}}}],["验证",{"_index":314,"t":{"769":{"position":[[4,2]]},"771":{"position":[[9,2]]},"773":{"position":[[6,2]]}}}],["默认",{"_index":313,"t":{"766":{"position":[[2,2]]}}}]],"pipeline":["stemmer"]}},{"documents":[{"i":3,"t":"公告 原 RRQM 系文档,可以加 qq 群(234762506),在群文件自行获取。","s":"当前版本","u":"/touchsocket/docs/","h":"#当前版本","p":1},{"i":5,"t":"TouchSocket 由作者若汝棋茗及其他贡献者开发,所有版权归作者若汝棋茗所有,程序集源代码在遵循 Apache License 2.0 的开源协议以及附加协议下,可免费供其他开发者二次开发或(商业)使用。","s":"使用前必要阅读","u":"/touchsocket/docs/","h":"#使用前必要阅读","p":1},{"i":7,"t":"永久权利 一旦被授权,永久拥有。 全球范围的权利 在一个国家获得授权,适用于所有国家。假如你在美国,许可是从印度授权的,也没有问题。 授权免费,且无版税 前期,后期均无任何费用。 授权无排他性 任何人都可以获得授权 授权不可撤消 一旦获得授权,没有任何人可以取消。比如,你基于该产品代码开发了衍生产品,你不用担心会在某一天被禁止使用该代码。","s":"Apache License 2.0 开源协议简述","u":"/touchsocket/docs/","h":"","p":1},{"i":10,"t":"不得将程序集用作违法犯罪活动。 不得将程序集单独包装售卖,申请专利等。 不得擦除程序集所有有关作者的信息。 以上内容必须全部符合,个人使用授权才成立。","s":"个人使用须知:","u":"/touchsocket/docs/","h":"#个人使用须知","p":1},{"i":12,"t":"不得将程序集用作违法犯罪活动。 不得将程序集单独包装售卖,申请专利等。 不得擦除程序集所有有关作者的信息。 二次开发完成后的作品必须附带源作品所有作者信息,包括但不限于作者名、Gitee、Github 地址等。 完成后的作品(仅 TouchSocket 部分)必须将发布时最新源代码提交一份给本作者,QQ 邮箱:505554090@qq.com。 以上内容必须全部符合,二次开发授权才成立。","s":"二次开发须知:","u":"/touchsocket/docs/","h":"#二次开发须知","p":1},{"i":14,"t":"不得将程序集用作违法犯罪活动。 不得将程序集单独包装售卖,申请专利等。 不得擦除程序集所有有关作者的信息,并必须于用户可见界面(如关于)中提名。 以上内容必须全部符合,使用授权才成立。","s":"盈利性(商业)用途使用须知:","u":"/touchsocket/docs/","h":"#盈利性商业用途使用须知","p":1},{"i":16,"t":"TouchSocketPro 是 TouchSocket 的企业版,其 99%功能与 TouchSocket 一致。所有版权归作者若汝棋茗所有。","s":"TouchSocketPro 商用许可","u":"/touchsocket/docs/","h":"#touchsocketpro-商用许可","p":1},{"i":18,"t":"限时(1h)免费测试,测试期间可参与商业使用。 付费使用,购买后还须遵循相关使用协议,详情咨询若汝棋茗。 TouchSocketPro 程序集源代码不公开开源,需要付费购买。","s":"TouchSocketPro 功能部分遵循:","u":"/touchsocket/docs/","h":"#touchsocketpro-功能部分遵循","p":1},{"i":20,"t":"在使用 TouchSocket或TouchSocketPro 之前请进行缜密的测试。在使用期间,由本程序集造成或间接造成的所有损失,均自己承担,与本程序集无关。","s":"免责申明","u":"/touchsocket/docs/","h":"","p":1},{"i":23,"t":"应用信使是在进程内的,行使注册和触发功能的组件。可代替事件,可跨越程序集,可依赖倒置。","s":"一、说明","u":"/touchsocket/docs/appmessenger","h":"#一说明","p":21},{"i":25,"t":"【声明主体】 实现IMessage接口,然后增加AppMessage标记的公共方法。 public class MessageObject : IMessage { [AppMessage] public int Add(int a, int b) { return a + b; } [AppMessage] public int Sub(int a, int b) { return a - b; } } 【注册】 下列演示时,是新实例化的AppMessenger,实际上,用户可以直接使用AppMessenger.Default默认实例。 AppMessenger appMessenger = new AppMessenger(); appMessenger.Register(); 【触发】 触发时,泛型类型,即时返回值类型。 int add = appMessenger.Send(\"Add\", 20, 10); Assert.Equal(30,add); int sub = appMessenger.Send(\"Sub\", 20, 10); Assert.Equal(10, sub);","s":"二、使用","u":"/touchsocket/docs/appmessenger","h":"#二使用","p":21},{"i":28,"t":"在TouchSocket中,适配器贯穿始终,其作用实际上有两个,分别为: 对发送和接收的数据进行预先的封装和解封,以达到解析数据的作用(可以简单理解为处理黏、分包)。 将特殊数据解析为可以传递的数据结构,以达到解析数据的目的。 很明显,大家看到了,数据处理适配器的作用用一句话说,就是解析数据用的。","s":"说明","u":"/touchsocket/docs/adapterdescription","h":"#说明","p":26},{"i":32,"t":"TouchSocket的适配器,在初始阶段(原始TCP),会收到一个ByteBlock数据,然后经过适配器处理以后,可选择两个参数(ByteBlock和IRequestInfo)的任意组合投递数据。 例如:FixedHeaderPackageAdapter,仅投递ByteBlock数据,届时IRequestInfo将为null。而如果是继承的CustomDataHandlingAdapter,则仅投递IRequestInfo,ByteBlock将为null。","s":"数据逻辑","u":"/touchsocket/docs/adapterdescription","h":"#数据逻辑","p":26},{"i":34,"t":"大家有时候可能会迷惑,为什么TouchSocket要设计两个参数投递,而不像其他的那样的,在会话里面,把适配器直接泛型规范了,直接抛出对应的类型。这是因为泛型约束太大,不够灵活。例如: 第一,不能随时切换适配器,例如适配webSocket,在握手阶段,要解析http数据,所以,此时应该选择http数据处理适配,而完成握手以后,就要解析ws数据格式了,所以此时应该切换适配器为ws数据处理适配器。 第二,两个参数能提高性能。例如HTTP数据处理适配器,在高性能工作模式下,由IRequestInfo投递请求头,由ByteBlock投递Body,这样Body是从内存池获得,就不存在内存消耗了。","s":"设计解释","u":"/touchsocket/docs/adapterdescription","h":"#设计解释","p":26},{"i":36,"t":"在TCP系中使用数据处理适配器是非常简单的一个过程。而且为了不同场景,TouchSocket支持多种方式的适配器使用。服务器和客户端使用一致","s":"三、TCP使用","u":"/touchsocket/docs/adapterdescription","h":"#三tcp使用","p":26},{"i":38,"t":"在Config配置使用时,相当于初始化赋值。比较单一,但是很可靠。 .SetDataHandlingAdapter(()=> { return new MyCustomBetweenAndDataHandlingAdapter(); })","s":"3.1 在Config配置中使用","u":"/touchsocket/docs/adapterdescription","h":"#31-在config配置中使用","p":26},{"i":40,"t":"只需要在OnConnecting方法(或Connecting事件)中对新连接的Client,调用SetDataHandlingAdapter进行赋值即可。 public class MyTcpService : TcpService { protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e) { socketClient.SetDataHandlingAdapter(new NormalDataHandlingAdapter());//直接对数据处理器赋值,立即生效 base.OnConnecting(socketClient, e); } }","s":"3.2 订阅Connecting相关事件","u":"/touchsocket/docs/adapterdescription","h":"#32-订阅connecting相关事件","p":26},{"i":42,"t":"使用插件实现该功能,实际上和步骤2一样,但是因为是基于插件,所以更好于管理。 class MyPlugin : TcpPluginBase { protected override void OnConnecting(ITcpClientBase client, ClientOperationEventArgs e) { client.SetDataHandlingAdapter(new NormalDataHandlingAdapter()); base.OnConnecting(client, e); } }","s":"3.3 使用插件,代替Connecting相关事件实现","u":"/touchsocket/docs/adapterdescription","h":"#33-使用插件代替connecting相关事件实现","p":26},{"i":44,"t":"实际上,大家可以从步骤2、3中看出来,适配器是可以被随意赋值的,这也就说明,适配器是可以随时被替换的。那么也就可以被随时赋值了。","s":"3.4 任意时刻设置","u":"/touchsocket/docs/adapterdescription","h":"#34-任意时刻设置","p":26},{"i":46,"t":"Udp使用的插件,只能从Config配置。 【UdpSession】 m_udpSession.Setup(new TouchSocketConfig() .SetBindIPHost(new IPHost(this.textBox2.Text)) .SetUdpDataHandlingAdapter(()=> { return new NormalUdpDataHandlingAdapter(); }) .ConfigureContainer(a => { a.SetSingletonLogger(new LoggerGroup(new EasyLogger(this.ShowMsg), new FileLogger())); })) .Start(); 注意:同一个适配器实例,只可被赋值一次,不然会异常。如果在构造函数(或其他一次性函数)中设置适配器的话,在重连时,最好重新设置适配器,因为框架在Disconnected时会置空适配器,同时在Connecting执行完后会检测适配器,如果没有再次设置适配器的话,会选择默认适配器(TcpClient会选择普通适配器,Protocol及派生会选择固定包头适配器)。","s":"四、UDP使用插件","u":"/touchsocket/docs/adapterdescription","h":"#四udp使用插件","p":26},{"i":48,"t":"限制使用的场景应用于自定义封装。例如:自己封装一个服务器,然后适配器仅特定使用,不允许外部随意赋值,那么可以如下实现: public class MySocketClient : SocketClient { /// /// /// public override sealed bool CanSetDataHandlingAdapter => false;//不允许随意赋值 private void InternalSetAdapter(DataHandlingAdapter adapter) { this.SetAdapter(adapter);//仅继承内部赋值 } }","s":"五、限制使用","u":"/touchsocket/docs/adapterdescription","h":"#五限制使用","p":26},{"i":50,"t":"当适配器在工作时,如果一个数据包在设置的周期内(默认1000ms)没有完成接收,则会清空所有缓存数据,然后重新接收。 这种设计是为了应对,当接收数据时,如果发送方发送了异常数据(也有可能在移动网时,由运营商发送的无效包)而导致整个接收队列数据无效的问题。 现在加入缓存超时设置,则如果发送上述情况,也会在一个周期后,快速恢复接收。 相关属性设置: CacheTimeoutEnable:是否启用缓存超时。 CacheTimeout:缓存超时时间 UpdateCacheTimeWhenRev:是否每次接收就更新缓存时间。默认true,意味着只要有数据接收,则缓存永远不会过期。当为false时,则每个缓存包,必须在设置的周期内完成接收。","s":"六、缓存超时(仅Tcp适配器)","u":"/touchsocket/docs/adapterdescription","h":"#六缓存超时仅tcp适配器","p":26},{"i":53,"t":"大数据固定包头,是对固定的包头模板的补充,一般来是,固定包头适配器,不能工作于超过2G的数据,但是在少数情况下,会有大量的数据传输需求。所以这部分的业务,可以用大数据固定包头实现。","s":"一、说明","u":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","h":"#一说明","p":51},{"i":55,"t":"可以自由适配99%的数据协议。 可以随意定制数据协议。 可以与任意语言、框架对接数据。 可以接收理论无限大的数据。","s":"二、特点","u":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","h":"#二特点","p":51},{"i":57,"t":"客户端与服务器均适用。下列以服务器为例。 步骤 声明新建类,实现IBigFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 声明新建类,继承BigFixedHeaderCustomDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 TouchSocketConfig配置中设置。 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 【MyBigFixedHeaderRequestInfo】 首先,新建MyBigFixedHeaderRequestInfo类,然后实现IBigFixedHeaderRequestInfo用户自定义固定包头接口。 然后在OnParsingHeader函数执行结束时,对实现的BodyLength属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。 /// /// 下列示例,没有实现逻辑,仅解释思路。 /// class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo { public long BodyLength => throw new NotImplementedException();//此处请使用字段实现。 public void OnAppendBody(byte[] buffer, int offset, int length) { //在这里会一直追加数据体,用户自行实现数据的保存。 //注意,buffer可能为内存块的成员,所以,一定一定不要直接引用。 } public bool OnFinished() { //触发该方法时,说明数据体接收完毕,返回true时,会触发Receive相关事件,否则不会。 return true; } public bool OnParsingHeader(byte[] header) { //解析头部。赋值BodyLength return true; } } 新建MyBigFixedHeaderCustomDataHandlingAdapter继承CustomBigFixedHeaderDataHandlingAdapter,然后对HeaderLength作出赋值,以此表明固定包头的长度是多少。 /// /// 模板解析“大数据固定包头”数据适配器 /// class MyBigFixedHeaderCustomDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter { public override int HeaderLength =>8; protected override MyBigFixedHeaderRequestInfo GetInstance() { return new MyBigFixedHeaderRequestInfo(); } } 【接收】 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 if (requestInfo is MyBigFixedHeaderRequestInfo myRequestInfo) { //此处可以处理MyBigFixedHeaderRequestInfo的相关信息了。 string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); } }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(() => { return new MyBigFixedHeaderCustomDataHandlingAdapter(); }))//配置适配器 .Start();//启动 提示 上述创建的适配器客户端与服务器均适用。","s":"三、使用","u":"/touchsocket/docs/bigfixedheadercustomdatahandlingadapter","h":"#三使用","p":51},{"i":60,"t":"直接调用,则是不使用任何代理,直接Call RPC,使用比较简单。 static void Main(string[] args) { var client = GetXmlRpcClient(); //直接调用 int result1 = client.Invoke(\"Sum\", InvokeOption.WaitInvoke, 10, 20); Console.WriteLine($\"直接调用,返回结果:{result1}\"); Console.ReadKey(); } static XmlRpcClient GetXmlRpcClient() { XmlRpcClient jsonRpcClient = new XmlRpcClient(); jsonRpcClient.Setup(\"http://127.0.0.1:7706/xmlRpc\"); jsonRpcClient.Connect(); Console.WriteLine(\"连接成功\"); return jsonRpcClient; } 【亦或者直接使用字符串调用】 在Http-Post方式即可。 Sum 10 20 ","s":"直接调用","u":"/touchsocket/docs/callxmlrpc","h":"#直接调用","p":58},{"i":62,"t":"代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。","s":"代理调用RPC","u":"/touchsocket/docs/callxmlrpc","h":"#代理调用rpc","p":58},{"i":64,"t":"获取代理文件详情","s":"如何生成获取代理文件?","u":"/touchsocket/docs/callxmlrpc","h":"#如何生成获取代理文件","p":58},{"i":66,"t":"当代理被客户端获取以后,客户端项目中会多出一个RRQMProxy的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的代理方法和代理类,可直接由代理类发起调用。 static void Main(string[] args) { var client = GetXmlRpcClient(); Server server = new Server(client); int result2 = server.Sum(10, 20); Console.WriteLine($\"代理调用,返回结果:{result2}\"); Console.ReadKey(); } static XmlRpcClient GetXmlRpcClient() { XmlRpcClient jsonRpcClient = new XmlRpcClient(); jsonRpcClient.Setup(\"http://127.0.0.1:7706/xmlRpc\"); jsonRpcClient.Connect(); Console.WriteLine(\"连接成功\"); return jsonRpcClient; }","s":"调用","u":"/touchsocket/docs/callxmlrpc","h":"#调用","p":58},{"i":69,"t":"直接调用,则是不使用任何代理,直接Call RPC,使用比较简单,浏览器也能直接调用实现。 【Url请求】 http://127.0.0.1:7789/ApiServer/Sum?a=10&b=20 【HttpClient调用】 WebApi的客户端和大家所熟识的有一些差距,TouchSocket的WebApi使用的是先连接,后请求的逻辑。请求时,先标记GET/POST的函数。如果是GET,则必须留空URL,如果是POST,则只写URL即可。 private static WebApiClient CreateWebApiClient() { WebApiClient client = new WebApiClient(); client.Setup(\"127.0.0.1:7789\"); client.Connect(); Console.WriteLine(\"连接成功\"); return client; } var client = CreateWebApiClient(); int sum1 = client.Invoke(\"GET:/ApiServer/Sum?a={0}&b={1}\", null, 10, 20); Console.WriteLine($\"Get调用成功,结果:{sum1}\"); int sum2 = client.Invoke(\"POST:/ApiServer/TestPost\", null, new MyClass() { A = 10, B = 20 }); Console.WriteLine($\"Post调用成功,结果:{sum2}\");","s":"直接调用","u":"/touchsocket/docs/callwebapi","h":"#直接调用","p":67},{"i":71,"t":"代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。","s":"代理调用RPC","u":"/touchsocket/docs/callwebapi","h":"#代理调用rpc","p":67},{"i":73,"t":"获取代理文件详情","s":"如何生成获取代理文件?","u":"/touchsocket/docs/callwebapi","h":"#如何生成获取代理文件","p":67},{"i":75,"t":"当代理被客户端获取以后,客户端项目中会多出一个RRQMProxy的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的代理方法和代理类,可直接由代理类发起调用。 int sum3 = client.TestPost(new MyClass() { A = 10, B = 20 }); Console.WriteLine($\"代理调用成功,结果:{sum3}\");","s":"调用","u":"/touchsocket/docs/callwebapi","h":"#调用","p":67},{"i":78,"t":"因为JsonRpc是通用调用协议,所以可以直接使用Json字符串调用。 以下字符串只是示例,具体的method参数,应当遵循当前路由。 【Tcp协议直接调用】 在TCP协议时,按照适配器,选择性的是否以\\r\\n结尾。 {\"jsonrpc\": \"2.0\", \"method\": \"testjsonrpc\", \"params\":[\"RRQM\"], \"id\": 1} 【Http协议直接调用】 在Http协议时,以Url+Post方式即可 {\"jsonrpc\": \"2.0\", \"method\": \"testjsonrpc\", \"params\":[\"RRQM\"], \"id\": 1} 【Websocket协议直接调用】 在Websocket协议时,以文本类型,直接发送到服务器即可。 {\"jsonrpc\": \"2.0\", \"method\": \"testjsonrpc\", \"params\":[\"RRQM\"], \"id\": 1}","s":"一、直接调用","u":"/touchsocket/docs/calljsonrpc","h":"#一直接调用","p":76},{"i":80,"t":"TouchSocket提供了JsonRpc的专属客户端,直接调用,则会则是不使用任何代理,直接Call RPC,使用比较简单。 【TCP协议】 JsonRpcClient jsonRpcClient = new JsonRpcClient(); jsonRpcClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"127.0.0.1:7705\") .SetJRPT(JRPT.Tcp)); jsonRpcClient.Connect(); Console.WriteLine(\"连接成功\"); string result = jsonRpcClient.Invoke(\"jsonrpcconsoleapp.server.testjsonrpc\", InvokeOption.WaitInvoke, \"TouchSocket\"); Console.WriteLine($\"Tcp返回结果:{result}\"); result = jsonRpcClient.Invoke(\"TestJsonRpc1\", InvokeOption.WaitInvoke, \"TouchSocket\"); Console.WriteLine($\"Tcp返回结果:{result}\"); result = jsonRpcClient.Invoke(\"jsonrpcconsoleapp.server.testgetcontext\", InvokeOption.WaitInvoke, \"TouchSocket\"); Console.WriteLine($\"Tcp返回结果:{result}\"); JObject obj = new JObject(); obj.Add(\"A\", \"A\"); obj.Add(\"B\", 10); obj.Add(\"C\", 100.1); JObject newObj = jsonRpcClient.Invoke(\"jsonrpcconsoleapp.server.testjobject\", InvokeOption.WaitInvoke, obj); Console.WriteLine($\"Tcp返回结果:{newObj}\"); 【Http协议】 static void JsonRpcClientInvokeByHttp() { JsonRpcClient jsonRpcClient = new JsonRpcClient(); jsonRpcClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"http://127.0.0.1:7706/jsonrpc\") .SetJRPT(JRPT.Http)); jsonRpcClient.Connect(); Console.WriteLine(\"连接成功\"); string result = jsonRpcClient.Invoke(\"server/testjsonrpc\", InvokeOption.WaitInvoke, \"TouchSocket\"); Console.WriteLine($\"Http返回结果:{result}\"); JObject obj = new JObject(); obj.Add(\"A\", \"A\"); obj.Add(\"B\", 10); obj.Add(\"C\", 100.1); JObject newObj = jsonRpcClient.Invoke(\"server/testjobject\", InvokeOption.WaitInvoke, obj); Console.WriteLine($\"Http返回结果:{newObj}\"); } 【Websocket协议】 JsonRpcClient jsonRpcClient = new JsonRpcClient(); jsonRpcClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"ws://127.0.0.1:7706/ws\")//此url就是能连接到websocket的路径。 .SetDataHandlingAdapter(() => new TerminatorPackageAdapter(\"\\r\\n\")) .SetJRPT(JRPT.Websocket)); jsonRpcClient.Connect(); Console.WriteLine(\"连接成功\"); string result = jsonRpcClient.TestJsonRpc(\"RRQM\"); Console.WriteLine($\"Websocket返回结果:{result}\"); result = jsonRpcClient.TestJsonRpc1(\"RRQM\"); Console.WriteLine($\"Websocket返回结果:{result}\"); result = jsonRpcClient.TestGetContext(\"RRQM\"); Console.WriteLine($\"Websocket返回结果:{result}\"); JObject obj = new JObject(); obj.Add(\"A\", \"A\"); obj.Add(\"B\", 10); obj.Add(\"C\", 100.1); JObject newObj = jsonRpcClient.TestJObject(obj); Console.WriteLine($\"Websocket返回结果:{newObj}\");","s":"二、客户端直接调用","u":"/touchsocket/docs/calljsonrpc","h":"#二客户端直接调用","p":76},{"i":82,"t":"代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。","s":"代理调用RPC","u":"/touchsocket/docs/calljsonrpc","h":"#代理调用rpc","p":76},{"i":84,"t":"获取代理文件详情","s":"如何生成获取代理文件?","u":"/touchsocket/docs/calljsonrpc","h":"#如何生成获取代理文件","p":76},{"i":86,"t":"当代理被客户端获取以后,客户端项目中会多出一个RRQMProxy(//TODO:这里需要修改,上面的获取代理文件详情的链接失效需要修改,下面截图需要修改)的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的代理方法和代理类,可直接由代理类发起调用。 JsonRpcClient jsonRpcClient = new JsonRpcClient(JRPT.Http); jsonRpcClient.Setup(\"http://127.0.0.1:7706/jsonrpc\"); jsonRpcClient.Connect(); Server server= new Server(jsonRpcClient);//Server是生成的代理类。 server.TestJsonRpc(\"TouchSocket\");//代理调用","s":"调用","u":"/touchsocket/docs/calljsonrpc","h":"#调用","p":76},{"i":89,"t":"这是一个很简单的控制台命令器,重要作用就是很方便的实现控制台控制。 Nuget Package:TouchSocket","s":"一、说明","u":"/touchsocket/docs/consoleaction","h":"#一说明","p":87},{"i":91,"t":"ConsoleAction consoleAction = new ConsoleAction(\"h|help|?\");//设置帮助命令 consoleAction.OnException += ConsoleAction_OnException;//订阅执行异常输出 //下列的ShareProxy,StopShareProxy,GetAll均为无参数的方法 consoleAction.Add(\"sp|shareProxy\", \"分享代理\", ShareProxy);//示例命令 consoleAction.Add(\"ssp|stopShareProxy\", \"停止分享代理\", StopShareProxy);//示例命令 consoleAction.Add(\"ga|getAll\", \"获取所有客户端信息\", GetAll);//示例命令 consoleAction.ShowAll(); while (true) { if (!consoleAction.Run(Console.ReadLine())) { Console.WriteLine(\"命令不正确,请输入“h|help|?”获得帮助。\"); } }","s":"二、使用","u":"/touchsocket/docs/consoleaction","h":"#二使用","p":87},{"i":94,"t":"RRQM承接WPF及网络通信相关的开发任务。价格详情咨询若汝棋茗。QQ:505554090 支付可通过淘宝。安全有保障。","s":"商业合作","u":"/touchsocket/docs/cooperation","h":"","p":93},{"i":97,"t":"HttpClient是Http客户端类。主要用于请求Http报文。","s":"说明","u":"/touchsocket/docs/createhttpclient","h":"#说明","p":95},{"i":99,"t":"继承TcpClient","s":"可配置项","u":"/touchsocket/docs/createhttpclient","h":"#可配置项","p":95},{"i":101,"t":"支持ITcpPlugin接口。","s":"支持插件接口","u":"/touchsocket/docs/createhttpclient","h":"#支持插件接口","p":95},{"i":102,"t":"HttpClient client = new HttpClient(); client.Setup(new TouchSocketConfig() .UsePlugin() .SetRemoteIPHost(new IPHost(\"http://localhost:7219\"))) .Connect();//先做连接 HttpRequest request = new HttpRequest(); request .InitHeaders() .SetUrl(\"/WeatherForecast\") .SetHost(client.RemoteIPHost.Host) .AsGet(); var respose = client.Request(request, timeout: 1000*10); Console.WriteLine(respose.GetBody());","s":"创建HttpClient","u":"/touchsocket/docs/createhttpclient","h":"#创建httpclient","p":95},{"i":104,"t":"如果需要连接到Https服务器。则必须手动配置Ssl。示例如下: 如果服务器证书是由证书机构颁发,则只需填充TargetHost和SslProtocols。 SetClientSslOption(new ClientSslOption() { TargetHost = \"localhost\", SslProtocols = SslProtocols.Tls12 }) 如果服务器证书是由自己制作的,则需要加载证书文件,和必要的验证。 .SetClientSslOption(new ClientSslOption() { ClientCertificates = new X509CertificateCollection() { new X509Certificate2(\"RRQMSocket.pfx\", \"RRQMSocket\") }, SslProtocols = SslProtocols.Tls12, TargetHost = \"127.0.0.1\", CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; } }));","s":"创建HttpsClient","u":"/touchsocket/docs/createhttpclient","h":"#创建httpsclient","p":95},{"i":106,"t":"方法名 功能简介 Request 请求Http数据,并等待返回","s":"主要方法简介","u":"/touchsocket/docs/createhttpclient","h":"#主要方法简介","p":95},{"i":110,"t":"HttpService是能够提供Http相关服务的基础类型。 注意 HttpService仅仅支持简单的web服务,如果是和TouchSocket的其他组件配合,则可以使用,如果想单独作为web服务器,则最好不要使用。因为其兼容性比较薄弱。","s":"一、说明","u":"/touchsocket/docs/createhttpservice","h":"#一说明","p":108},{"i":112,"t":"支持HTTPS。 多种数据接收模式 多地址监听(可以一次性监听多个IP及端口)","s":"二、产品特点","u":"/touchsocket/docs/createhttpservice","h":"#二产品特点","p":108},{"i":114,"t":"HTTP基础使用场景:可跨平台、跨语言使用。","s":"三、产品应用场景","u":"/touchsocket/docs/createhttpservice","h":"#三产品应用场景","p":108},{"i":116,"t":"服务器在收到新客户端连接时,会创建一个HttpSocketClient的派生类实例,与远程HttpClient对应,后续的数据通信均由此实例负责。","s":"四、服务器架构","u":"/touchsocket/docs/createhttpservice","h":"#四服务器架构","p":108},{"i":118,"t":"声明自定义实例类,然后实现IHttpPlugin接口,即可实现下列事务的触发。或者继承自HttpPluginBase类,重写相应方法即可。 插件方法 功能 OnDelete 当收到Delete请求时 OnGet 当收到OnGet请求时 OnPost 当收到OnPost请求时 OnPut 当收到OnPut请求时 OnReceivedOtherHttpRequest 当收到OnReceivedOtherHttpRequest请求时","s":"五、支持插件接口","u":"/touchsocket/docs/createhttpservice","h":"#五支持插件接口","p":108},{"i":120,"t":"HttpService的创建,基本和TcpService一致,也可以通过继承实现,下列仅演示最简单实现。 HttpService的相关事务,会通过插件触发。 var service = new HttpService(); service.Setup(new TouchSocketConfig()//加载配置 .UsePlugin() .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => { a.AddConsoleLogger(); }) .ConfigurePlugins(a => { a.Add(); //default插件应该最后添加,其作用是 //1、为找不到的路由返回404 //2、处理header为Option的探视跨域请求。 a.UseDefaultHttpServicePlugin(); })) .Start(); 提示 DefaultHttpServicePlugin插件最好添加在插件中,如果没有添加的话,最好自己做好缺省路由和跨域配置。 在插件中,通过重写(或实现)的方式,进入OnGet、OnPost、OnDelete、OnPut等函数,即可处理对应请求。 /// /// 支持GET、Post、Put,Delete,或者其他 /// internal class MyHttpPlug : HttpPluginBase { protected override void OnGet(HttpSocketClient client, HttpContextEventArgs e) { if (e.Context.Request.UrlEquals(\"/success\")) { //直接响应文字 e.Context.Response.FromText(\"Success\").Answer();//直接回应 Console.WriteLine(\"处理完毕\"); e.Handled = true; } else if (e.Context.Request.UrlEquals(\"/file\")) { //直接回应文件。 e.Context.Response .SetStatus()//必须要有状态 .FromFile(@\"D:\\System\\Windows.iso\", e.Context.Request); } else if (e.Context.Request.UrlEquals(\"/html\")) { //回应html StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"TouchSocket\"); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"
\"); stringBuilder.AppendLine(\"王二麻子\"); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"
\"); stringBuilder.AppendLine(\"\"); stringBuilder.AppendLine(\"\"); e.Context.Response .SetStatus()//必须要有状态 .SetContentTypeByExtension(\".html\") .SetContent(stringBuilder.ToString()); e.Context.Response.Answer(); } } protected override void OnPost(HttpSocketClient client, HttpContextEventArgs e) { } }","s":"六、创建HttpService","u":"/touchsocket/docs/createhttpservice","h":"#六创建httpservice","p":108},{"i":122,"t":"Https服务器,和http服务器几乎一样,只不过增加了一个Ssl的配置。 .SetServiceSslOption(new ServiceSslOption() { Certificate = new X509Certificate2(\"RRQMSocket.pfx\", \"RRQMSocket\"), SslProtocols = SslProtocols.Tls12 }))","s":"七、创建加密Ssl的HttpsService","u":"/touchsocket/docs/createhttpservice","h":"#七创建加密ssl的httpsservice","p":108},{"i":125,"t":"RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。RPC它假定某些协议的存在,例如TPC/UDP等,为通信程序之间携带信息数据。在OSI网络七层模型中,RPC跨越了传输层和应用层,RPC使得开发,包括网络分布式多程序在内的应用程序更加容易。 过程是什么? 过程就是业务处理、计算任务,更直白的说,就是程序,就是想调用本地方法一样调用远程的过程。 TouchRpc支持服务器与客户端互相调用,也支持客户端之间相互调用。","s":"一、说明","u":"/touchsocket/docs/createandcallrpc","h":"#一说明","p":123},{"i":127,"t":"在被调用端中新建一个类名为MyRpcServer。 继承于RpcServer类、或实现IRpcServer。亦或者将服务器声明为瞬时生命的服务,继承TransientRpcServer、或ITransientRpcServer。 在该类中写公共方法,并用TouchRpc属性标签标记。 public class MyRpcServer : RpcServer { [Description(\"登录\")]//服务描述,在生成代理时,会变成注释。 [TouchRpc(\"Login\")]//服务注册的函数键,此处为显式指定。默认不传参的时候,为该函数类全名+方法名的全小写。 public bool Login(string account,string password) { if (account==\"123\"&&password==\"abc\") { return true; } return false; } } public class MyRpcServer : TransientRpcServer { [Description(\"登录\")]//服务描述,在生成代理时,会变成注释。 [TouchRpc(\"Login\")]//服务注册的函数键,此处为显式指定。默认不传参的时候,为该函数类全名+方法名的全小写。 public bool Login(string account,string password) { if (account==\"123\"&&password==\"abc\") { return true; } return false; } } 提示 瞬时生命的服务,最大的特点就是,每个请求,都会创建一个新的服务类对象。然后可以通过this.CallContext直接访问当前的调用上下文。","s":"二、定义服务","u":"/touchsocket/docs/createandcallrpc","h":"#二定义服务","p":123},{"i":129,"t":"以下仅示例基于Tcp协议TouchRpc。其他协议的服务器请看创建TouchRpc服务器 var service =new TcpTouchRpcService(); TouchSocketConfig config= new TouchSocketConfig()//配置 .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureRpcStore(a=> { a.RegisterServer();//注册服务 }) .SetVerifyToken(\"TouchRpc\"); service.Setup(config) .Start(); service.Logger.Info($\"{service.GetType().Name}已启动\");","s":"三、启动Rpc服务器","u":"/touchsocket/docs/createandcallrpc","h":"#三启动rpc服务器","p":123},{"i":132,"t":"直接调用,则是不使用任何代理,使用字符串和参数直接Call Rpc,使用比较简单。 下列以TcpTouchRpcClient为例,其他客户端一模一样。 TcpTouchRpcClient client = new TcpTouchRpcClient(); client.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"127.0.0.1:7789\") .SetVerifyToken(\"TouchRpc\")); client.Connect(); //直接调用时,第一个参数为调用键 //第二个参数为调用配置参数,可设置调用超时时间,取消调用等功能。示例中使用的预设,实际上可以自行new InvokeOption(); //后续参数为调用参数。 //泛型为返回值类型。 bool result = client.Invoke(\"Login\", InvokeOption.WaitInvoke, 123, \"abc\");","s":"4.1 直接调用","u":"/touchsocket/docs/createandcallrpc","h":"#41-直接调用","p":123},{"i":134,"t":"代理调用的便捷在于,客户端不用再知道哪些服务可调,也不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。 详细步骤: 生成代理文件 将生成的cs文件添加到调用端一起编译。 备注 以上示例,会生成下列代理代码。 【生成的代理】 using TouchSocket.Rpc; using System.Threading.Tasks; namespace RpcProxy { public interface IMyRpcServer : IRemoteServer { /// ///登录 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default); /// ///登录 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 Task LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default); } public class MyRpcServer : IMyRpcServer { public MyRpcServer(IRpcClient client) { this.Client = client; } public IRpcClient Client { get; private set; } /// ///登录 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 public System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default) { if (Client == null) { throw new RpcException(\"IRpcClient为空,请先初始化或者进行赋值\"); } if (Client.TryCanInvoke?.Invoke(Client) == false) { throw new RpcException(\"Rpc无法执行。\"); } object[] parameters = new object[] { account, password }; System.Boolean returnData = Client.Invoke(\"Login\", invokeOption, parameters); return returnData; } /// ///登录 /// public Task LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default) { if (Client == null) { throw new RpcException(\"IRpcClient为空,请先初始化或者进行赋值\"); } if (Client.TryCanInvoke?.Invoke(Client) == false) { throw new RpcException(\"Rpc无法执行。\"); } object[] parameters = new object[] { account, password }; return Client.InvokeAsync(\"Login\", invokeOption, parameters); } } public static class MyRpcServerExtensions { /// ///登录 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 public static System.Boolean Login(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { if (client.TryCanInvoke?.Invoke(client) == false) { throw new RpcException(\"Rpc无法执行。\"); } object[] parameters = new object[] { account, password }; System.Boolean returnData = client.Invoke(\"Login\", invokeOption, parameters); return returnData; } /// ///登录 /// public static Task LoginAsync(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { if (client.TryCanInvoke?.Invoke(client) == false) { throw new RpcException(\"Rpc无法执行。\"); } object[] parameters = new object[] { account, password }; return client.InvokeAsync(\"Login\", invokeOption, parameters); } } } 使用代理扩展直接调用。 TcpTouchRpcClient client = new TcpTouchRpcClient(); client.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"127.0.0.1:7789\") .SetVerifyToken(\"TouchRpc\")); client.Connect(); bool result = client.Login(123, \"abc\");//Login是扩展方法。可能需要额外添加命名空间。","s":"4.2、代理调用","u":"/touchsocket/docs/createandcallrpc","h":"#42代理调用","p":123},{"i":136,"t":"一般的rpc服务都是客户端发起,服务器响应。但是有时候也需要服务器主动调用客户端,所以需要反向rpc。","s":"五、反向Rpc","u":"/touchsocket/docs/createandcallrpc","h":"#五反向rpc","p":123},{"i":138,"t":"实际上,所有的Rpc客户端(TcpTouchRpcClient、UdpTouchRpc(不区分客户端)、HttpTouchRpcClient、WSTouchRpcClient)也实现了IRpcParser接口,这意味着反向RPC其实也是RPC,所以,所有操作一模一样。因为当客户端和服务器建立连接以后,就不再区分谁是客户端,谁是服务器了。只关心,谁能提供服务,谁在调用服务。 下列就以简单的示例下,由客户端声明服务,服务器调用服务。 具体步骤: 在客户端项目中定义服务 用TouchRpc标记 public class ReverseCallbackServer : RpcServer { [TouchRpc] public string SayHello(string name) { return $\"{name},hi\"; } } 【客户端发布服务】 发布服务,实际上是让TcpTouchRpcClient也拥有提供RPC的能力。 TcpTouchRpcClient client = new TcpTouchRpcClient(); client.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"127.0.0.1:7789\") .ConfigureContainer(a => { a.AddConsoleLogger(); a.AddFileLogger(); }) .ConfigureRpcStore(a => { a.RegisterServer(); }) .SetVerifyToken(\"TouchRpc\")); client.Connect();","s":"5.1 定义、发布反向RPC服务","u":"/touchsocket/docs/createandcallrpc","h":"#51-定义发布反向rpc服务","p":123},{"i":140,"t":"服务器回调客户端,最终必须通过服务器辅助类客户端(ISocketClient的派生类),以TcpTouchRpcService为例,其辅助客户端为TcpTouchRpcSocketClient。 因为,TcpTouchRpcSocketClient已实现IRpcClient接口,意味着,反向RPC也可以使用代理调用。所有用法和RPC一致。 下列示例以TcpTouchRpcSocketClient为例,其余一致。 提示 反向RPC也可以使用代理调用。所有用法和RPC一致。","s":"5.2 调用反向RPC","u":"/touchsocket/docs/createandcallrpc","h":"#52-调用反向rpc","p":123},{"i":142,"t":"可以获取所有终端。 foreach (var item in tcpTouchRpcService.GetClients()) { client.Logger.Info(item.Invoke(\"ReverseRpcConsoleApp.ReverseCallbackServer.SayHello\".ToLower(), InvokeOption.WaitInvoke, \"张三\")); } 也可以先筛选ID,然后再调用。 string id = tcpTouchRpcService.GetIDs().FirstOrDefault(a => a.Equals(\"特定id\")); if (tcpTouchRpcService.TryGetSocketClient(id, out var rpcSocketClient)) { rpcSocketClient.Invoke(\"ReverseRpcConsoleApp.ReverseCallbackServer.SayHello\".ToLower(), InvokeOption.WaitInvoke, \"张三\"); } 5.2.2 通过调用上下文获取​ 具体步骤 设置调用上下文 上下文的Caller,即为服务器辅助类终端,进行强转即可。","s":"5.2.1 通过服务器直接获取","u":"/touchsocket/docs/createandcallrpc","h":"#521-通过服务器直接获取","p":123},{"i":144,"t":"除了正向RPC,反向RPC,TouchRpc还支持客户端之间互Call RPC。服务的定义与Rpc一样。","s":"六、客户端互Call RPC","u":"/touchsocket/docs/createandcallrpc","h":"#六客户端互call-rpc","p":123},{"i":146,"t":"客户端A调用客户端B的方法,需要知道对方的ID。和方法名。然后使用下列函数调用即可。 提示 互Call RPC也支持调用上下文。 服务器注意 客户端互Call的时候,每个请求,都需要服务同意路由,才可以被转发。所以服务器需要做一些允许操作。 internal class MyTouchRpcPlugin : TouchRpcPluginBase { protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e) { if (e.RouterType== RouteType.Rpc) { e.IsPermitOperation = true; } base.OnRouting(client, e); } }","s":"6.1 互Call RPC","u":"/touchsocket/docs/createandcallrpc","h":"#61-互call-rpc","p":123},{"i":149,"t":"内存池是TouchSocketCore的最重要的组成部分,在TouchSocket产品中,BytePool贯穿始终。所以熟悉使用BytePool,也是非常重要的。 Nuget Package:TouchSocket","s":"一、说明","u":"/touchsocket/docs/bytepool","h":"#一说明","p":147},{"i":151,"t":"内存池(BytePool)的最小实现单体是内存块(ByteBlock),它是继承自Stream的类,拥有和MemoryStream一样的功能和RRQM的增强功能。而且拥有释放回收能力,所以如果有MemoryStream的使用需求的话,就可以完全让ByteBlock替代。","s":"二、功能","u":"/touchsocket/docs/bytepool","h":"#二功能","p":147},{"i":153,"t":"BytePool是静态类,无需创建,直接使用即可。ByteBlock可通过BytePool创建,也可以直接new对象,这两者实际操作一致。 注意:创建的ByteBlock必须释放(Dispose),虽然不会内存泄露,但是会影响性能。 ByteBlock byteBlock1 = new ByteBlock(byteSize:1024*1024,equalSize:false); byteBlock1.Dispose(); ByteBlock byteBlock2 = BytePool.GetByteBlock(byteSize:1024*1024,equalSize:false); byteBlock2.Dispose(); using (ByteBlock byteBlock3=new ByteBlock()) { }","s":"三、创建","u":"/touchsocket/docs/bytepool","h":"#三创建","p":147},{"i":155,"t":"基础使用和MemoryStream一致,下面仅介绍特定使用。","s":"四、使用","u":"/touchsocket/docs/bytepool","h":"#四使用","p":147},{"i":157,"t":"using (ByteBlock byteBlock = new ByteBlock()) { byteBlock.Write(byte.MaxValue); byteBlock.Write(int.MaxValue); byteBlock.Write(long.MaxValue); byteBlock.Write(\"RRQM\"); byteBlock.WriteObject(new Person(), SerializationType.Json); byteBlock.WriteBytesPackage(new byte[1024]); byteBlock.Pos = 0;//读取时,先将游标移动到初始写入的位置,然后按写入顺序,依次读取 byte ByteValue = byteBlock.ReadByte(); int IntValue = byteBlock.ReadInt32(); long LongValue = byteBlock.ReadInt64(); string StringValue = byteBlock.ReadString(); Person ObjectValue = byteBlock.ReadObject(SerializationType.Json); byte[] BytesValue = byteBlock.ReadBytesPackage(); }","s":"4.1 写入、读取数据对象","u":"/touchsocket/docs/bytepool","h":"#41-写入读取数据对象","p":147},{"i":159,"t":"在多线程异步时,设计架构应当遵守谁(Thread)创建的ByteBlock,由谁释放,这样就能很好的避免未释放的情况发生。实际上RRQMSocket中,就是秉承这样的设计,任何非用户创建的ByteBlock,都会由创建的线程最后释放。但是在使用中,经常出现异步多线程的操作。 以RRQMSocket的TcpClient为例。如果直接在收到数据时,使用Task异步,则必定会发生关于ByteBlock的各种各样的异常。 原因非常简单,byteBlock对象在到达HandleReceivedData时,触发Task异步,此时触发线程会立即返回,并释放byteBlock,而Task异步线程会滞后,然后试图从已释放的byteBlock中获取数据,所以,必定发生异常。 public class MyTClient : TcpClient { protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) { Task.Run(()=> { string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); Console.WriteLine($\"已接收到信息:{mes}\"); }); } } 解决方法也非常简单,只需要在异步前锁定,然后使用完成后取消锁定,且不用再调用Dispose。 public class MyTClient : TcpClient { protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) { byteBlock.SetHolding(true);//异步前锁定 Task.Run(()=> { string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); byteBlock.SetHolding(false);//使用完成后取消锁定,且不用再调用Dispose Console.WriteLine($\"已接收到信息:{mes}\"); }); } }","s":"4.2 多线程同步协作(Hold)","u":"/touchsocket/docs/bytepool","h":"#42-多线程同步协作hold","p":147},{"i":162,"t":"TouchRpc客户端对应的,也有四种不同协议的版本。","s":"一、说明","u":"/touchsocket/docs/createtouchrpcclient","h":"#一说明","p":160},{"i":164,"t":"可配置项 SetVerifyTimeout​ 设置验证超时时间,默认3000ms。(仅TcpTouchRpc可用) 。 SetVerifyToken​ 设置验证口令。 SetHeartbeatFrequency​ 设置心跳。默认为间隔2000ms,连续3次无响应即视为断开。 SetSerializationSelector​ 设置序列化选择器。 SetResponseType​ 设置允许的响应类型 SetRootPath​ 设置根路径","s":"二、可配置项","u":"/touchsocket/docs/createtouchrpcclient","h":"#二可配置项","p":160},{"i":166,"t":"声明自定义实例类,然后实现ITouchRpcPlugin接口,即可实现下列事务的触发。 或者继承自TouchRpcPluginBase类,重写相应方法即可。 插件方法 功能 OnHandshaking 客户端在验证连接。默认情况下,框架会首先验证连接Token是否正确,如果不正确则直接拒绝。不会有任何投递。用户也可以使用Metadata进行动态验证。 OnHandshaked 客户端完成连接验证 OnFileTransfering 在文件传输即将进行时触发。 OnFileTransfered 当文件传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。 OnLoadingStream 在远程请求加载流时触发。 OnReceivedProtocolData 收到协议数据 OnRemoteAccessing 在远程操作访问之前。 OnRemoteAccessed 在远程操作访问之后。 OnRouting 当需要转发路由包时。一般所有的客户端之间的数据传输,都需要经过该函数的运行。 OnStreamTransfering 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 OnStreamTransfered 流数据处理,用户需要在此事件中对e.Bucket手动释放。 当流数据传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。","s":"三、支持插件接口","u":"/touchsocket/docs/createtouchrpcclient","h":"#三支持插件接口","p":160},{"i":169,"t":"基本创建如下,支持创建TcpClient的所有配置。 TcpTouchRpcClient client = new TcpTouchRpcClient(); client.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"127.0.0.1:7789\") .SetVerifyToken(\"TouchRpc\")); client.Connect();","s":"4.1 TcpTouchRpcClient","u":"/touchsocket/docs/createtouchrpcclient","h":"#41-tcptouchrpcclient","p":160},{"i":171,"t":"基本创建如下,支持创建TcpClient的所有配置。 HttpTouchRpcClient client = new HttpTouchRpcClient(); client.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"127.0.0.1:7789\") .SetVerifyToken(\"TouchRpc\")); client.Connect();","s":"4.2 HttpTouchRpcClient","u":"/touchsocket/docs/createtouchrpcclient","h":"#42-httptouchrpcclient","p":160},{"i":173,"t":"基本创建如下,支持@的所有配置。 UdpTouchRpc client = new UdpTouchRpc(); client.Setup(new TouchSocketConfig() .SetBindIPHost(7794) .SetRemoteIPHost(\"127.0.0.1:7789\"));//设置目标地址。 client.Start();","s":"4.3 UdpTouchRpc","u":"/touchsocket/docs/createtouchrpcclient","h":"#43-udptouchrpc","p":160},{"i":175,"t":"WSTouchRpcClient client = new WSTouchRpcClient(); client.Setup(new TouchSocketConfig() .SetRemoteIPHost(\"ws://127.0.0.1:5000/wstouchrpc\")); client.ConnectAsync();","s":"4.4 WSTouchRpcClient","u":"/touchsocket/docs/createtouchrpcclient","h":"#44-wstouchrpcclient","p":160},{"i":178,"t":"TcpClient是Tcp系客户端基类,他直接参与tcp的连接、发送、接收、处理、断开等,他的业务与服务器的SocketClient是一一对应的。","s":"一、说明","u":"/touchsocket/docs/createtcpclient","h":"#一说明","p":176},{"i":180,"t":"简单易用。 IOCP多线程。 内存池支持 高性能 适配器预处理,一键式解决分包、粘包、对象解析(如HTTP,Json)等。 超简单的同步发送、异步发送、接收等操作。 基于委托、插件驱动,让每一步都能执行AOP。","s":"二、特点","u":"/touchsocket/docs/createtcpclient","h":"#二特点","p":176},{"i":182,"t":"所有Tcp基础使用场景:可跨平台、跨语言使用。 自定义协议解析场景:可解析任意数据格式的TCP数据报文。","s":"三、产品应用场景","u":"/touchsocket/docs/createtcpclient","h":"#三产品应用场景","p":176},{"i":184,"t":"可配置项 SetBufferLength​ 发送、接收缓存容量(单位:byte),默认1024×64。设置建议: 如果数据包较小,建议10k左右的值。更加节约内存。 如果数据包较大,例如文件传输等,建议64k,甚至更大的值。 该值虽然无上限,但是一般不要超过1Mb,不然不仅没意义,还很浪费 SetMaxPackageSize​ 数据包最大值(单位:byte),默认1024×1024×10。该值会在适当时间,直接作用DataHandlingAdapter.MaxPackageSize。 SetThreadCount​ 多线程数量。该值在Auto模式下指示线程池的最少线程数量和IO线程数量。 设置建议: 异步处理接收数据,此时线程数量设置为内核线程左右的值即可。 同步处理接收数据,此时应当考虑两个因素。该操作是否为耗时操作,如果是,则该值在允许范围内,应当设置更可能大的值。如果不是,则设置为内核线程左右的值即可。 SetGetDefaultNewID​ 配置初始ID的分配策略 SetListenIPHosts​ 监听IP和端口号组,可以一次性设置多个地址。 SetServerName​ 服务器标识名称,无实际使用意义。 SetBacklogProperty​ Tcp半连接挂起连接队列的最大长度。默认为30 SetMaxCount​ 最大可连接数,默认为10000 SetReceiveType​ 接收类型。 AUTO:自动接收模式。 None:不投递IO接收申请,用户可通过GetStream,获取到流以后,自己处理接收。注意:连接端不会感知主动断开。 UsePlugin​ 是否启用插件。在启用时或许会带来一点点性能损耗,基本上不是千万数据交互根本不值一提。 SetServiceSslOption​ Ssl配置,为Null时则不启用。 UseNoDelay​ 设置Socket的NoDelay属性,默认false。 UseDelaySender​ 使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。 使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: 如果一个包大于512kb,则不会延迟,直接发送。 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。 UseReuseAddress​ 启用端口复用。该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题。 SetRemoteIPHost​ 链接到的远程IPHost,支持域名。支持类型: 使用IP&Port,传入形如:127.0.0.1:7789的字符串即可。 使用域名,必须包含协议类型,形如:http://baidu.com或者https://baidu.com:80 SetClientSslOption​ 客户端Ssl配置,为Null时则不启用。 注意,当RemoteIPHost使用https、wss的域名时,该配置会使用系统默认配置生效。 SetKeepAliveValue​ 为Socket设置的属性。 注意:该配置仅在window平台生效。 SetBindIPHost​ 绑定端口。 在UdpSessionBase中表示本地监听地址 在TcpClient中表示固定客户端端口号。 UseDelaySender​ 使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。 使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: 如果一个包大于512kb,则不会延迟,直接发送。 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。 UseNoDelay​ 设置Socket的NoDelay属性,默认false。 UseBroadcast​ 该值指定可以发送或接收广播数据包。","s":"四、可配置项","u":"/touchsocket/docs/createtcpclient","h":"#四可配置项","p":176},{"i":186,"t":"支持ITcpPlugin接口,或者继承自TcpPluginBase类,重写相应方法即可。 插件方法 功能 OnConnecting 在Socket完成初始化,但是并未连接时触发。 OnConnected 在Socket完成连接,且成功后触发 OnDisconnecting 当客户端主动调用Close时触发 OnDisconnected 当客户端断开连接后触发 OnReceivingData 在收到原始数据时触发,所有的数据均在ByteBlock里面。 OnReceivedData 在收到适配器数据时触发,根据适配器类型,数据可能在ByteBlock或者IRequestInfo里面。 OnSendingData 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。","s":"五、支持插件","u":"/touchsocket/docs/createtcpclient","h":"#五支持插件","p":176},{"i":188,"t":"简单的处理逻辑可通过Connecting、Connected、Received等委托直接实现。 代码如下: TcpClient tcpClient = new TcpClient(); tcpClient.Connected += (client, e) => { };//成功连接到服务器 tcpClient.Disconnected += (client, e) => { };//从服务器断开连接,当连接不成功时不会触发。 tcpClient.Received += (client, byteBlock, requestInfo) => { //从服务器收到信息 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); Console.WriteLine($\"接收到信息:{mes}\"); }; //声明配置 TouchSocketConfig config = new TouchSocketConfig(); config.SetRemoteIPHost(new IPHost(\"127.0.0.1:7789\")) .UsePlugin(); //载入配置 tcpClient.Setup(config); tcpClient.Connect(); tcpClient.Send(\"RRQM\");","s":"六、创建TcpClient","u":"/touchsocket/docs/createtcpclient","h":"#六创建tcpclient","p":176},{"i":190,"t":"在TcpClient中,接收数据的方式有很多种。多种方式可以组合使用。","s":"七、接收数据","u":"/touchsocket/docs/createtcpclient","h":"#七接收数据","p":176},{"i":192,"t":"当使用TcpClient创建客户端时,内部已经定义好了一个外置委托Received,可以通过该委托直接接收数据。 TcpClient tcpClient = new TcpClient(); tcpClient.Received += (client, byteBlock, requestInfo) => { //从服务器收到信息 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); Console.WriteLine($\"接收到信息:{mes}\"); }; //声明配置 TouchSocketConfig config = new TouchSocketConfig(); config.SetRemoteIPHost(new IPHost(\"127.0.0.1:7789\")) .UsePlugin(); //载入配置 tcpClient.Setup(config); tcpClient.Connect();","s":"7.1 Received委托处理","u":"/touchsocket/docs/createtcpclient","h":"#71-received委托处理","p":176},{"i":194,"t":"按照TouchSocket的设计理念,使用插件处理数据,是一项非常简单,且高度解耦的方式。步骤如下: 服务器配置启用插件(UsePlugin) 新建插件类 添加插件 代码如下: (1)声明插件 public class MyPlugin : TcpPluginBase { public MyPlugin() { this.Order = 0;//此值表示插件的执行顺序,当多个插件并存时,该值越大,越在前执行。 } protected override void OnReceivedData(TcpClient client, ReceivedDataEventArgs e) { //这里处理数据接收 //根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。 ByteBlock byteBlock = e.ByteBlock; IRequestInfo requestInfo = e.RequestInfo; //e.Handled = true;//表示该数据已经被本插件处理,无需再投递到其他插件。 base.OnReceivedData(client, e); } } (2)创建使用插件处理的客户端 TcpClient client = new TcpClient(); client.Setup(new TouchSocketConfig() .SetRemoteIPHost(new IPHost(\"127.0.0.1:7789\")) .UsePlugin() .ConfigureContainer(a=> { a.AddConsoleLogger(); }) .ConfigurePlugins(a => { a.Add(); })) .Connect();","s":"7.2 插件处理推荐","u":"/touchsocket/docs/createtcpclient","h":"#72-插件处理推荐","p":176},{"i":196,"t":"【同步发送】 TcpClient已经内置了三种同步发送方法,直接调用就可以发送,但需要注意的是,通过该方法发送的数据,会经过适配器,如果想要直接发送,请使用DefaultSend。如果发送失败,则会立即抛出异常。 public virtual void Send(byte[] buffer); public virtual void Send(ByteBlock byteBlock); public virtual void Send(byte[] buffer, int offset, int length); 【异步发送】 TcpClient已经内置了三种异步发送方法,直接调用就可以发送。如果发送失败,await就会触发异常。 public virtual Task SendAsync(byte[] buffer); public virtual Task SendAsync(byte[] buffer, int offset, int length);","s":"八、发送数据","u":"/touchsocket/docs/createtcpclient","h":"#八发送数据","p":176},{"i":199,"t":"UDP组件是基于UDP协议的最基础组件,其功能简单,易用。它既能充当服务器,又能够作为客户端。","s":"一、说明","u":"/touchsocket/docs/createudpsession","h":"#一说明","p":197},{"i":201,"t":"简单易用。 多线程。 内存池 高性能","s":"二、产品特点","u":"/touchsocket/docs/createudpsession","h":"#二产品特点","p":197},{"i":203,"t":"UDP基础使用场景:可跨平台、跨语言使用。","s":"三、产品应用场景","u":"/touchsocket/docs/createudpsession","h":"#三产品应用场景","p":197},{"i":205,"t":"声明自定义实例类,然后实现IUdpSessionPlugin接口,即可实现下列事务的触发。或者继承自UdpSessionPluginBase类,重写相应方法即可。 插件方法 功能 OnReceivedData 在收到数据时触发","s":"四、支持插件接口","u":"/touchsocket/docs/createudpsession","h":"#四支持插件接口","p":197},{"i":207,"t":"UdpSession udpSession = new UdpSession(); udpSession.Received += (remote, byteBlock,requestInfo) => { udpSession.Send(remote, byteBlock); Console.WriteLine($\"收到:{Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len)}\"); }; udpSession.Setup(new TouchSocketConfig() .SetBindIPHost(new IPHost(7789))) .Start(); Console.WriteLine(\"等待接收\"); 注意 即使不监听地址,Setup和Start都是必须要的。 当udp作为客户端时,Config如果不设置SetBindIPHost,将不会接收,如果不知道绑定那个端口,可以直接绑定0端口,这样,就会使用系统空闲的一个端口了。","s":"四、使用UdpSession","u":"/touchsocket/docs/createudpsession","h":"#四使用udpsession","p":197},{"i":210,"t":"TcpService是Tcp系服务器基类,它不参与实际的数据交互,只是配置、激活、管理、注销、重建SocketClient类实例。而SocketClient是当TcpClient(客户端)成功连接服务器以后,由服务器新建的一个实例类,后续的所有通信,也都是通过该实例完成的。","s":"一、说明","u":"/touchsocket/docs/createtcpservice","h":"#一说明","p":208},{"i":212,"t":"简单易用。 IOCP多线程。 内存池支持 高性能(实测服务器单客户端单线程,每秒可接收200w条8字节的信息,接收数据流量可达2.5GB/s)。 多地址监听(可以一次性监听多个IP及端口) 适配器预处理,一键式解决分包、粘包、对象解析(如HTTP,Json)等。 超简单的同步发送、异步发送、接收等操作。 基于委托、插件驱动,让每一步都能执行AOP。","s":"二、特点","u":"/touchsocket/docs/createtcpservice","h":"#二特点","p":208},{"i":214,"t":"所有Tcp基础使用场景:可跨平台、跨语言使用。 自定义协议解析场景:可解析任意数据格式的TCP数据报文。","s":"三、产品应用场景","u":"/touchsocket/docs/createtcpservice","h":"#三产品应用场景","p":208},{"i":216,"t":"服务器在收到新客户端连接时,会创建一个SocketClient的派生类实例,与客户端TcpClient一一对应,后续的数据通信均由此实例负责。 SocketClient在Service里面以字典映射。ID为键,SocketClient本身为值。","s":"四、服务器架构","u":"/touchsocket/docs/createtcpservice","h":"#四服务器架构","p":208},{"i":218,"t":"可配置项 SetBufferLength​ 发送、接收缓存容量(单位:byte),默认1024×64。设置建议: 如果数据包较小,建议10k左右的值。更加节约内存。 如果数据包较大,例如文件传输等,建议64k,甚至更大的值。 该值虽然无上限,但是一般不要超过1Mb,不然不仅没意义,还很浪费 SetMaxPackageSize​ 数据包最大值(单位:byte),默认1024×1024×10。该值会在适当时间,直接作用DataHandlingAdapter.MaxPackageSize。 SetThreadCount​ 多线程数量。该值在Auto模式下指示线程池的最少线程数量和IO线程数量。 设置建议: 异步处理接收数据,此时线程数量设置为内核线程左右的值即可。 同步处理接收数据,此时应当考虑两个因素。该操作是否为耗时操作,如果是,则该值在允许范围内,应当设置更可能大的值。如果不是,则设置为内核线程左右的值即可。 SetGetDefaultNewID​ 配置初始ID的分配策略 SetListenIPHosts​ 监听IP和端口号组,可以一次性设置多个地址。 SetServerName​ 服务器标识名称,无实际使用意义。 SetBacklogProperty​ Tcp半连接挂起连接队列的最大长度。默认为30 SetMaxCount​ 最大可连接数,默认为10000 SetReceiveType​ 接收类型。 AUTO:自动接收模式。 None:不投递IO接收申请,用户可通过GetStream,获取到流以后,自己处理接收。注意:连接端不会感知主动断开。 UsePlugin​ 是否启用插件。在启用时或许会带来一点点性能损耗,基本上不是千万数据交互根本不值一提。 SetServiceSslOption​ Ssl配置,为Null时则不启用。 UseNoDelay​ 设置Socket的NoDelay属性,默认false。 UseDelaySender​ 使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。 使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: 如果一个包大于512kb,则不会延迟,直接发送。 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。 UseReuseAddress​ 启用端口复用。该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题。 SetRemoteIPHost​ 链接到的远程IPHost,支持域名。支持类型: 使用IP&Port,传入形如:127.0.0.1:7789的字符串即可。 使用域名,必须包含协议类型,形如:http://baidu.com或者https://baidu.com:80 SetClientSslOption​ 客户端Ssl配置,为Null时则不启用。 注意,当RemoteIPHost使用https、wss的域名时,该配置会使用系统默认配置生效。 SetKeepAliveValue​ 为Socket设置的属性。 注意:该配置仅在window平台生效。 SetBindIPHost​ 绑定端口。 在UdpSessionBase中表示本地监听地址 在TcpClient中表示固定客户端端口号。 UseDelaySender​ 使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。 使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: 如果一个包大于512kb,则不会延迟,直接发送。 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。 UseNoDelay​ 设置Socket的NoDelay属性,默认false。 UseBroadcast​ 该值指定可以发送或接收广播数据包。","s":"五、可配置项","u":"/touchsocket/docs/createtcpservice","h":"#五可配置项","p":208},{"i":220,"t":"支持ITcpPlugin接口,或者继承自TcpPluginBase类,重写相应方法即可。 插件方法 功能 OnConnecting 此时Socket实际上已经完成连接,但是并没有启动接收,然后触发。 OnConnected 同意连接,且成功启动接收后触发 OnDisconnecting 当客户端主动调用Close时触发 OnDisconnected 当客户端断开连接后触发 OnReceivingData 在收到原始数据时触发,所有的数据均在ByteBlock里面。 OnReceivedData 在收到适配器数据时触发,根据适配器类型,数据可能在ByteBlock或者IRequestInfo里面。 OnSendingData 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 OnIDChanged 当SocketClient的ID发生改变时触发。","s":"六、支持插件","u":"/touchsocket/docs/createtcpservice","h":"#六支持插件","p":208},{"i":223,"t":"直接初始化TcpService,会使用默认的SocketClient。 简单的处理逻辑可通过Connecting、Connected、Received等委托直接实现。 代码如下: TcpService service = new TcpService(); service.Connecting = (client, e) => { };//有客户端正在连接 service.Connected = (client, e) => { };//有客户端成功连接 service.Disconnected = (client, e) => { };//有客户端断开连接 service.Received = (client, byteBlock, requestInfo) => { //从客户端收到信息 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); client.Logger.Info($\"已从{client.ID}接收到信息:{mes}\"); client.Send(mes);//将收到的信息直接返回给发送方 //client.Send(\"id\",mes);//将收到的信息返回给特定ID的客户端 var ids = service.GetIDs(); foreach (var clientId in ids)//将收到的信息返回给在线的所有客户端。 { if (clientId != client.ID)//不给自己发 { service.Send(clientId, mes); } } }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(\"tcp://127.0.0.1:7789\"), new IPHost(7790) })//同时监听两个地址 .ConfigureContainer(a =>//容器的配置顺序应该在最前面 { a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) }) .ConfigurePlugins(a => { //a.Add();//此处可以添加插件 })) .Start();//启动","s":"7.1 简单创建","u":"/touchsocket/docs/createtcpservice","h":"#71-简单创建","p":208},{"i":225,"t":"通过泛型创建服务器,可以实现很多有意思,且能重写一些有用的功能。下面就演示,如何通过泛型创建服务器。 代码如下: (1)建立SocketClient继承类。 public class MySocketClient : SocketClient { protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) { //此处逻辑单线程处理。 //此处处理数据,功能相当于Received委托。 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); Console.WriteLine($\"已接收到信息:{mes}\"); } } (2)建立TcpService继承类。实际上如果业务不涉及服务器配置的话,可以省略该步骤,使用TcpService的泛型直接创建。 public class MyService : TcpService { protected override void LoadConfig(TouchSocketConfig config) { //此处加载配置,用户可以从配置中获取配置项。 base.LoadConfig(config); } protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e) { //此处逻辑会多线程处理。 //e.ID:对新连接的客户端进行ID初始化,例如可以设置为其IP地址。 //e.IsPermitOperation:指示是否允许该客户端链接。 base.OnConnecting(socketClient, e); } } (3)创建服务器(包含MyService)。 MyService service = new MyService(); service.Connecting = (client, e) => { };//有客户端正在连接 service.Connected = (client, e) => { };//有客户端成功连接 service.Disconnected = (client, e) => { };//有客户端断开连接 service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(\"tcp://127.0.0.1:7789\"), new IPHost(7790) })//同时监听两个地址 .ConfigureContainer(a =>//容器的配置顺序应该在最前面 { a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) }) .ConfigurePlugins(a => { //a.Add();//此处可以添加插件 })) .Start();//启动 (4)创建服务器(不含MyService)。 TcpService service = new TcpService(); service.Connecting = (client, e) => { };//有客户端正在连接 service.Connected = (client, e) => { };//有客户端成功连接 service.Disconnected = (client, e) => { };//有客户端断开连接 service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(\"tcp://127.0.0.1:7789\"), new IPHost(7790) })//同时监听两个地址 .ConfigureContainer(a =>//容器的配置顺序应该在最前面 { a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) }) .ConfigurePlugins(a => { //a.Add();//此处可以添加插件 })) .Start();//启动 建议 由上述代码可以看出,通过继承,可以更加灵活的实现扩展。但实际上,很多业务我们希望大家能通过插件完成。","s":"7.2 泛型创建","u":"/touchsocket/docs/createtcpservice","h":"#72-泛型创建","p":208},{"i":227,"t":"在TcpService中,接收数据的方式有很多种。多种方式可以组合使用。","s":"八、接收数据","u":"/touchsocket/docs/createtcpservice","h":"#八接收数据","p":208},{"i":229,"t":"当使用TcpService(非泛型)创建服务器时,内部已经定义好了一个外置委托Received,可以通过该委托直接接收数据。 TcpService service = new TcpService(); service.Received = (client, byteBlock, requestInfo) => { //从客户端收到信息 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); client.Logger.Info($\"已从{client.ID}接收到信息:{mes}\"); }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(\"tcp://127.0.0.1:7789\"), new IPHost(7790) })//同时监听两个地址 .ConfigureContainer(a =>//容器的配置顺序应该在最前面 { a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) })) .Start();//启动","s":"8.1 Received委托处理","u":"/touchsocket/docs/createtcpservice","h":"#81-received委托处理","p":208},{"i":231,"t":"正如6.2所示,可以直接在MySocketClient的重写HandleReceivedData中直接处理数据。","s":"8.2 重写SocketClient处理","u":"/touchsocket/docs/createtcpservice","h":"#82-重写socketclient处理","p":208},{"i":233,"t":"按照TouchSocket的设计理念,使用插件处理数据,是一项非常简单,且高度解耦的方式。步骤如下: 服务器配置启用插件(UsePlugin) 新建插件类 添加插件 代码如下: (1)声明插件 public class MyPlugin : TcpPluginBase { public MyPlugin() { this.Order = 0;//此值表示插件的执行顺序,当多个插件并存时,该值越大,越在前执行。 } protected override void OnReceivedData(SocketClient client, ReceivedDataEventArgs e) { //这里处理数据接收 //根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。 ByteBlock byteBlock = e.ByteBlock; IRequestInfo requestInfo = e.RequestInfo; //e.Handled = true;//表示该数据已经被本插件处理,无需再投递到其他插件。 base.OnReceivedData(client, e); } } (2)创建使用插件处理的服务器 TcpService service = new TcpService(); service.Setup(new TouchSocketConfig() .SetListenIPHosts(new IPHost[] { new IPHost(\"127.0.0.1:7789\"), new IPHost(7790) }) .UsePlugin() .ConfigureContainer(a=> { a.UseConsoleLogger(); }) .ConfigurePlugins(a => { a.Add(); })) .Start();","s":"8.3 插件处理 推荐","u":"/touchsocket/docs/createtcpservice","h":"#83-插件处理-推荐","p":208},{"i":235,"t":"首先建议安装TouchSocket.AspNetCore或者TouchSocketPro.AspNetCore,因为这个里面有很多可以直接使用的注入项。 建议 在安装TouchSocket.AspNetCore或者TouchSocketPro.AspNetCore的同时,最好也安装TouchSocket或者TouchSocketPro。这样更新也即时一些。 在AspNetCore中使用TcpService,不应该像普通端一样,订阅Received。应该是通过插件,注入等方式实现。步骤如下: 注入TcpService,并做好配置(和常规服务器配置一样)。 新建插件,处理收到的数据。 代码如下: (1)声明插件 public class MyTcpPlugin : TcpPluginBase { private ILogger m_logger; public MyTcpPlugin(ILogger logger) { this.m_logger = logger; } protected override void OnConnected(SocketClient client, TouchSocketEventArgs e) { m_logger.LogInformation(\"客户端连接\"); base.OnConnected(client, e); } protected override void OnReceivedData(SocketClient client, ReceivedDataEventArgs e) { //这里处理数据接收 //根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。 ByteBlock byteBlock = e.ByteBlock; IRequestInfo requestInfo = e.RequestInfo; } } (2)注入服务 public void ConfigureServices(IServiceCollection services) { var tcpService = services.AddTcpService(config => { config.SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .UsePlugin() .UseAspNetCoreContainer(services) .ConfigurePlugins(a => { a.Add();//此插件就可以处理接收数据 }); }); } 然后在任意地方,也可获得服务。 提示 此时,TcpService与整个AspNetCore是共享IOC容器的。即:TcpService中的任何地方(例如:插件)也能获得AspNetCore已注册的服务。","s":"九、AspNetCore中创建","u":"/touchsocket/docs/createtcpservice","h":"#九aspnetcore中创建","p":208},{"i":237,"t":"按照架构图,每个客户端成功连接后,服务器都会创建一个派生自SocketClient的实例,通过该实例即可将数据发送至客户端。","s":"十、发送数据","u":"/touchsocket/docs/createtcpservice","h":"#十发送数据","p":208},{"i":239,"t":"(1)直接获取所有在线客户端 通过service.GetClients方法,获取当前在线的所有客户端。 SocketClient[] socketClients = service.GetClients(); 注意 由于SocketClient的生命周期是由框架控制的,所以最好尽量不要直接引用该实例,可以引用SocketClient.ID,然后再通过服务器查找。 (2)通过ID获取 先调用service.GetIDs方法,获取当前在线的所有客户端的ID,然后选择需要的ID,通过TryGetSocketClient方法,获取到想要的客户端。 string[] ids = service.GetIDs(); if (service.TryGetSocketClient(ids[0], out SocketClient socketClient)) { }","s":"10.1 如何获取SocketClient?","u":"/touchsocket/docs/createtcpservice","h":"#101-如何获取socketclient","p":208},{"i":241,"t":"【同步发送】 SocketClient已经内置了三种同步发送方法,直接调用就可以发送,如果发送失败,则会立即抛出异常。 public virtual void Send(byte[] buffer); public virtual void Send(ByteBlock byteBlock); public virtual void Send(byte[] buffer, int offset, int length); 【异步发送】 TcpClient已经内置了三种异步发送方法,直接调用就可以发送。如果发送失败,await就会触发异常。 public virtual Task SendAsync(byte[] buffer); public virtual Task SendAsync(ByteBlock byteBlock); public virtual Task SendAsync(byte[] buffer, int offset, int length); 提示 通过上述方法发送的数据,都会经过适配器,如果想要直接发送,请使用DefaultSend。","s":"10.2 发送","u":"/touchsocket/docs/createtcpservice","h":"#102-发送","p":208},{"i":243,"t":"通过ID发送数据。 public virtual void Send(string id, ByteBlock byteBlock); public virtual void Send(string id, byte[] buffer, int offset, int length); public virtual void Send(string id, byte[] buffer); public virtual Task SendAsync(string id, ByteBlock byteBlock); public virtual Task SendAsync(string id, byte[] buffer, int offset, int length); public virtual Task SendAsync(string id, byte[] buffer);","s":"10.3 通过TcpService发送","u":"/touchsocket/docs/createtcpservice","h":"#103-通过tcpservice发送","p":208},{"i":246,"t":"TouchRpc的服务器有多种形式的host,每种服务器的创建都大同小异,且功能基本一致。","s":"一、说明","u":"/touchsocket/docs/createtouchrpcservice","h":"#一说明","p":244},{"i":248,"t":"TouchRpc服务器的架构与其所属的基础协议架构一致,例如,在基于tcp协议时,其架构就和tcp服务器一致。在收到新客户端连接时,会创建一个TcpTouchRpcSocketClient的类实例,与客户端TcpTouchRpcClient一一对应,后续的数据通信均由此实例负责。","s":"二、服务器架构","u":"/touchsocket/docs/createtouchrpcservice","h":"#二服务器架构","p":244},{"i":250,"t":"可配置项 SetVerifyTimeout​ 设置验证超时时间,默认3000ms。(仅TcpTouchRpc可用) 。 SetVerifyToken​ 设置验证口令。 SetHeartbeatFrequency​ 设置心跳。默认为间隔2000ms,连续3次无响应即视为断开。 SetSerializationSelector​ 设置序列化选择器。 SetResponseType​ 设置允许的响应类型 SetRootPath​ 设置根路径","s":"三、可配置项","u":"/touchsocket/docs/createtouchrpcservice","h":"#三可配置项","p":244},{"i":252,"t":"声明自定义实例类,然后实现ITouchRpcPlugin接口,即可实现下列事务的触发。 或者继承自TouchRpcPluginBase类,重写相应方法即可。 插件方法 功能 OnHandshaking 客户端在验证连接。默认情况下,框架会首先验证连接Token是否正确,如果不正确则直接拒绝。不会有任何投递。用户也可以使用Metadata进行动态验证。 OnHandshaked 客户端完成连接验证 OnFileTransfering 在文件传输即将进行时触发。 OnFileTransfered 当文件传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。 OnLoadingStream 在远程请求加载流时触发。 OnReceivedProtocolData 收到协议数据 OnRemoteAccessing 在远程操作访问之前。 OnRemoteAccessed 在远程操作访问之后。 OnRouting 当需要转发路由包时。一般所有的客户端之间的数据传输,都需要经过该函数的运行。 OnStreamTransfering 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 OnStreamTransfered 流数据处理,用户需要在此事件中对e.Bucket手动释放。 当流数据传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。","s":"四、支持插件接口","u":"/touchsocket/docs/createtouchrpcservice","h":"#四支持插件接口","p":244},{"i":255,"t":"这是基于Tcp协议TouchRpc。在可配置TouchRpc的基础之上,还可以配置与TcpService可配置项相关的配置。 var service = new TcpTouchRpcService(); var config = new TouchSocketConfig()//配置 .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => { a.AddConsoleLogger(); a.AddFileLogger(); }) .SetVerifyToken(\"TouchRpc\");//设定连接口令,作用类似账号密码 service.Setup(config) .Start(); service.Logger.Info($\"{service.GetType().Name}已启动\");","s":"5.1 基于Tcp协议","u":"/touchsocket/docs/createtouchrpcservice","h":"#51-基于tcp协议","p":244},{"i":257,"t":"这是基于Http升级协议。在该解析器中,配置设置HttpService一致。 var service = new HttpTouchRpcService(); TouchSocketConfig config = new TouchSocketConfig()//配置 .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => { a.AddConsoleLogger(); a.AddFileLogger(); }) .SetVerifyToken(\"TouchRpc\"); service.Setup(config) .Start(); service.Logger.Info($\"{service.GetType().Name}已启动\");","s":"5.2 基于Http协议","u":"/touchsocket/docs/createtouchrpcservice","h":"#52-基于http协议","p":244},{"i":259,"t":"这是基于UDP协议解析器。在该解析器中,配置设置与UdpSession一致。因为udp是无连接的,所以不需要SetVerifyToken。 var service = new UdpTouchRpc(); TouchSocketConfig config = new TouchSocketConfig()//配置 .SetBindIPHost(new IPHost(7789)) .ConfigureContainer(a => { a.AddConsoleLogger(); a.AddFileLogger(); }); service.Setup(config) .Start(); service.Logger.Info($\"{service.GetType().Name}已启动\");","s":"5.3 基于Udp协议","u":"/touchsocket/docs/createtouchrpcservice","h":"#53-基于udp协议","p":244},{"i":261,"t":"具体步骤 nuget 安装TouchSocket.AspNetCore或者TouchSocketPro.AspNetCore。 IServiceCollection添加AddWSTouchRpc,并进行相关配置(不用配置端口,会和asp使用同一端口)。 IApplicationBuilder必须先使用UseWebSockets。 IApplicationBuilder调用UseWSTouchRpc,并传入url设置。 在ConfigureServices时,添加AddWSTouchRpc,并且配置相关项。 public void ConfigureServices(IServiceCollection services) { //向Asp服务中添加IWSTouchRpcService services.AddWSTouchRpc(new TouchSocketConfig() .UseAspNetCoreContainer(services));//设置IOC容器 services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc(\"v1\", new OpenApiInfo { Title = \"API Demo\", Version = \"v1\" }); }); } 启用中间件 首先必须启用WebSocket。其次使用UseWSTouchRpc即可。 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // Swagger app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint(\"/swagger/v1/swagger.json\", \"API Demo v1\"); }); app.UseWebSockets();//必须先使用WebSocket app.UseWSTouchRpc(\"/wstouchrpc\");//该操作不会影响原有的WebSocket,只要url不同即可。 app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }","s":"5.4 基于AspNetCore的Websocket协议","u":"/touchsocket/docs/createtouchrpcservice","h":"#54-基于aspnetcore的websocket协议","p":244},{"i":263,"t":"此页面展示用户通过TouchSocket自行实现的适配器案例。更好的共享资源。 欢迎大家提交更多。邮箱:505554090@qq.com","s":"说明","u":"/touchsocket/docs/adapterdemodescription","h":"#说明","p":262},{"i":265,"t":"通过单元测试。 编码尽可能规范。","s":"提交要求","u":"/touchsocket/docs/adapterdemodescription","h":"#提交要求","p":262},{"i":268,"t":"区间适配器,一般用于字符串类的消息,类似“Hello##”,该数据,以开头,以##结尾。当然,区间适配器也能用于二进制数据,但是会有概率发生标识重复的情况。所以,用于二进制时,应当设置较复杂的区间标识。 该适配器与[终止因子分割适配器](../8.2 Tcp适配器/d.终止因子分割数据处理适配器.mdx)相比,可以设置开头的字符区间。","s":"一、说明","u":"/touchsocket/docs/custombetweenanddatahandlingadapter","h":"#一说明","p":266},{"i":270,"t":"可以自由适配很多的字符串数据协议。 可以随意定制数据协议。 可以与任意语言、框架对接数据。","s":"二、特点","u":"/touchsocket/docs/custombetweenanddatahandlingadapter","h":"#二特点","p":266},{"i":272,"t":"客户端与服务器均适用。下列以服务器为例。 步骤 声明新建类,实现IBetweenAndRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 声明新建类,继承CustomBetweenAndDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 TouchSocketConfig配置中设置。 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 【MyBetweenAndRequestInfo】 首先,新建MyBetweenAndRequestInfo类,然后实现IBetweenAndRequestInfo接口。 /// /// 以**12##12##,Min=5为例。 /// class MyBetweenAndRequestInfo : IBetweenAndRequestInfo { public void OnParsingBody(byte[] body) { //这里的Body应该为12##12 } public bool OnParsingEndCode(byte[] endCode) { return true;//该返回值决定,是否执行Receive } public bool OnParsingStartCode(byte[] startCode) { return true; } } 新建MyCustomBetweenAndDataHandlingAdapter继承CustomBetweenAndDataHandlingAdapter,然后对StartCode、EndCode作出赋值,以此表明起始字符与结束字符的值。 class MyCustomBetweenAndDataHandlingAdapter : CustomBetweenAndDataHandlingAdapter { public MyCustomBetweenAndDataHandlingAdapter() { this.MinSize = 5;//表示,实际数据体不会小于5,例如“**12##12##”数据,解析后会解析成“12##12” } public override byte[] StartCode => Encoding.UTF8.GetBytes(\"**\");//可以为0长度字节,意味着没有起始标识。 public override byte[] EndCode => Encoding.UTF8.GetBytes(\"##\");//必须为有效值。 protected override MyBetweenAndRequestInfo GetInstance() { return new MyBetweenAndRequestInfo(); } } 【接收】 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 if (requestInfo is MyBetweenAndRequestInfo myRequestInfo) { //此处可以处理MyBigFixedHeaderRequestInfo的相关信息了。 } }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(() => { return new MyCustomBetweenAndDataHandlingAdapter(); }))//配置适配器 .Start();//启动 提示 上述创建的适配器客户端与服务器均适用。","s":"三、使用","u":"/touchsocket/docs/custombetweenanddatahandlingadapter","h":"#三使用","p":266},{"i":275,"t":"WebSocket是基于Http协议的升级协议,所以应当挂载在http服务器执行。","s":"一、说明","u":"/touchsocket/docs/createwebsocketservice","h":"#一说明","p":273},{"i":277,"t":"继承HttpService","s":"二、可配置项","u":"/touchsocket/docs/createwebsocketservice","h":"#二可配置项","p":273},{"i":279,"t":"支持ITcpPlugin、IHttpPlugin、IWebSocketPlugin","s":"三、支持插件接口","u":"/touchsocket/docs/createwebsocketservice","h":"#三支持插件接口","p":273},{"i":281,"t":"OnHandshaking 表示在即将握手连接时。 OnHandshaked 表示完成握手后。 OnHandleWSDataFrame 当收到WS数据时。","s":"IWebSocketPlugin","u":"/touchsocket/docs/createwebsocketservice","h":"#iwebsocketplugin","p":273},{"i":284,"t":"通过插件创建的话,只能指定一个特殊url路由。如果想获得连接前的Http请求,也必须再添加一个实现IWebSocketPlugin接口的插件,然后从OnHandshaking方法中捕获。 var service = new HttpService(); service.Setup(new TouchSocketConfig()//加载配置 .UsePlugin() .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => { a.SetSingletonLogger(); }) .ConfigurePlugins(a => { a.Add()//添加WebSocket功能 .SetWSUrl(\"/ws\") .SetCallback(WSCallback);//WSCallback回调函数是在WS收到数据时触发回调的。 a.Add();//MyWebSocketPlugin是继承自WebSocketPluginBase的插件。 })) .Start(); Console.WriteLine(\"Http服务器已启动\"); Console.WriteLine(\"ws://127.0.0.1:7789/ws\");","s":"4.1 简单通过插件创建","u":"/touchsocket/docs/createwebsocketservice","h":"#41-简单通过插件创建","p":273},{"i":286,"t":"通过WebApi的方式会更加灵活,也能很方便的获得Http相关参数。还能实现多个Url的连接路由。 实现步骤: 必须启用插件 必须配置ConfigureRpcStore,和注册MyServer 必须添加WebApiParserPlugin var service = new HttpService(); service.Setup(new TouchSocketConfig()//加载配置 .UsePlugin() .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => { a.SetSingletonLogger(); }) .ConfigureRpcStore(a=> { a.RegisterServer(); }) .ConfigurePlugins(a => { a.Add(); })) .Start(); Console.WriteLine(\"服务器已启动,可使用下列地址连接\"); Console.WriteLine(\"ws://127.0.0.1:7789/MyServer/ConnectWS\"); public class MyServer : RpcServer { private readonly ILog m_logger; public MyServer(ILog logger) { this.m_logger = logger; } [Router(\"/[api]/[action]\")] [WebApi(HttpMethodType.GET, MethodFlags = MethodFlags.IncludeCallContext)] public void ConnectWS(IWebApiCallContext callContext) { if (callContext.Caller is HttpSocketClient socketClient) { if (socketClient.SwitchProtocolToWebSocket(callContext.Context)) { m_logger.Message(\"WS通过WebApi连接\"); } } } }","s":"4.2 通过WebApi创建","u":"/touchsocket/docs/createwebsocketservice","h":"#42-通过webapi创建","p":273},{"i":288,"t":"创建WSs服务器时,其他配置不变,只需要在config中配置SslOption代码即可。 在RRQMBox中,放置了一个自制Ssl证书,密码为“RRQMSocket”以供测试。使用配置非常方便。 var config = new TouchSocketConfig(); config.UsePlugin() .SetReceiveType(ReceiveType.Auto) .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .SetServiceSslOption(new ServiceSslOption() //Ssl配置,当为null的时候,相当于创建了ws服务器,当赋值的时候,相当于wss服务器。 { Certificate = new X509Certificate2(\"RRQMSocket.pfx\", \"RRQMSocket\"), SslProtocols = SslProtocols.Tls12 });","s":"创建基于Ssl的WebSocket服务","u":"/touchsocket/docs/createwebsocketservice","h":"#创建基于ssl的websocket服务","p":273},{"i":290,"t":"【回调接收】 在添加WebSocketServerPlugin插件后,可以调用SetCallback函数,然后设置一个回调函数(如下所示),然后该函数在服务器收到信息时,会触发(并发触发)。 static void WSCallback(ITcpClientBase client, WSDataFrameEventArgs e) { switch (e.DataFrame.Opcode) { case WSDataType.Cont: Console.WriteLine($\"收到中间数据,长度为:{e.DataFrame.PayloadLength}\"); break; case WSDataType.Text: Console.WriteLine(e.DataFrame.ToText()); break; case WSDataType.Binary: if (e.DataFrame.FIN) { Console.WriteLine($\"收到二进制数据,长度为:{e.DataFrame.PayloadLength}\"); } else { Console.WriteLine($\"收到未结束的二进制数据,长度为:{e.DataFrame.PayloadLength}\"); } break; case WSDataType.Close: { Console.WriteLine(\"远程请求断开\"); client.Close(\"断开\"); } break; case WSDataType.Ping: break; case WSDataType.Pong: break; default: break; } } 【继承源插件接收】 实际上WebSocketServerPlugin是可以被继承的,然后重写OnHandleWSDataFrame函数,但尽量不要覆盖基类方法,不然插件其他将不会触发。 class MyWebSocketServerPlugin: WebSocketServerPlugin { protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) { base.OnHandleWSDataFrame(client, e); } } 【插件接口接收】 WS服务器,虽然是Http的插件,但是也能触发插件接口。适用于WS的插件接口是IWebSocketPlugin(或者从WebSocketPluginBase继承),声明任意类,实现该接口即可。 class MyWebSocketServerPlugin: WebSocketPluginBase { protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) { //此处的父类方法可以直接覆盖。 base.OnHandleWSDataFrame(client, e); } }","s":"接收消息","u":"/touchsocket/docs/createwebsocketservice","h":"#接收消息","p":273},{"i":292,"t":"在以上接收、或直接从HttpService获取Clients,将client对象转为HttpSocketClient,即可使用扩展方法,进行发送。 不要直接Send,7.x版本直接Send可以,但8.0以后,Send只会以TCP数据回应。 作为一条消息发送 服务器广播发送 //广播给所有人 if (client is HttpSocketClient socketClient && socketClient.Service is HttpService service) { var clients = service.GetClients(); foreach (var item in clients) { item.SendWithWS(e.DataFrame.ToText()); } } 将一个数据分包发送 例如:发送的数据为{0,1,2,3,4,5,6,7,8,9},当设置packageSize为5时,会先发送{0,1,2,3,4}作为头包,然后发送{5,6,7,8,9}的后继包。","s":"回复、响应数据","u":"/touchsocket/docs/createwebsocketservice","h":"#回复响应数据","p":273},{"i":295,"t":"和原始适配器相比,用户自定义适配器(CustomDataHandlingAdapter)简单很多。因为他只需要考虑接下来如何处理即可。","s":"一、说明","u":"/touchsocket/docs/customdatahandlingadapter","h":"#一说明","p":293},{"i":297,"t":"返回指令类型: FilterResult.Cache:将ByteBlock中的,从ByteBlock.Pos到结束的所有数据进行缓存,用于和下次接收数据做拼接。 FilterResult.Success:完成本次数据解析,向Received投递IRequestInfo对象。在返回之前,请一定确保已经修改ByteBlock.Pos属性。不然会发生无限循环的危险情况。 FilterResult.GoOn:将ByteBlock.Pos至结束的数据重新投递,所以在返回之前,请一定确保已经修改ByteBlock.Pos属性,至少已经递增一位。不然会发生无限循环的危险情况。 注意 返回Success或者GoOn指令时,请一定确保已经修改ByteBlock.Pos属性,至少已经递增一位。不然会发生无限循环的危险情况。","s":"二、运行逻辑","u":"/touchsocket/docs/customdatahandlingadapter","h":"#二运行逻辑","p":293},{"i":299,"t":"更加自由度的操作数据。 能够简单的缓存不能解析的数据。","s":"三、特点","u":"/touchsocket/docs/customdatahandlingadapter","h":"#三特点","p":293},{"i":301,"t":"还是以下列数据为例: 步骤 声明新建类,实现IRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 声明新建类,继承CustomDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 TouchSocketConfig配置中设置。 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 【定义适配器】 internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter { /// /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 /// 当不满足解析条件时,请返回,此时会保存的数据 /// 当数据部分异常时,请移动到指定位置,然后返回 /// 当完全满足解析条件时,请返回最后将移至指定位置。 /// /// 字节块 /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 /// 对象。 /// 缓存容量指导,指示当需要缓存时,应该申请多大的内存。 /// protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref MyRequestInfo request, ref int tempCapacity) { //以下解析思路为一次性解析,不考虑缓存的临时对象。 if (byteBlock.CanReadLen < 3) { return FilterResult.Cache;//当头部都无法解析时,直接缓存 } int pos = byteBlock.Pos;//记录初始游标位置,防止本次无法解析时,回退游标。 MyRequestInfo myRequestInfo = new MyRequestInfo(); //此操作实际上有两个作用, //1.填充header //2.将byteBlock.Pos递增3的长度。 byteBlock.Read(out byte[] header, 3);//填充header //因为第一个字节表示所有长度,而DataType、OrderType已经包含在了header里面。 //所有只需呀再读取header[0]-2个长度即可。 byte bodyLength = (byte)(header[0] - 2); if (bodyLength > byteBlock.CanReadLen) { //body数据不足。 byteBlock.Pos = pos;//回退游标 return FilterResult.Cache; } else { //此操作实际上有两个作用, //1.填充body //2.将byteBlock.Pos递增bodyLength的长度。 byteBlock.Read(out byte[] body, bodyLength); myRequestInfo.Header = header; myRequestInfo.DataType = header[1]; myRequestInfo.OrderType = header[2]; myRequestInfo.Body = body; request = myRequestInfo;//赋值ref return FilterResult.Success;//返回成功 } } } internal class MyRequestInfo : IRequestInfo { /// /// 自定义属性,Body /// public byte[] Body { get; internal set; } /// /// 自定义属性,Header /// public byte[] Header { get; internal set; } /// /// 自定义属性,DataType /// public byte DataType { get; internal set; } /// /// 自定义属性,OrderType /// public byte OrderType { get; internal set; } } 【接收】 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 if (requestInfo is MyRequestInfo myRequestInfo) { //此处可以处理MyRequestInfo的相关信息了。 string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); } }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(() => { return new MyCustomDataHandlingAdapter(); }))//配置适配器 .Start();//启动 提示 上述创建的适配器客户端与服务器均适用。","s":"四、使用","u":"/touchsocket/docs/customdatahandlingadapter","h":"#四使用","p":293},{"i":304,"t":"和用户自定义适配器相比,使用模板解析将会更加简单流程。例如在上节所说的数据格式,前三个字节是固定长度的,为3,而后续长度则由第一个字节计算可得,所以我们把类似这样的数据格式,叫做“固定包头”数据,那么,他就可以使用固定包头数据解析模板。","s":"一、说明","u":"/touchsocket/docs/customfixedheaderdatahandlingadapter","h":"#一说明","p":302},{"i":306,"t":"可以自由适配99%的数据协议(例如:modbus,电力控制协议等)。 可以随意定制数据协议。 可以与任意语言、框架对接数据。","s":"二、特点","u":"/touchsocket/docs/customfixedheaderdatahandlingadapter","h":"#二特点","p":302},{"i":308,"t":"客户端与服务器均适用。下列以服务器为例。 步骤 声明新建类,实现IFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 声明新建类,继承CustomFixedHeaderDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 TouchSocketConfig配置中设置。 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 【MyFixedHeaderRequestInfo】 首先,新建MyFixedHeaderRequestInfo类,然后实现IFixedHeaderRequestInfo用户自定义固定包头接口。 然后在OnParsingHeader函数执行结束时,对实现的BodyLength属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。 public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo { private int bodyLength; /// /// 接口实现,标识数据长度 /// public int BodyLength { get { return bodyLength; } } private byte dataType; /// /// 自定义属性,标识数据类型 /// public byte DataType { get { return dataType; } } private byte orderType; /// /// 自定义属性,标识指令类型 /// public byte OrderType { get { return orderType; } } private byte[] body; /// /// 自定义属性,标识实际数据 /// public byte[] Body { get { return body; } } public bool OnParsingBody(byte[] body) { if (body.Length == this.bodyLength) { this.body = body; return true; } return false; } public bool OnParsingHeader(byte[] header) { //在该示例中,第一个字节表示后续的所有数据长度,但是header设置的是3,所以后续还应当接收length-2个长度。 this.bodyLength = header[0]-2; this.dataType = header[1]; this.orderType = header[2]; return true; } } 新建MyFixedHeaderCustomDataHandlingAdapter继承CustomFixedHeaderDataHandlingAdapter,然后对HeaderLength作出赋值,以此表明固定包头的长度是多少。 public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter { /// /// 接口实现,指示固定包头长度 /// public override int HeaderLength => 3; /// /// 获取新实例 /// /// protected override MyFixedHeaderRequestInfo GetInstance() { return new MyFixedHeaderRequestInfo(); } } 【接收】 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 if (requestInfo is MyFixedHeaderRequestInfo myRequestInfo) { //此处可以处理MyFixedHeaderRequestInfo的相关信息了。 string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); } }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(() => { return new MyFixedHeaderCustomDataHandlingAdapter(); }))//配置适配器 .Start();//启动 提示 上述示例的数据是经典的固定包头格式,具有Header+Body的明显分割点。但有时候,也有一些数据有好几段,例如:具有Crc校验的数据,也就是Header+Body+Crc的格式,这时候,我们可以把Body+Crc看做一段数据,然后从Header解析BodyLength以后,加上Crc的长度。最后会在OnParsingBody时,将Body和Crc一起投递,届时做好数据分割即可。 提示 上述创建的适配器客户端与服务器均适用。","s":"三、使用","u":"/touchsocket/docs/customfixedheaderdatahandlingadapter","h":"#三使用","p":302},{"i":311,"t":"支持Ssl的WebSocket客户端。","s":"说明","u":"/touchsocket/docs/createwebsocketclient","h":"#说明","p":309},{"i":313,"t":"继承HttpClient。","s":"可配置项","u":"/touchsocket/docs/createwebsocketclient","h":"#可配置项","p":309},{"i":315,"t":"支持ITcpPlugin、IWebSocketPlugin","s":"支持插件接口","u":"/touchsocket/docs/createwebsocketclient","h":"#支持插件接口","p":309},{"i":317,"t":"WebSocketClient myWSClient = new WebSocketClient(); //myWSClient.Received += this.MyWSClient_Received; //myWSClient.Handshaked += this.MyWSClient_Handshaked; myWSClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(this.textBox3.Text) .ConfigureContainer(a => { a.SetSingletonLogger(new LoggerGroup(new EasyLogger(this.ShowMsg), new FileLogger())); })); myWSClient.Connect(); myWSClient.Logger.Message(\"连接成功\");","s":"创建WS客户端","u":"/touchsocket/docs/createwebsocketclient","h":"#创建ws客户端","p":309},{"i":319,"t":"*当需要连接到由证书机构颁发的网址(例如:小程序、__物联网__等)时,仅需要设置url即可。* wss://127.0.0.1:7789/ws 当连接自定义证书的Ssl:wss://127.0.0.1:7789/ws WebSocketClient myWSClient = new WebSocketClient(); myWSClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(new IPHost(\"wss://127.0.0.1:7789/ws\")) .SetClientSslOption( new ClientSslOption() { ClientCertificates = new X509CertificateCollection() { new X509Certificate2(\"RRQMSocket.pfx\", \"RRQMSocket\") }, SslProtocols = SslProtocols.Tls12, TargetHost = \"127.0.0.1\", CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; } })) .Connect(); Console.WriteLine(\"连接成功\"); while (true) { myWSClient.SendWithWS(Console.ReadLine()); } 注意:当使用域名连接时,TargetHost为域名,例如连接到IPHost(\"ws://baidu.com\")时,TargetHost应当填写:baidu.com","s":"创建WSs客户端","u":"/touchsocket/docs/createwebsocketclient","h":"#创建wss客户端","p":309},{"i":321,"t":"将client对象转为HttpClient,即可使用扩展方法,进行发送。 作为一条消息发送 将一个数据分包发送 例如:发送的数据为{0,1,2,3,4,5,6,7,8,9},当设置packageSize为5时,会先发送{0,1,2,3,4}作为头包,然后发送{5,6,7,8,9}的后继包。","s":"发送数据","u":"/touchsocket/docs/createwebsocketclient","h":"#发送数据","p":309},{"i":323,"t":"订阅Received事件实现,或使用插件实现。 client.Received += (c, e) => { switch (e.Opcode) { case WSDataType.Cont: break; case WSDataType.Text: break; case WSDataType.Binary: break; case WSDataType.Close: break; case WSDataType.Ping: break; case WSDataType.Pong: break; default: break; } }; 附加插件实现 该操作和服务器一致。","s":"接收数据","u":"/touchsocket/docs/createwebsocketclient","h":"#接收数据","p":309},{"i":326,"t":"邑*物联有限公司","s":"定制方","u":"/touchsocket/docs/dataforwarding","h":"#定制方","p":324},{"i":328,"t":"应该公司要求,开发一个能够转发数据的服务器。按照一定规则,设计转发规则。","s":"说明","u":"/touchsocket/docs/dataforwarding","h":"#说明","p":324},{"i":330,"t":"网络编程","s":"技术点","u":"/touchsocket/docs/dataforwarding","h":"#技术点","p":324},{"i":334,"t":"适配器测试是测试适配器在正常情况下,极端工作的一种测试方式。能够在前期,解决100%的算法问题。也能在极端配置下,模拟极端工作环境,能够简单,直观的展示出适配器的稳定性和工作性能。","s":"一、说明","u":"/touchsocket/docs/dataadaptertester","h":"#一说明","p":332},{"i":336,"t":"假设发送数据为{0,1,2,3,4},连续发送10次。 当bufferLength=1时,会先接收一个字节,然后适配器判断无法解析,然后缓存,然后再接收下一个字节,直到成功解析一个完整数据包。该模式解决的就是大家所说的分包,也就是能很好的模拟网络很差的环境。 当bufferLength>5时,假如为8,则会先接收{0,1,2,3,4,0,1,2},然后适配器成功判断解析前五字节,然后缓存后三字节,然后再接收下一个续包,直到解析结束。","s":"1.1 测试原理","u":"/touchsocket/docs/dataadaptertester","h":"#11-测试原理","p":332},{"i":338,"t":"bufferLength应该多次设置,且最好不要整除于发送数据的长度,这样避免巧合发生,测不出极端问题。 Run的次数应该多设,模拟高频情况。","s":"1.2 测试事项","u":"/touchsocket/docs/dataadaptertester","h":"#12-测试事项","p":332},{"i":340,"t":"Tcp适配器的工作环境,只需考虑单线程即可。因为是客户端与适配器是一一对应的。 下列以 固定包头数据处理适配器 为例 //Tcp适配器测试 //bufferLength的作用是模拟tcp接收缓存区,例如: //发送数据为{0,1,2,3,4}时 //当bufferLength=1时,会先接收一个字节,然后适配器判断无法解析,然后缓存,然后再接收下一个字节,直到成功解析。 //该模式能很好的模拟网络很差的环境。 //当bufferLength=8时,会先接收{0,1,2,3,4,0,1,2},然后适配器判断解析前五字节,然后缓存后三字节,然后再接收下一个续包,直到解析结束 for (int bufferLength = 1; bufferLength < 1024 * 10; bufferLength += 1024) { bool isSuccess = true; var data = new byte[] { 0, 1, 2, 3, 4 }; DataAdapterTester tester = DataAdapterTester.CreateTester(new FixedHeaderPackageAdapter() , bufferLength, (byteBlock, requestInfo) => { //此处就是接收,如果是自定义适配器,可以将requestInfo强制转换为实际对象,然后判断数据的确定性 if (byteBlock.Len!=5||(!byteBlock.ToArray().SequenceEqual(data))) { isSuccess = false; } }); //data是发送的数据,因为此处使用的是固定包头适配器, //发送前适配器会自动添加包头,所以,此处只发送数据即可。 //如果测试的是自定义适配器,发送前没有封装的话,就需要自行构建发送数据。 //随后的两个参数,10,10是测试次数,和期望次数,一般这两个值是相等的。 //意为:本次数据将循环发送10次,且会接收10次。不然此处会一直阻塞。 //最后一个参数是测试的最大超时时间。 var time = tester.Run(data, 10, 10, 1000 * 10); Thread.Sleep(1000); Console.WriteLine($\"测试结束,状态:{isSuccess},用时:{time}\"); } Console.WriteLine(\"测试结束\");","s":"二、Tcp适配器","u":"/touchsocket/docs/dataadaptertester","h":"#二tcp适配器","p":332},{"i":343,"t":"有时候,我们需要解析的数据的包头是不定的,例如:HTTP数据格式,其数据头和数据体由“\\r\\n”隔开,而数据头又因为请求者的请求信息的不同,头部数据量不固定,而数据体的长度,也是由数据头的ContentLength的值显式指定的,所以,可以考虑使用CustomUnfixedHeaderDataHandlingAdapter解析。","s":"一、说明","u":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","h":"#一说明","p":341},{"i":345,"t":"可以自由适配所有的数据协议。 可以随意定制数据协议。 可以与任意语言、框架对接数据。","s":"二、特点","u":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","h":"#二特点","p":341},{"i":347,"t":"客户端与服务器均适用。下列以服务器为例。 步骤 声明新建类,实现IFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 声明新建类,继承CustomUnfixedHeaderDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 TouchSocketConfig配置中设置。 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 【MyUnfixedHeaderRequestInfo】 首先,新建MyFixedHeaderRequestInfo类,然后实现IUnfixedHeaderRequestInfo用户自定义固定包头接口。 然后在OnParsingHeader函数执行结束时,对实现的BodyLength属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。 public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo { private int bodyLength; /// /// 接口实现,标识数据长度 /// public int BodyLength { get { return bodyLength; } } private byte[] body; /// /// 自定义属性,标识实际数据 /// public byte[] Body { get { return body; } } public bool OnParsingBody(byte[] body) { if (body.Length == this.bodyLength) { this.body = body; return true; } return false; } public bool OnParsingHeader(ByteBlock byteBlock) { //此处逻辑和固定包头模板基本一致。也需要对BodyLength作出赋值。 //但是不同固定包头的是,需要自己移动已读的游标。并且返回正确的值。 //下列通过假逻辑实现Http协议的解析。 //从现有的可读数据中,读取“\\r\\n\\r\\n”,以此来分割http的headers和body。 int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, Encoding.UTF8.GetBytes(\"\\r\\n\\r\\n\")); if (index > 0) { //索引到了“\\r\\n\\r\\n”,以此推断出,在当前缓存区中,由byteBlock.Pos至index的数据即为headers。 int headerLength = index - byteBlock.Pos; string headers = Encoding.UTF8.GetString(byteBlock.Buffer, byteBlock.Pos,headerLength);//解码headers byteBlock.Pos += headerLength;//然后将缓存区的游标移至headers结束的位置。 //最后通过headers,解析出后续的body的长度,然后在此处赋值。 this.bodyLength = 0;//此处的0是占位值。 return true; } else { //没索引到“\\r\\n\\r\\n”,以此推断出,在当前缓存区中,header的接收尚未完成, //所以返回false,并且不需要修改游标。 return false; } } } 新建MyCustomUnfixedHeaderDataHandlingAdapter继承CustomUnfixedHeaderDataHandlingAdapter。 public class MyCustomUnfixedHeaderDataHandlingAdapter : CustomUnfixedHeaderDataHandlingAdapter { protected override MyUnfixedHeaderRequestInfo GetInstance() { return new MyUnfixedHeaderRequestInfo(); } } 【接收】 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 if (requestInfo is MyUnfixedHeaderRequestInfo myRequestInfo) { //此处可以处理MyUnfixedHeaderRequestInfo的相关信息了。 string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); } }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(() => { return new MyCustomUnfixedHeaderDataHandlingAdapter(); }))//配置适配器 .Start();//启动 提示 上述创建的适配器客户端与服务器均适用。","s":"三、使用","u":"/touchsocket/docs/customunfixedheaderdatahandlingadapter","h":"#三使用","p":341},{"i":350,"t":"Nuget Package:TouchSocket 【加密】 var dataLocked = DataSecurity.EncryptDES(data, \"12345678\");//加密口令,长度为8。 【解密】 var newData = DataSecurity.DecryptDES(dataLocked, \"12345678\");//解密口令,和加密一致。","s":"一、3DES","u":"/touchsocket/docs/datasecurity","h":"#一3des","p":348},{"i":353,"t":"这是群友开发者,使用TouchRpc开发的一个内部工程师软件工具箱 。","s":"说明","u":"/touchsocket/docs/engineertoolbox","h":"#说明","p":351},{"i":357,"t":"自定义适配器可从两个方面入手。 则是直接从DataHandlingAdapter继承,此时可以接触到最原始的TCP数据,可以自定实现数据的继续投递方式。但一般实现算法比较困难,因为所考虑的情况比较多。 则是从CustomDataHandlingAdapter(用户快捷自定义适配器)继承,此时数据的投递必须通过IRequestInfo,ByteBlock将为null。所需考虑的情况比较单一,对于数据的处理也比较简单。","s":"说明","u":"/touchsocket/docs/datahandleadapter","h":"#说明","p":355},{"i":359,"t":"自己实现适配器,然后使其工作。例如:假设如下数据格式,第一个字节表示整个数据长度(包括数据类型和指令类型),第二字节表示数据类型,第三字节表示指令类型,后续字节表示其他数据。 其次,希望在发送时,只传入数据类型,指令类型和其他数据,而数据长度则由适配器自行封装。最后,希望在接收端每次能接收到一个完整的数据。","s":"原始DataHandlingAdapter","u":"/touchsocket/docs/datahandleadapter","h":"#原始datahandlingadapter","p":355},{"i":361,"t":"首先,创建类,继承自DataHandlingAdapter,然后实现对应属性,及方法。 class MyDataHandleAdapter : DataHandlingAdapter { public override bool CanSplicingSend => false; public override bool CanSendRequestInfo => false; protected override void PreviewReceived(ByteBlock byteBlock) { } protected override void PreviewSend(byte[] buffer, int offset, int length) { } protected override void PreviewSend(IRequestInfo requestInfo) { } protected override void PreviewSend(IList> transferBytes) { } protected override void Reset() { } } 【封装发送数据长度】 封装发送数据时,比较简单,示例如下: protected override void PreviewSend(byte[] buffer, int offset, int length) { int dataLen = length - offset;//先获取需要发送的实际数据长度 if (dataLen > byte.MaxValue)//超长判断 { throw new OverlengthException(\"发送数据太长。\"); } //从内存池申请内存块,因为此处数据绝不超过255,所以避免内存池碎片化,每次申请64K //ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。 using (ByteBlock byteBlock = new ByteBlock(64 * 1024)) { byteBlock.Write((byte)dataLen);//先写长度 byteBlock.Write(buffer, offset, length);//再写数据 this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); } } 【解析接收数据】 从原生适配器解封数据,需要考虑的情况比较多。在本示例中,需要考虑以下情况: 一次刚好接收一个数据。 一次刚好接收了多个数据。 一次接收了多个数据,但最后一个数据不完整。 一次未接收完一个数据。 综上,情况比较复杂,所以就必须自己做接收数据的缓存容器。 /// /// 临时包,此包仅当前实例储存 /// private ByteBlock tempByteBlock; /// /// 包剩余长度 /// private byte surPlusLength; protected override void PreviewReceived(ByteBlock byteBlock) { byte[] buffer = byteBlock.Buffer; int r = byteBlock.Len; if (this.tempByteBlock == null)//如果没有临时包,则直接分包。 { SplitPackage(buffer, 0, r); } else { if (surPlusLength == r)//接收长度正好等于剩余长度,组合完数据以后直接处理数据。 { this.tempByteBlock.Write(buffer, 0, surPlusLength); PreviewHandle(this.tempByteBlock); this.tempByteBlock = null; surPlusLength = 0; } else if (surPlusLength < r)//接收长度大于剩余长度,先组合包,然后处理包,然后将剩下的分包。 { this.tempByteBlock.Write(buffer, 0, surPlusLength); PreviewHandle(this.tempByteBlock); this.tempByteBlock = null; SplitPackage(buffer, surPlusLength, r); } else//接收长度小于剩余长度,无法处理包,所以必须先组合包,然后等下次接收。 { this.tempByteBlock.Write(buffer, 0, r); surPlusLength -= (byte)r; } } } /// /// 分解包 /// /// /// /// private void SplitPackage(byte[] dataBuffer, int index, int r) { while (index < r) { byte length = dataBuffer[index]; int recedSurPlusLength = r - index - 1; if (recedSurPlusLength >= length) { ByteBlock byteBlock = new ByteBlock(length); byteBlock.Write(dataBuffer, index + 1, length); PreviewHandle(byteBlock); surPlusLength = 0; } else//半包 { this.tempByteBlock = new ByteBlock(length); surPlusLength = (byte)(length - recedSurPlusLength); this.tempByteBlock.Write(dataBuffer, index + 1, recedSurPlusLength); } index += length + 1; } } /// /// 处理数据 /// /// private void PreviewHandle(ByteBlock byteBlock) { try { this.GoReceived(byteBlock, null); } finally { byteBlock.Dispose();//在框架里面将内存块释放 } }","s":"实现","u":"/touchsocket/docs/datahandleadapter","h":"#实现","p":355},{"i":363,"t":"自定义适配器的使用和预设的适配器一样。不过在该案例中,发送数据时,应当传入三个有效值,分别为数据类型,指令类型,其他数据。","s":"使用自定义适配器","u":"/touchsocket/docs/datahandleadapter","h":"#使用自定义适配器","p":355},{"i":365,"t":"在上述案例中,发送数据时应当传入数据类型,指令类型,其他数据三个有效值,而在RRQM中,发送函数仅有Send(和重载),这无疑需要我们自己封装其他方法。 假设以下情况需要实现: 数据类型有两种,分别为Up(1),Down(0)。指令类型有两种,分别为Go(1)、Hold(0)。数据类型和指令类型可以任意组合,且均可携带其他数据。 面对上述情况,我们可以封装以下函数使用: public class MySocketClient : SimpleSocketClient { public void Up_Go_Send(byte[] data) { ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[]. byteBlock.Write((byte)1); byteBlock.Write((byte)1); byteBlock.Write(data); try { this.Send(byteBlock); } finally { byteBlock.Dispose(); } } public void Down_Go_Send(byte[] data) { ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[]. byteBlock.Write((byte)0); byteBlock.Write((byte)1); byteBlock.Write(data); try { this.Send(byteBlock); } finally { byteBlock.Dispose(); } } public void Up_Hold_Send(byte[] data) { ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[]. byteBlock.Write((byte)1); byteBlock.Write((byte)0); byteBlock.Write(data); try { this.Send(byteBlock); } finally { byteBlock.Dispose(); } } public void Down_Hold_Send(byte[] data) { ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[]. byteBlock.Write((byte)0); byteBlock.Write((byte)0); byteBlock.Write(data); try { this.Send(byteBlock); } finally { byteBlock.Dispose(); } } } 为什么要分片发送?? 在示例代码中不难看出,封装的函数将发送数据进行了Write操作(相当于Copy),这无疑是消耗性能的。只是在该案例中,复制的数据最大为255,感觉优化效果甚微,倘若我们需要发送的数据是1Mb,那就相当于在封装数据时,因为前两个字节的存在而复制1Mb的数据(冤死了),然后在适配器中还需要因为数据包头,再复制一次。 优化。。。 所以我们在封装时,可以使用分片发送,但是同时也需要适配器支持。不然内部会出错。 protected override void PreviewSend(IList> transferBytes) { int dataLen = 0; foreach (var item in transferBytes) { dataLen += item.Count; } if (dataLen > byte.MaxValue)//超长判断 { throw new OverlengthException(\"发送数据太长。\"); } //从内存池申请内存块,因为此处数据绝不超过255,所以避免内存池碎片化,每次申请64K //ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。 using (ByteBlock byteBlock = new ByteBlock(64 * 1024)) { byteBlock.Write((byte)dataLen);//先写长度 foreach (var item in transferBytes) { byteBlock.Write(item.Array, item.Offset, item.Count);//依次写入 } this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); } } 重新封装函数。。。 public void Up_Go_SplicingSend(byte[] data) { List transferBytes = new List(); transferBytes.Add(new TransferByte(new byte[] { 1})); transferBytes.Add(new TransferByte(new byte[] { 1})); transferBytes.Add(new TransferByte(data)); this.Send(transferBytes); } public void Down_Go_SplicingSend(byte[] data) { List transferBytes = new List(); transferBytes.Add(new TransferByte(new byte[] { 0 })); transferBytes.Add(new TransferByte(new byte[] { 1 })); transferBytes.Add(new TransferByte(data)); this.Send(transferBytes); } public void Up_Hold_SplicingSend(byte[] data) { List transferBytes = new List(); transferBytes.Add(new TransferByte(new byte[] { 1 })); transferBytes.Add(new TransferByte(new byte[] { 0 })); transferBytes.Add(new TransferByte(data)); this.Send(transferBytes); } public void Down_Hold_SplicingSend(byte[] data) { List transferBytes = new List(); transferBytes.Add(new TransferByte(new byte[] { 0 })); transferBytes.Add(new TransferByte(new byte[] { 0 })); transferBytes.Add(new TransferByte(data)); this.Send(transferBytes); }","s":"封装函数及分片发送意义","u":"/touchsocket/docs/datahandleadapter","h":"#封装函数及分片发送意义","p":355},{"i":368,"t":"您的支持就是我不懈努力的动力。","s":"赞助TouchSocket项目","u":"/touchsocket/docs/donate","h":"#赞助touchsocket项目","p":366},{"i":370,"t":"Bobo Joker(200¥) UnitySir(66¥) Coffee(100¥) Ninety(50¥) *琼(100¥) **安(5¥) **文(200+200¥) tonychen899(50¥) *平(50¥) 杜(400+100¥) 施*双(666¥) *童(20¥) Tom (88¥) *强(200¥) *潮(10+20+1+2¥) *星(20¥) 舔狗反咬事件(66¥) 美少女酱(30¥) 流水游鱼(9.99¥) 华丽谢幕(33+20¥) 阁主悦澜殇(50+50¥) 烈日(20+20¥) Silent(50¥) 月华散(50¥) 黄*德(PayPal:1000NT$) 一头大狮子(20¥) 蒋*秋(188¥) **发(100+100¥) 梦想遥不可及(128+98¥) 可爱又善良的我(100¥) *君(6.6¥) *于(30¥) J*n(100¥) D*Y(20¥) *人(50¥) *光(66¥) Estel(100¥) 1(200¥) **阳(100¥) chenqiang(6.6¥) Azure(50¥) 广东-小白(1.5¥)","s":"爱心赞助名单(以下排名只按照打赏时间顺序)","u":"/touchsocket/docs/donate","h":"#爱心赞助名单以下排名只按照打赏时间顺序","p":366},{"i":374,"t":"用过WPF的小伙伴一定对依赖属性不陌生。所以TouchSocket模仿其结构,创建了适用于网络框架的依赖属性。","s":"一、说明","u":"/touchsocket/docs/dependencyproperty","h":"#一说明","p":372},{"i":376,"t":"我们知道常规属性,就是拥有get,set访问器的字段,叫做属性。 class MyClass { public int MyProperty { get; set; } } 而依赖属性,则是具有注入特征的属性。它可以像普通属性一样,声明在类内部(示例1)。也可以声明在任何地方(示例2)。 【示例1】 继承DependencyObject 按如下格式生成属性项(propdp代码块可快速实现) class MyClass: DependencyObject { /// /// 属性项 /// public int MyProperty { get { return GetValue(MyPropertyProperty); } set { SetValue(MyPropertyProperty, value); } } /// /// 依赖项 /// public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(\"MyProperty\", typeof(MyClass), 10); } 【示例2】 假设以下情况: 对于TouchSocket的IClient接口对象(已经实现IDependencyObject),希望创建一个int类型的,名为MyProperty的依赖项属性。 那么,可以用下列代码实现 public static class DependencyExtensions { /// /// 依赖项 /// public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(\"MyProperty\", typeof(MyClass), 10); /// /// 设置MyProperty /// /// /// /// /// public static TClient SetMyProperty(this TClient client, int value) where TClient : IClient { client.SetValue(MyPropertyProperty, value); return client; } /// /// 获取MyProperty /// /// /// /// public static int GetMyProperty(this TClient client) where TClient : IClient { return client.GetValue(MyPropertyProperty); } } TcpClient tcpClient = new TcpClient(); tcpClient.SetMyProperty(100); int MyProperty = tcpClient.GetMyProperty();","s":"二、什么是依赖属性?","u":"/touchsocket/docs/dependencyproperty","h":"#二什么是依赖属性","p":372},{"i":378,"t":"优点: 可以不声明在类内部。这意味着可以从外部注入。 不需要初始赋值,也就意味着创建大量对象时,可以不需要占用太多内存。 缺点: 对于值类型,涉及拆装箱操作,对性能有一定性能影响(不是几百万操作,可以忽略)。 注意 当一个属性被频繁(千万级别)使用时,不建议使用依赖属性。","s":"三、优缺点","u":"/touchsocket/docs/dependencyproperty","h":"#三优缺点","p":372},{"i":381,"t":"网友“陶”","s":"定制方","u":"/touchsocket/docs/filesynchronization","h":"#定制方","p":379},{"i":383,"t":"应该网友要求,需要开发一个服务器,一个客户端,客户端的职能就是同步本地文件服务器。有点类似OneDrive。","s":"说明","u":"/touchsocket/docs/filesynchronization","h":"#说明","p":379},{"i":385,"t":"数据同步:设置配置数据、项目文件数据等。 文件:断点续传、换网续传。 登录:登录授权。登录验证。","s":"技术点","u":"/touchsocket/docs/filesynchronization","h":"#技术点","p":379},{"i":389,"t":"EventBus功能是企业版专属功能,其职能类似MQTT的发布订阅模式,也类似RabbitMQ的Sub模式。如果没有使用密钥,可以试用参考。","s":"说明","u":"/touchsocket/docs/eventbus","h":"#说明","p":387},{"i":391,"t":"服务器的创建就是TouchRpc服务器。除udp协议外,tcp、http、websocket协议的版本均支持该功能。 下列以TcpTouchRpcService为例。 TcpTouchRpcService tcpRpcService = new TcpTouchRpcService(); var config = new RRQMConfig(); config.SetListenIPHosts(new IPHost[] { new RRQMSocket.IPHost(7789) }); tcpRpcService .Setup(config) .Start(); 由服务器发布一个事件。 第一个参数为事件名,第二个为访问权限。 tcpRpcService.PublishEvent(\"Hello\", AccessType.Owner | AccessType.Service | AccessType.Everyone);","s":"创建服务器","u":"/touchsocket/docs/eventbus","h":"#创建服务器","p":387},{"i":393,"t":"客户端订阅该事件。 TcpTouchRpcClient tcpRpcClient = new TcpTouchRpcClient(); tcpRpcClient .Setup(\"127.0.0.1:7789\") .Connect(); tcpRpcClient.SubscribeEvent(\"Hello\", SubscribeEvent); 其中SubscribeEvent是接收委托。此处用方法转换接收。其目的为,当服务器触发该方法时,就会分发到此处。 private void SubscribeEvent(EventSender eventSender, string arg) { this.ShowMsg($\"从{eventSender.RaiseSourceType}收到通知事件{eventSender.EventName},信息:{arg}\"); }","s":"创建客户端","u":"/touchsocket/docs/eventbus","h":"#创建客户端","p":387},{"i":395,"t":"第一个参数是事件名,第二个是事件参数。可以是任意类型,但是目前仅支持一个参数。 tcpRpcService.RaiseEvent(\"Hello\", \"Hi\");","s":"服务器触发","u":"/touchsocket/docs/eventbus","h":"#服务器触发","p":387},{"i":397,"t":"实际上在TouchRpc架构中。TouchService、TouchSocketClient、TouchClient三者均已实现IEventObject接口,这意味均可以发布、取消发布、订阅、取消订阅、触发等操作(会验证操作权限)。","s":"其他","u":"/touchsocket/docs/eventbus","h":"#其他","p":387},{"i":400,"t":"固定包头数据处理适配器是处理粘包、分包问题的最有力、最可靠、最高效、最稳定的一种方案,它基本上适用于所有场景。即使跨语言使用,也只需要在其他语言中设计相同算法就可以。","s":"一、说明","u":"/touchsocket/docs/fixedheaderpackageadapter","h":"#一说明","p":398},{"i":402,"t":"最有力的解决粘包。分包问题。 是自定义协议的不二选择。 支持指定包头长度,Byte、Ushort、Int三种类型作为包头。 最好在客户端与服务器均使用TouchSocket组件时使用。不然就需要非TouchSocket的一方适配包头算法。","s":"二、特点","u":"/touchsocket/docs/fixedheaderpackageadapter","h":"#二特点","p":398},{"i":404,"t":"Byte包头算法:以第一个字节作为后续整个数据的长度,整个数据长度区间为[0,255]。 Ushort包头算法:前2个字节,且为默认端序(小端)的排列,作为后续整个数据的长度,整个数据长度区间为[0,65535]。 Int包头算法(默认配置):前4个字节,且为默认端序(小端)排列,作为后续整个数据的长度,整个数据长度区间为[0,2^31]。","s":"三、协议算法","u":"/touchsocket/docs/fixedheaderpackageadapter","h":"#三协议算法","p":398},{"i":406,"t":"客户端与服务器均适用。下列以服务器为例。 步骤 TouchSocketConfig配置中设置(可以同时指定HeaderType等属性) 通过Received(事件、方法、插件)中的ByteBlock读取数据。 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //从客户端收到信息 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(() => { return new FixedHeaderPackageAdapter() { FixedHeaderType= FixedHeaderType.Int }; }))//配置适配器 .Start();//启动 注意 接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。 提示 该适配器,客户端与服务器均适用。","s":"四、使用","u":"/touchsocket/docs/fixedheaderpackageadapter","h":"#四使用","p":398},{"i":409,"t":"文件在读,或写的时候,一直都是独占状态。这个问题在不同进程中,似乎是合理的,但是如果在相同进程里,就会显得很呆。例如:我们在下载文件的时候,希望能同一时间多个读取同一个文件。且能有一个闭环的管理。那么,使用FilePool,就显得非常必要了。","s":"一、说明","u":"/touchsocket/docs/filepool","h":"#一说明","p":407},{"i":411,"t":"从FilePool.GetReader的静态函数中,获取一个线程安全的文件读取访问器,该访问器具有读,和相关的操作属性。在每次读取后,Position会递增。 使用完成后,可以随时释放。 int len = 0; byte[] buffer = new byte[1024 * 1024]; using (var reader = FilePool.GetReader(path)) { while (true) { int r = reader.Read(buffer, 0, buffer.Length); if (r == 0) { break; } len += r; } } Console.WriteLine(len);","s":"二、使用读","u":"/touchsocket/docs/filepool","h":"#二使用读","p":407},{"i":413,"t":"从FilePool.GetWriter的静态函数中,获取一个文件写入访问器线程安全,该访问器,具有写,和相关的操作属性。在每次写入后,Position会递增。 使用完成后,可以随时释放。 注意默认调用Dispose后,文件会根据创建类型是否为单一访问而决定是否立即释放。 byte[] buffer = new byte[1024]; using (var writer = FilePool.GetWriter(path,true)) { writer.Position = num * package; int surLen = package; while (surLen > 0) { int r = Math.Min(surLen, buffer.Length); writer.Write(buffer, 0, r); surLen -= r; } } Console.WriteLine(\"完成\");","s":"三、使用写","u":"/touchsocket/docs/filepool","h":"#三使用写","p":407},{"i":415,"t":"当某个文件没有及时释放,或者由于不可知异常而没有释放时,可以调用FilePool.TryReleaseFile减少引用,并尝试释放资源。 减少引用的意思是,当某个文件,被创建多个访问器时,会递增其引用数,当引用数不为0时,是不会释放的。所以当调用FilePool.TryReleaseFile时,首先会减少引用,然后才会判断是否可以释放。 当需要强制释放某个文件时,可以采取下列措施。 while (FilePool.TryReleaseFile(fileName, 0).ResultCode!= ResultCode.Success) { }","s":"四、手动释放文件资源","u":"/touchsocket/docs/filepool","h":"#四手动释放文件资源","p":407},{"i":418,"t":"固定长度数据处理适配器是将发送的数据通过分割、填补的操作,以达到每次发送、接收的数据都是固定的长度来处理粘包、分包问题。这种方案一般适用于机械臂,机器人控制等场景。","s":"一、说明","u":"/touchsocket/docs/fixedsizepackageadapter","h":"#一说明","p":416},{"i":420,"t":"无论何时,发送与接收的数据长度永远为设定值。 算法简单,可以比较轻松的实现跨语言、跨框架。 一般适用于业务数据固定场景,","s":"二、特点","u":"/touchsocket/docs/fixedsizepackageadapter","h":"#二特点","p":416},{"i":422,"t":"客户端与服务器均适用。下列以服务器为例。 步骤 TouchSocketConfig配置中设置,同时指定数据的长度。 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //从客户端收到信息 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(()=> { return new FixedSizePackageAdapter(10); }))//配置适配器,固定数据长度为10字节。 .Start();//启动 注意 接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。 提示 该适配器,客户端与服务器均适用。","s":"三、使用","u":"/touchsocket/docs/fixedsizepackageadapter","h":"#三使用","p":416},{"i":424,"t":"B站首页","s":"FPS实时游戏","u":"/touchsocket/docs/fpsgame","h":"","p":423},{"i":427,"t":"该序列化以二进制方式进行序列化,不要求序列化与反序列化类型相同,使用体验和兼容性与json相似。支持基础类型、自定义实体类、结构体、元组、数组、字典、List等。","s":"一、说明","u":"/touchsocket/docs/fastbinaryformatter","h":"#一说明","p":425},{"i":429,"t":"var obj = \"TouchSocket\"; var data = SerializeConvert.FastBinarySerialize(obj); var newobj = SerializeConvert.FastBinaryDeserialize(data);","s":"二、序列化、反序列化","u":"/touchsocket/docs/fastbinaryformatter","h":"#二序列化反序列化","p":425},{"i":431,"t":"自定义转化器的使用,可以解决所有类型的序列化,但是这需要自己编写一些代码。具体操作如下: 声明转换器。 /// /// 继承或者实现 /// class StudentFastBinaryConverter : FastBinaryConverter { protected override Student Read(byte[] buffer, int offset, int len) { var byteBlock = new ValueByteBlock(buffer); byteBlock.Pos = offset; var obj = new Student(); obj.P1 = byteBlock.ReadInt32(); obj.P2 = byteBlock.ReadString(); return obj; } protected override int Write(ByteBlock byteBlock, Student obj) { //此处可以直接嵌套Json序列化,但是为演示效果,下列将依然使用二进制方式 int pos = byteBlock.Pos; byteBlock.Write(obj.P1); byteBlock.Write(obj.P2); return byteBlock.Pos - pos;//返回的即是obj所有的字节长度 } } 附加转换器 [FastConverter(typeof(StudentFastBinaryConverter))] class Student { public int P1 { get; set; } public string P2 { get; set; } } tip 当类型已经定义,无法通过特性添加转换器时,可以通过FastBinaryFormatter.AddFastBinaryConverter(typeof(Student),new StudentFastBinaryConverter());直接添加。","s":"三、自定义转换器","u":"/touchsocket/docs/fastbinaryformatter","h":"#三自定义转换器","p":425},{"i":434,"t":"待测试类型 [Serializable] public class MyPackPerson { public int Age { get; set; } public string Name { get; set; } } 结果 以下测试是执行10000次序列化和反序列的结果。","s":"4.1 简单测试","u":"/touchsocket/docs/fastbinaryformatter","h":"#41-简单测试","p":425},{"i":436,"t":"待测试类 [Serializable] public class Student { public int P1 { get; set; } public string P2 { get; set; } public long P3 { get; set; } public byte P4 { get; set; } public DateTime P5 { get; set; } public double P6 { get; set; } public byte[] P7 { get; set; } public List List1 { get; set; } public List List2 { get; set; } public List List3 { get; set; } public Dictionary Dic1 { get; set; } public Dictionary Dic2 { get; set; } public Dictionary Dic3 { get; set; } public Dictionary Dic4 { get; set; } } [Serializable] public class Arg { public Arg(int myProperty) { this.MyProperty = myProperty; } public Arg() { Person person = new Person(); person.Name = \"张三\"; person.Age = 18; } public int MyProperty { get; set; } } [Serializable] public class Person { public string Name { get; set; } public int Age { get; set; } } 赋值 Student student = new Student(); student.P1 = 10; student.P2 = \"若汝棋茗\"; student.P3 = 100; student.P4 = 0; student.P5 = DateTime.Now; student.P6 = 10; student.P7 = new byte[1024 * 64]; Random random = new Random(); random.NextBytes(student.P7); student.List1 = new List(); student.List1.Add(1); student.List1.Add(2); student.List1.Add(3); student.List2 = new List(); student.List2.Add(\"1\"); student.List2.Add(\"2\"); student.List2.Add(\"3\"); student.List3 = new List(); student.List3.Add(new byte[1024]); student.List3.Add(new byte[1024]); student.List3.Add(new byte[1024]); student.Dic1 = new Dictionary(); student.Dic1.Add(1, 1); student.Dic1.Add(2, 2); student.Dic1.Add(3, 3); student.Dic2 = new Dictionary(); student.Dic2.Add(1, \"1\"); student.Dic2.Add(2, \"2\"); student.Dic2.Add(3, \"3\"); student.Dic3 = new Dictionary(); student.Dic3.Add(\"1\", \"1\"); student.Dic3.Add(\"2\", \"2\"); student.Dic3.Add(\"3\", \"3\"); student.Dic4 = new Dictionary(); student.Dic4.Add(1, new Arg(1)); student.Dic4.Add(2, new Arg(2)); student.Dic4.Add(3, new Arg(3)); 结果 Fast的效率比System自带的,快了近7倍,比System.Text.Json快了4倍多,比NewtonsoftJson快了近30倍。","s":"4.2 复杂类型测试","u":"/touchsocket/docs/fastbinaryformatter","h":"#42-复杂类型测试","p":425},{"i":440,"t":"使用rpc的原则就是像使用本地方法一样,让开发者感觉不到任何的不同。所以就必须把服务代理到本地,常见的方式有三种,动态代理接口,静态织入,静态编译。三种方式殊途同归,最终都是构建本地数据结构,然后和远程通信。三种方式各有优缺,具体如下: 优缺点 动态代理接口 静态织入 静态编译 优点 动态构建类,灵活、适应性强。 静态代码生成,自定义类参数自动生成,修改较灵活,调用效率高 自定义类参数自动生成,密封性强,安全性高,调用效率高。 缺点 调用效率较低,自定义类参数须自行构建,实现须IL支持,对调用平台有要求,例如:IOS不允许动态类生成,则不可使用。 项目代码管理难统一,强迫症猝死 服务一旦有破坏性升级,则必须重新替换dll,灵活性几乎为0。","s":"1.1 为什么要生成代理?","u":"/touchsocket/docs/generateproxy","h":"#11-为什么要生成代理","p":437},{"i":442,"t":"【原因一】 支持out和ref参数,在使用代理时,效率不高。 【原因二】 需要在参数支持调用上下文,所以无法直接用接口调用。 【原因三】 支持单次调用的调用配置(例如超时时间,取消调用,序列化方式等) 【原因四】 引用问题,当在服务接口中,使用了其他的项目的数据结构的话,在接口调用项目上也需要引用该项目。太麻烦。","s":"1.2 为什么不直接支持接口代理调用?","u":"/touchsocket/docs/generateproxy","h":"#12-为什么不直接支持接口代理调用","p":437},{"i":444,"t":"源文件代理相比接口代理,几乎没什么缺点。有人会觉得接口代理更整洁、方便?实际上源文件代理只会更整洁、方便。 假设一个场景,你需要开发服务器和客户端,这时,你需要做: 先单独定义一个接口项目 再定义一个实现项目 编译接口项目 引用到客户端 上述步骤中,还不包括,接口项目和实现项目需要引入其他引用的情况,也不包括,接口中包含了其他项目的自定义数据结构。如果包含了的话,客户端还需要引入其他项目。 而且,还需要考虑接口项目的编译目标平台和其他编译参数。最难受的是,如果这些工作,是你和同事合作的话,那可能就是出个bug,同事传你一个dll v1.0版本,再有问题,v1.1修复版,等等。 而最要命的,当属程序集数据泄露。设想一下,如果某个同事在写数据库操作的项目时,把连接信息直接放在了代码里(或某个逻辑),本身如果这个项目只在服务器应用,也没有关系,但是因为你懒,你在接口中使用了该项目的一个数据结构,这就使得你不得不把这个项目一同交给调用方的同事,但你对这些毫无察觉。嗷嚎,黑用户一反编译,直接帮你把数据整理了。 但是如果用生成的源代码,那上述的可怕问题根本不用考虑。其次,会更整洁,更方便。 假设相同场景,你需要开发服务器和客户端,这时,你需要做: 先定义一个服务项目(可以写接口,也能写逻辑,当然也可以分成两个项目) 编译项目,然后导出代理源代码。 引用到客户端 不需要考虑数据结构引用问题,因为代理会转写。 不需要考虑编译参数问题,因为客户端拿到的也是源码。 不需要再让同事一次次发你dll,只需要,他启动服务,你更新引用就ok。 不需要怕程序集数据泄露,因为一切都是转写的,而且只转写应用的、公共的部分。","s":"1.3 TouchRpc源文件代理相比接口代理,有什么优缺点?","u":"/touchsocket/docs/generateproxy","h":"#13-touchrpc源文件代理相比接口代理有什么优缺点","p":437},{"i":447,"t":"在开发过程中,如果服务器和客户端,都是我们自己开发的话(在同一个电脑),就可以使用本地代理生成。 调用下列代码,会将已注册的所有服务,导出代理为字符串。 RpcStore是实例,或者是IRpcParser的属性。 string code=RpcStore.GetProxyCodes(\"MyNameSpace\")); 【示例1】 将代理字符串,写成.cs文件,然后通过链接的形式,将代码添加到客户端项目。 服务器代码,在服务器执行后,会在运行路径下,生成一个WhisperServers.cs的文件。 var service = new TcpTouchRpcService(); var config = new TouchSocketConfig()//配置 .SetListenIPHosts(new IPHost[] { new IPHost(port) }) .ConfigureContainer(a => { a.AddConsoleLogger(); a.AddFileLogger(); }) .ConfigureRpcStore(a => { a.RegisterServer();//注册服务 #if DEBUG File.WriteAllText(\"../../../WhisperServers.cs\", a.GetProxyCodes(\"WhisperServers\",new Type[] { typeof(TouchRpcAttribute) })); #endif }) .SetVerifyToken(\"TouchRpc\"); service.Setup(config) .Start(); 然后打开需要引入的客户端解决方案。选择需要添加代理的项目,依次执行: 右击项目=》添加=》现有项 然后选择服务器生成的.cs文件,选择“添加”的下拉框,选择“添加为连接”。 最后确认文件被正确添加为链接。 这样,每次当服务有更新的时候,只需要启动一下服务器,代理就会自动刷新。 实际上在RpcStore完成服务注册、解析器添加以后,调用GetProxyInfo,输入代理类型、即可获得代理信息,然后再通过CodeGenerator.ConvertToCode方法,转换为可以直接编译的代码。 此时,你可以复制、或者直接把代理代码写成源代码(cs文件)。 然后你可以把这个代码引入到客户端。 //或者直接本地导出代理文件。 ServerCellCode[] codes = rpcStore.GetProxyInfo(RpcStore.ProxyAttributeMap.Values.ToArray()); string codeString = CodeGenerator.ConvertToCode(\"RRQMProxy\", codes); 亦或者,为防止篡改生成的代码,不想把代理代码直接投入使用,那可以考虑将代码单独编译成dll,然后将编译的程序集加载到客户端。 提示 上述行为,均是导出所有已注册的服务,当需要在同一个服务端,生成多个不同代理的源码时,可通过CodeGenerator静态类的相关方法直接生成。例如: string codes=CodeGenerator.GetProxyCodes(\"Namespace\",new Type[]{typeof(RpcServer) },new Type[] { typeof(TouchRpcAttribute)});","s":"2.1 生成代理","u":"/touchsocket/docs/generateproxy","h":"#21-生成代理","p":437},{"i":449,"t":"通过之前的学习,大家可能大概明白了,在RRQMRPC中,客户端与服务器在进行交互时,所需的数据结构不要求是同一类型,仅是数据类型结构相同即可。所以在声明了服务以后,服务中所包含的自定义类型,会被复刻成结构相同的类型,但是这也仅仅局限于参数与服务相同程序集的时候。如果服务中引入了其他程序集的数据结构,则不会复刻。所以在客户端调用时,需要引入同一程序集。 但是,往往在服务中,会引入其他程序集,例如,我们习惯在项目中建立一个Models程序集,用于存放所有的实体模型,那是不是意味着客户端也必须引入这个程序集才能调用呢?没别的方法了?? 有,且不只有一种","s":"2.2 代理类型添加","u":"/touchsocket/docs/generateproxy","h":"#22-代理类型添加","p":437},{"i":451,"t":"在服务注册之前,任意时刻,可调用CodeGenerator.AddProxyType静态方法,添加代理类型,同时可传入一个bool值,表明是否深度搜索,比如,假如RpcArgsClassLib.ProxyClass1中还有其他类型,则参数为True时,依然会代理。 RPCService rpcService = new RPCService(); CodeGenerator.AddProxyType(); CodeGenerator.AddProxyType(deepSearch:true);","s":"2.2.1 添加代理类型","u":"/touchsocket/docs/generateproxy","h":"#221-添加代理类型","p":437},{"i":453,"t":"在需要代理的类上面声明RpcProxy标签,然后也可以重新指定代理类名。 [RpcProxy(\"MyArgs\")] public class Args { }","s":"2.2.2 标记自定义类","u":"/touchsocket/docs/generateproxy","h":"#222-标记自定义类","p":437},{"i":455,"t":"前一种方式已经算是几近完美的代理生成方案,但是有时候,当大家协作时,喜欢全部自己敲写。 例如: 对于下列服务,有时候就是喜欢自己写个接口,然后直接调用。 public class MyRpcServer : RpcServer { [TouchRpc] public bool Login(string account, string password) { if (account == \"123\" && password == \"abc\") { return true; } return false; } } public interface IMyRpcServer { public bool Login(string account, string password); } 以往来说,实现这种方式的绝大多数,大概是使用IL动态构建一个类,然后动态实现接口代理,伪代码如下: IMyRpcServer myRpcServer=ProxyGenerator.CreateProxy(); 但是现在,时代变了,我们有了源代码生成,那么事情将变得无比简单。 同样,我们需要设置接口,如下: /// /// GeneratorRpcProxy的标识,表明这个接口应该被生成其他源代码。 /// ConsoleApp2.MyRpcServer参数是整个rpc调用的前缀,即:除方法名的所有,包括服务的类名。 /// [GeneratorRpcProxy(\"ConsoleApp2.MyRpcServer\")] interface IMyRpcServer { [Description(\"这是登录方法\")]//该作用是生成注释 [GeneratorRpcMethod]//表面该方法应该被代理,也可以通过参数,直接设置调用键 public bool Login(string account, string password); } 这时候,神奇的一幕发生了,凡是实现IRpcClient的接口的实例,都增加了扩展方法。而这功能,和服务器生成的扩展Rpc方法的功能是一致的。 提示 大家可能会疑问,源代码生成代理,和服务端生成代理,有什么区别?或者说有什么优点? 实际上没有区别,也没有优点。之所以设计这个,是因为之前有人提过需求,想要完全分离前、后端。即:后端写好服务后,前端自由定义服务接口,和调用参数,仅此而已。 所以,生成代理的方式,按照大家的习惯需求选择就可以。 源代码生成代理示例代码","s":"三、客户端源代码生成代理 企业版","u":"/touchsocket/docs/generateproxy","h":"#三客户端源代码生成代理-企业版","p":437},{"i":458,"t":"HttpStaticPagePlugin静态网页托管插件,是用于Http的内容响应。 var service = new HttpService(); var config = new TouchSocketConfig(); config.UsePlugin() .SetReceiveType(ReceiveType.Auto) .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigurePlugins(a => { a.Add().AddFolder(\"../../../../../api\");//添加静态页面文件夹 }); service.Setup(config).Start(); Console.WriteLine(\"Http服务器已启动\");","s":"静态网页托管插件仅服务器支持","u":"/touchsocket/docs/httpstaticpageplugin","h":"#静态网页托管插件仅服务器支持","p":456},{"i":461,"t":"该Http服务器及客户端,仅仅是轻量级的Http工具,不具备广泛的兼容性,所以请慎重使用。","s":"一、说明","u":"/touchsocket/docs/httpfiletransfer","h":"#一说明","p":459},{"i":463,"t":"该操作支持大型文件,也支持断点续传、支持迅雷加速等。 internal class MyHttpPlug : HttpPluginBase { protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) { if (e.Context.Request.UrlEquals(\"/file\")) { e.Context.Response .SetStatus()//必须要有状态 .FromFile(@\"D:\\System\\Windows.iso\", e.Context.Request);//直接回应文件。 } base.OnGet(client, e); } }","s":"二、服务器响应文件","u":"/touchsocket/docs/httpfiletransfer","h":"#二服务器响应文件","p":459},{"i":465,"t":"该操作目前仅支持小文件上传,实测100Mb没问题。 internal class MyHttpPlug : HttpPluginBase { protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) { if (e.Context.Request.UrlEquals(\"/uploadfile\")) { try { if (e.Context.Request.ContentLen>1024*1024*100)//全部数据体超过100Mb则直接拒绝接收。 { e.Context.Response .SetStatus(\"403\", \"数据过大\") .Answer(); return; } //此操作会先接收全部数据,然后再分割数据。 //所以上传文件不宜过大,不然会内存溢出。 var multifileCollection = e.Context.Request.GetMultifileCollection(); foreach (var item in multifileCollection) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append($\"文件名={item.FileName}\\t\"); stringBuilder.Append($\"数据长度={item.Length}\"); client.Logger.Info(stringBuilder.ToString()); } e.Context.Response .SetStatus() .FromText(\"Ok\") .Answer(); } catch (Exception ex) { client.Logger.Exception(ex); } } base.OnPost(client, e); } }","s":"三、服务器接收上传文件","u":"/touchsocket/docs/httpfiletransfer","h":"#三服务器接收上传文件","p":459},{"i":468,"t":"适配器的机制,是非常好的解封包机制,那这么好的机制,我们在设计的时候,也想到了单独使用适配器的情况。例如: 对于串口通信,可以使用适配器解包。 有时候可能大家只想用原生Socket实现。那么也可以使用适配器解包,或者封包。","s":"一、说明","u":"/touchsocket/docs/independentusedatahandlingadapter","h":"#一说明","p":466},{"i":470,"t":"FixedHeaderPackageAdapter adapter = new FixedHeaderPackageAdapter(); bool sendCallBack = false; bool receivedCallBack = false; byte[] sentData = null; adapter.SendCallBack = (buffer, offset, length) => { //此处会回调发送的最终调用。例如:此处使用固定包头,则发送的数据为4+n的封装。 sentData = new byte[length]; Array.Copy(buffer, offset, sentData, 0, length); if (length == 4 + 4) { sendCallBack = true; } }; adapter.ReceivedCallBack += (byteBlock, requestInfo) => { //此处会回调接收的最终触发,例如:此处使用的固定包头,会解析4+n的数据为n。 if (byteBlock.Len == 4) { receivedCallBack = true; } }; byte[] data = Encoding.UTF8.GetBytes(\"RRQM\"); adapter.SendInput(data, 0, data.Length);//模拟输入,会在SendCallBack中输出最终要发送的数据。 using (ByteBlock block = new ByteBlock()) { block.Write(sentData); block.Pos = 0; adapter.ReceivedInput(block);//模拟输出,会在ReceivedCallBack中输出最终收到的实际数据。 } 提示 上述仅仅是以固定包头适配器示例的,实际上对于其他所有的适配器均可以使用。","s":"二、使用","u":"/touchsocket/docs/independentusedatahandlingadapter","h":"#二使用","p":466},{"i":473,"t":"继承ILog接口,然后实现以下方法。即可实现内部的日志记录。 当用户自行输出日志时,可自行实现过程。 class MyLogger : ILog { public LogType LogType { get; set; } = LogType.Debug | LogType.Error; public void Log(LogType logType, object source, string message, Exception exception) { //此处就是日志实际输出的位置。 } } 注意 LogType 表示当前日志的可输出类型,并非输出级别,所以当需要输出多种类型时,请进行位域操作。","s":"一、日志记录接口(ILog)","u":"/touchsocket/docs/ilog","h":"#一日志记录接口ilog","p":471},{"i":475,"t":"在使用控制台日志记录器时,会按照以下格式输出。","s":"二、控制台日志记录器(ConsoleLogger)","u":"/touchsocket/docs/ilog","h":"#二控制台日志记录器consolelogger","p":471},{"i":477,"t":"在使用文件日志记录器时,先会在指定目录下创建“logs”目录,然后按日期生成“.log”文件。","s":"三、文件日志记录器(FileLogger)","u":"/touchsocket/docs/ilog","h":"#三文件日志记录器filelogger","p":471},{"i":479,"t":"使用日志组记录器时,可以同时记录多个日志,例如:下列示例就同时在控制台和文件记录日志。 LoggerGroup logger = new LoggerGroup(new ConsoleLogger(),new FileLogger());","s":"四、日志组记录器(LoggerGroup)","u":"/touchsocket/docs/ilog","h":"#四日志组记录器loggergroup","p":471},{"i":481,"t":"引入命名空间。可快捷记录日志。 LoggerGroup logger = new LoggerGroup(new ConsoleLogger(),new FileLogger()); logger.Info(\"Message\"); logger.Warning(\"Warning\"); logger.Error(\"Error\");","s":"五、日志扩展","u":"/touchsocket/docs/ilog","h":"#五日志扩展","p":471},{"i":485,"t":"心跳机制一般是客户端向服务器定时发送一个特定的数据包,让服务器知道自己还在线,以确保连接的有效性的机制。 网络中的接收和发送数据都是使用操作系统中的 SOCKET 进行实现。 但是如果此 套接字 已经断开,那发送数据和接收数据的时候就一定会有问题。 可是如何判断这个套接字是否还可以使用呢? 这个就需要在系统中创建心跳机制。 其实TCP中已经为我们实现了一个内置心跳机制(SetKeepAliveValue)。但是该机制受限于操作系统,而且很容易误报。所以很少被大家使用。 大家使用最多的,就是自己设计数据包,然后预留心跳格式,当对方收到心跳包时,直接返回响应包即可。 那么,按这个思路,让我们使用优雅的实现吧。","s":"1.1 为什么要设置心跳?","u":"/touchsocket/docs/heartbeat","h":"#11-为什么要设置心跳","p":482},{"i":487,"t":"使用心跳之前,必须要明确数据格式,绝对不能混淆业务数据。一般在适配Plc等现成模块时,他们是有固定的数据格式,这时候你可以参阅数据处理适配器,快速的解析数据。 但是在本文中,并没有规定的格式,所以我们需要先设计一种简单高效的数据格式。 如下: 数据长度 数据类型 载荷数据 2字节(Ushort) 1字节(Byte) n字节(<65535)","s":"二、设计数据格式","u":"/touchsocket/docs/heartbeat","h":"#二设计数据格式","p":482},{"i":489,"t":"下列代码主要实现对上述数据格式的解析 internal class MyFixedHeaderDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter { public override int HeaderLength => 3; public override bool CanSendRequestInfo => false; protected override MyRequestInfo GetInstance() { return new MyRequestInfo(); } protected override void PreviewSend(IRequestInfo requestInfo) { throw new NotImplementedException(); } } internal class MyRequestInfo : IFixedHeaderRequestInfo { public DataType DataType { get; set; } public byte[] Data { get; set; } public int BodyLength { get; private set; } public bool OnParsingBody(byte[] body) { if (body.Length == this.BodyLength) { this.Data = body; return true; } return false; } public bool OnParsingHeader(byte[] header) { if (header.Length == 3) { this.BodyLength = TouchSocketBitConverter.Default.ToUInt16(header, 0) - 1; this.DataType = (DataType)header[2]; return true; } return false; } public void Package(ByteBlock byteBlock) { byteBlock.Write((ushort)((this.Data == null ? 0 : this.Data.Length) + 1)); byteBlock.Write((byte)this.DataType); if (Data != null) { byteBlock.Write(Data); } } public byte[] PackageAsBytes() { using ByteBlock byteBlock = new ByteBlock(); this.Package(byteBlock); return byteBlock.ToArray(); } public override string ToString() { return $\"数据类型={this.DataType},数据={(this.Data == null ? \"null\" : Encoding.UTF8.GetString(this.Data))}\"; } } internal enum DataType : byte { Ping, Pong, Data }","s":"2.1 解析数据格式","u":"/touchsocket/docs/heartbeat","h":"#21-解析数据格式","p":482},{"i":491,"t":"下列代码可选,主要实现对Client增加Ping的扩展方法。方便调用。 /// /// 一个心跳计数器扩展。 /// internal static class DependencyExtensions { public static readonly DependencyProperty HeartbeatTimerProperty = DependencyProperty.Register(\"HeartbeatTimer\", typeof(DependencyExtensions), null); public static bool Ping(this TClient client) where TClient : ITcpClientBase { try { client.Send(new MyRequestInfo() { DataType = DataType.Ping }.PackageAsBytes()); return true; } catch (Exception ex) { client.Logger.Exception(ex); } return false; } public static bool Pong(this TClient client) where TClient : ITcpClientBase { try { client.Send(new MyRequestInfo() { DataType = DataType.Pong }.PackageAsBytes()); return true; } catch (Exception ex) { client.Logger.Exception(ex); } return false; } }","s":"三、创建扩展类","u":"/touchsocket/docs/heartbeat","h":"#三创建扩展类","p":482},{"i":493,"t":"下列代码主要实现心跳插件的功能。默认每五秒自动触发一次。且接收方收到Ping后,直接会回复Pong。 internal class HeartbeatAndReceivePlugin : TcpPluginBase { private readonly int m_timeTick; private readonly ILog logger; [DependencyInject(1000 * 5)] public HeartbeatAndReceivePlugin(int timeTick, ILog logger) { this.m_timeTick = timeTick; this.logger = logger; } protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e) { if (client is ISocketClient) { return;//此处可判断,如果为服务器,则不用使用心跳。 } if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer) { timer.Dispose(); } client.SetValue(DependencyExtensions.HeartbeatTimerProperty, new Timer((o) => { client.Ping(); }, null, 0, m_timeTick)); base.OnConnected(client, e); } protected override void OnDisconnected(ITcpClientBase client, ClientDisconnectedEventArgs e) { base.OnDisconnected(client, e); if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer) { timer.Dispose(); client.SetValue(DependencyExtensions.HeartbeatTimerProperty, null); } } protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) { if (e.RequestInfo is MyRequestInfo myRequest) { this.logger.Info(myRequest.ToString()); if (myRequest.DataType == DataType.Ping) { client.Pong(); } } base.OnReceivedData(client, e); } }","s":"四、创建心跳插件类","u":"/touchsocket/docs/heartbeat","h":"#四创建心跳插件类","p":482},{"i":495,"t":"/// /// 示例心跳。 /// 博客地址 /// /// private static void Main(string[] args) { ConsoleAction consoleAction = new ConsoleAction(); //服务器 TcpService service = new TcpService(); service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(\"127.0.0.1:7789\"), new IPHost(7790) })//同时监听两个地址 .UsePlugin() .SetDataHandlingAdapter(()=>new MyFixedHeaderDataHandlingAdapter()) .ConfigureContainer(a => { a.AddConsoleLogger(); }) .ConfigurePlugins(a => { a.Add(); })) .Start();//启动 service.Logger.Info(\"服务器成功启动\"); //客户端 TcpClient tcpClient = new TcpClient(); tcpClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(new IPHost(\"127.0.0.1:7789\")) .UsePlugin() .SetDataHandlingAdapter(() => new MyFixedHeaderDataHandlingAdapter()) .ConfigureContainer(a => { a.AddConsoleLogger(); }) .ConfigurePlugins(a => { a.Add(); })); tcpClient.Connect(); tcpClient.Logger.Info(\"客户端成功连接\"); consoleAction.OnException += ConsoleAction_OnException; consoleAction.Add(\"1\", \"发送心跳\", () => { tcpClient.Ping(); }); consoleAction.Add(\"2\", \"发送数据\", () => { tcpClient.Send(new MyRequestInfo() { DataType = DataType.Data, Data = Encoding.UTF8.GetBytes(Console.ReadLine()) } .PackageAsBytes()); }); consoleAction.ShowAll(); while (true) { consoleAction.Run(Console.ReadLine()); } } private static void ConsoleAction_OnException(Exception obj) { Console.WriteLine(obj); }","s":"五、测试、启动","u":"/touchsocket/docs/heartbeat","h":"#五测试启动","p":482},{"i":498,"t":"JsonRpc是通用的RPC规范,与编程语言无关、操作系统无关。详细说明请参阅JsonRpc 2.0 官方文档,在TouchSocket中封装了前后端,使其使用更加方便、高效。 目前支持Tcp、Http、Websocket三种协议调用。","s":"一、说明","u":"/touchsocket/docs/jsonrpcdescription","h":"#一说明","p":496},{"i":500,"t":"异常反馈 。 插件支持。 支持自定义类型。 支持类型嵌套。 支持js、Android等调用。","s":"二、特点:","u":"/touchsocket/docs/jsonrpcdescription","h":"#二特点","p":496},{"i":503,"t":"包序列化模式是为了解决极限序列化的问题。常规序列化的瓶颈,主要是反射、表达式树、创建对象等几个方面,这几个问题在运行时阶段,都没有一个好的解决方案。目前在net6以后,微软大力支持源代码生成,这使得这类问题得到了很大程度的解决。但是对于老项目,或者无法使用net6和vs2022以上的项目,是无法使用的。所以,这时候包序列化模式就显得非常需要了。","s":"一、说明","u":"/touchsocket/docs/ipackage","h":"#一说明","p":501},{"i":505,"t":"【优点】 简单、可靠、高效 可以支持所有类型(需要自己编写代码) 数据量最少(从理论来说这是占数据量最轻量的设计) 【缺点】 要求序列化端和反序列化端必须保持一致,可以存在数据差异,但是不能出现数据断层。","s":"二、特点","u":"/touchsocket/docs/ipackage","h":"#二特点","p":501},{"i":507,"t":"【实体类】 class MyClass : IPackage { public int P1 { get; set; } public string P2 { get; set; } public char P3 { get; set; } public double P4 { get; set; } public List P5 { get; set; } public Dictionary P6 { get; set; } public void Package(ByteBlock byteBlock) { //基础类型直接写入。 byteBlock.Write(P1); byteBlock.Write(P2); byteBlock.Write(P3); byteBlock.Write(P4); //集合类型,可以先判断是否为null byteBlock.WriteIsNull(P5); if (P5 != null) { //如果不为null //就先写入集合长度 //然后遍历将每个项写入 byteBlock.Write(P5.Count); foreach (var item in P5) { byteBlock.Write(item); } } //字典类型,可以先判断是否为null byteBlock.WriteIsNull(P6); if (P6 != null) { //如果不为null //就先写入字典长度 //然后遍历将每个项,按键、值写入 byteBlock.Write(P6.Count); foreach (var item in P6) { byteBlock.Write(item.Key); byteBlock.WritePackage(item.Value);//因为值MyClassModel实现了IPackage,所以可以直接写入 } } } public void Unpackage(ByteBlock byteBlock) { //基础类型按序读取。 this.P1 = byteBlock.ReadInt32(); this.P2 = byteBlock.ReadString(); this.P3 = byteBlock.ReadChar(); this.P4 = byteBlock.ReadDouble(); var isNull = byteBlock.ReadIsNull(); if (!isNull) { int count = byteBlock.ReadInt32(); var list = new List(count); for (int i = 0; i < count; i++) { list.Add(byteBlock.ReadInt32()); } this.P5 = list; } isNull = byteBlock.ReadIsNull();//复用前面的变量,省的重新声明 if (!isNull) { int count = byteBlock.ReadInt32(); var dic = new Dictionary(count); for (int i = 0; i < count; i++) { dic.Add(byteBlock.ReadInt32(), byteBlock.ReadPackage()); } this.P6 = dic; } } } class MyClassModel : PackageBase { public DateTime P1 { get; set; } public override void Package(ByteBlock byteBlock) { byteBlock.Write(P1); } public override void Unpackage(ByteBlock byteBlock) { this.P1 = byteBlock.ReadDateTime(); } } 【打包和解包】 var myClass = new MyClass(); myClass.P1 = 1; myClass.P2 = \"若汝棋茗\"; myClass.P3 = 'a'; myClass.P4= 3; myClass.P5=new List { 1, 2, 3 }; myClass.P6= new Dictionary() { { 1,new MyClassModel(){ P1=DateTime.Now} }, { 2,new MyClassModel(){ P1=DateTime.Now} } }; using (ByteBlock byteBlock=new ByteBlock()) { myClass.Package(byteBlock);//打包,相当于序列化 byteBlock.Seek(0);//将流位置重置为0 var myNewClass = new MyClass(); myNewClass.Unpackage(byteBlock);//解包,相当于反序列化 }","s":"三、使用","u":"/touchsocket/docs/ipackage","h":"#三使用","p":501},{"i":509,"t":"基准测试表明: 包序列化模式和使用源代码生成方式工作的MemoryPack几乎一样。比json方式快了10倍多,比微软的json快了近4倍。","s":"四、性能评测","u":"/touchsocket/docs/ipackage","h":"#四性能评测","p":501},{"i":512,"t":"在服务器端中新建一个类,继承于RpcServer类(或实现IRpcServer),然后在该类中写公共方法,并用JsonRpc属性标签标记,如果方法有重载,需要重新指定函数键。 支持代理生成注释。 public class JsonRpcServer : RpcServer { [JsonRpc] public string TestJsonRpc(string str) { return \"TouchSocket\" + str; } /// /// 当标记为true时直接使用方法名称 /// /// /// [JsonRpc(true)] public string TestJsonRpc1(string str) { return \"TouchSocket\" + str; } /// /// 使用调用上下文。 /// 可以从上下文获取调用的SocketClient。从而获得IP和Port等相关信息。 /// /// /// /// [JsonRpc(MethodFlags = MethodFlags.IncludeCallContext)] public string TestGetContext(ICallContext callContext, string str) { if (callContext.Caller is HttpSocketClient) { Console.WriteLine(\"HTTP请求\"); var client = callContext.Caller as HttpSocketClient; var ip = client.IP; var port = client.Port; Console.WriteLine($\"HTTP请求{ip}:{port}\"); } if (callContext.Caller is SocketClient) { Console.WriteLine(\"Tcp请求\"); var client = callContext.Caller as SocketClient; var ip = client.IP; var port = client.Port; client.Send(Encoding.UTF8.GetBytes(\"Hello Word\")); Console.WriteLine($\"Tcp请求{ip}:{port}\"); } return \"TouchSocket\" + str; } [JsonRpc] public JObject TestJObject(JObject obj) { return obj; } }","s":"一、定义服务","u":"/touchsocket/docs/jsonrpcservice","h":"#一定义服务","p":510},{"i":514,"t":"服务解析器是实际的服务接收、触发、调用、反馈的实际载体,通俗来说就是通信服务器。 当JsonRpcParserPlugin插件添加在TcpService服务器时,会使用TCP协议。此时的调用,会根据适配器类型,决定是否需要有调用结束标识,一般以\\r\\n结尾。 TcpService service = new TcpService(); service.Setup(new TouchSocketConfig() .UsePlugin() .ConfigureRpcStore(a => { a.RegisterServer();//配置RpcStore必须在最前面。 }) .ConfigurePlugins(a => { a.Add();//tcp中路由路径无效 }) .SetDataHandlingAdapter(() => { return new NormalDataHandlingAdapter(); //return new TerminatorPackageAdapter(\"\\r\\n\");使用该适配器时,调用方必须在最后追加相应的结束调用符。 }) .SetListenIPHosts(new IPHost[] { new IPHost(7705) })) .Start();","s":"二、使用Tcp创建服务解析器","u":"/touchsocket/docs/jsonrpcservice","h":"#二使用tcp创建服务解析器","p":510},{"i":516,"t":"当JsonRpcParserPlugin插件添加在HttpService服务器时,会使用Http、Websocket协议。 创建后,如果想使用Http调用,只需要以Post方式,将调用Json字符串路由到设定路由地址即可(下文示例“/jsonRpc”)。 如果想使用Websocket调用,只需要以文本形式,传递到服务器即可。服务器会判定:如果内容中包含“jsonrpc”则认定为调用,会做调用处理。 HttpService service = new HttpService(); service.Setup(new TouchSocketConfig() .UsePlugin() .SetListenIPHosts(new IPHost[] { new IPHost(7706) }) .ConfigureRpcStore(a =>//Rpc的配置必须在插件之前。 { a.RegisterServer(); }) .ConfigurePlugins(a => { a.Add() .SetWSUrl(\"/ws\");//启用websocket,使用/ws路由连接。 a.Add() .SetJsonRpcUrl(\"/jsonRpc\"); })) .Start();","s":"三、使用Http或Websocket创建服务解析器","u":"/touchsocket/docs/jsonrpcservice","h":"#三使用http或websocket创建服务解析器","p":510},{"i":519,"t":"在TouchSocket中,内置了Json序列化与反序列化。 string jsonstr=SerializeConvert.ToJson(new object());//序列化 object obj=SerializeConvert.FromJson(jsonstr);//反序列化","s":"一、说明","u":"/touchsocket/docs/jsonserialize","h":"#一说明","p":517},{"i":521,"t":"默认情况下: 在net45和netstandard2.0平台时,序列化方式是由JsonFast(群友老江)提供的单文件json序列化。该json工具能够序列化大多数数据结构,且性能和Newtonsoft.Json不相上下(见下测试)。 在netcoreapp3.1及以上平台时,序列化方式使用System.Text.Json。 但是 当应用中加载了Newtonsoft.Json的程序集后,所有的平台的序列化,均会使用Newtonsoft.Json。可通过**SerializeConvert.NewtonsoftJsonIsSupported**静态属性获取当前是否支持Newtonsoft.Json。 也可以手动加载Newtonsoft.Json(一般在Unity3d中需要手动加载)。 bool IsSupported=SerializeConvert.LoadNewtonsoftJson(typeof(JsonConvert));//返回值指示是否成功加载 当加载了Newtonsoft.Json的程序集,但是不想使用该工具序列化时,可将**SerializeConvert.NewtonsoftJsonFirst**静态属性设为false。","s":"二、动态调整的Json策略","u":"/touchsocket/docs/jsonserialize","h":"#二动态调整的json策略","p":517},{"i":523,"t":"【简单数据对象】 public class SimpleObject { public int Age { get; set; } public string Name { get; set; } } [Benchmark] public void JsonFast_SimpleObject() { var v = new SimpleObject { Age = 40, Name = \"John\" }; for (int i = 0; i < Count; i++) { var str = JsonFastConverter.JsonTo(v); var val = JsonFastConverter.JsonFrom(str); } } 下图为1w次的序列化与反序列化。JsonFast的效率甚至还稍高一些。 【复杂对象】 public class ComplexObject { public Dictionary Dic1 { get; set; } public Dictionary Dic2 { get; set; } public Dictionary Dic3 { get; set; } public Dictionary Dic4 { get; set; } public List List1 { get; set; } public List List2 { get; set; } public List List3 { get; set; } public int P1 { get; set; } public string P2 { get; set; } public long P3 { get; set; } public byte P4 { get; set; } public DateTime P5 { get; set; } public double P6 { get; set; } public byte[] P7 { get; set; } } public class Arg { public Arg() { } public Arg(int myProperty) { MyProperty = myProperty; } public int MyProperty { get; set; } } 初始化 private ComplexObject GetComplexObject() { ComplexObject complexObject = new ComplexObject(); complexObject.P1 = 10; complexObject.P2 = \"天下无敌\"; complexObject.P3 = 100; complexObject.P4 = 0; complexObject.P5 = DateTime.Now; complexObject.P6 = 10; complexObject.P7 = new byte[1024 * 64]; Random random = new Random(); random.NextBytes(complexObject.P7); complexObject.List1 = new List(); complexObject.List1.Add(1); complexObject.List1.Add(2); complexObject.List1.Add(3); complexObject.List2 = new List(); complexObject.List2.Add(\"1\"); complexObject.List2.Add(\"2\"); complexObject.List2.Add(\"3\"); complexObject.List3 = new List(); complexObject.List3.Add(new byte[1024]); complexObject.List3.Add(new byte[1024]); complexObject.List3.Add(new byte[1024]); complexObject.Dic1 = new Dictionary(); complexObject.Dic1.Add(1, 1); complexObject.Dic1.Add(2, 2); complexObject.Dic1.Add(3, 3); complexObject.Dic2 = new Dictionary(); complexObject.Dic2.Add(1, \"1\"); complexObject.Dic2.Add(2, \"2\"); complexObject.Dic2.Add(3, \"3\"); complexObject.Dic3 = new Dictionary(); complexObject.Dic3.Add(\"1\", \"1\"); complexObject.Dic3.Add(\"2\", \"2\"); complexObject.Dic3.Add(\"3\", \"3\"); complexObject.Dic4 = new Dictionary(); complexObject.Dic4.Add(1, new Arg(1)); complexObject.Dic4.Add(2, new Arg(2)); complexObject.Dic4.Add(3, new Arg(3)); return complexObject; } [Benchmark] public void JsonFast_ComplexObject() { var v = GetComplexObject(); for (int i = 0; i < Count; i++) { var str = JsonFastConverter.JsonTo(v); var val = JsonFastConverter.JsonFrom(str); } } 下图为100次序列化与反序列化,JsonFast性能稍弱,但是基本满足要求。","s":"三、JsonFast性能","u":"/touchsocket/docs/jsonserialize","h":"#三jsonfast性能","p":517},{"i":526,"t":"多线程文件传输,顾名思义,就是多个连接链路,共同传输一个文件。 多线程传输的优点是什么?和常规文件传输相比,场景有哪些不同? 首先,常规文件传输是基于单个连接链路的,所以,单个连接的传输速率上限,就是常规传输的上限。一般来说,局域网当中,单个连接即可占满所有带宽,所以这时候多线程传输和常规传输并无差别。但是,在云服务器,或者在有流量均衡算法的网络中,每个连接的最大速率不是带宽的最大速率,那么这时候,两个差距是比较大的。 例如,我自己租的一个单核云服务器,它的单个连接速率只有1Mb,但是弹性带宽却有10Mb。宏观表象就是,一个客户端连接时,可以用1Mb带宽,两个客户端连接时,就可以用2Mb。那么这时候,多线程传输就显得格外重要了。 其次,多线程传输是无状态的,所以对于断线重连,换网重连等操作,是完全无感的。","s":"一、说明 企业版","u":"/touchsocket/docs/multithreadingfiletransfer","h":"#一说明-企业版","p":524},{"i":528,"t":"因为是多链路传输,所以,就必须建立多个客户端的连接到服务器。这里使用已经封装好的通信模型ClientFactory。 ClientFactory的通信模型使用的是一个主通信端+多个传输客户端。 对于客户端的配置,请详细参考创建TouchRpc客户端 private TcpTouchRpcClientFactory CreateClientFactory() { TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory() { MinCount = 5, MaxCount = 10, OnGetMainConfig = () =>//配置主通信 { return new TouchSocketConfig() .SetRemoteIPHost(\"tcp://127.0.0.1:7789\"); }, OnGetTransferConfig = () => //配置辅助通信 { return new TouchSocketConfig() .SetRemoteIPHost(\"tcp://127.0.0.1:7789\"); } }; return clientFactory; } 【拉取文件】 TcpTouchRpcClientFactory clientFactory = CreateClientFactory(); var resultCon = clientFactory.CheckStatus();//检验主通信器连接状态。默认如果没有连接,则会建立。 if (resultCon.IsSuccess()) { var fileOperator = new MultithreadingFileOperator() { ResourcePath = path,//请求资源路径 SavePath = savePath,//本地保存路径 }; //此处相当于Timer,每秒获取传输的速度和进度 LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) => { if (fileOperator.IsEnd) { loop.SafeDispose(); } Console.WriteLine($\"速度:{fileOperator.Speed()},进度:{fileOperator.Progress}\"); }); _=loopAction.RunAsync(); Result result= await clientFactory.PullFileAsync(fileOperator); if (result.IsSuccess()) { MessageBox.Show(result.ToString()); } } else { MessageBox.Show(resultCon.ToString()); } 【推送文件】 TcpTouchRpcClientFactory clientFactory = CreateClientFactory(); var resultCon = clientFactory.CheckStatus();//检验主通信器连接状态。默认如果没有连接,则会建立。 if (resultCon.IsSuccess()) { var fileOperator = new MultithreadingFileOperator() { ResourcePath = path, SavePath = savePath, }; //此处相当于Timer,每秒获取传输的速度和进度 LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) => { if (fileOperator.IsEnd) { loop.SafeDispose(); } Console.WriteLine($\"速度:{fileOperator.Speed()},进度:{fileOperator.Progress}\"); }); _=loopAction.RunAsync(); Result result=await clientFactory.PushFileAsync(fileOperator); if (result.IsSuccess()) { MessageBox.Show(result.ToString()); } } else { MessageBox.Show(resultCon.ToString()); }","s":"二、使用","u":"/touchsocket/docs/multithreadingfiletransfer","h":"#二使用","p":524},{"i":530,"t":"该功能也支持客户端之间互相传输。使用方法基本一致,需要额外指定目标Id,以及获取传输的Id集合即可。 多线程的客户端之间传输文件,不像其他操作类型那么简单。因为除了需要指定目的Id外,还需要指定获取目标Id的,传输客户端的Id集合,不然,获取数据的时候,仍然会是单线程工作的。 此外,服务器也需要同意路由 internal class MyTouchRpcPlugin : TouchRpcPluginBase { protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e) { if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile) { e.IsPermitOperation = true; } base.OnRouting(client, e); } } 【获取目标传输客户端的Id集合】 在TcpTouchRpcClientFactory属性中,有个OnFindTransferIds。通过实现该属性,使其能够获取到对应客户端的传输客户端Id集合(下列代码为模拟值,要具体实现该功能,还得自行实现)。 TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory() { MinCount = 5, MaxCount = 10, OnGetMainConfig = () =>//配置主通信 { return new TouchSocketConfig() .SetRemoteIPHost(\"tcp://127.0.0.1:7789\") .SetVerifyToken(\"FileService\"); }, OnGetTransferConfig = () => //配置辅助通信 { return new TouchSocketConfig() .SetRemoteIPHost(\"tcp://127.0.0.1:7789\") .SetVerifyToken(\"FileService\"); } , OnFindTransferIds = (client,targetId) => { //此处的操作不唯一,可能需要rpc实现。 //其目的比较简单,就是获取到targetId对应的主客户端的所有传输客户端的Id集合。 //这样就实现了多个客户端向多个客户端传输文件的目的。 return new string[] { targetId};//此处为模拟结果。 } };","s":"三、客户端之间传输文件","u":"/touchsocket/docs/multithreadingfiletransfer","h":"#三客户端之间传输文件","p":524},{"i":533,"t":"NATService是具有转发功能的TCP服务器。他的职能是将收到的TCP数据转发到多个目标服务器。也能将多个目标服务器的数据转发到连接客户端。","s":"一、说明","u":"/touchsocket/docs/natservice","h":"#一说明","p":531},{"i":535,"t":"调试场景:在生产环境中,想要调试客户端,要么中断服务器,要么就将实际数据转发到NAT,然后在不影响实际场景的情况下进行调试。 内网穿透场景:一般tcp都会使用转发式的内网穿透。","s":"二、常见使用场景","u":"/touchsocket/docs/natservice","h":"#二常见使用场景","p":531},{"i":537,"t":"static void Main(string[] args) { MyNATService service = new MyNATService(); var config = new TouchSocketConfig(); config.SetListenIPHosts(new IPHost[] { new IPHost(7788) }); service.Setup(config); service.Start(); Console.WriteLine(\"转发服务器已启动。已将7788端口转发到127.0.0.1:7789与127.0.0.1:7790地址\"); } 提示 NATService支持客户端适配器和Ssl。也支持转发适配器和Ssl。 class MyNATService : NATService { protected override void OnConnected(NATSocketClient socketClient, RRQMEventArgs e) { base.OnConnected(socketClient, e); try { //此处模拟的是只要连接到NAT服务器,就转发。 //实际上,这个方法可以随时调用。 socketClient.AddTargetClient(new TouchSocketConfig().SetRemoteIPHost(\"127.0.0.1:7789\")); socketClient.AddTargetClient(new TouchSocketConfig().SetRemoteIPHost(\"127.0.0.1:7790\")); } catch (Exception ex) { socketClient.Logger.Exception(ex); } } protected override void OnTargetClientDisconnected(NATSocketClient socketClient, ITcpClient tcpClient, ClientDisconnectedEventArgs e) { socketClient.Logger.Message($\"{socketClient.IP}:{socketClient.Port}的转发客户端{tcpClient.IP}:{tcpClient.Port}已经断开连接。\"); base.OnTargetClientDisconnected(socketClient, tcpClient, e); } protected override byte[] OnNATReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) { //服务器收到的数据 return base.OnNATReceived(socketClient, byteBlock, requestInfo); } protected override byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ByteBlock byteBlock, IRequestInfo requestInfo) { //连接的客户端收到的数据 return base.OnTargetClientReceived(socketClient, tcpClient, byteBlock, requestInfo); } }","s":"三、创建NATService","u":"/touchsocket/docs/natservice","h":"#三创建natservice","p":531},{"i":539,"t":"try { //此处模拟的是只要连接到NAT服务器,就转发。 //实际上,这个方法可以随时调用。 socketClient.AddTargetClient(new TouchSocketConfig() .SetRemoteIPHost(\"127.0.0.1:7789\") .ConfigurePlugins(a=> { //在企业版中,使用以下任意方式,可实现转发客户端的断线重连。 a.Add>() .SetTick(1000);//每秒检查 //a.UseReconnection(); })); } catch (Exception ex) { socketClient.Logger.Exception(ex); }","s":"四、转发断线重连 企业版","u":"/touchsocket/docs/natservice","h":"#四转发断线重连-企业版","p":531},{"i":542,"t":"所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。通俗来讲,就是把有依赖关系的类放到容器中,然后在我们需要这些类时,容器自动解析出这些类的实例。依赖注入最大的好处时实现类的解耦,利于程序拓展、单元测试、自动化模拟测试等。依赖注入的英文为:Dependency Injection,简称 DI。(说明来自网络) TouchSocket内置了Container容器。只需要引入TouchSocket.Core即可使用。","s":"一、说明","u":"/touchsocket/docs/ioc","h":"#一说明","p":540},{"i":544,"t":"支持构造函数、属性、方法三种注入方式,可以选择其中部分生效。 支持 Singleton、Scoped、Transient三种生命周期。 支持单接口,多实现注入。 支持当获取类型是可实例类型时,即使不注册,也能成功构造。 支持默认参数注入。 支持构建参数注入。 支持标签参数注入。 支持泛型注入。 支持Object注入。","s":"二、特点","u":"/touchsocket/docs/ioc","h":"#二特点","p":540},{"i":546,"t":"对于一个类,默认情况下,会支持构造函数、属性、方法三种注入方式。但是,当明确知道该类型仅会使用其中部分方式注入时,可以设置注入类型,以此节约性能。 /// /// 让MyClass仅支持构造函数和属性注入 /// [DependencyType(DependencyType.Constructor | DependencyType.Property)] class MyClass { }","s":"三、注入方式","u":"/touchsocket/docs/ioc","h":"#三注入方式","p":540},{"i":548,"t":"其中MyLog1,MyLog2虽然没有注册,但是因为是实例,所以依然可以成功构造。 [Fact] public void CtorShouldBeOk() { Container container = new Container(); container.RegisterTransient(); var log3 = container.Resolve() as MyLog3; Assert.NotNull(log3.MyLog1); Assert.NotNull(log3.MyLog2); } public class MyLog3 : ILog { public MyLog3(MyLog1 myLog1, MyLog2 myLog2) { this.MyLog1 = myLog1; this.MyLog2 = myLog2; } public MyLog1 MyLog1 { get; } public MyLog2 MyLog2 { get; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } }","s":"3.1 构造函数注入","u":"/touchsocket/docs/ioc","h":"#31-构造函数注入","p":540},{"i":550,"t":"使用DependencyParamterInject,或者DependencyInject标记属性,即可注入。 示例中使用的是单接口多实现,所以使用DependencyParamterInject标记。 [Fact] public void PropertyShouldBeOk() { Container container = new Container(); container.RegisterTransient(\"MyLog1\"); container.RegisterTransient(\"MyLog2\"); container.RegisterTransient(\"MyLog3\"); container.RegisterTransient(); var log5 = container.Resolve() as MyLog5; Assert.NotNull(log5.MyLog1); Assert.NotNull(log5.MyLog2); Assert.True(log5.MyLog1.GetType() == typeof(MyLog1)); Assert.True(log5.MyLog2.GetType() == typeof(MyLog2)); } public class MyLog5 : ILog { [DependencyParamterInject(\"MyLog1\")] public ILog MyLog1 { get; set; } [DependencyParamterInject(\"MyLog2\")] public ILog MyLog2 { get; set; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } }","s":"3.2 属性注入","u":"/touchsocket/docs/ioc","h":"#32-属性注入","p":540},{"i":552,"t":"使用DependencyInject标记属性,即可对方法注入。 同时,示例中演示了默认参数设定。在初始化MyLog6后,A=10,B=\"TouchSocket\"。 同时,还能嵌套MyLog1和MyLog4的同一接口的不同实现,和实现的默认参数构造。 [Fact] public void MethodShouldBeOk() { Container container = new Container(); container.RegisterTransient(\"MyLog1\"); container.RegisterTransient(\"MyLog2\"); container.RegisterTransient(\"MyLog3\"); container.RegisterTransient(\"MyLog4\"); container.RegisterTransient(\"MyLog5\"); container.RegisterTransient(); var log6 = container.Resolve() as MyLog6; Assert.NotNull(log6.MyLog1); Assert.NotNull(log6.MyLog4); Assert.True(log6.MyLog1.GetType() == typeof(MyLog1)); Assert.True(log6.MyLog4.GetType() == typeof(MyLog4)); Assert.True(((MyLog4)log6.MyLog4).A == 20); Assert.True(((MyLog4)log6.MyLog4).B == \"IOU\"); } public class MyLog6 : ILog { [DependencyInject(10, \"TouchSocket\")] public void DependencyMethod(int a, string b, [DependencyParamterInject(\"MyLog1\")] ILog myLog1, [DependencyParamterInject(\"MyLog4\", 20, \"IOU\")] ILog myLog4) { this.A = a; this.B = b; this.MyLog1 = myLog1; this.MyLog4 = myLog4; } public int A { get; set; } public string B { get; set; } public ILog MyLog1 { get; set; } public ILog MyLog4 { get; set; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } Object注入 [Fact] public void ObjectSingletonShouldBeOk() { Container container = new Container(); container.RegisterSingleton(); container.RegisterSingleton(\"10\"); var log10 = container.Resolve(\"10\") as MyLog10; Assert.NotNull(log10); Assert.NotNull(log10.MyLog1); Assert.True(log10.MyLog1.GetType() == typeof(MyLog1)); } public class MyLog10 : ILog { [DependencyParamterInject(typeof(ILog))] public object MyLog1 { get; set; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } }","s":"3.2 方法注入","u":"/touchsocket/docs/ioc","h":"#32-方法注入","p":540},{"i":554,"t":"生命周期是对注入构造的实例的有效性而言的。TouchSocket支持三种生命周期。 Singleton:单例注入,当注入,并且实例化以后,全局唯一实例。 Transient:瞬时注入,每次获取的实例都是新实例。 Scoped:区域单例注入,当在一个IScopedContainer时,实例唯一。 对于前两种,熟悉IOC的同学,相信都知道到。那接下来就演示一下Scoped。 实际上使用Scoped时,得先明确区域,也就是创建一个IScopedContainer的区域容器(类似Aps.net的IServiceProvider)。然后后续实例从IScopedContainer获得即可。 [Fact] public void ScopedShouldBeOk() { Container container = new Container(); container.RegisterScoped(); var log1 = container.Resolve(); var log2 = container.Resolve(); Assert.NotNull(log1); Assert.False(log1 == log2); IScopedContainer scopedContainer = container.Resolve(); log1 = scopedContainer.Resolve(); log2 = scopedContainer.Resolve(); Assert.NotNull(log1); Assert.True(log1 == log2); }","s":"四、生命周期","u":"/touchsocket/docs/ioc","h":"#四生命周期","p":540},{"i":556,"t":"public interface IGeneric { } public class Generic : IGeneric { } public class MyLog1 : ILog { public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } public class MyLog2 : ILog { public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } public class MyLog3 : ILog { public MyLog3(MyLog1 myLog1, MyLog2 myLog2) { this.MyLog1 = myLog1; this.MyLog2 = myLog2; } public MyLog1 MyLog1 { get; } public MyLog2 MyLog2 { get; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } public class MyLog4 : ILog { [DependencyInject(10, \"TouchSocket\")] public MyLog4(int a, string b, MyLog1 myLog1, MyLog2 myLog2) { this.A = a; this.B = b; this.MyLog1 = myLog1; this.MyLog2 = myLog2; } public int A { get; } public string B { get; } public MyLog1 MyLog1 { get; } public MyLog2 MyLog2 { get; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } public class MyLog5 : ILog { [DependencyParamterInject(\"MyLog1\")] public ILog MyLog1 { get; set; } [DependencyParamterInject(\"MyLog2\")] public ILog MyLog2 { get; set; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } public class MyLog6 : ILog { [DependencyInject(10, \"TouchSocket\")] public void DependencyMethod(int a, string b, [DependencyParamterInject(\"MyLog1\")] ILog myLog1, [DependencyParamterInject(\"MyLog4\", 20, \"IOU\")] ILog myLog4) { this.A = a; this.B = b; this.MyLog1 = myLog1; this.MyLog4 = myLog4; } public int A { get; set; } public string B { get; set; } public ILog MyLog1 { get; set; } public ILog MyLog4 { get; set; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } public class MyLog7 : ILog { public MyLog7(IGeneric generic) { this.Generic = generic; } public IGeneric Generic { get; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } [DependencyType(DependencyType.Constructor)] public class MyLog8 : ILog { [DependencyInject(10, \"RRQM\")] public void DependencyMethod(int a, string b, [DependencyParamterInject(\"MyLog1\")] ILog myLog1, [DependencyParamterInject(\"MyLog4\", 20, \"IOU\")] ILog myLog4) { this.A = a; this.B = b; this.MyLog1 = myLog1; this.MyLog4 = myLog4; } public int A { get; set; } public string B { get; set; } public ILog MyLog1 { get; set; } public ILog MyLog4 { get; set; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } } [DependencyType(DependencyType.Constructor | DependencyType.Method)] public class MyLog9 : ILog { [DependencyInject(10, \"RRQM\")] public void DependencyMethod(int a, string b, [DependencyParamterInject(\"MyLog1\")] ILog myLog1, [DependencyParamterInject(\"MyLog4\", 20, \"IOU\")] ILog myLog4) { this.A = a; this.B = b; this.MyLog1 = myLog1; this.MyLog4 = myLog4; } public int A { get; set; } public string B { get; set; } public ILog MyLog1 { get; set; } public ILog MyLog4 { get; set; } public void Debug(LogType logType, object source, string message, Exception exception) { } public void Debug(LogType logType, object source, string message) { } }","s":"所有模型定义","u":"/touchsocket/docs/ioc","h":"#所有模型定义","p":540},{"i":559,"t":"Pipeline适配器,是结合IOCP与管道模型结合的产物。功能类似于NetworkStream,但与之不同的是,Pipeline每当有数据到达时,会先触发一个事件(OnReveived),然后用户在事件中可无限制的Read或Write数据。如果本次接收完成,可退出接收。当下一段数据抵达时,会再次通知接收。","s":"一、说明","u":"/touchsocket/docs/pipelinedatahandlingadapter","h":"#一说明","p":557},{"i":561,"t":"下列示例代码实现,当读到换行时,结束本次接收。 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { if (requestInfo is Pipeline pipeline)//实际上Pipeline继承自Stream { pipeline.ReadTimeout = 1000 * 60;//设置读取超时时间为60秒。 StreamReader streamReader = new StreamReader(pipeline);//所以可以直接用StreamReader构造 string ss = streamReader.ReadLine();//会一直等换行,直到等到换行,才继续向下执行 Console.WriteLine(ss); } //当Pipeline退出该事件方法时,会被自动释放,下次会投递新的Pipeline实例。 // 如果里面还有未Read完的数据,下次会继续投递,如果想直接丢弃,则在此处直接调用Disopose即可。 }; //声明配置 var config = new TouchSocketConfig(); config.SetListenIPHosts(new IPHost[] { new IPHost(\"127.0.0.1:7789\"), new IPHost(7790) })//同时监听两个地址 .SetDataHandlingAdapter(() => new PipelineDataHandlingAdapter());//配置适配器为Pipeline //载入配置 service.Setup(config); //启动 service.Start(); 提示 上述创建的适配器客户端与服务器均适用。","s":"二、使用","u":"/touchsocket/docs/pipelinedatahandlingadapter","h":"#二使用","p":557},{"i":564,"t":"插件是对TouchSocket产品的横向扩展。","s":"说明","u":"/touchsocket/docs/pluginsmanager","h":"#说明","p":562},{"i":566,"t":"简单易用。 易扩展。","s":"产品特点","u":"/touchsocket/docs/pluginsmanager","h":"#产品特点","p":562},{"i":568,"t":"TCP基础使用场景。 自定义协议解析场景。","s":"产品应用场景","u":"/touchsocket/docs/pluginsmanager","h":"#产品应用场景","p":562},{"i":570,"t":"【多线程并发】 插件的所有触发,均是同一实例,所以在服务器运行时,几乎都是并发触发的,所有应当考虑并发问题。 【插件先行】 当启用插件时,插件的触发仅次于方法重写,而优于事件。 【执行顺序】 每个插件都有一个Order属性,该属性表示该插件的执行顺序,数值小,越提前执行(Order在Add之前生效,后续修改无效)。 【中断传递】 当某个插件在响应时,如果设置e.Handled=true,则该数据将不会再触发后续的插件、事件、重写方法。","s":"插件特性","u":"/touchsocket/docs/pluginsmanager","h":"#插件特性","p":562},{"i":572,"t":"用户通过实现框架预设的插件接口,即可接收相应的触发。每个组件都有详细的插件支持说明。 例如:ITcpPlugin、ITokenPlugin、IProtocolPlugin等。","s":"用户自定义插件","u":"/touchsocket/docs/pluginsmanager","h":"#用户自定义插件","p":562},{"i":574,"t":"当各位朋友使用TouchSocket封装自己的dll时,可能需要一些定义插件。那么这个需求TouchSocket也能满足大家。 例如:实现基于TCP的特殊信息自定义插件,当收到字母‘A’时,希望触发实现IAPlugin接口插件的GoToA方法。 具体操作如下: 声明IAPlugin接口,继承IPlugin。 声明GoToA接口方法(该方法必须两个参数,第一参数无要求,一般为触发主体,第二参数必须继承自TouchSocketEventArgs)。 在合适时候,判断当前配置是否支持插件,然后使用服务器或客户端的PluginsManager属性调用Raise方法,此处的泛型(IAPlugin)必须为接口类型。 public interface IAPlugin : IPlugin { void GoToA(ITcpClientBase client,TouchSocketEventArgs e); } public class MyTClient : TcpClient { protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) { if (this.UsePlugin) { if (byteBlock.ToString()==\"A\") { this.PluginsManager.Raise(\"GoToA\",this,new TouchSocketEventArgs()); } } } }","s":"系统自定义插件","u":"/touchsocket/docs/pluginsmanager","h":"#系统自定义插件","p":562},{"i":577,"t":"支持直接访问远程文件、文件夹的快捷操作。","s":"一、说明 企业版","u":"/touchsocket/docs/remotefilecontrol","h":"#一说明-企业版","p":575},{"i":579,"t":"以下内容,所有TouchRpc均支持(包括基于udp协议的)。 操作 文件 文件夹 获取信息 支持:获取文件名称,大小,修改时间等。 支持:获取文件夹名称,大小,子文件夹,文件名称、修改时间等。 创建 不支持文件的直接创建。 支持 删除 支持 支持 复制 支持 支持 移动 支持 支持","s":"二、支持的操作","u":"/touchsocket/docs/remotefilecontrol","h":"#二支持的操作","p":575},{"i":581,"t":"以获取文件夹信息为例: client为TouchRpc的终端。可以是逻辑客户端,也可以是逻辑服务器所包含的SocketClient //client必选先建立连接(udp协议的除外) //Metadata可以向对方传递更多的有用信息。 //5000是超时时间,单位毫秒。 //CancellationToken包含一个可取消令箭 RemoteDirectoryInfoResult rootDirectoryInfoResult = client.GetDirectoryInfo(dirPath,new Metadata(),5000,new CancellationToken()); 其余操作基本一致。","s":"三、代码示例","u":"/touchsocket/docs/remotefilecontrol","h":"#三代码示例","p":575},{"i":584,"t":"网友","s":"定制方","u":"/touchsocket/docs/remotemonitoring","h":"#定制方","p":582},{"i":586,"t":"应该网友要求,基本完成了预定的所有功能,包括远程更新、远程屏幕监测、屏幕操作、远程文件资源管理器、远程控制台、远程注册表操作、远程文件操作(删除、复制、重命名、压缩)、等等。","s":"说明","u":"/touchsocket/docs/remotemonitoring","h":"#说明","p":582},{"i":588,"t":"整体界面:应定制方要求,界面使用原始控件。 各种远程操作:均采用的是RRQM通信框架。","s":"技术点","u":"/touchsocket/docs/remotemonitoring","h":"#技术点","p":582},{"i":590,"t":"【客户端——被控制端】 客户端是个winform的无界面程序。 【服务器——管理端】","s":"效果","u":"/touchsocket/docs/remotemonitoring","h":"#效果","p":582},{"i":593,"t":"所谓断线重连,即tcp客户端在断开服务器后,主动发起的再次连接请求。","s":"一、说明","u":"/touchsocket/docs/reconnection","h":"#一说明","p":591},{"i":595,"t":"使用断线重连非常简单,仅一行代码完成。 .UsePlugin() .ConfigurePlugins(a=> { a.UseReconnection(5, true, 1000);//如需永远尝试连接,tryCount设置为-1即可。 }); 注意 断线重连,必须满足以下几个要求: 必须完成第一次连接 必须是被动断开,如果是客户端主动调用Close、Disconnect等方法主动断开的话,不会生效。 必须有显式的断开信息,也就是说,直接拔网线的话,不会立即生效,会等tcp保活到期后再生效。","s":"二、使用Reconnection插件","u":"/touchsocket/docs/reconnection","h":"#二使用reconnection插件","p":591},{"i":597,"t":"企业版使用断线重连,在兼容上述方法的同时,还支持一种无人值守的连接方式,即轮询式连接,使用也非常简单,仅一行代码完成。 .UsePlugin() .ConfigurePlugins(a=> { a.Add>() .SetTick(1000);//每秒检查 }); 注意 PollingKeepAlive断线重连,必须满足以下几个要求: 不要和UseReconnection一同使用 必须有显式的断开信息,也就是说,直接拔网线的话,不会立即生效,会等tcp保活到期后再生效。","s":"三、使用PollingKeepAlive插件 企业版","u":"/touchsocket/docs/reconnection","h":"#三使用pollingkeepalive插件-企业版","p":591},{"i":600,"t":"TouchSocket从网上搜集了Crc1-23的计算方法。并封装在了Crc类中。 以最常用的Crc16为例。 byte[] data = new byte[10]; byte[] result = Crc.Crc16(data, 0, data.Length);","s":"一、Crc计算","u":"/touchsocket/docs/othercore","h":"#一crc计算","p":598},{"i":602,"t":"功能:封装的Stopwatch,测量运行Action的时间。 TimeSpan timeSpan = TimeMeasurer.Run(() => { Thread.Sleep(1000); });","s":"二、时间测量器(TimeMeasurer)","u":"/touchsocket/docs/othercore","h":"#二时间测量器timemeasurer","p":598},{"i":604,"t":"string str = MD5.GetMD5Hash(\"TouchSocket\"); bool b = MD5.VerifyMD5Hash(\"TouchSocket\",str);","s":"三、MD5计算","u":"/touchsocket/docs/othercore","h":"#三md5计算","p":598},{"i":606,"t":"【将16进制的字符转换为数组】 public static byte[] ByHexStringToBytes(this string hexString, string splite = default) 【将16进制的字符转换为int32】 public static int ByHexStringToInt32(this string hexString)","s":"四、16进制相关","u":"/touchsocket/docs/othercore","h":"#四16进制相关","p":598},{"i":608,"t":"雪花ID,会生成long类型的不重复ID。 SnowflakeIDGenerator generator = new SnowflakeIDGenerator(4); long id=generator.NextID();","s":"五、雪花ID生成","u":"/touchsocket/docs/othercore","h":"#五雪花id生成","p":598},{"i":610,"t":"内部封装了Gzip的压缩。使用静态方法即可完成。 byte[] data = new byte[1024]; new Random().NextBytes(data); using (ByteBlock byteBlock=new ByteBlock()) { GZip.Compress(byteBlock,data,0,data.Length);//压缩 var decompressData2 = GZip.Decompress(byteBlock.ToArray());//解压 } 压缩接口 内部还定义了一个IDataCompressor的压缩接口。目的是为了向成熟框架传递压缩方法(例如TcpClient)。 默认配备了一个GZipDataCompressor。可以直接使用。当然大家可以自由扩展其他压缩方法。 class MyDataCompressor : IDataCompressor { public byte[] Compress(ArraySegment data) { //此处实现压缩 throw new NotImplementedException(); } public byte[] Decompress(ArraySegment data) { //此处实现压缩 throw new NotImplementedException(); } }","s":"六、数据压缩","u":"/touchsocket/docs/othercore","h":"#六数据压缩","p":598},{"i":613,"t":"每个客户端在连接时,服务器都会为连接的客户端新分配一个唯一的ID。也就是说,在服务器中ID与SocketClient实例就是一一对应的。","s":"一、说明","u":"/touchsocket/docs/resetid","h":"#一说明","p":611},{"i":615,"t":"默认情况下服务器都会根据历史连接数量,为连接的客户端新分配ID。也就是说,第一个连接的,其ID就是1,以此类推。 当然我们可以自由的定义ID策略,只需要在Config配置中,配置SetGetDefaultNewID,自定义新ID来源即可。要求不和现连接的客户端ID重复。 下列示例,就是使用Guid作为初始ID。 .SetGetDefaultNewID(()=> { return new Guid().ToString(); })","s":"二、配置初始ID策略","u":"/touchsocket/docs/resetid","h":"#二配置初始id策略","p":611},{"i":617,"t":"上述这种ID规范,是与连接信息没有任何关联的,这也就意味着,这种方式是无法关联SocketClient的。 但往往,有时候,我们希望,SocketClient的ID,能一定程度的代表一些信息。例如:以客户端的IP和端口,作为唯一ID。 那这时候,服务器可以订阅Connecting,然后,为新连接的SocketClient,设置与之有关联信息的ID。 m_service.Connecting = (client, e) => { e.ID = $\"{client.IP}:{client.Port}\"; };//有客户端正在连接 提示 上述行为通过插件实现可能更加优雅。","s":"三、创建能代表连接的ID","u":"/touchsocket/docs/resetid","h":"#三创建能代表连接的id","p":611},{"i":619,"t":"上述修改ID的方式,应该还不足以应对所有情况。有时候我们希望,在该连接完成,且经过某种验证之后再设置新的ID,那么我们可以通过ResetID的方法,来实现需求。","s":"四、即时修改ID","u":"/touchsocket/docs/resetid","h":"#四即时修改id","p":611},{"i":621,"t":"service.ResetID(\"oldId\",\"newId\");","s":"4.1 通过Service直接修改","u":"/touchsocket/docs/resetid","h":"#41-通过service直接修改","p":611},{"i":623,"t":"socketClient.ResetID(\"newId\"); 备注 上述的ID标识,仅仅是服务器(TcpService)和辅助客户端(SocketClient)之间的关联。与客户端(TcpClient)是没有任何关系的。","s":"4.2 通过SocketClient修改","u":"/touchsocket/docs/resetid","h":"#42-通过socketclient修改","p":611},{"i":626,"t":"可以在通信对方,创建一个Stream,然后映射到本地,由本地直接进行读、写等操作。","s":"一、说明 企业版","u":"/touchsocket/docs/remotestreamaccess","h":"#一说明-企业版","p":624},{"i":628,"t":"当远程主机拥有一个超大流数据(可能是文件,或者其他)时,本地只想访问其部分数据的话,就可以使用该功能。 例如,假设C服务器有个10Gb的文件。A客户端需要其10000-20000字节之间的数据,那你此时可以使用该功能,直接进行读取。","s":"二、场景","u":"/touchsocket/docs/remotestreamaccess","h":"#二场景","p":624},{"i":630,"t":"下列以客户端作为请求端,以服务器作为响应端。实际上服务器也可以做请求端。 【请求端】 任意TouchRpc终端(除udp协议)均可以调用LoadRemoteStream创建一个流数据映射。 同时可以传递一个元数据组。用于载入自定义消息。 RemoteStream remoteStream = client.LoadRemoteStream(new Metadata().AddOrUpdate(\"1\", \"1\")); 【响应端】 响应端定义一个插件,重写OnLoadingStream,然后实现需要载入的具体流信息。示例中是以MemoryStream作为流主体。 class MyTcpTouchRpcPlugin : TouchRpcPluginBase { protected override void OnLoadingStream(ITouchRpc client, LoadingStreamEventArgs e) { if (e.Metadata[\"1\"]==\"1\") { e.Stream = new MemoryStream(); } base.OnLoadingStream(client, e); } }","s":"三、代码示例","u":"/touchsocket/docs/remotestreamaccess","h":"#三代码示例","p":624},{"i":632,"t":"当RemoteStream被成功创建以后,即可直接Read、Write。因为RemoteStream继承自Stream。 var client = GetClient(); RemoteStream remoteStream = client.LoadRemoteStream(new Metadata().AddOrUpdate(\"1\", \"1\")); byte[] data = new byte[] { 0, 1, 2, 3, 4 }; remoteStream.Write(data); Assert.True(remoteStream.Length==5); Assert.True(remoteStream.Position==5); remoteStream.Position = 0; byte[] buffer=new byte[5]; remoteStream.Read(buffer); Assert.True(buffer.SequenceEqual(data)); Assert.True(remoteStream.Position == 5); Assert.True(remoteStream.Length == 5); remoteStream.SafeDispose();","s":"四、读写","u":"/touchsocket/docs/remotestreamaccess","h":"#四读写","p":624},{"i":634,"t":"当断开连接,或者请求方主动调用Dispose时,响应方的Stream均会被实际的Dispose掉。","s":"五、释放","u":"/touchsocket/docs/remotestreamaccess","h":"#五释放","p":624},{"i":636,"t":"图中示例为直接读取一个Window.iso文件所示。","s":"六、性能","u":"/touchsocket/docs/remotestreamaccess","h":"#六性能","p":624},{"i":639,"t":"RPC服务是无状态的,即只知道当前服务被调用,但无法得知是被谁调用,这个问题给日志记录、RPC回调等带来了很多麻烦事。但是,Touch的Rpc支持调用上下文获取。在上下文中可以获得调用者(ICaller)信息等。","s":"一、说明","u":"/touchsocket/docs/rpcallcontext","h":"#一说明","p":637},{"i":641,"t":"步骤: Rpc标签需要传入MethodFlags.IncludeCallContext参数。 定义的服务的第一个参数必须是ICallContext或其派生类。 最后获得其Caller属性即可得到调用者。 public class MyRpcServer : RpcServer { [Description(\"登录\")] [TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]//使用调用上才文 public bool Login(ICallContext callContext,string account,string password) { if (callContext.Caller is TcpTouchRpcSocketClient) { Console.WriteLine(\"TcpTouchRpc请求\"); } if (account==\"123\"&&password==\"abc\") { return true; } return false; } }","s":"二、通过标签参数获取","u":"/touchsocket/docs/rpcallcontext","h":"#二通过标签参数获取","p":637},{"i":643,"t":"步骤: 继承TransientRpcServer或者实现ITransientRpcServer接口。 public class MyRpcServer : TransientRpcServer { [Description(\"登录\")] [TouchRpc] public bool Login(string account,string password) { if ( this.CallContext.Caller is TcpTouchRpcSocketClient) { Console.WriteLine(\"TcpTouchRpc请求\"); } if (account==\"123\"&&password==\"abc\") { return true; } return false; } }","s":"三、通过瞬时生命周期获取","u":"/touchsocket/docs/rpcallcontext","h":"#三通过瞬时生命周期获取","p":637},{"i":646,"t":"RPC服务在被调用是,可以使用实现IRpcActionFilter的特性(Attribute),进行相关AOP操作。","s":"一、说明","u":"/touchsocket/docs/rpcactionfilter","h":"#一说明","p":644},{"i":648,"t":"public class MyRpcActionFilterAttribute : RpcActionFilterAttribute { public override void Executing(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) { //invokeResult = new InvokeResult() //{ // Status = InvokeStatus.UnEnable, // Message = \"不允许执行\", // Result = default //}; if (callContext.Caller is TcpTouchRpcSocketClient client) { client.Logger.Info($\"即将执行RPC-{callContext.MethodInstance.Name}\"); } base.Executing(callContext, parameters, ref invokeResult); } public override void Executed(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) { if (callContext.Caller is TcpTouchRpcSocketClient client) { client.Logger.Info($\"执行RPC-{callContext.MethodInstance.Name}完成,状态={invokeResult.Status}\"); } base.Executed(callContext, parameters, ref invokeResult); } public override void ExecutException(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception) { if (callContext.Caller is TcpTouchRpcSocketClient client) { client.Logger.Info($\"执行RPC-{callContext.MethodInstance.Name}异常,信息={invokeResult.Message}\"); } base.ExecutException(callContext, parameters, ref invokeResult, exception); } } 提示 每个方法都有详细的注释,仔细查看可能会事半功倍。","s":"二、声明特性","u":"/touchsocket/docs/rpcactionfilter","h":"#二声明特性","p":644},{"i":650,"t":"[Description(\"性能测试\")] [TouchRpc] [MyRpcActionFilter] public int Performance(int a) { return a; }","s":"三、使用","u":"/touchsocket/docs/rpcactionfilter","h":"#三使用","p":644},{"i":653,"t":"RPC在调用时,的调用状态有三种状态可选,分别为:OnlySend、WaitSend、WaitInvoke。区别是: OnlySend WaitSend WaitInvoke 仅发送RPC请求,在TCP底层协议下,能保证发送成功,但是不反馈服务器任何状态,也不会取得返回值、异常等信息。在UDP底层协议下,不保证发送成功,仅仅是具有请求动作而已。 发送RPC请求,并且等待收到状态返回,能保证RPC请求顺利到达服务,但是不能得知RPC服务是否成功执行,也不会取得返回值、异常等信息 发送RPC请求,且返回所有信息,包括是否成功调用,执行后的返回值或异常等信息。","s":"一、调用反馈类型","u":"/touchsocket/docs/rpcoption","h":"#一调用反馈类型","p":651},{"i":655,"t":"同样的,在InvokeOption中可以直接赋值使用。 InvokeOption invokeOption = new InvokeOption(); invokeOption.FeedbackType = FeedbackType.WaitInvoke; //invokeOption.FeedbackType = FeedbackType.OnlySend; //invokeOption.FeedbackType = FeedbackType.WaitSend; string returnString = client.Invoke(\"TestOne\", invokeOption, \"10\"); 注意:假如IInvokeOption使用的是InvokeOption的话,在new的时候,应该对其他参数也进行设置(因为它是结构体)。","s":"1.1 使用","u":"/touchsocket/docs/rpcoption","h":"#11-使用","p":651},{"i":657,"t":"调用RPC,不能无限制等待,必须要有计时器,或者任务取消的功能。","s":"二、调用超时设置","u":"/touchsocket/docs/rpcoption","h":"#二调用超时设置","p":651},{"i":659,"t":"直接对InvokeOption的Timeout 属性赋值即可,单位为毫秒。 InvokeOption invokeOption = new InvokeOption(); invokeOption.Timeout = 1000 * 10;//10秒后无反应,则抛出RRQMTimeoutException异常 string returnString = client.Invoke(\"TestOne\", invokeOption, \"10\");","s":"2.1 计时器设置","u":"/touchsocket/docs/rpcoption","h":"#21-计时器设置","p":651},{"i":661,"t":"在RPC调用时,计时器是一个好的选择,但是还不够完美,有时候我们希望能手动终结某个调用任务。这时候,计时器就不堪重任,需要能主动取消任务的功能。熟悉.net的小伙伴都知道,CancellationToken是具备这个功能的。同样的,只需要对InvokeOption的CancellationToken 赋值即可。 InvokeOption invokeOption = new InvokeOption(); CancellationTokenSource tokenSource = new CancellationTokenSource(); invokeOption.CancellationToken = tokenSource.Token; //tokenSource.Cancel();//调用时取消任务 string returnString = client.Invoke(\"TestOne\", invokeOption, \"10\");","s":"2.2 任务取消","u":"/touchsocket/docs/rpcoption","h":"#22-任务取消","p":651},{"i":663,"t":"实际上7.2的取消任务,仅仅能实现让客户端取消请求,但是服务器并不知道,如果想让服务器也感知任务消息,就必须依托于调用上下文。 此处的取消,有可能是调用者主动取消。也有可能是调用者已经掉线。 public class ElapsedTimeRpcServer : ServerProvider { [Description(\"测试可取消的调用\")] [RRQMRPC(MethodFlags.IncludeCallContext)] public bool DelayInvoke(ICallContext serverCallContext,int tick)//同步服务 { for (int i = 0; i < tick; i++) { Thread.Sleep(100); if (serverCallContext.TokenSource.IsCancellationRequested) { Console.WriteLine(\"客户端已经取消该任务!\"); return false;//实际上在取消时,客户端得不到该值 } } return true; } }","s":"2.3 服务任务取消","u":"/touchsocket/docs/rpcoption","h":"#23-服务任务取消","p":651},{"i":666,"t":"在RPC中,并没有对传输的数据做限制,但是因为RPC默认使用的固定包头适配器中,默认设置的可传递数据为10Mb,所以在RPC中,用户可一次性传递的数据包大约为9.9Mb。所以,如果用户传递超出阈值的数据,适配器则会触发异常,而无法接收。但在实际上RPC的使用中,大数据的传输也是很重要的一个环节,所以RRQM已经做了大数据的传输思路建议,希望能有效解决大家的麻烦。","s":"一、说明","u":"/touchsocket/docs/rpcstream","h":"#一说明","p":664},{"i":668,"t":"操作原理:在固定包头适配器中,默认限制了单次可发送数据包的最大值,所以可以修改此值实现目的。 该方法简单粗暴,能够解决一定程度的大数据问题,但并不建议这么做。 注意:客户端必须同样设置。 TouchSocketConfig config = new TouchSocketConfig()//配置 .SetMaxPackageSize(1024 * 1024 * 10)","s":"二、设置适配器参数(推荐指数:⭐)","u":"/touchsocket/docs/rpcstream","h":"#二设置适配器参数推荐指数","p":664},{"i":670,"t":"操作原理:先利用RPC让客户端与服务器约定特定的Channel,然后后续数据通过Channel传递,最后由RPC返回结果。","s":"三、RPC嵌套Channel(推荐指数:⭐⭐⭐⭐⭐)","u":"/touchsocket/docs/rpcstream","h":"#三rpc嵌套channel推荐指数","p":664},{"i":672,"t":"【Service端】 /// /// \"测试ServiceToClient创建通道,从而实现流数据的传输\" /// /// /// [Description(\"测试ServiceToClient创建通道,从而实现流数据的传输\")] [TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)] public int RpcPullChannel(ICallContext callContext, int channelID) { int size = 0; int package = 1024 * 1024; if (callContext.Caller is TcpTouchRpcSocketClient socketClient) { if (socketClient.TrySubscribeChannel(channelID, out Channel channel)) { for (int i = 0; i < 1024; i++) { size += package; channel.Write(new byte[package]); } channel.Complete();//必须调用指令函数,如Complete,Cancel,Dispose } } return size; } 【Client端】 ChannelStatus status = ChannelStatus.Default; int size = 0; Channel channel = client.CreateChannel();//创建通道 Task task = Task.Run(() =>//这里必须用异步 { using (channel) { while (channel.MoveNext()) { byte[] data = channel.GetCurrent(); size += data.Length; } status = channel.Status; } }); int result = client.RpcPullChannel(channel.ID);//RpcPullChannel是代理方法,此处会阻塞至服务器全部发送完成。 await task;//等待异步接收完成 Console.WriteLine($\"状态:{status},size={size}\");","s":"3.1 请求流数据","u":"/touchsocket/docs/rpcstream","h":"#31-请求流数据","p":664},{"i":674,"t":"【Service端】 /// /// \"测试推送\" /// /// /// [Description(\"测试ServiceToClient创建通道,从而实现流数据的传输\")] [TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)] public int RpcPushChannel(ICallContext callContext, int channelID) { int size = 0; if (callContext.Caller is TcpTouchRpcSocketClient socketClient) { if (socketClient.TrySubscribeChannel(channelID, out Channel channel)) { while (channel.MoveNext()) { size += channel.GetCurrent().Length; } } } return size; } 【Client端】 ChannelStatus status = ChannelStatus.Default; int size = 0; int package = 1024 * 1024; Channel channel = client.CreateChannel();//创建通道 Task task = Task.Run(() =>//这里必须用异步 { for (int i = 0; i < 1024; i++) { size += package; channel.Write(new byte[package]); } channel.Complete();//必须调用指令函数,如Complete,Cancel,Dispose }); int result = client.RpcPushChannel(channel.ID);//RpcPushChannel是代理方法,此处会阻塞至服务器全部完成。 await task;//等待异步接收完成 Console.WriteLine($\"状态:{status},result={result}\");","s":"3.2 推送流数据","u":"/touchsocket/docs/rpcstream","h":"#32-推送流数据","p":664},{"i":677,"t":"从下图(图片来源网络)可以看出,序列化是RPC中至关重要的一个环节,可以说,序列化的优劣,会很大程度的影响RPC调用性能。","s":"一、说明","u":"/touchsocket/docs/serializationselector","h":"#一说明","p":675},{"i":679,"t":"在TouchRpc中,内置了四种序列化方式,分别为FastBinary、Json、Xml、SystemBinary。这四种方式的特点,就是其序列化的特点。 FastBinary Json Xml SystemBinary 特点 序列化方式速度快,数据量小,但是兼容的数据格式也比较有限。仅支持基础类型、自定义实体类、数组、List、字典 兼容性好,可读性强,但是受字符串影响,性能不出众,且数据量受限制 兼容性一般,可读性强,同样受字符串影响,性能不出众,且数据量受限制 序列化速度快。但是兼容性低。且要求类必须一致,不然需要重新指定图根。","s":"二、支持的序列化","u":"/touchsocket/docs/serializationselector","h":"#二支持的序列化","p":675},{"i":681,"t":"在TouchRpc中,选择序列化是非常简单的,且序列化方式完全由调用端决定。 在实际的调用中,通过InvokeOption的参数指定。 实际上,只需要传入相关参数即可。 InvokeOption invokeOption = new InvokeOption() //InvokeOption是结构体,所以成员必须全部初始化。 { FeedbackType = FeedbackType.WaitInvoke, Timeout = 1000 * 10 }; ; invokeOption.SerializationType = SerializationType.FastBinary; //invokeOption.SerializationType = Serialization.SerializationType.Json; //invokeOption.SerializationType = Serialization.SerializationType.Xml; string returnString = client.Invoke(\"TestOne\", invokeOption, \"10\");","s":"三、使用预设序列化","u":"/touchsocket/docs/serializationselector","h":"#三使用预设序列化","p":675},{"i":684,"t":"想要实现自定义序列化,必须通过重写序列化选择器,实现SerializeParameter和DeserializeParameter函数。 下列代码将以MemoryPack序列化作为示例,并且保留了预设序列化。 public class MemoryPackSerializationSelector:DefaultSerializationSelector { public override byte[] SerializeParameter(SerializationType serializationType, object parameter) { if ((byte)serializationType == 4) { return MemoryPackSerializer.Serialize(parameter.GetType(),parameter); } return base.SerializeParameter(serializationType, parameter); } public override object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType) { if ((byte)serializationType == 4) { if (parameterBytes==null) { return default; } return MemoryPackSerializer.Deserialize(parameterType,parameterBytes); } return base.DeserializeParameter(serializationType, parameterBytes, parameterType); } }","s":"4.1 定义自定义序列化器","u":"/touchsocket/docs/serializationselector","h":"#41-定义自定义序列化器","p":675},{"i":686,"t":"必须在服务器和客户端的Config配置中设置解析器。 var config = new TouchSocketConfig()//配置 .SetSerializationSelector(new MemoryPackSerializationSelector()); 然后,因为赋值时是SerializationType的枚举类型,所以执行强制类型转换即可。 InvokeOption invokeOption = new InvokeOption() { FeedbackType = FeedbackType.WaitInvoke, SerializationType = (SerializationType)4, Timeout = 1000 * 10 }; var msg = client.Login(new LoginModel() { Account = \"Account\", Password = \"Password\" }, invokeOption); 提示 因为使用的是MemoryPack序列化,所以最好将Rpc的所有参数声明在单独的程序集中。这样客户端与服务器项目都可以直接引用。 序列化选择器示例代码","s":"4.2 使用","u":"/touchsocket/docs/serializationselector","h":"#42-使用","p":675},{"i":689,"t":"小文件传输是指,当传输文件小于设定大小(默认1024*1024字节)时的传输。 为什么要设立小文件传输?与常规文件传输相比,优点在哪里? 常规传输,建立一个传输通道,大约需要传输两端,往返通信4-6次。这在本地局域网中,显得无所谓。但是在互联网环境中,一次ping延迟平均50ms,那么建立一个传输,就大约需要200-300ms。这也就意味着,即使一个文件只有一字节,也需要这些时间。所以,这明显是不合理的。所以TouchRpc又新增了小文件传输,只要文件在1Mb以内,仅往返1次,就可以完成传输。 当然,对于小文件的最高效传输方式依然是先压缩,后传输的方式。","s":"一、说明","u":"/touchsocket/docs/smallfiletransfer","h":"#一说明","p":687},{"i":691,"t":"【拉取文件】 直接调用PullSmallFile或者PullSmallFileAsync,获取到实际的文件数据。 通过Save方法,将数据写入文件。也可以自行保存。 var result = await this.fileClient.PullSmallFileAsync(path);//拉取文件 var saveResult = result.Save(savePath);//将拉取的数据进行保存。 【推送文件】 直接调用PushSmallFile或者PushSmallFileAsync。 返回值即表示是否成功。 var result = await this.fileClient.PushSmallFileAsync(savePath, fileInfo); if (result.IsSuccess()) { } 其他可选参数可以自己定义。","s":"二、使用","u":"/touchsocket/docs/smallfiletransfer","h":"#二使用","p":687},{"i":693,"t":"该功能也支持客户端之间互相传输。使用方法基本一致,需要额外指定目标Id即可。 此外,服务器也需要同意路由 internal class MyTouchRpcPlugin : TouchRpcPluginBase { protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e) { if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile) { e.IsPermitOperation = true; } base.OnRouting(client, e); } }","s":"三、客户端之间传输","u":"/touchsocket/docs/smallfiletransfer","h":"#三客户端之间传输","p":687},{"i":697,"t":"本代码仅适用以下协议。 协议中,由Packet_Length表示序号7-11的长度。也就是Packet_Length=N+2+2+1+1。 但是在设计时,会将序号1-10,视为固定包头。序号11-13为Body。","s":"说明","u":"/touchsocket/docs/stategridtransmission","h":"#说明","p":695},{"i":699,"t":"该代码所有版权归若汝棋茗所有,使用时请务必注明。","s":"版权","u":"/touchsocket/docs/stategridtransmission","h":"#版权","p":695},{"i":702,"t":"using TouchSocket.Core; using TouchSocket.Sockets; namespace AdapterConsoleApp { /// /// 国网输电i1标准版 /// internal class SGCCCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter { public override int HeaderLength => 30; public override bool CanSendRequestInfo => false; protected override SGCCRequestInfo GetInstance() { return new SGCCRequestInfo(); } protected override void PreviewSend(IRequestInfo requestInfo) { throw new System.NotImplementedException(); } } public class SGCCRequestInfo : IFixedHeaderRequestInfo { private byte[] m_sync; private int m_bodyLength; private byte[] m_cMDID; private byte[] m_sample; private byte[] m_cRC16; public int BodyLength { get => m_bodyLength; } /// /// 报文头:5AA5 /// public byte[] Sync { get => m_sync; set => m_sync = value; } /// /// 报文长度 /// public ushort PacketLength { get => (ushort)(this.m_bodyLength - 3); } /// /// 状态监测装置ID(17位编码) /// public byte[] CMDID { get => m_cMDID; set => m_cMDID = value; } /// /// 帧类型—参考附表C8-1相关含义 /// public byte FrameType { get; set; } /// /// 报文类型—参考附表C8-2相关含义 /// public byte PacketType { get; set; } /// /// 帧序列号(无符号整数) /// public byte FrameNo { get; set; } /// /// 通道号—表示采集装置上的摄像机编号。如:一个装连接⒉部摄像机,则分别标号为1、2 /// public byte ChannelNo { get; set; } /// /// 预置位号—即云台摄像所设置的预置位号,不带云台摄像机,预置位号为255 /// public byte PresettingNo { get; set; } /// /// 总包数(无符号整数,取值范围:大于等于0) /// public ushort PacketNo { get; set; } /// /// 子包包号(无符号整数,取值范围:大于等于0> /// public ushort SubpacketNo { get; set; } /// /// 数据区 /// public byte[] Sample { get => m_sample; set => m_sample = value; } /// /// 校验位 /// public byte[] CRC16 { get => m_cRC16; } /// /// 报文尾:0x96 /// public byte End { get; set; } public bool OnParsingHeader(byte[] header) { if (header.Length == 30) { using (ByteBlock byteBlock = new ByteBlock(header)) { byteBlock.Pos = 0; byteBlock.Read(out m_sync, 2); byte[] lenBuffer; byteBlock.Read(out lenBuffer, 2); this.m_bodyLength = TouchSocketBitConverter.LittleEndian.ToUInt16(lenBuffer, 0) + 3 - 6;//先把crc校验和end都获取。 byteBlock.Read(out m_cMDID, 17); this.FrameType = (byte)byteBlock.ReadByte(); this.PacketType = (byte)byteBlock.ReadByte(); this.FrameNo = (byte)byteBlock.ReadByte(); this.ChannelNo = (byte)byteBlock.ReadByte(); this.PresettingNo = (byte)byteBlock.ReadByte(); this.PacketNo = byteBlock.ReadUInt16(); this.SubpacketNo = byteBlock.ReadUInt16(); return true; } } return false; } public bool OnParsingBody(byte[] body) { if (body.Length == this.BodyLength && body[^1] == 150) { using (ByteBlock byteBlock = new ByteBlock(body)) { byteBlock.Read(out this.m_sample, this.m_bodyLength - 3); byteBlock.Read(out this.m_cRC16, 2); this.End = (byte)byteBlock.ReadByte(); } return true; } return false; } } }","s":"代码","u":"/touchsocket/docs/stategridtransmission","h":"#代码","p":695},{"i":705,"t":"TouchSocket(Pro)是基于.Net发布的程序集,所以它可以被用于对应.Net版本的C#、F#、VB.net等语言项目。它不区分您的项目是控制台、Winform、Wpf、或者是Aspnetcore,它统统都支持。 下面我们将以最简单的C# 控制台程序作为入门,让您最直观的感受ToucSocket的强大。","s":"一、说明","u":"/touchsocket/docs/startguide","h":"#一说明","p":703},{"i":707,"t":"由于TouchSocket(Pro)是基于net45、netstandard2.0、netcoreapp3.1三个平台作为常期支持平台,net7.0作为最新发布平台的程序,所以您可以用vs2010及以上的任意版本创建项目。 下面我们将以vs2022作为示例: 说明 如果您选择vs code等其他的编译工具,那么我相信您已不是新手。那么您只需要安装TouchSocket(Pro)的最新nuget包即可。","s":"二、创建项目","u":"/touchsocket/docs/startguide","h":"#二创建项目","p":703},{"i":714,"t":"右击项目=》点击“管理Nuget程序包”。 点击“浏览”,然后在搜索框输入TouchSocket,然后在搜索结果中选择。最后点击安装。","s":"3.1 Nuget安装","u":"/touchsocket/docs/startguide","h":"#31-nuget安装","p":703},{"i":716,"t":"单击项目,打开项目编辑,然后在空白根内部引用。 提示 Version=\"1.2.3\"可能不是最新的版本,请前往Nuget官网查看。","s":"3.2 PackageReference","u":"/touchsocket/docs/startguide","h":"#32-packagereference","p":703},{"i":718,"t":"在Nuget官网中,选择需要的,然后选择“Download package”,即可下载一个后缀为.nupkg文件。 提示 如果下载速度较慢,可以考虑使用迅雷等工具加速。 将下载的后缀为.nupkg的文件,通过压缩工具解压。得到如下目录结构。 然后进入“lib”的文件夹。选择对应平台。 提示 一般来说,所有基于.NET Framework的项目,都最好引用net45的库。然后其他版本的,选择最近的,较低的库即可。在本示例中,选择netcoreapp3.1的库。 把下列文件引用到项目即可。","s":"3.3 Dll直接引用","u":"/touchsocket/docs/startguide","h":"#33-dll直接引用","p":703},{"i":720,"t":"恭喜你,到这里,你就完成了入门的教学,你可能会好奇,做了这么多,还是什么都没有做啊。这是因为TouchSocket并不是一个单功能的,而是一个多功能程序库。所以,你必须在其他模块中查看你所需要的内容。 祝你好运!!!","s":"四、结束","u":"/touchsocket/docs/startguide","h":"#四结束","p":703},{"i":723,"t":"Stream的直接发送,单个TCP连接上可以同时进行多个传输。客户端与服务器之间可以任意相互发送。","s":"一、说明","u":"/touchsocket/docs/streamtransfer","h":"#一说明","p":721},{"i":725,"t":"实时检测速度,进度等信息。 从Stream.Position开始,直到Read结束。","s":"二、特性","u":"/touchsocket/docs/streamtransfer","h":"#二特性","p":721},{"i":727,"t":"下列以服务器作为Stream的接收方。客户端为发送方。 【服务器】 TcpTouceRpcService service = CreateTcpTouceRpcService(); service.StreamTransfering += (socketClient, e) => { e.Bucket = new MemoryStream();//此处用MemoryStream作为接收容器,也可以使用FileStream。 e.AddOperation(Operation.Permit);//允许接收该流 Metadata metadata = e.Metadata;//获取元数据 StreamOperator streamOperator = e.StreamOperator;//获取操作器,可用于取消任务,获取进度等。 //Console.WriteLine(\"设置最大传输速度为1024byte\"); //streamOperator.SetMaxSpeed(1024); //Console.WriteLine(\"5秒后设置为5Mb\"); //RRQMCore.Run.EasyAction.DelayRun(5, () => //{ // streamOperator.SetMaxSpeed(1024 * 1024 * 5); //}); Task.Run(async () => { while (streamOperator.Result.ResultCode == ResultCode.Default) { Console.WriteLine($\"速度={streamOperator.Speed()},进度={streamOperator.Progress}\"); await Task.Delay(1000); } Console.WriteLine($\"从循环传输结束,状态={streamOperator.Result}\"); }); Console.WriteLine(\"开始接收流数据\"); }; service.StreamTransfered += (socketClient, e) => { //此处不管传输成功与否,都会执行,具体状态通过e.Status判断。 if (e.Result.ResultCode == ResultCode.Success) { } e.Bucket.Dispose();//必须手动释放流数据。 Console.WriteLine($\"从ReceivedStream传输结束,状态={e.Result}\"); }; 【客户端】 TcpTouchRpcClient client = CreateTcpTouchRpcClient(); byte[] data = new byte[1024 * 1024 * 50]; new Random().NextBytes(data); MemoryStream stream = new MemoryStream(data); stream.Position = 0; Console.WriteLine($\"即将发送流数据,长度为:{stream.Length}\"); StreamOperator streamOperator = new StreamOperator(); streamOperator.PackageSize = 1024 * 64;//分包长度 //streamOperator.SetMaxSpeed(1024 * 1024 * 5);//最大传输值 //streamOperator.Cancel();//随时取消传输 LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (a) => { if (streamOperator.Result.ResultCode != ResultCode.Default) { a.Dispose(); } Console.WriteLine($\"速度:{streamOperator.Speed()},进度:{streamOperator.Progress}\"); }); loopAction.RunAsync(); Metadata metadata = new Metadata();//将键值对的元数据传到接收端 metadata.Add(\"1\", \"1\"); metadata.Add(\"2\", \"2\"); //该方法会阻塞,直到结束 Result result = client.SendStream(stream, streamOperator, metadata); Console.WriteLine(result);","s":"三、示例","u":"/touchsocket/docs/streamtransfer","h":"#三示例","p":721},{"i":729,"t":"C# TCP如何限制单个客户端的访问流量 C# Tcp服务器如何限制同一个IP的连接数量? C# 实现为Tcp服务器设计访问黑名单、白名单 C# Tcp服务器实现多端口、多协议解析","s":"其他场景应用","u":"/touchsocket/docs/tcpother","h":"","p":728},{"i":732,"t":"TcpCommandLinePlugin命令行执行插件,是用于TCP的快捷事务实现。该类是抽象类,必须通过继承,在继承类中,声明的具的公共的且名称以Command结尾的方法,均可被快捷执行。","s":"一、说明","u":"/touchsocket/docs/tcpcommandlineplugin","h":"#一说明","p":730},{"i":734,"t":"/// /// 命令执行插件。方法必须以Command结尾。 /// class MyCommandLinePlugin : TcpCommandLinePlugin { private readonly ILog logger; public MyCommandLinePlugin(ILog logger) : base(logger) { this.ReturnException = true;//表示执行异常的时候,是否返回异常信息 this.logger = logger; } /// /// 加法 /// /// /// /// public int AddCommand(int a, int b) { this.logger.Info($\"执行{nameof(AddCommand)}\"); return a + b; } /// /// 乘法,并且获取调用者信息 /// /// /// /// /// public int MULCommand(ISocketClient socketClient,int a, int b) { this.logger.Info($\"{socketClient.IP}:{socketClient.Port}执行{nameof(MULCommand)}\"); return a * b; } /// /// 测试异常 /// /// public void ExcCommand() { throw new Exception(\"我异常了\"); } }","s":"二、创建快捷执行插件","u":"/touchsocket/docs/tcpcommandlineplugin","h":"#二创建快捷执行插件","p":730},{"i":736,"t":"TcpService service = new TcpService(); var config = new TouchSocketConfig(); config.SetListenIPHosts(new IPHost[] { new IPHost(\"127.0.0.1:7789\"), new IPHost(7790) }) //同时监听两个地址 .SetDataHandlingAdapter(() => { //return new TerminatorPackageAdapter(1024, \"\\r\\n\");//命令行中使用\\r\\n结尾 return new NormalDataHandlingAdapter();//亦或者省略\\r\\n,但此时调用方不能高速调用,会粘包 }) .UsePlugin() .ConfigureContainer(a => { a.AddConsoleLogger(); }) .ConfigurePlugins(a => { a.Add(); }); //载入配置 service.Setup(config); //启动 service.Start(); service.Logger.Info(\"服务器成功启动。\"); service.Logger.Info(\"使用:“Add 10 20”测试\"); service.Logger.Info(\"使用:“MUL 10 20”测试\"); service.Logger.Info(\"使用:“Exc”测试异常\");","s":"三、创建服务器","u":"/touchsocket/docs/tcpcommandlineplugin","h":"#三创建服务器","p":730},{"i":738,"t":"上述快捷执行插件,即可被普通tcp客户端,或cmd/telnet等便捷调用。 调用数据格式: Add 10 20 /r/n /r/n非必须,但是当适配器选为终止字符分割适配器时,则必须。不然,则不可连续调用,会粘包。 提示 调用的参数也支持自定义实体类,届时蚕食使用Json数据格式即可。","s":"四、调用","u":"/touchsocket/docs/tcpcommandlineplugin","h":"#四调用","p":730},{"i":741,"t":"终止因子数据处理适配器是通过特殊字符或数值的方式,来达到处理粘包、分包的目的。可随意设置分割因子的值,以及编码方式。不仅如此,还有异常数据设置,在达到设定值时,如果还没有发现分割因子,则抛弃数据。其稳定性仅次于固定包头,且使用场景也比较广泛。","s":"一、说明","u":"/touchsocket/docs/terminatorpackageadapter","h":"#一说明","p":739},{"i":743,"t":"最适用于字符串类(Json,Xml等)的信息交互。 算法简单,非常容易实现跨语言、跨框架。 发送普通流数据时,有很小的概率发生提前终止的情况(可设置复杂终止因子来解决)。","s":"二、特点","u":"/touchsocket/docs/terminatorpackageadapter","h":"#二特点","p":739},{"i":745,"t":"客户端与服务器均适用。下列以服务器为例。 步骤 TouchSocketConfig配置中设置,同时指定数据的长度。 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //从客户端收到信息 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(()=> { return new TerminatorPackageAdapter(\"\\r\\n\"); }))//配置终止字符适配器,以\\r\\n结尾。 .Start();//启动 提示 默认情况下终止因子不会保留在数据中,用户可通过ReserveTerminatorCode属性,设为true,来保留终止因子。 注意 接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。 提示 该适配器,客户端与服务器均适用。","s":"三、使用","u":"/touchsocket/docs/terminatorpackageadapter","h":"#三使用","p":739},{"i":748,"t":"TLV适配器,定义了一种简单高效的三元组编码,简称TLV编码。它是由数据的类型Tag(T),数据的长度Length(L),数据的值Value(V)构成的一组数据报文。TLV是基于二进制编码的,将数据以(T -L- V)的形式编码为字节数组,即TLV是字节流的数据传输协议。它规定了一帧数据的首个字节或几个字节来表示数据类型,紧接着一个或几个字节表示数据长度,最后是数据的内容。 数据协议如下: Tag 标识数据的类型。 占2字节 大端序无符号整型。 0-9保留系统使用。[10,65535]客户端自行定义。 已用Tag:0表示Close,载荷Value为关闭消息。 已用Tag:1表示Ping,无载荷,对方收到后必须无条件返回Pong。 已用Tag:2表示Pong,无载荷。 Length 标识后续Value的长度。 按LengtType的指定,可以用1字节、2字节、4字节来表示长度,分别对应255、65535、2147483647字节的对应值。 1字节时,不区分端序。 2字节时,大端序无符号整型。 4字节时,大端序有符号整型。 默认使用2字节的Ushort类型。 Value 载荷数据。可以为任意类型。","s":"一、说明 企业版","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#一说明-企业版","p":746},{"i":750,"t":"【适配器使用】 设置的FixedHeaderType类型后,实际的支持最大数据还受SetMaxPackageSize影响。默认为1024102410字节。 .SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//如果使用TLVPlugin插件,此步骤可省略。 【插件】 只需要添加TLVPlugin插件即可。客户端亦然。 使用插件,相当于自动设置适配器,并且主动回应Ping。 var config = new TouchSocketConfig(); config.UsePlugin() .SetMaxPackageSize(1024 * 1024 * 10) //.SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//如果使用TLVPlugin插件,此步骤可省略。 .ConfigurePlugins(a => { a.Add()//使用插件,相当于自动设置适配器,并且主动回应Ping。 .SetLengthType(FixedHeaderType.Int);//设置支持的最大数据类型,该值还受SetMaxPackageSize影响。 });","s":"二、使用","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#二使用","p":746},{"i":752,"t":"TLV数据协议中,定义了Tag=1时为ping,Tag=2时为Pong。所以可以依靠这套机制,进行保活。 实际上,在插件中,已经做了Ping,Pong的处理。客户端可以直接调用。 该操作,服务器也可以直接ping客户端。 bool result=this.m_client.Ping();//返回值为true时,对端一定在线。此方法服务器也可以主动ping客户端。","s":"三、保活机制","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#三保活机制","p":746},{"i":754,"t":"利用PollingKeepAlivePlugin插件自动Ping。","s":"自动ping","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#自动ping","p":746},{"i":756,"t":"如果对方是其他语言,请使用约定的方式发送数据。 如果是CSharp的话,构建数据非常简单。 构建数据时,可用TLVDataFrame构建。或者其值类型构建,此处推荐ValueTLVDataFrame 【直接构造】 ValueTLVDataFrame requestInfo = new ValueTLVDataFrame(10, new byte[] { 0, 1, 2, 3 }); 【追加型构建】 ValueTLVDataFrame requestInfo = new ValueTLVDataFrame(); requestInfo.AppendValue(new byte[] { 0, 1, 2, 3 }); requestInfo.AppendValue(new byte[] { 4, 5, 6, 7 });","s":"四、构建数据","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#四构建数据","p":746},{"i":758,"t":"构建完数据后,直接发送。 client.Send(new ValueTLVDataFrame(10,Encoding.UTF8.GetBytes(\"rrqm\")));//推荐写法,如果使用自己Build,则需要明确指出FixedHeaderType的值。 提示 上述创建的适配器客户端与服务器均适用。","s":"五、发送数据","u":"/touchsocket/docs/tlvdatahandlingadapter","h":"#五发送数据","p":746},{"i":761,"t":"大小端在计算机业界,Endian表示数据在存储器中的存放顺序。 大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放; 小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。","s":"一、说明","u":"/touchsocket/docs/touchsocketbitconverter","h":"#一说明","p":759},{"i":763,"t":"byte[] data= TouchSocketBitConverter.BigEndian.GetBytes(10); //结果 {0,0,0,10}","s":"二、绝对大端","u":"/touchsocket/docs/touchsocketbitconverter","h":"#二绝对大端","p":759},{"i":765,"t":"byte[] data= TouchSocketBitConverter.LittleEndian.GetBytes(10); //结果 {10,0,0,0}","s":"三、绝对小端","u":"/touchsocket/docs/touchsocketbitconverter","h":"#三绝对小端","p":759},{"i":767,"t":"TouchSocket系全采用默认“小端”模式。可通过DefaultEndianType属性,修改为大端。 TouchSocketBitConverter.DefaultEndianType = EndianType.Big; byte[] data= TouchSocketBitConverter.Default.GetBytes(10);","s":"四、默认端","u":"/touchsocket/docs/touchsocketbitconverter","h":"#四默认端","p":759},{"i":770,"t":"连接验证可以初步保证连接客户端的安全性。框架内部默认使用一个string类型的Token作为验证凭证。当然也允许服务器进行其他验证。具体如下:","s":"一、连接验证","u":"/touchsocket/docs/touchrpcbase","h":"#一连接验证","p":768},{"i":772,"t":"在服务器或客户端的配置上,设置VerifyToken,即可实现字符串Token验证。 var config = new TouchSocketConfig()//配置 .SetVerifyToken(\"TouchRpc\");","s":"1.1 Token验证","u":"/touchsocket/docs/touchrpcbase","h":"#11-token验证","p":768},{"i":774,"t":"使用插件,重写OnHandshaking相关。然后可以自行判断一些信息,比如:IP地址、元数据等。 internal class MyTouchRpcPlugin : TouchRpcPluginBase { protected override void OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e) { if (e.Metadata[\"a\"] != \"a\") { e.IsPermitOperation = false;//不允许连接 e.Message = \"元数据不对\";//同时返回消息 e.Handled= true;//表示该消息已在此处处理。 return; } if (e.Token == \"123\") { e.IsPermitOperation = true; e.Handled = true; return; } base.OnHandshaking(client, e); } }","s":"1.2 动态验证","u":"/touchsocket/docs/touchrpcbase","h":"#12-动态验证","p":768},{"i":776,"t":"在TouchRpc中,存在于服务器的辅助客户端(SocketClient),与远程客户端(Client)是一一对应关系,其ID也完全一致。所以在任意一方修改ID(调用ResetID),都会同时修改远程ID。所以合理使用该操作,可以完成复用ID(重置ID)的需求。","s":"二、ID同步","u":"/touchsocket/docs/touchrpcbase","h":"#二id同步","p":768},{"i":778,"t":"协议扩展功能,就是对现有的TouchRpc进行自定义的扩展协议。其目的就是为了应对更加复杂,高要求的需求。 例1:当需要广播消息时,可能大家都会想到使用rpc直接进行广播。但是如此一来,每广播一个客户端,就需要序列化一次。因为数据都是一样的,所以多次序列化显得非常没有必要。那么这时候,可以自定义协议,然后先序列化,然后直接广播数据。 自定义协议效率如何呢? 自定义协议的效率是非常高的,99%接近于底层协议(可能是tcp、udp、websocket)效率。","s":"三、协议扩展","u":"/touchsocket/docs/touchrpcbase","h":"#三协议扩展","p":768},{"i":780,"t":"使用起来是非常简单的,每个TouchRpc客户端或者TouchRpc服务端,都实现了Send方法接口。 第一个参数为short类型,使用者可以约定任意数值(不要使用小于0的,因为框架内部在使用)。 在接收方在OnReceivedProtocolData函数中,已经包含了协议参数,所以直接自行筛选即可。 internal class MyTouchRpcPlugin : TouchRpcPluginBase { protected override void OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e) { if (e.Protocol == 10) { //判断完协议以后,从e.ByteBlock可以拿到实际的数据 //但是需要注意的是,真实数据会整体向右偏移2个字节。 string msg = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 2, e.ByteBlock.Len - 2); } base.OnReceivedProtocolData(client, e); } } 注意 从ProtocolDataEventArgs解析的ByteBlock,其真实数据会整体向右偏移2个字节。因为前两个字节是ushort的Protocol。","s":"3.1 使用","u":"/touchsocket/docs/touchrpcbase","h":"#31-使用","p":768},{"i":783,"t":"TouchRpc是一个简单易用,便捷高效,且易于扩展的自定义数据格式的可靠执行传输协议。 【协议格式】 | 2字节 | n字节 | 协议格式非常简单。 前两个字节为默认端序的小端,int16有符号类型。其中小于0的协议一般不要占用,因为框架在使用。 后续字节则为本次协议的载荷数据。 细心的小伙伴可能会问,这个数据协议没有分包标识啊,也就是无法分辨一个数据包是不是完整的。这是因为TouchRpc支持多种协议运行,可能在一些协议上,就已经涵盖了分包机制,所以为避免过度封装,所以TouchRpc并未制定分包。所以TouchRpc在不同协议工作时,可能实际的数据格式也不相同。 例如:在Tcp工作时,其分包算法使用的是固定包头。在websocket工作时,使用的就是其自身的分包算法。 可能好多人会疑惑,TouchRpc和tcp、udp有什么关系?或者说,类似tcp,本身就是可靠传输协议了,那TouchRpc的可靠又体现在什么地方呢?","s":"一、说明","u":"/touchsocket/docs/touchrpcdescription","h":"#一说明","p":781},{"i":785,"t":"TouchRpc像http和websocket一样,也是封装的应用层协议。它可以基于最基本的tcp或udp工作,也能基于http和websocket工作。所以,可以认为TouchRpc是更为高级的应用层协议。","s":"1.1 TouchRpc和Tcp、Udp有什么关系?","u":"/touchsocket/docs/touchrpcdescription","h":"#11-touchrpc和tcpudp有什么关系","p":781},{"i":787,"t":"首先呢,我们得明确,tcp的可靠,是在保持连接的时候,才可靠。当突然断网时,这种可靠将被打破。其次这种可靠是单项的,举例来说,发送方只是负责将数据发给接收方,至于接收方处理了没有,或者处理结果如何,都是未知的。那么这时候聪明的小伙伴就会想到让接收方回复一个状态不就行了?是的,这就是TouchRpc工作的场景之一了。 当然,TouchRpc的功能远非上述的两个场景,详细概览如下:","s":"1.2 Tcp本身就是可靠传输协议了,那TouchRpc的可靠又体现在什么地方呢?","u":"/touchsocket/docs/touchrpcdescription","h":"#12-tcp本身就是可靠传输协议了那touchrpc的可靠又体现在什么地方呢","p":781},{"i":790,"t":"支持连接验证,也支持动态信息验证。 支持ID同步,每个客户端连接到服务器后,自身ID会与服务器ID同步,且支持重置。 支持ssl加密。 支持协议扩展。","s":"2.1 基础功能","u":"/touchsocket/docs/touchrpcdescription","h":"#21-基础功能","p":781},{"i":792,"t":"支持常规rpc操作。 支持代理代码生成。 支持自定义类型的参数。 支持out、ref关键字参数。 支持服务器主动Call客户端和客户端之间互Call。 支持调用上下文,可进行服务AOP。 支持异步调用。 支持调用超时、调用中断。 支持全异常反馈,被调用方发生的一切异常,都会传递到调用方。 支持.NET二进制序列化、Json序列化、xml序列化、Fast序列化,以及自定义序列化扩展。 高性能调用,在保证送达但不返回的情况下,10w次调用用时0.8s,在返回的情况下,用时3.9s。","s":"2.2 Rpc功能","u":"/touchsocket/docs/touchrpcdescription","h":"#22-rpc功能","p":781},{"i":794,"t":"支持任意大小的文件传输。 支持断点续传。 支持传输限速。 支持服务器主动向客户端请求、发送文件。 支持客户端之间互相请求、发送文件。 支持小文件快速传输。 支持超大文件多链路、多线程传输。","s":"2.3 文件传输","u":"/touchsocket/docs/touchrpcdescription","h":"#23-文件传输","p":781},{"i":796,"t":"支持创建文件夹。 支持文件的删除、移动、重命名等操作。 支持服务器对客户端的主动操作。 支持客户端之间的操作。","s":"2.4 远程操作","u":"/touchsocket/docs/touchrpcdescription","h":"#24-远程操作","p":781},{"i":798,"t":"支持发送任意类型的Stream。 支持将远程的流数据映射到本地,然后直接Read或Write。 支持实施传输压缩。","s":"2.5 流数据方面","u":"/touchsocket/docs/touchrpcdescription","h":"#25-流数据方面","p":781},{"i":800,"t":"支持独立通道数据,可进行数据隔离。 支持服务器到客户端,客户端到客户端的操作。","s":"2.6 Channel数据","u":"/touchsocket/docs/touchrpcdescription","h":"#26-channel数据","p":781},{"i":802,"t":"支持事件的创建、订阅、取消、触发等。 支持触发权限。 支持事件广播。","s":"2.7 EventBus","u":"/touchsocket/docs/touchrpcdescription","h":"#27-eventbus","p":781},{"i":804,"t":"支持string为键的任意类型的数据。 支持服务器向客户端存储。 支持存储持久化。","s":"2.8 Redis","u":"/touchsocket/docs/touchrpcdescription","h":"#28-redis","p":781},{"i":806,"t":"什么情况下使用TouchRpc比较好呢?首先,你得先了解RPC,了解完后,因为TouchRpc无法跨语言,所以,建议以下场景使用TouchRpc比较稳妥。 不需要跨语言的终端,例如:Unity游戏,Winform、WPF、MAUI等软件。 服务器之间集群。 扩展微服务,此时可以使用反向RPC实现。 实际上TouchRpc有四个版本,分别为: 类型 特性 Tcp版 基于TCP协议,连接性能最好,执行效率最高,支持TouchRpc所有功能。 Udp版 基于UDP Package协议,无连接,执行效率高,仅支持TouchRpc的Rpc功能。 Http版 基于Http握手连接,数据交互仍然使用TCP。连接性能一般,但兼容性强,支持JsonRpc,WebApi,XmlRpc,WebSocket等一系列Http组件,且执行效率和TCP版一样高,支持TouchRpc所有功能。 WebSocket版 该版本是仅适用于Asp.Net Core的版本,特点就是和Asp.Net Core共用端口。但是执行数据使用的是WebSocket,所有效率只有Tcp版的80%。支持TouchRpc所有功能","s":"三、场景","u":"/touchsocket/docs/touchrpcdescription","h":"#三场景","p":781},{"i":809,"t":"Udp的适配器,主要承担组包和解析数据。其基本逻辑和Tcp相似。但是需要注意的是,Udp适配器是多线程操作。在解析数据时,应当充分考虑并发问题。 class MyUdpAdatper : UdpDataHandlingAdapter { public override bool CanSplicingSend => false; protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock) { } protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length, bool isAsync) { } protected override void PreviewSend(EndPoint endPoint, IList transferBytes, bool isAsync) { } protected override void Reset() { } }","s":"说明","u":"/touchsocket/docs/udpdatahandlingadapter","h":"#说明","p":807},{"i":811,"t":"使用UdpDataAdapterTester即可测试。","s":"单元测试","u":"/touchsocket/docs/udpdatahandlingadapter","h":"#单元测试","p":807},{"i":814,"t":"UDP由于自身限制,每次发送的数据包最大约64K,但是在局域网内,有时候希望传输更大的数据。所以必须有策略发送。 TouchSocket可通过简单设置,实现该功能。","s":"一、说明","u":"/touchsocket/docs/udptransmitbigdata","h":"#一说明","p":812},{"i":816,"t":"只需要在配置中,设置其适配器为UdpPackageAdapter类型即可(默认为NormalUdpDataHandlingAdapter)。同时可以根据传输数据的大小,修改相关属性,如:MTU,Timeout等。 UdpSession udpSession = new UdpSession(); udpSession.Received += (endpoint, byteBlock, requestInfo) => { }; udpSession.Setup(new TouchSocketConfig() .SetBindIPHost(new IPHost($\"127.0.0.1:7789\")) .SetUdpDataHandlingAdapter(()=> new UdpPackageAdapter()));//加载配置 udpSession.Start();//启动 注意 此模式下,发送端与接收端均必须为TouchSocket(或实现相同算法),且为相同设置。","s":"二、使用","u":"/touchsocket/docs/udptransmitbigdata","h":"#二使用","p":812},{"i":818,"t":"在发送时,会将要发送的数据分割成MTU长度的数据。然后为其编号,然后发送,最后由接收方重组。","s":"三、原理","u":"/touchsocket/docs/udptransmitbigdata","h":"#三原理","p":812},{"i":820,"t":"ID:由雪花算法生成,在并发请求时1毫秒中有400w分之一的概率发生ID重复。但基本可以忽略不计。 Bit 说明 7 6 5 4 3 2 1 0 协议名 byte1 PackageID为long类型,占用8字节,标识数据包唯一性。 byte2 byte3 byte4 byte5 byte6 byte7 byte8 SN为Ushort占2字节,标识帧序 byte9 byte10 flag,占1字节,最高位标识是否为结束,其他位保留。 1 byte? 有效载荷数据 byte^2 当不为终结帧时,此处仍然为载荷数据。当是终结帧时,倒数两个字节为Crc16校验。 byte^1","s":"3.1 数据格式","u":"/touchsocket/docs/udptransmitbigdata","h":"#31-数据格式","p":812},{"i":822,"t":"演示: 可以看到,下图正在上传一个Window的系统镜像文件,大约4.2Gb,传输速度已达到800Mb/s,GC基本上没有释放,性能非常强悍(中间有稍微停顿,因为程序在获取文件MD5值)。","s":"传输文件","u":"/touchsocket/docs/transferfile","h":"","p":821},{"i":824,"t":"常规C/S应用使用场景:开发使用非常方便,连接验证,数据业务,文件传输等一系列功能完全集成。 Unity游戏场景:性能卓越,功能丰富,使用方便。","s":"产品应用场景","u":"/touchsocket/docs/transferfile","h":"#产品应用场景","p":821},{"i":826,"t":"其传输架构是基于Channel工作的。所以当在同一时间,可进行多个传输并行,且数据互不影响。 在文件传输时,每个连接端和服务器均是平等权利的,所以RRQM将其命名为对点。任意两个对点之间均可Pull(拉取或下载)或Push(推送或上传)文件,例如下图中,Client1、SocketClient1、Client2、SocketClient2四个互相为对点,均可自由传输文件。","s":"服务架构","u":"/touchsocket/docs/transferfile","h":"#服务架构","p":821},{"i":828,"t":"文件传输是每个框架都需要的功能,也是检验一个框架性能的非常重要的指标。 TouchRpc开辟了对点文件传输。即,当客户端连接服务器以后,两者可以任意,随时的互相发送文件。不仅如此,即使是客户端之间,可以发送文件。 下列示例仅演示由TcpTouchRpcClient到TcpTouchRpcService(实际上是TcpTouchRpcSocketClient)的操作。 对点之间可以任意pull(拉取)、push(推送)文件。接收对点可以订阅FileTransfering和FileTransfered事件,来获取相关信息,发起对点直接通过传输控制器或返回值获取传输信息。 值得注意的是,FileTransfered事件的触发并不意味着完成传输,具体结果还要通过Result属性值进行判断。","s":"一、说明","u":"/touchsocket/docs/transferfile","h":"#一说明","p":821},{"i":830,"t":"由TcpTouchRpcClient向TcpTouchRpcService发起Pull请求时,相当于由客户端从服务器下载文件。 响应流程: 发起Pull请求。 接收对点(即此处的服务器)触发FileTransfering事件。 返回文件信息,然后检验是否续传等,然后开始接收。 接收完成或异常。 接收对点触发FileTransfered事件。 发起对点函数返回,控制器状态改变。 具体请求: 请求参数 参数属性 请求参数属性描述 | FileOperator:FileOperator是本次传输的请求操作器,主要用于获取传输进度、速度、状态以及取消传输等操作。接收方的控制器从FileTransfering事件的参数e中获得。 | ResourcePath | ResourcePath属性为请求文件在接收对点的路径,当该值为相对路径时,会与接收对点的RootPath组合路径。当为绝对路径时,则会直接访问路径文件(此时如果不在对点设置条件,则有可能会有文件安全隐患,设置详情链接)。 | | | SavePath | SavePath属性是发起对点本地的保存路径。 | | | Flags | 可通过叠加位域的形式,尝试断点续传。 | | | CompletedLength | 已完成流长度。 | | | Speed 函数 | 从上次获取到此次获得的速度。一般请每秒钟调用一次获取速度值。 | | | Progress | 传输进度,范围0-1。 | | | Result | 获取传输状态以及状态信息。当ResultCode为Default时,意味着传输正在进行。 | | | Token | CancellationToken类型的可取消令箭。 | | | Metadata | string类型的键值对,用于和接收方交互数据。 |","s":"二、Pull文件","u":"/touchsocket/docs/transferfile","h":"#二pull文件","p":821},{"i":832,"t":"【服务器】 var service = new TouchSocketConfig()//配置 .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .UsePlugin() .ConfigureContainer(a => { a.AddConsoleLogger(); a.AddFileLogger(); }) .ConfigurePlugins(a => { a.Add(); }) .SetVerifyToken(\"File\")//连接验证口令。 .BuildWithTcpTouchRpcService();//此处build相当于new TcpTouchRpcService,然后Setup,然后Start。 service.Logger.Info(\"服务器成功启动\"); class MyPlugin : TouchRpcPluginBase { protected override void OnFileTransfering(TcpTouchRpcSocketClient client, FileOperationEventArgs e) { e.IsPermitOperation = true;//运行操作 //有可能是上传,也有可能是下载 client.Logger.Info($\"有客户端请求传输文件,ID={client.ID},请求类型={e.TransferType},请求文件名={e.ResourcePath}\"); } protected override void OnFileTransfered(TcpTouchRpcSocketClient client, FileTransferStatusEventArgs e) { //传输结束,但是不一定成功,需要从e.Result判断状态。 client.Logger.Info($\"客户端传输文件结束,ID={client.ID},请求类型={e.TransferType},文件名={e.ResourcePath},请求状态={e.Result}\"); } protected override void OnHandshaked(TcpTouchRpcSocketClient client, VerifyOptionEventArgs e) { client.Logger.Info($\"有客户端成功验证,ID={client.ID}\"); } protected override void OnDisconnected(TcpTouchRpcSocketClient client, ClientDisconnectedEventArgs e) { client.Logger.Info($\"有客户端断开,ID={client.ID}\"); base.OnDisconnected(client, e); } } 【客户端】 TcpTouchRpcClient client = new TouchSocketConfig() .SetRemoteIPHost(\"127.0.0.1:7789\") .SetVerifyToken(\"File\") .UsePlugin() .ConfigureContainer(a => { a.AddConsoleLogger(); a.AddFileLogger(); }) .ConfigurePlugins(a => { a.UseTouchRpcHeartbeat(); }) .BuildWithTcpTouchRpcClient(); client.Logger.Info(\"连接成功\"); Metadata metadata = new Metadata();//传递到服务器的元数据 metadata.Add(\"1\", \"1\"); metadata.Add(\"2\", \"2\"); FileOperator fileOperator = new FileOperator()//实例化本次传输的控制器,用于获取传输进度、速度、状态等。 { Flags = TransferFlags.BreakpointResume,//尝试断点续传,使用断点续传时,会验证MD5值 SavePath = $@\"Windows.iso\",//保存路径 ResourcePath = @\"D:\\System\\Windows.iso\",//请求路径 Metadata= metadata//传递到服务器的元数据 }; fileOperator.Timeout = TimeSpan.FromSeconds(60);//当传输大文件,且启用断点续传时,服务器可能会先计算MD5,而延时响应,所以需要设置超时时间。 //此处的作用相当于Timer,定时每秒输出当前的传输进度和速度。 LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) => { if (fileOperator.Result.ResultCode != ResultCode.Default) { loop.Dispose(); } client.Logger.Info($\"进度:{fileOperator.Progress},速度:{fileOperator.Speed()}\"); }); loopAction.RunAsync(); //此方法会阻塞,直到传输结束,也可以使用PullFileAsync IResult result = client.PullFile(fileOperator); client.Logger.Info(result.ToString());","s":"示例代码:","u":"/touchsocket/docs/transferfile","h":"#示例代码","p":821},{"i":834,"t":"Push和Pull操作一致,仅需要在最后调用PushFile即可。","s":"三、Push文件","u":"/touchsocket/docs/transferfile","h":"#三push文件","p":821},{"i":836,"t":"该功能支持客户端之间传输文件,使用方法基本一致,只需要额外增加目标Id即可。 此外,服务器也需要同意路由。需要注意的是,使用该方式文件传输时,还会发起通道路由,所以,需要允许的路由应该还额外增加通道类型。 internal class MyTouchRpcPlugin : TouchRpcPluginBase { protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e) { if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile||e.RouterType== RouteType.CreateChannel) { e.IsPermitOperation = true; } base.OnRouting(client, e); } }","s":"四、客户端之间传输文件","u":"/touchsocket/docs/transferfile","h":"#四客户端之间传输文件","p":821},{"i":839,"t":"广播BroadCast:主机之间“一对所有”的通讯模式,广播者可以向网络中所有主机发送信息。广播禁止在Internet宽带网上传输(广播风暴)。 多播MultiCast:主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据。","s":"一、说明","u":"/touchsocket/docs/udpbroadcast","h":"#一说明","p":837},{"i":841,"t":"组播使用非常简单, 配置中启用广播UseBroadcast重要 在UdpSession启动后。调用JoinMulticastGroup即可加入组播。调用DropMulticastGroup,退出组播。","s":"二、组播使用","u":"/touchsocket/docs/udpbroadcast","h":"#二组播使用","p":837},{"i":843,"t":"//创建udpService UdpSession udpService = new UdpSession(); udpService.Received = (remote, byteBlock, requestInfo) => { Console.WriteLine(byteBlock.ToString()); }; udpService.Setup(new TouchSocketConfig() .SetBindIPHost(new IPHost(7789)) .UseBroadcast() .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) .Start(); //加入组播组 udpService.JoinMulticastGroup(IPAddress.Parse(\"224.5.6.7\"));","s":"2.1 创建组播服务器","u":"/touchsocket/docs/udpbroadcast","h":"#21-创建组播服务器","p":837},{"i":845,"t":"UdpSession udpClient = new UdpSession(); udpClient.Setup(new TouchSocketConfig() .SetBindIPHost(new IPHost(7788)) .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) .Start(); udpClient.Send(new IPEndPoint(IPAddress.Parse(\"224.5.6.7\"), 7789), Encoding.UTF8.GetBytes(\"我是组播\"));","s":"2.2 发送组播数据","u":"/touchsocket/docs/udpbroadcast","h":"#22-发送组播数据","p":837},{"i":847,"t":"广播使用非常简单, 配置中启用广播UseBroadcast重要","s":"三、广播","u":"/touchsocket/docs/udpbroadcast","h":"#三广播","p":837},{"i":849,"t":"广播接收时,是不需要加入组播组的。 //创建udpService UdpSession udpService = new UdpSession(); udpService.Received = (remote, byteBlock, requestInfo) => { Console.WriteLine(byteBlock.ToString()); }; udpService.Setup(new TouchSocketConfig() .SetBindIPHost(new IPHost(7789)) .UseBroadcast() .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) .Start();","s":"3.1 创建广播服务器","u":"/touchsocket/docs/udpbroadcast","h":"#31-创建广播服务器","p":837},{"i":851,"t":"UdpSession udpClient = new UdpSession(); udpClient.Setup(new TouchSocketConfig() .UseBroadcast()//该配置在发送广播时是必须的 .SetBindIPHost(new IPHost(7788)) .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) .Start(); udpClient.Send(new IPEndPoint(IPAddress.Parse(\"255.255.255.255\"), 7789), Encoding.UTF8.GetBytes(\"我是广播\")); 注意 在发送广播数据时,发送端配置UseBroadcast是必须的。","s":"3.2 发送广播数据","u":"/touchsocket/docs/udpbroadcast","h":"#32-发送广播数据","p":837},{"i":854,"t":"有很多小伙伴一直有一些需求: 客户端发送一个数据,然后等待服务器回应。 服务器向客户端发送一个数据,然后等待客户端回应。 那针对这些需求,可以使用WaitingClient。其内部实现了IWaitSender接口,能够在发送完成后,等待返回。","s":"一、说明","u":"/touchsocket/docs/waitingclient","h":"#一说明","p":852},{"i":857,"t":"TcpClient m_tcpClient = new TcpClient(); var config = new TouchSocketConfig(); config.SetRemoteIPHost(new IPHost(\"127.0.0.1:7789\")); //载入配置 m_tcpClient.Setup(config); m_tcpClient.Connect(); //调用GetWaitingClient获取到IWaitingClient的对象。 var waitClient = m_tcpClient.GetWaitingClient(new WaitingOptions() { AdapterFilter = AdapterFilter.AllAdapter,//表示发送和接收的数据都会经过适配器 BreakTrigger = true,//表示当连接断开时,会立即触发 ThrowBreakException = true//表示当连接断开时,是否触发异常 }); //然后使用SendThenReturn。 byte[] returnData = waitClient.SendThenReturn(Encoding.UTF8.GetBytes(\"RRQM\")); m_tcpClient.Logger.Info($\"收到回应消息:{Encoding.UTF8.GetString(returnData)}\"); //同时,如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时,可以使用SendThenResponse. ResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes(\"RRQM\")); IRequestInfo requestInfo = responsedData.RequestInfo;//同步收到的RequestInfo","s":"2.1 以TcpClient为例","u":"/touchsocket/docs/waitingclient","h":"#21-以tcpclient为例","p":852},{"i":859,"t":"var service = new TcpService(); service.Received = (client, byteBlock, requestInfo) => { //调用GetWaitingClient获取到IWaitingClient的对象。 var waitClient = client.GetWaitingClient(new WaitingOptions() { AdapterFilter = AdapterFilter.AllAdapter,//表示发送和接收的数据都会经过适配器 BreakTrigger = true,//表示当连接断开时,会立即触发 ThrowBreakException = true//表示当连接断开时,是否触发异常 }); //然后使用SendThenReturn。 byte[] returnData = waitClient.SendThenReturn(Encoding.UTF8.GetBytes(\"RRQM\")); client.Logger.Info($\"收到回应消息:{Encoding.UTF8.GetString(returnData)}\"); //同时,如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时,可以使用SendThenResponse. ResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes(\"RRQM\")); IRequestInfo responseRequestInfo = responsedData.RequestInfo;//同步收到的RequestInfo }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(\"tcp://127.0.0.1:7789\"), new IPHost(7790) })//同时监听两个地址 .ConfigureContainer(a =>//容器的配置顺序应该在最前面 { a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) }) .ConfigurePlugins(a => { //a.Add();//此处可以添加插件 })) .Start();//启动 提示 实际上上述行为,只要实现IClient, IDefaultSender, ISend三个接口的类均可以使用。 注意事项 发送完数据,在等待时,如果收到其他返回数据,则可能得到错误结果。 发送采用Lock锁,一个事务没结束,另一个请求也发不出去。","s":"2.2 以TcpService为例","u":"/touchsocket/docs/waitingclient","h":"#22-以tcpservice为例","p":852},{"i":862,"t":"WebApi是通用的RPC调用,与编程语言无关,与操作系统无关。其路由机制模仿AspNetCore,可实现很多路由机制。但是因为http兼容性错综复杂,所以目前TouchSocket的WebApi仅支持GET、POST函数。使用体验接近于AspNetCore。","s":"一、说明","u":"/touchsocket/docs/webapidescription","h":"#一说明","p":860},{"i":864,"t":"高性能,100个客户端,10w次调用,仅用时17s。 全异常反馈 。 支持大部分路由规则。 支持js、Android等调用。","s":"二、特点","u":"/touchsocket/docs/webapidescription","h":"#二特点","p":860},{"i":866,"t":"TouchSocket 框架升级/发版规则 升级前重点关注可能造成【破坏性】的标签类型: 修复、 调整、 移除、 升级 版本号规则:主版本号.次版本号.修订版本号 只要【确认】为框架 bug,则当天修复,当天发版,修订版本号 加 1。 如果 .csproj 文件有变更,则当天发版,修订版本号 加 1。 其余情况,每年发布一个 主版本。","s":"历史更新","u":"/touchsocket/docs/upgrade","h":"","p":865},{"i":868,"t":"更新日期:2023.2.2 更新描述:兼容性更新。 优化 TouchRpc支持命名元组。 修复 TouchRpc在调用WaitSend下失败的bug。 修复 TouchRpc在Handshaked时,调用Rpc超时bug。 修复 序列化、反射在unity中使用il2cpp编译的bug。 新增 ByteBlock对于int,long等数据,写入和读取的时候支持大小端指定。 新增 IServicePlugin插件,用于显示通知服务器的启动状态。 调整 将BytePool由静态调整为实例,且由其Default实例作为默认。","s":"v1.2.1","u":"/touchsocket/docs/upgrade","h":"#v121","p":865},{"i":870,"t":"更新日期:2023.1.13 更新描述:小版本升级,可能会有不兼容。请按下列提示修改。 优化 TouchRpc系文件传输时,文件夹不存在的提示。 优化 WaitingClient,当客户端断开连接时,可选是否抛出异常。 优化 Fast序列化时。可选序列化只读属性。 修复 多个不稳定Bug。 新增 Tcp客户端新增Disconnecting事件。在主动Close时生效。 调整 多个事件类名称修改,请按照提示修改即可。 移除 多个无用方法参数。","s":"v1.1.0","u":"/touchsocket/docs/upgrade","h":"#v110","p":865},{"i":872,"t":"更新日期:2023.1.1 更新描述:大版本升级,请详细阅读下列更新日志。 升级 将最高版本升级为NET7。 优化 Tcp系异步发送效率。 优化 TouchRpc系Channel的稳健性。 修复 多个不稳定Bug。 新增 ValueByteBlock,在简单代码块里面能有效减少创建的类。 新增 MemoryCache类,其功能类似微软官方。但是支持全部泛型。 新增 IPackage系。该系列能以超高效率的进行二进制序列化。 新增 SingleTimer类,不可重入的Timer。 新增 Jsonrpc支持自定义适配器解析(EE) 新增 严重TouchRpc系OnRouting通知,所有的客户端之间的通信,都必须经过OnRouting的筛查。 新增 TouchRpc系小文件传输,在文件小于1Mb时,其传输效率是常规传输的10倍以上。 新增 TouchRpc系超大文件多链路传输,支持多个客户端协同传输同一个文件,这在互联网环境中,效率比常规传输提高类3-5倍。 新增 TouchRpc系Redis组件,能实现双端共同存储。 调整 严重精简所有命名空间,删除所有三级命名空间。例如:TouchSocket.Core.ByteManager精简为TouchSocket.Core。 调整 严重删除Newtonsoft.Json的源代码嵌入。全局的Json会根据环境动态调整,详情见Json工具 调整 严重框架默认日志由ConsoleLogger,替换为EmptyLogger(不输出任何东西)。 调整 严重Tcp全系,在连接时,ID的初始值使用long类型从0递增。 调整 严重Tcp服务器,将定时清理无数据交互的选项替换为UseCheckClear插件。并且默认没有启用,需要手动加入。 调整 Tcp系适配器,取消部分参数。 调整 DataLock改名为DataSecurity。 调整 EasyAction改名EasyTask。 调整 IMessage改名IMessageObject。 调整 TokenInstance改名MessageInstance。 调整 TouchRpc系,精简常规文件传输操作。 调整 严重TouchRpc系,所有插件通知参数,默认都设为不允许操作,需要手动设置e.IsPermitOperation=true。 移除 Newtonsoft.Json的源代码嵌入。全局的Json会根据环境动态调整,详情见Json工具。 更新示例指南 (1)适配器参数报错:直接删除isAsync参数,以及isAsync为True的所有逻辑。 (2)依赖属性的声明报错:增加泛型约束即可,详情查看依赖属性 (3)服务端定时清理警告:在配置插件中使用UseCheckClear,并且进行相关配置。","s":"v1.0.0","u":"/touchsocket/docs/upgrade","h":"#v100","p":865},{"i":874,"t":"更新日期:2022.9.21 更新描述:兼容性更新,增强型更新。RPC内容需要客户端与服务器同步更新。 更新详情: 优化 Fast二进制序列化,支持自定义序列化。 TouchRpc全系,在文件传输等大型IO时,由于心跳失败而断开连接。 优化AspNetCore的IContainer。 TcpCommandLinePlugin与WSCommandLinePlugin支持获取客户端参数。 新增 插件实例会以单例注入容器。 所有适配器支持缓存超时设定。 修改所有事件为委托。 开放AspnetCore创建Tcp,Http等服务器的配置。 IClient增加发送、接收的最后时间记录。 Http支持多文件上传(目前仅支持小文件,具体大小以实际运行内存为准,实测100Mb没问题)。 Websocket插件默认会处理Close报文。且插件支持Close。 Rpc支持模板代码重写。 TouchRpc支持元组。 JsonRpc支持Websocket协议。 修改 IScopedContainer修改为IContainerProvider 修复 BytePool回收内存时不判断大小的bug。 删除 无。","s":"版本号: 0.7.0","u":"/touchsocket/docs/upgrade","h":"#版本号-070","p":865},{"i":876,"t":"更新日期:2022.9.10 更新描述:兼容性更新,增强型更新。专为Unity 3D适配。 更新详情: 优化 Gzip的压缩效率。 发送效率。 新增 IDataCompressor数据传输压缩接口。 RemoteStream支持数据读写压缩。 WaitResultPackageBase类,专属非序列化的数据格式化。 DelaySender延迟缓存发送。 修改 无 修复 Rpc注册服务为单例时,实际上是瞬时服务的bug。 删除 独立线程发送。","s":"版本号: 0.6.0","u":"/touchsocket/docs/upgrade","h":"#版本号-060","p":865},{"i":878,"t":"更新日期:2022.9.1 更新描述:兼容性更新,增强型更新。 更新详情: 优化 全局资源的获取逻辑。 新增 Container增加卸载注册功能。 FilePool新增FileStorageStream的获取。 http客户端(及websocket)支持代理和验证代理。 TouchRpc全系新增远程文件操作 TouchRpc(除udp)新增远程流访问 修改 无 修复 修复Http客户端请求重复Header时的bug。 删除 TouchRpc全系的事件操作,推荐直接插件的方式,或者使用TouchRpcActionPlugin然后添加委托。 更新示例 TouchRpc的相关事件均已使用插件代替。所以请使用插件实现操作。如果需要事件等功能的话,可以用TouchRpcActionPlugin的插件实现。例如: .UsePlugin() .ConfigurePlugins(a=> { a.Add>()//此处的逻辑可用插件替代完成。 .SetFileTransfering((client, e) => { //有可能是上传,也有可能是下载 client.Logger.Info($\"服务器请求传输文件,ID={client.ID},请求类型={e.TransferType},文件名={e.FileInfo.FileName}\"); }) .SetFileTransfered((client, e) => { //传输结束,但是不一定成功,需要从e.Result判断状态。 client.Logger.Info($\"服务器传输文件结束,ID={client.ID},请求类型={e.TransferType},文件名={e.FileInfo.FileName},请求状态={e.Result}\"); }); })","s":"版本号: 0.5.0","u":"/touchsocket/docs/upgrade","h":"#版本号-050","p":865},{"i":880,"t":"更新日期:2022.8.25 更新描述:兼容性更新,增强型更新。 更新详情: 优化 FileLogger的写入逻辑,大大地提升了写入效率。 新增 Pipeline适配器 TLV适配器 WaitingClient支持按条件等待返回。 日志系统可以筛选日志的输出类型 Rpc系统,可以使用单例、瞬时生命周期的服务。 Rpc系统,可定义持久化模型。 Rpc在使用瞬时生命周期的服务时,可以直接获取调用上下文。 XmlRpc增加调用上下文。 修改 日志系统。 Rpc的调用上下文均采用接口,例如:JsonRpc改为IJsonRpcCallContext,WebApi为IWebApiCallContext。 IRpcActionFilter的参数列表。 修复 UdpSession资源不释放的Bug。 删除 冗余元素。","s":"版本号: 0.4.5","u":"/touchsocket/docs/upgrade","h":"#版本号-045","p":865},{"i":882,"t":"更新日期:2022.8.12 更新描述:兼容性更新,增强型更新。 更新详情: 优化 各类客户端发送逻辑。 Method类的调用逻辑。 新增 适配器可以设定发送IRequestInfo对象。 插件新增UseWebSocket的快捷方式。 ReconnectionPlugin插件可以获得重连次数的重载设置。 【企业版】TcpService的服务注入。 【企业版】HttpService的服务注入。 【企业版】IOC容器的共享使用。 修改 各类发送逻辑,以最小化发送方法为基础,其余方法改为扩展方法。 相关接口的实现。 由网友修改GetInfo 修复 Container获取泛型失败bug。 BetweenAnd适配器适配器部分bug。 Router标签无法路由的bug。 修复TouchRpc推送文件状态不正确bug 修复独立线程在断线重连后发送bug。 删除 冗余的发送方法,不影响上版本任何使用。","s":"版本号: 0.3.5","u":"/touchsocket/docs/upgrade","h":"#版本号-035","p":865},{"i":884,"t":"更新日期:2022.7.28 更新描述:兼容性更新。 更新详情: 优化 优化IOC容器。 优化Metadata的写入方式。 FileLogger,当日志文件达到1Mb时,会再新增文件序号。 新增 Mapper类,支持简单类型映射 Tcp服务器、客户端、udp等增加端口复用配置。 【企业版】轮询式断线重连。 【企业版】NATService转发客户端重连。 修改 RRQM二进制序列化,改名为Fast。 TouchRpcClient连接时的Metadata,改为由Config配置注入。 FilePool,取消延迟释放机制。 修复 修复WebSocket连接问题 删除 客户端直接调用的短线重连方式。仅保留在Config注入的功能。","s":"版本号: 0.2.4","u":"/touchsocket/docs/upgrade","h":"#版本号-024","p":865},{"i":886,"t":"更新日期:2022.7.16 更新描述:初始化版本发布。由RRQMSocket迁移而来。 迁移指南:","s":"版本号: 0.1.0","u":"/touchsocket/docs/upgrade","h":"#版本号-010","p":865},{"i":889,"t":"原类型名称 新类型名称 RRQMBitConverter TouchSocketBitConverter RRQMConfig TouchSocketConfig RRQMConverter TouchSocketConverter RRQMDependencyObject DependencyObject MsgEventArgs MsgEventArgs RRQMEventAgrs TouchSocketEventArgs IServerProvider IRpcServer ServerProvider RpcServer RRQMOverlengthException OverlengthException","s":"2.类型名称修改","u":"/touchsocket/docs/upgrade","h":"#2类型名称修改","p":865},{"i":891,"t":"1)原RRQMConfig设置Logger的方法,改为容器注入: 断线重连逻辑 RpcStore使用变更 如果是仅有一个Rpc解析器,那么可以直接删除RpcStore的声明,从而使用对应的解析器实例,直接注册服务。然后可以通过其属性RpcStore,获取到具体的RpcStore实例。 如果是有多个解析器,那么,首先可以使用任意一个解析器的RpcStore属性实例,作为主RpcStore,然后添加其他解析器。当然也可以直接new RpcStore,然后统一管理解析器。其中构造函数中的Container容器,可以直接new Container(),但是更建议使用和解析器相同的容器,这样注入的服务会变得全局可用。","s":"3.使用逻辑修改","u":"/touchsocket/docs/upgrade","h":"#3使用逻辑修改","p":865},{"i":894,"t":"在服务器端中新建一个类,继承于RpcServer类(或实现IRpcServer),然后在该类中写公共方法,并用WebApi属性标签标记,如果方法有重载,需要重新指定函数键。 支持代理生成注释。 public class ApiServer : RpcServer { [Router(\"[api]/[action]ab\")]//此路由会以\"/Server/Sumab\"实现 [WebApi(HttpMethodType.GET)] public int Sum(int a, int b) { return a + b; } [WebApi(HttpMethodType.POST)] public int TestPost(MyClass myClass) { return myClass.A + myClass.B; } /// /// 使用调用上下文,响应文件下载。 /// /// [WebApi(HttpMethodType.GET, MethodFlags = MethodFlags.IncludeCallContext)] public Task DownloadFile(IWebApiCallContext callContext, string id) { if (id == \"rrqm\") { callContext.HttpContext.Response.FromFile(@\"D:\\System\\Windows.iso\", callContext.HttpContext.Request); return Task.FromResult(\"ok\"); } return Task.FromResult(\"id不正确。\"); } } public class MyClass { public int A { get; set; } public int B { get; set; } }","s":"定义服务","u":"/touchsocket/docs/webapiservice","h":"#定义服务","p":892},{"i":896,"t":"HttpService service = new HttpService(); service.Setup(new TouchSocketConfig() .UsePlugin() .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => { a.SetSingletonLogger();//注册一个日志 }) .ConfigureRpcStore(a => { a.RegisterServer();//注册服务 }) .ConfigurePlugins(a => { a.Add();//添加支持WebApi的插件。此处可能需要using TouchSocket.Core.Plugins; })) .Start(); Console.WriteLine(\"以下连接用于测试webApi\"); Console.WriteLine($\"使用:http://127.0.0.1:7789/ApiServer/Sum?a=10&b=20\"); Console.ReadKey();","s":"创建简单服务器","u":"/touchsocket/docs/webapiservice","h":"#创建简单服务器","p":892},{"i":899,"t":"网友“软件开发”","s":"定制方","u":"/touchsocket/docs/webdataforwarding","h":"#定制方","p":897},{"i":901,"t":"应该网友要求,需要实现Web端数据向Winform端转发的功能。","s":"说明","u":"/touchsocket/docs/webdataforwarding","h":"#说明","p":897},{"i":903,"t":"网络编程","s":"技术点","u":"/touchsocket/docs/webdataforwarding","h":"#技术点","p":897},{"i":906,"t":"定制方 凯**有限公司 说明 应该公司要求,开发以WPF为技术框架的桌面项目管理应用,其界面类似QQ(此处因为涉及UI版权,不展示实际效果)。并且以RRQMSocket为通信基础,解决项目文件的上传和下载。实际的解决了在2G网,甚至更差的网络环境下的大文件传输。 技术点 整体界面:圆角窗体、窗体阴影、最小化嵌入、拖拽效果等。 项目树视图:样式、搜索、定向搜索、搜索项定位、树视图连线。 数据同步:设置配置数据、项目文件数据等。","s":"WPF界面、文件传输项目","u":"/touchsocket/docs/wpfuifiletransfer","h":"","p":905},{"i":909,"t":"WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。","s":"产品介绍","u":"/touchsocket/docs/websocketdescription","h":"#产品介绍","p":907},{"i":911,"t":"简单易用。 多线程。 内存池 高性能 多种数据接收模式(IOCP,BIO,Select)。 多地址监听(可以一次性监听多个IP及端口)","s":"产品特点","u":"/touchsocket/docs/websocketdescription","h":"#产品特点","p":907},{"i":913,"t":"WebSocket基础使用场景:可跨平台、跨语言使用。 自定义协议解析场景:可解析任意数据格式的WebSocket数据报文。","s":"产品应用场景","u":"/touchsocket/docs/websocketdescription","h":"#产品应用场景","p":907},{"i":915,"t":"服务器运行挂载在HttpService上,所以架构和HttpService一致。","s":"服务器架构","u":"/touchsocket/docs/websocketdescription","h":"#服务器架构","p":907},{"i":917,"t":"XmlRpc是通用的工作在Internet上的RPC。一个XML-RPC消息就是一个请求体为xml的http-post请求,被调用的方法在服务器端执行并将执行结果以xml格式编码后返回。这与编程语言无关,与操作系统无关。在RRQM中封装了前后端,使其使用更加方便、高效。","s":"产品及架构介绍","u":"/touchsocket/docs/xmlrpcdescription","h":"","p":916},{"i":919,"t":"异常反馈 。 支持自定义类型。 支持类型嵌套。 支持Web等调用。","s":"特点:","u":"/touchsocket/docs/xmlrpcdescription","h":"#特点","p":916},{"i":921,"t":"XmlRpc示例","s":"示例代码","u":"/touchsocket/docs/xmlrpcdescription","h":"#示例代码","p":916},{"i":925,"t":"WSCommandLinePlugin命令行执行插件,是用于WebSocket的快捷事务实现,让WS在Text文本中,用最简单的文字消息即可完成相关事务的执行。该类是抽象类,必须通过继承,在继承类中,声明的具的公共的且名称以Command结尾的方法,均可被快捷执行。 例如:下列插件,即可被普通WS客户端,或服务器便捷调用。 调用数据格式: Add 10 20支持Json数据格式 var service = new HttpService(); var config = new TouchSocketConfig(); config.UsePlugin() .SetReceiveType(ReceiveType.Auto) .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a=> { a.SetSingletonLogger(); }) .ConfigurePlugins(a=> { a.Add();//添加WebSocket功能 a.Add();//添加WS命令行事务。 }); service.Setup(config) .Start(); service.Logger.Message(\"Http服务器已启动\"); service.Logger.Message(\"WS访问:ws://127.0.0.1:7789/ws\"); /// /// 命令行插件。 /// 声明的方法必须以\"Command\"结尾,支持json字符串,参数之间空格隔开。 /// class MyWSCommandLinePlugin : WSCommandLinePlugin { public int AddCommand(int a, int b) { return a + b; } public SumClass SumCommand(SumClass sumClass) { sumClass.Sum = sumClass.A + sumClass.B; return sumClass; } } class SumClass { public int A { get; set; } public int B { get; set; } public int Sum { get; set; } }","s":"命令行执行插件客户端、服务器均支持","u":"/touchsocket/docs/wscommandlineplugin","h":"#命令行执行插件客户端服务器均支持","p":923},{"i":928,"t":"在服务器端中新建一个类,继承于ServerProvider类(或实现IServerProvider),然后在该类中写公共方法,并用XmlRpc属性标签标记,如果方法有重载,需要重新指定函数键。 支持代理生成注释。 public class Server : ServerProvider { [XmlRpc] public int Sum(int a, int b) { return a + b; } [XmlRpc] public int TestClass(MyClass myClass) { return myClass.A + myClass.B; } } public class MyClass { public int A { get; set; } public int B { get; set; } }","s":"定义服务","u":"/touchsocket/docs/xmlrpcservice","h":"#定义服务","p":926},{"i":930,"t":"服务解析器是实际的服务接收、触发、调用、反馈的实际载体,通俗来说就是通信服务器。 static IRpcParser CreateXmlRpcRpcParser() { HttpService service = new HttpService(); service.Setup(new RRQMConfig().UsePlugin() .SetListenIPHosts(new IPHost[] { new IPHost(7706) })) .Start(); return service.AddPlugin() .SetProxyToken(\"RPC\") .SetXmlRpcUrl(\"/xmlRpc\"); }","s":"创建服务解析器","u":"/touchsocket/docs/xmlrpcservice","h":"#创建服务解析器","p":926},{"i":932,"t":"添加解析器(添加时需要以键、值方式添加,方便后续查找),然后注册服务即可。 static void Main(string[] args) { RpcService rpcService = new RpcService(); //添加解析器,解析器根据传输协议,序列化方式的不同,调用RPC服务 rpcService.AddRpcParser(\"xmlRpcParser \", CreateXmlRpcRpcParser()); //注册当前程序集的所有服务 rpcService.RegisterAllServer(); //分享代理,代理文件可通过RRQMTool远程获取。 rpcService.ShareProxy(new IPHost(8848)); //或者直接本地导出代理文件。 //RpcProxyInfo proxyInfo = rpcService.GetProxyInfo(RpcType.RRQMRPC, \"RPC\"); //string codeString = CodeGenerator.ConvertToCode(\"RRQMProxy\", proxyInfo.Codes); Console.WriteLine(\"服务器已启动\"); Console.ReadKey(); }","s":"注册、发布服务","u":"/touchsocket/docs/xmlrpcservice","h":"#注册发布服务","p":926},{"i":935,"t":"TouchSocketPro是TouchSocket系的加强版本。其基础功能完全包含TouchSocket,除此之外,还有一些附加功能,这需要付费购买密钥,然后才能使用。具体详细区别如下表格所示。 同时TouchSocketPro还提供企业定制服务及必要的远程协助,具体收费可以咨询作者若汝棋茗,联系方式:QQ:505554090。","s":"一、说明","u":"/touchsocket/docs/enterprise","h":"#一说明","p":933},{"i":938,"t":"轮询式断线重连 企业版 TLV适配器 企业版 其余功能","s":"2.1 Tcp组件","u":"/touchsocket/docs/enterprise","h":"#21-tcp组件","p":933},{"i":940,"t":"转发客户端重连 企业版 其余功能","s":"2.2 NAT组件","u":"/touchsocket/docs/enterprise","h":"#22-nat组件","p":933},{"i":942,"t":"所有功能","s":"2.3 UDP组件","u":"/touchsocket/docs/enterprise","h":"#23-udp组件","p":933},{"i":944,"t":"自定义解析 企业版 其余功能","s":"2.4 JsonRpc","u":"/touchsocket/docs/enterprise","h":"#24-jsonrpc","p":933},{"i":946,"t":"所有功能","s":"2.5 WebApi","u":"/touchsocket/docs/enterprise","h":"#25-webapi","p":933},{"i":948,"t":"所有功能","s":"2.6 XmlRpc","u":"/touchsocket/docs/enterprise","h":"#26-xmlrpc","p":933},{"i":950,"t":"远程文件操作 企业版 远程流访问 企业版 文件传输功能 多线程文件传输 企业版 小文件传输 文件传输限速 企业版 EventBus功能 企业版 Redis","s":"2.7 TouchRpc(tcp、udp、http、websocket)","u":"/touchsocket/docs/enterprise","h":"#27-touchrpctcpudphttpwebsocket","p":933},{"i":952,"t":"超大文件传输 多通道文件续传 静态网页展示 文件传输限速","s":"2.8 Http组件","u":"/touchsocket/docs/enterprise","h":"#28-http组件","p":933},{"i":954,"t":"全部功能 提示 上述的功能中,所有带有 企业版 的标识,均为TouchSocketPro包含的内容。其余功能TouchSocket也均支持。","s":"WebSocket","u":"/touchsocket/docs/enterprise","h":"#websocket","p":933},{"i":957,"t":"在TouchSocketPro中,可以通过适配器对数据进行预处理和对象解析,目前TouchSocketPro拥有的适配器仅有固定包头、固定长度、终止分割、Json字符串解析、Http对象解析五种适配器。但是往往这些适配器不是我们想要的,例如:串口信号、AGV数据格式等。那么我们可以为您提供解析数据格式(对象)的服务。","s":"3.1 数据处理适配器的重写","u":"/touchsocket/docs/enterprise","h":"#31-数据处理适配器的重写","p":933},{"i":959,"t":"程序库为的是能提供基础服务,所以某个功能的出现,均是为了具备更好的普适性,但是有时候也会与您的需求背道而驰,那么我们也可以为您定制某个功能(或禁用某个功能)。","s":"3.2 增加或限制某个功能","u":"/touchsocket/docs/enterprise","h":"#32-增加或限制某个功能","p":933},{"i":961,"t":"类型 个人独立授权 个人企业授权 企业授权 功能 全部功能 全部功能 全部功能 使用期限 永久 永久 永久 授权归属 个人 个人 企业 协助服务 无 无 全部现有功能协助 个性化功能扩展 支持 支持 支持 激活方式 密钥激活 密钥激活 密钥激活和源码引用 后续升级 Nuget升级 Nuget升级 Nuget升级或随时索要最新源码 源代码开放 不开放 不开放 开放 用于盈利 允许 允许 允许 个性化功能扩展 支持 支持 支持 开具发票 原则上不开具 开具 开具 赠品 送您1束玫瑰 送您2束玫瑰 送您3束玫瑰,和一个自定义适配器,或复杂度相同的个性化服务。 价格 298¥ 已停售 998¥","s":"四、TouchSocketPro","u":"/touchsocket/docs/enterprise","h":"#四touchsocketpro","p":933},{"i":963,"t":"授权归属于购买者个人所有,规定购买者可将所购产品只能应用于所属个人的任何软件(产品)上,可以以此盈利,但必须遵守个人使用协议。","s":"4.1 个人独立授权","u":"/touchsocket/docs/enterprise","h":"#41-个人独立授权","p":933},{"i":965,"t":"授权归属于购买者个人所有,规定购买者可将所购产品应用于购买者服务(工作)的企业的任何软件(产品)上,但授权期限与购买者服务(工作)期限一致,一旦购买者离职(或不再服务于企业),授权将在30个工作日后失效。同时,购买者在将所购产品应用于企业时,有必要告知义务,在离职(或不再服务于企业)时,也应当再次告知企业详情。 (个人企业版在2023.1.1日后不再售卖。已售卖的个人企业版原始功能不变。或者联系作者,可免费升级至企业版)","s":"4.2 个人企业授权","u":"/touchsocket/docs/enterprise","h":"#42-个人企业授权","p":933},{"i":967,"t":"当授权归属于企业所有时,永久授权。且仅企业享有授权,所有职员均无授权。 当授权归属个人所有时,永久授权。且保留一次企业冠名权益,现有授权自动降为“个人企业授权”条款。。","s":"4.3 企业授权","u":"/touchsocket/docs/enterprise","h":"#43-企业授权","p":933},{"i":969,"t":"首先请确保所有的项目完全卸载删除TouchSocket,并且在需要的项目中安装了TouchSocketPro。 当购买密钥后,您会获得类似“D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1”这样的密钥。然后在程序初始化(例如Main函数)时。使用以下代码即可。 Enterprise.Default.LicenceKey = \"密钥\"; AspNetCore中使用时,建议自定义服务注入的方式实现。步骤如下: 新建项目,引用Microsoft.Extensions.DependencyInjection和TouchSocketPro.AspNetCore。 新建静态类ServiceCollectionExtension,创建IServiceCollection的扩展方法。 在IServiceCollection的扩展方法中,注入密钥。 在AspNetCore引用新建的项目。 在服务中注入。 部分代码示例如下: public static class ServiceCollectionExtension { public static void AddLicence(this IServiceCollection service) { Enterprise.Default.LicenceKey = \"D1D1D1D1D1D1D1\"; } } public void ConfigureServices(IServiceCollection services) { services.AddLicence(); }","s":"五、密钥使用","u":"/touchsocket/docs/enterprise","h":"#五密钥使用","p":933},{"i":971,"t":"为方便大家测试,TouchSocketPro提供限时1小时的测试功能,当时间结束时企业版功能关闭,重启进程即可再次试用1小时,以此往复。 调用ForTest时,会抛出可控异常。如果坚持使用企业版,使用Try拦截即可。 try { Enterprise.ForTest(); } catch (Exception ex) { Console.WriteLine(ex.Message); }","s":"六、限时测试","u":"/touchsocket/docs/enterprise","h":"#六限时测试","p":933},{"i":973,"t":"购买可通过以下方式。购买前请先联系作者若汝棋茗。联系QQ:505554090。 扫描下列微信码,或者点击淘宝链接。","s":"七、购买通道","u":"/touchsocket/docs/enterprise","h":"#七购买通道","p":933},{"i":976,"t":"正常数据处理适配器就是处理普通的TCP报文,内部不进行任何数据处理,这也就意味着它并不能解决粘、分包的问题,它只是能够将数据进行接收和处理而已。","s":"一、说明","u":"/touchsocket/docs/normaldatahandlingadapter","h":"#一说明","p":974},{"i":978,"t":"能够接收所有TCP报文,与语言、框架无关。 相当于加强版的Socket,但是数据发送与接收是完全一致的。","s":"二、特点","u":"/touchsocket/docs/normaldatahandlingadapter","h":"#二特点","p":974},{"i":980,"t":"步骤 TouchSocketConfig配置中设置 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。 TcpService service = new TcpService(); service.Received += (client, byteBlock, requestInfo) => { //从客户端收到信息 string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) .SetDataHandlingAdapter(()=> { return new NormalDataHandlingAdapter(); }))//配置适配器 .Start();//启动 提示 该适配器,客户端与服务器均适用。","s":"三、使用","u":"/touchsocket/docs/normaldatahandlingadapter","h":"#三使用","p":974}],"index":{"version":"2.3.9","fields":["t"],"fieldVectors":[["t/3",[0,8.454,1,7.19,2,4.627,3,5.55,4,6.515,5,1.745,6,7.692,7,5.866,8,10.075,9,8.454,10,3.149,11,5.175,12,3.395]],["t/5",[13,2.632,14,6.294,15,6.116,16,6.116,17,6.116,18,7.13,19,7.13,20,4.567,21,3.125,22,5.747,23,6.064,24,3.779,25,4.365,26,4.681,27,6.064,28,7.13,29,7.13,30,2.808,31,1.929,32,6.487,33,3.441,34,5.285,35,5.747,36,5.747,37,6.487,38,3.148,39,6.064,40,6.487,41,6.487,42,1.257]],["t/7",[5,1.668,20,3.83,21,2.06,36,4.821,42,1.054,43,6.874,44,8.083,45,6.874,46,7.4,47,4.433,48,5.981,49,4.609,50,1.676,51,8.083,52,5.489,53,3.22,54,4.821,55,5.981,56,5.981,57,5.086,58,5.981,59,3.933,60,3.122,61,5.981,62,5.441,63,5.981,64,2.476,65,3.273,66,5.981,67,5.981,68,8.083,69,2.248,70,4.149,71,5.981,72,3.586,73,5.086,74,3.17,75,6.229,76,3.694,77,5.981,78,4.032,79,5.981,80,1.395,81,5.981,82,5.441]],["t/10",[14,5.018,21,2.492,24,5.323,25,6.148,42,1.275,46,4.876,83,8.541,84,3.18,85,6.151,86,6.151,87,6.151,88,5.018,89,6.151,90,5.83,91,6.151,92,2.492,93,6.151,94,6.151,95,2.934,96,4.876,97,4.876,98,2.718,99,4.633,100,6.151,101,5.574,102,5.018,103,6.151]],["t/12",[7,5.433,13,2.107,14,6.673,21,2.697,24,4.737,25,5.471,26,3.747,40,7.124,46,3.848,83,7.601,84,3.105,85,4.854,86,4.854,87,4.854,88,3.96,89,4.854,90,4.601,91,4.854,92,2.697,93,4.854,94,4.854,95,3.176,96,3.848,97,3.848,98,3.359,99,3.656,100,4.854,102,3.96,103,4.854,104,3.496,105,8.938,106,5.708,107,5.193,108,3.96,109,5.708,110,3.848,111,5.708,112,5.708,113,3.073,114,2.549,115,3.494,116,3.848,117,1.28,118,4.601,119,5.193,120,5.708,121,4.086,122,5.193,123,4.399,124,4.399]],["t/14",[14,4.81,21,2.388,24,5.218,25,6.027,42,1.222,46,4.674,83,8.373,84,3.095,85,5.896,86,5.896,87,5.896,88,4.81,89,5.896,90,5.588,91,5.896,92,2.388,93,5.896,94,5.896,95,2.812,96,4.674,97,4.674,98,3.348,99,4.44,100,5.896,102,4.81,103,5.896,125,3.674,126,6.933,127,5.588,128,6.308,129,1.628,130,6.933]],["t/16",[13,3.682,14,5.768,15,5.605,16,5.605,17,5.605,21,3.436,22,6.702,23,7.071,131,5.458,132,4.795,133,4.795,134,6.407,135,3.042,136,4.709]],["t/18",[15,4.984,16,4.984,17,4.984,24,3.919,25,4.526,26,4.854,27,6.288,32,6.727,33,2.804,36,5.96,41,6.727,42,1.788,131,4.854,137,6.727,138,7.393,139,5.165,140,6.727,141,6.727,142,8.444,143,7.481,144,6.727,145,3.597,146,4.346,147,6.288,148,7.393,149,2.132]],["t/20",[13,2.855,21,2.665,24,5.06,25,5.844,42,1.683,64,3.202,121,6.834,131,5.079,139,4.305,140,7.038,150,5.079,151,3.979,152,3.415,153,7.736,154,8.686,155,7.736,156,7.736,157,4.165,158,7.038,159,5.962]],["t/23",[24,4.407,25,5.089,135,3.042,160,5.768,161,8.314,162,7.071,163,5.952,164,8.314,165,4.887,166,3.8,167,5.952,168,7.564,169,4.045,170,7.564,171,6.162,172,8.314]],["t/25",[5,1.063,42,0.908,117,1.635,125,2.73,165,3.027,166,3.331,173,2.382,174,4.38,175,1.464,176,6.631,177,2.249,178,1.637,179,3.298,180,8.459,181,3.472,182,3.573,183,1.541,184,2.964,185,1.717,186,7.289,187,4.383,188,4.255,189,5.515,190,2.79,191,8.369,192,2.068,193,3.573,194,3.027,195,3.5,196,3.573,197,10.585,198,2.382,199,1.541,200,2.917,201,2.3,202,1.119,203,4.38,204,3.088,205,3.027,206,2.282,207,4.686,208,3.573,209,4.056,210,4.561,211,3.431,212,5.402,213,6.631,214,3.687]],["t/28",[5,1.753,13,2.378,84,2.238,129,1.513,152,2.844,198,2.98,215,2.765,216,5.861,217,5.861,218,6.239,219,3.266,220,4.47,221,2.945,222,2.562,223,2.165,224,2.295,225,6.442,226,3.715,227,5.861,228,6.442,229,6.546,230,4.731,231,2.844,232,6.442,233,2.945,234,6.442,235,3.862,236,5.479,237,4.229,238,4.775,239,4.47,240,5.479,241,3.715,242,5.861,243,4.031,244,6.442,245,5.861,246,4.965,247,2.844]],["t/32",[13,2.49,50,1.891,80,1.574,84,3.041,114,3.909,178,2.145,215,2.849,219,3.42,224,2.124,233,3.083,248,4.829,249,5.737,250,5.199,251,2.49,252,2.978,253,3.901,254,4.548,255,3.692,256,4.13,257,2.913,258,5.232,259,3.326,260,5,261,6.081,262,2.736,263,5.438,264,5.737,265,4.713,266,2.425,267,2.945,268,4.68]],["t/34",[13,1.79,38,2.142,52,2.908,57,4.125,80,1.629,104,2.166,199,2.089,204,4.187,205,4.105,206,1.519,215,3.088,219,3.54,224,1.06,230,3.27,241,2.798,243,5.12,245,4.413,249,4.125,253,1.84,255,2.655,256,2.969,257,3.016,258,2.612,261,5.12,262,3.319,269,3.107,270,2.3,271,4.851,272,4.125,273,4.37,274,2.908,275,3.595,276,4.851,277,3.27,278,3.738,279,3.595,280,2.851,281,3.91,282,4.413,283,3.738,284,2.612,285,4.413,286,3.91,287,4.413,288,3.27,289,3.27,290,6.984,291,4.845,292,2.612,293,5.629,294,3.353,295,2.291,296,4.187,297,3.645,298,4.851,299,4.473,300,2.908,301,4.125,302,2.244,303,4.413,304,2.747,305,3.473,306,2.747,307,2.908,308,2.272,309,3.738,310,4.585,311,2.908,312,3.887,313,3.107,314,1.892,315,3.595,316,3.91]],["t/36",[3,5.159,13,2.9,42,1.838,50,2.202,129,1.845,136,4.45,215,3.137,243,4.917,251,2.9,317,4.917,318,6.055,319,6.334,320,5.452,321,4.532,322,4.373,323,2.351,324,5.824,325,3.356,326,1.751,327,1.809]],["t/38",[42,1.478,117,1.881,190,3.209,202,1.821,328,4.134,329,2.75,330,5.504,331,5.246,332,4.666,333,5.652,334,7.13,335,3.122,336,6.461,337,4.666,338,7.628]],["t/40",[129,1.595,149,1.959,152,2.999,169,3.305,183,2.032,184,2.379,185,2.264,194,3.992,199,2.032,202,1.475,221,4.019,224,1.485,332,4.893,337,4.893,339,6.764,340,3.443,341,2.246,342,2.176,343,1.89,344,2.228,345,6.792,346,3.349,347,6.776,348,3.068,349,2.933,350,2.529,351,4.744,352,5.776,353,3.972,354,5.234,355,6.792,356,4.579,357,4.712,358,3.545]],["t/42",[30,2.849,42,1.275,74,3.834,135,2.646,175,2.056,185,2.411,198,3.346,202,1.571,295,2.373,335,2.694,337,4.026,339,6.351,342,3.218,348,3.267,349,3.123,350,2.694,352,6.151,353,4.135,354,5.574,358,3.776,359,3.262,360,3.776,361,4.428,362,3.123,363,6.151,364,5.178,365,5.83,366,5.178,367,5.178]],["t/44",[5,2.243,30,3.095,129,1.845,198,3.635,215,3.137,241,4.532,289,6.498,314,3.76,332,5.364,360,4.101,368,4.041,369,7.857,370,5.625,371,5.452,372,6.682,373,4.3]],["t/46",[38,2.239,42,0.894,59,2.468,80,2.251,117,1.138,129,1.191,190,1.942,195,2.436,201,2.265,202,2.178,215,3.491,256,5.135,266,2.592,328,2.501,329,1.664,332,2.823,340,2.571,359,1.808,362,2.19,374,2.776,375,3.909,376,4.733,377,5.072,378,3.519,379,1.747,380,1.705,381,3.248,382,1.889,383,5.072,384,3.519,385,3.759,386,3.759,387,2.688,388,3.759,389,4.088,390,4.615,391,4.313,392,3.759,393,2.078,394,2.318,395,3.519,396,3.248,397,3.174,398,2.535,399,4.088,400,3.519,401,2.501,402,3.015,403,4.238,404,3.174,405,3.248,406,3.33,407,3.248,408,2.609,409,3.759,410,5.072,411,5.072,412,4.615,413,2.535,414,2.468,415,3.631,416,4.615,417,3.909,418,2.535,419,3.631,420,4.615,421,3.631,422,2.648,423,2.776]],["t/48",[5,1.33,42,1.497,50,1.805,114,3.793,157,3.469,160,4.47,175,1.831,178,2.048,184,2.976,185,2.148,215,2.097,226,4.899,262,2.613,267,2.813,322,3.585,326,1.436,332,5.289,347,4.965,349,2.782,350,2.399,351,3.135,370,6.081,373,3.525,424,4.612,425,2.667,426,4.775,427,4.899,428,5.479,429,3.177,430,4.434,431,6.442,432,6.442,433,3.266,434,6.442,435,3.266,436,3.715,437,6.442,438,4.965,439,7.728,440,6.442,441,3.862]],["t/50",[21,1.671,50,1.957,59,2.36,60,2.532,80,1.629,98,1.823,104,3.118,117,2.008,145,2.36,163,5,178,1.542,201,3.118,215,1.579,222,3.56,223,3.422,224,1.789,266,2.942,270,2.3,274,2.908,306,2.747,314,1.892,320,3.366,398,2.425,402,3.218,407,3.107,435,2.459,442,3.185,443,8.183,444,4.851,445,4.851,446,4.851,447,3.366,448,4.125,449,3.035,450,2.851,451,4.851,452,4.851,453,5.939,454,3.444,455,4.851,456,3.738,457,4.125,458,4.413,459,3.595,460,6.182,461,5.009,462,4.413,463,3.91,464,4.851,465,2.008,466,4.851,467,3.491,468,2.969,469,4.851,470,4.028,471,4.851,472,3.185,473,2.851,474,1.911,475,2.969,476,3.473,477,4.125,478,2.655,479,4.851,480,2.908]],["t/53",[5,1.493,80,1.687,175,2.056,215,2.354,221,3.306,224,2.195,284,4.929,288,4.876,295,2.373,306,4.097,335,2.694,422,5.51,423,5.776,481,5.574,482,6.581,483,3.834,484,5.361,485,6.581,486,7.233,487,3.667,488,6.581,489,5.361,490,5.018,491,7.233,492,5.361]],["t/55",[5,2.249,33,3.673,134,6.103,223,2.662,224,2.383,259,3.905,291,5.495,370,5.67,408,4.073,493,5.495,494,5.495,495,4.567,496,6.384,497,7.205,498,7.92]],["t/57",[5,0.505,11,1.497,31,0.662,42,0.929,53,2.202,59,1.19,64,1.693,80,0.954,84,1.421,95,1.659,114,1.092,117,1.182,125,2.167,129,1.446,145,1.99,151,1.258,166,1.869,169,1.99,173,3.169,175,2.235,177,1.785,178,1.958,183,1.577,184,2.4,185,1.363,187,2.116,190,2.357,192,1.642,199,0.732,202,1.708,204,2.452,205,2.404,206,0.766,215,2.23,221,1.869,223,2.07,224,1.719,230,1.915,233,1.118,253,1.551,265,1.317,267,1.785,268,1.697,270,1.16,280,1.438,284,1.317,295,0.802,297,1.277,310,4.043,312,1.361,326,1.174,327,0.941,329,1.729,332,2.933,337,1.361,342,0.784,346,2.016,348,1.105,349,1.766,350,0.911,359,0.872,360,2.751,371,1.697,379,0.843,380,1.374,382,1.523,393,1.002,394,1.118,401,1.206,402,0.879,414,1.19,421,1.751,422,2.751,423,2.884,425,1.012,430,3.215,433,2.073,465,2.181,474,2.075,478,1.339,481,1.885,499,1.317,500,3.692,501,2.273,502,5.27,503,2.135,504,1.697,505,1.649,506,1.751,507,1.385,508,3.151,509,2.446,510,1.466,511,1.138,512,2.135,513,1.885,514,0.822,515,2.671,516,2.75,517,1.606,518,1.751,519,1.497,520,1.105,521,7.5,522,1.438,523,3.151,524,1.339,525,3.906,526,3.296,527,2.928,528,1.751,529,1.361,530,3.478,531,1.092,532,1.438,533,2.446,534,1.972,535,1.697,536,1.697,537,1.972,538,1.728,539,2.225,540,2.225,541,2.446,542,1.676,543,2.044,544,1.649,545,2.016,546,1.606,547,1.813,548,2.08,549,2.837,550,1.751,551,1.751,552,2.225,553,2.503,554,1.567,555,1.606,556,2.446,557,2.446,558,1.223,559,2.446,560,1.697,561,2.08,562,5.27,563,4.089,564,3.151,565,1.885,566,1.092,567,1.531,568,1.813,569,2.096,570,1.317,571,3.553,572,0.857,573,1.206,574,1.206,575,1.339,576,1.317,577,1.056,578,1.361,579,1.105,580,1.145,581,1.277,582,0.887]],["t/60",[31,2.245,42,1.462,65,2.721,187,2.854,190,1.903,199,2.865,202,1.08,210,4.448,211,2.883,294,2.912,325,2.124,340,2.52,341,1.644,342,2.277,343,2.519,344,1.631,350,1.851,379,1.713,511,1.978,558,2.485,572,1.742,583,2.272,584,3.449,585,2.101,586,3.559,587,4.261,588,3.685,589,3.352,590,1.921,591,6.467,592,7.108,593,3.264,594,5.088,595,3.264,596,3.449,597,3.582,598,3.069,599,2.922,600,4.007,601,7.548,602,7.297,603,2.101,604,3.685,605,3.449,606,2.388,607,2.079,608,2.922,609,3.449,610,3.685,611,4.228,612,7.108,613,7.108,614,6.38,615,6.481,616,9.053]],["t/62",[69,3.049,78,5.469,80,1.892,206,2.539,257,3.503,343,2.735,362,3.503,583,4.492,617,5.807,618,6.539,619,6.539,620,6.539,621,5.195,622,5.469,623,5.469,624,6.539,625,5.807]],["t/64",[10,3.439,12,3.708,146,5.427,583,4.221]],["t/66",[10,2.734,12,2.09,21,1.793,31,1.986,50,1.458,80,1.214,129,1.997,149,1.501,183,1.557,187,2.09,190,1.992,199,1.557,202,1.595,210,3.256,211,2.111,255,2.848,266,1.871,294,2.132,326,1.16,327,1.959,340,2.638,341,1.721,342,2.352,343,2.043,350,1.938,379,1.793,501,2.71,511,1.448,558,2.601,572,1.823,583,4.622,587,4.402,588,3.857,589,3.508,590,2.011,591,6.68,594,3.725,597,3.674,598,3.17,599,3.059,600,4.195,601,7.74,602,7.449,603,2.199,604,3.857,605,3.61,606,2.499,607,2.176,626,4.018,627,4.425,628,4.01,629,2.896,630,3.001,631,4.425,632,3.12,633,3.61,634,7.121,635,7.342]],["t/69",[13,1.618,31,2.464,42,1.361,65,2.399,98,1.648,117,0.983,175,1.246,181,2.955,187,3.427,189,4.629,190,1.678,199,2.31,202,1.409,210,4.831,211,3.132,241,2.528,265,3.492,266,2.332,294,1.796,302,2.028,308,3.615,327,1.009,340,2.222,341,2.145,342,3.161,343,2.534,344,1.438,379,1.51,401,2.162,436,2.528,507,2.483,511,2.148,532,2.577,583,2.004,584,3.042,585,1.853,586,3.138,587,2.628,590,1.694,593,4.258,594,4.643,597,3.334,598,3.334,599,3.812,603,2.741,606,3.708,609,5.92,636,3.988,637,5.527,638,2.53,639,6.566,640,3.249,641,4.643,642,4.384,643,3.988,644,3.115,645,4.384,646,2.743,647,7.72,648,6.486,649,6.486,650,6.486,651,3.728,652,3.138]],["t/71",[69,3.049,78,5.469,80,1.892,206,2.539,257,3.503,343,2.735,362,3.503,583,4.492,617,5.807,618,6.539,619,6.539,620,6.539,621,5.195,622,5.469,623,5.469,624,6.539,625,5.807]],["t/73",[10,3.439,12,3.708,146,5.427,583,4.221]],["t/75",[10,3.15,12,2.571,21,2.205,50,1.794,80,1.493,129,2.224,149,1.846,183,1.915,187,2.571,189,3.838,199,1.915,202,1.39,210,4.005,211,2.596,255,3.503,266,2.301,326,1.427,327,2.181,342,2.051,343,2.354,501,3.122,583,4.92,597,2.764,598,2.764,599,3.762,606,3.074,607,2.677,626,4.629,627,5.444,628,4.933,629,3.562,630,3.692,631,5.444,632,3.838,633,4.441,651,5.444,652,4.583,653,8.458]],["t/78",[2,4.656,5,1.074,27,4.425,30,3.351,31,2.302,33,3.942,42,0.917,117,1.908,199,2.915,206,1.629,215,1.694,251,2.71,257,2.247,292,3.953,294,3.008,295,1.707,325,2.223,326,1.16,343,2.712,344,2.409,362,2.247,467,2.601,511,2.367,531,2.324,608,4.315,609,3.61,614,5.449,637,3.725,654,6.067,655,4.195,656,2.802,657,2.947,658,4.01,659,3.12,660,7.859,661,3.185,662,3.333,663,3.059,664,3.61,665,5.204,666,3.333,667,3.185,668,3.61,669,6.858,670,3.889,671,4.425,672,5.204]],["t/80",[2,2.951,13,2.575,31,2.037,33,2.045,42,0.741,65,1.382,80,0.589,188,4.012,189,3.233,199,1.257,202,1.943,211,2.187,247,1.115,251,2.779,292,4.296,294,2.858,299,2.69,302,1.169,327,0.582,337,1.406,340,2.734,341,2.078,343,0.703,350,0.941,379,1.858,380,1.812,511,2.095,558,4.471,572,2.795,583,1.155,584,1.753,585,1.068,586,1.808,587,1.515,593,4.942,595,4.942,596,5.223,597,4.132,598,4.132,599,5.258,602,8.681,603,2.279,604,3.114,606,2.59,634,5.376,637,1.808,654,2.758,666,1.618,667,1.546,669,4.347,673,1.753,674,2.148,675,2.773,676,2.298,677,5.392,678,4.906,679,5.51,680,5.392,681,3.822,682,3.822,683,8.353,684,7.318,685,3.861,686,3.54,687,6.849,688,4.906,689,2.526,690,1.753,691,2.036]],["t/82",[69,3.049,78,5.469,80,1.892,206,2.539,257,3.503,343,2.735,362,3.503,583,4.492,617,5.807,618,6.539,619,6.539,620,6.539,621,5.195,622,5.469,623,5.469,624,6.539,625,5.807]],["t/84",[10,3.439,12,3.708,146,5.427,583,4.221]],["t/86",[10,3.205,12,2.993,13,1.961,21,1.831,31,2.016,50,1.489,80,1.24,129,2.02,146,3.124,149,2.69,183,1.59,199,1.59,202,1.618,255,2.908,266,1.91,294,3.053,326,1.184,327,1.981,340,2.694,343,2.073,379,1.831,501,3.176,511,1.479,546,3.489,583,4.877,602,8.207,603,2.246,604,3.939,607,2.223,626,4.078,627,4.519,628,4.095,629,4.147,630,3.065,631,4.519,632,3.186,633,3.687,634,7.569,654,3.489,669,4.284,678,4.835,692,5.314,693,4.789,694,4.835,695,3.804,696,4.835,697,4.095,698,5.314]],["t/89",[13,3.094,50,2.35,175,2.383,218,5.504,231,3.701,247,3.701,699,6.758,700,7.13,701,5.504,702,6.002,703,5.504,704,6.758,705,5.652,706,5.504]],["t/91",[12,2.279,21,1.955,52,3.403,64,2.349,95,2.302,151,2.919,183,1.698,188,4.122,192,2.279,202,1.233,257,2.451,327,1.307,398,2.837,402,2.04,414,2.762,474,2.235,531,3.979,583,3.565,597,3.368,598,2.451,621,3.635,700,8.554,707,10.128,708,7.799,709,7.799,710,7.799,711,7.096,712,5.164,713,3.826,714,4.063,715,8.108,716,8.911,717,8.911,718,5.676,719,7.096,720,5.676,721,5.676,722,5.676,723,5.164,724,3.826,725,4.575,726,4.575]],["t/94",[2,4.404,7,5.583,15,5.425,16,5.425,17,5.425,20,5.154,123,6.201,145,3.915,146,4.73,147,6.843,514,2.704,727,8.047,728,6.201,729,8.047,730,5.964,731,7.321,732,8.047,733,7.321,734,6.843,735,8.047]],["t/97",[294,4.234,308,4.134,327,2.032,501,3.258,640,6.542,736,6.319,737,5.188,738,5.653]],["t/99",[267,4.107,418,4.703]],["t/101",[177,4.069,323,2.788,739,6.908]],["t/102",[202,2.234,211,2.736,294,2.764,340,3.42,341,2.231,342,3.295,379,2.324,380,2.267,382,2.512,590,2.607,597,2.913,598,2.913,640,6.488,644,3.24,675,3.47,740,3.326,741,6.138,742,6.746,743,4.321,744,8.754,745,7.363,746,6.746,747,6.746,748,6.746,749,6.746,750,5.737,751,6.138,752,6.746,753,8.754,754,5,755,4.044,756,6.746]],["t/104",[10,2.188,31,2.161,98,2.208,149,2.303,157,3.163,190,2.249,202,2.114,266,3.261,294,2.407,326,2.022,329,1.928,341,1.943,429,2.897,474,2.314,511,1.635,531,2.624,603,2.483,741,5.346,757,4.076,758,3.961,759,8.279,760,5.346,761,5.346,762,4.355,763,5.346,764,8.254,765,8.206,766,6.437,767,7.266,768,6.437,769,5.875,770,3.857,771,4.528,772,3.523,773,5.346,774,5.346,775,4.736,776,5.541,777,4.736,778,5.346,779,5.346,780,4.736,781,5.346,782,5.346]],["t/106",[110,5.899,135,3.201,183,2.618,224,1.913,294,3.585,308,4.097,558,4.374,745,6.264,783,8.75,784,5.899]],["t/110",[5,1.482,13,2.651,38,3.171,42,1.606,88,4.983,145,3.494,167,5.141,206,2.248,231,3.171,266,3.276,294,2.942,323,2.149,326,1.601,333,4.842,362,3.101,394,3.282,406,4.715,512,3.749,554,4.599,673,4.983,785,5.463,786,4.599,787,3.851,788,3.997,789,5.141,790,7.749,791,7.181,792,4.983,793,4.396,794,7.181]],["t/112",[5,1.73,113,4.514,223,2.818,224,1.833,294,3.435,307,5.026,323,2.508,324,6.214,400,5.817,795,4.376,796,6.136,797,4.376,798,5.246,799,5.246]],["t/114",[42,1.831,294,3.649,322,4.956,495,5.136,788,4.956,800,6.863,801,5.847]],["t/116",[50,2.237,64,3.304,80,1.862,117,1.791,194,4.692,195,4.674,252,3.524,280,4.692,326,1.779,327,1.838,341,2.64,529,4.443,582,2.895,640,5.916,802,6.152,803,6.435,804,4.443,805,6.789,806,6.789,807,5.916]],["t/118",[117,2.365,135,2.387,166,2.983,173,3.019,175,2.435,177,2.849,178,2.075,183,2.563,192,2.621,195,3.134,252,4.656,267,2.849,308,4.938,344,2.81,359,2.326,425,2.701,501,3.162,607,2.729,808,5.938,809,4.528,810,5.261,811,3.836,812,4.528,813,5.938,814,5.938,815,7.285,816,7.285,817,7.794,818,8.567]],["t/120",[5,0.5,10,0.902,13,0.894,30,0.954,38,1.069,59,1.179,80,0.565,92,0.834,98,1.524,114,1.082,129,0.952,136,1.372,145,1.179,157,1.304,166,1.107,175,1.488,185,0.808,188,1.121,192,0.973,193,1.681,199,1.566,200,1.372,202,1.48,218,1.59,231,1.069,233,1.854,266,0.871,267,1.058,273,2.538,280,1.424,297,1.264,308,1.899,310,2.663,323,0.725,325,1.035,329,1.331,342,1.3,344,0.795,346,1.194,348,1.832,349,1.752,350,1.511,353,4.089,359,2.428,379,0.834,380,0.814,382,1.511,384,1.681,387,1.284,393,0.992,401,1.194,403,1.424,406,2.663,430,2.117,474,0.954,511,0.674,514,1.759,558,1.211,560,1.681,567,1.516,569,1.613,577,1.046,580,1.134,582,0.878,590,0.936,597,1.046,598,1.046,607,1.013,609,1.681,615,2.904,625,1.734,638,0.945,663,2.384,670,2.798,686,3.435,740,1.194,745,4.382,770,1.59,785,3.137,801,2.663,802,4.033,809,1.681,810,1.953,811,1.424,813,2.204,814,2.204,815,3.45,816,3.45,817,2.204,819,1.633,820,1.516,821,1.264,822,3.45,823,1.372,824,2.616,825,2.422,826,2.204,827,2.422,828,2.422,829,2.422,830,3.45,831,2.422,832,2.422,833,2.422,834,2.204,835,2.422,836,1.452,837,3.45,838,6.618,839,4.45,840,3.126,841,1.516,842,2.204,843,4.934,844,2.204,845,3.69,846,3.746,847,2.422,848,1.867,849,1.953,850,3.45,851,2.22,852,2.06,853,1.795,854,1.681,855,1.681,856,1.867,857,7.371,858,9.217,859,9.616,860,2.422,861,4.056,862,2.422,863,2.422,864,2.422,865,3.69,866,4.056,867,2.422,868,6.121,869,6.121,870,2.06,871,2.422,872,2.422,873,2.422,874,2.204,875,5.233,876,2.422,877,3.878,878,2.422,879,2.422,880,6.121,881,4.45,882,6.121,883,2.422,884,1.953,885,2.422,886,2.204,887,2.422,888,4.056,889,3.45,890,2.422,891,4.056,892,2.422,893,2.422,894,2.422,895,2.422,896,2.422,897,2.422,898,2.422,899,2.422,900,1.59]],["t/122",[50,2.202,179,5.032,202,2.093,294,3.949,326,2.148,329,2.578,361,4.81,758,5.297,765,7.769,768,6.334,775,6.334,776,6.687,777,6.334,780,6.334,901,6.055,902,7.857,903,6.334,904,7.149]],["t/125",[20,3.298,24,4.484,33,3.209,92,1.774,95,2.089,108,3.573,129,1.209,149,1.485,170,4.686,183,1.541,224,1.126,233,2.354,246,3.969,247,3.735,262,2.089,308,2.412,315,3.817,318,7.089,323,2.181,326,1.148,327,1.678,343,2.701,361,3.153,374,2.818,492,3.817,514,1.731,584,3.573,585,3.888,630,2.97,730,3.817,787,2.177,792,3.573,795,2.688,804,4.708,905,4.151,906,5.15,907,3.472,908,5.756,909,4.686,910,4.686,911,4.38,912,4.686,913,5.15,914,5.15,915,5.15,916,3.088,917,4.128,918,4.686,919,5.15,920,5.15,921,4.38,922,5.15,923,4.686,924,4.151,925,5.15,926,5.15,927,5.15,928,3.223,929,4.686,930,3.817,931,4.38,932,3.472,933,5.15,934,2.028,935,3.817,936,4.686]],["t/127",[5,0.785,50,1.633,69,1.429,80,1.652,84,1.321,110,3.928,117,1.307,129,1.368,165,3.424,173,1.759,175,1.081,178,1.208,181,2.563,182,2.637,183,2.119,184,2.782,185,1.942,190,3.04,194,2.234,199,1.137,201,2.601,247,1.678,267,2.544,308,1.78,326,0.847,343,1.621,401,3.915,433,2.953,435,2.953,465,1.574,474,2.295,480,2.279,500,2.279,501,3.16,503,1.984,514,1.278,538,2.462,572,2.782,580,1.78,582,1.378,583,2.663,607,1.59,629,3.242,646,2.379,662,2.435,787,3.974,934,2.79,937,1.955,938,3.459,939,5.071,940,3.928,941,3.064,942,4.696,943,5.826,944,5.301,945,3.459,946,2.817,947,3.064,948,2.563,949,4.042,950,4.318,951,3.645,952,5.826,953,4.318,954,5.684,955,4.042,956,4.696,957,3.928,958,3.088,959,4.49,960,5.826,961,3.493,962,5.826,963,4.171,964,5.826,965,5.885,966,5.885,967,4.171,968,4.318,969,2.496,970,3.233,971,2.563,972,2.234,973,2.496]],["t/129",[33,3.277,38,2.919,74,3.505,114,2.953,151,3.401,165,3.887,202,2.217,251,2.441,326,1.926,328,4.261,329,2.169,379,2.278,380,2.904,382,3.218,393,2.709,531,2.953,569,4.059,577,2.855,579,2.987,582,2.398,590,2.555,638,2.579,657,3.745,787,2.795,934,3.791,939,4.734,974,4.458,975,4.734,976,4.734,977,3.887,978,3.217,979,3.68,980,4.734,981,3.68]],["t/132",[5,1.097,11,3.253,31,2.016,38,2.346,42,1.644,65,2.908,72,3.186,92,1.831,117,1.192,129,1.248,135,1.944,192,2.134,198,2.458,199,2.574,202,1.869,204,3.186,205,3.124,206,1.664,208,3.687,257,4.396,327,1.223,329,1.743,340,2.694,342,2.988,343,2.909,379,1.831,380,1.786,402,1.91,433,3.777,461,3.253,470,3.065,499,2.861,511,1.479,529,2.958,531,2.373,583,2.429,584,3.687,585,2.246,586,3.804,593,3.489,595,4.892,596,3.687,603,2.246,608,3.124,638,2.073,675,2.733,679,3.01,934,2.093,954,3.804,955,3.687,967,3.804,968,3.939,977,3.124,982,5.511,983,4.835,984,3.253,985,4.095,986,4.284]],["t/134",[10,1.161,13,2.477,31,0.843,38,2.201,42,0.314,69,0.669,76,0.814,78,2.101,80,0.727,84,0.619,96,1.2,149,0.514,151,1.603,152,1.376,183,0.533,184,2.62,185,1.039,190,1.909,192,0.715,199,0.533,200,3.529,202,1.805,206,0.557,257,0.769,265,1.678,270,0.844,327,0.41,331,1.95,332,1.734,340,0.903,342,3.195,343,2.312,360,0.929,362,0.769,379,0.613,380,0.598,398,3.56,412,2.835,414,2.426,430,4.337,433,0.903,435,2.527,436,1.027,461,3.052,511,0.495,531,0.795,536,4.324,572,2.911,583,2.849,585,3.763,587,2.491,593,4.091,595,5.114,603,0.753,607,1.303,617,1.275,618,1.435,619,1.435,620,1.435,621,1.14,622,1.2,623,1.2,624,1.435,625,1.275,629,2.775,638,0.695,644,1.497,675,0.916,679,1.008,787,0.753,824,1.558,854,7.317,934,0.701,937,0.916,939,2.231,950,4.619,954,5.354,965,5.774,966,5.774,967,1.275,968,1.32,977,1.047,982,1.996,987,1.2,988,1.62,989,1.781,990,1.235,991,1.62,992,1.62,993,1.32,994,1.62,995,1.868,996,1.372,997,3.361,998,1.514,999,1.62,1000,1.435,1001,2.835,1002,1.781,1003,6.154,1004,6.698,1005,4.986,1006,4.986,1007,8.309,1008,5.67,1009,4.155,1010,5.3,1011,1.008,1012,6.232,1013,4.986,1014,2.989,1015,4.676,1016,6.057,1017,4.24,1018,3.116,1019,1.781,1020,5.3,1021,1.765,1022,1.435,1023,1.372,1024,1.514]],["t/136",[69,3.049,149,2.834,269,5.195,295,2.661,326,2.19,327,2.263,335,3.021,343,2.257,483,4.299,585,4.154,633,5.628,787,3.429,841,5.076,1025,4.594,1026,6.252]],["t/138",[21,2.381,31,1.87,47,3.544,116,4.66,129,1.123,173,2.212,175,1.359,177,2.088,181,3.224,184,2.421,185,1.594,190,1.83,192,1.92,198,3.197,202,1.501,231,2.111,255,2.617,295,1.569,302,2.212,314,2.696,326,1.809,327,2.334,340,2.424,341,1.581,342,2.601,343,1.923,362,2.065,379,1.647,380,1.607,387,2.534,475,2.927,511,1.331,531,2.135,570,2.574,572,2.421,585,3.758,603,2.021,626,2.617,638,1.865,673,4.795,675,2.459,787,4.284,820,2.992,934,3.197,940,3.224,975,3.423,976,3.423,977,2.81,981,3.846,982,5.695,983,4.35,1026,3.685,1027,4.066,1028,5.878,1029,4.35,1030,4.35,1031,4.066,1032,4.35,1033,1.848,1034,3.544,1035,4.35,1036,4.781,1037,4.066,1038,6.288,1039,4.35,1040,4.35,1041,4.35,1042,3.544]],["t/140",[5,1.76,21,2.939,42,1.504,98,2.437,136,5.399,175,1.843,177,2.831,192,2.604,326,1.901,327,2.195,343,2.374,362,2.8,475,3.969,499,4.593,501,2.393,514,2.179,531,2.895,580,3.036,583,3.899,585,4.281,803,5.227,974,4.371,1010,5.514,1026,6.574,1043,4.997,1044,4.997,1045,6.322,1046,5.514,1047,6.427,1048,8.53,1049,4.499]],["t/142",[5,1.591,12,3.096,21,1.923,30,3.036,152,2.464,178,1.774,213,5.077,326,1.244,342,1.788,343,2.458,344,1.831,402,2.006,426,4.136,501,2.06,514,1.876,517,3.664,572,3.094,590,2.979,593,5.061,595,5.061,596,5.349,644,2.68,670,4.354,973,5.799,974,5.955,978,2.715,979,3.106,1037,4.746,1038,7.014,1039,7.014,1045,4.136,1050,6.214,1051,4.136,1052,5.941,1053,4.498,1054,7.709,1055,7.709,1056,7.014,1057,5.941,1058,4.498,1059,4.746,1060,5.581,1061,5.077,1062,3.872,1063,7.709,1064,3.106,1065,3.872,1066,5.581]],["t/144",[323,2.487,327,1.914,361,5.089,570,4.476,584,5.768,585,4.683,787,3.514,917,4.709,934,3.274,1026,6.407,1067,7.564,1068,8.314,1069,7.071]],["t/146",[5,1.192,42,1.018,69,2.17,102,4.006,110,3.893,149,2.593,178,1.836,183,2.361,185,1.925,189,3.462,192,2.319,295,1.894,308,2.704,323,1.727,326,1.759,327,2.07,342,2.528,343,2.196,344,1.894,348,2.608,349,2.493,350,2.15,353,4.366,358,3.014,394,2.639,427,3.33,474,2.274,480,3.462,507,3.27,580,2.704,584,5.475,585,3.335,663,3.394,670,2.639,743,3.698,787,2.44,836,3.462,961,3.462,973,3.791,987,3.893,1033,2.231,1069,6.711,1070,4.279,1071,5.774,1072,4.45,1073,3.698,1074,4.279,1075,3.791,1076,5.65,1077,4.133,1078,4.654,1079,4.654,1080,4.654,1081,4.006]],["t/149",[13,3.61,42,1.419,75,6.201,129,1.889,216,7.321,217,7.321,295,2.64,312,4.478,313,5.154,702,7.001,705,5.425,706,5.283,1082,8.047,1083,8.047,1084,7.537,1085,6.843,1086,5.425]],["t/151",[2,3.93,5,1.482,42,1.266,47,6.754,135,3.334,175,2.042,253,3.456,266,2.581,267,3.135,295,2.356,312,5.071,313,4.599,314,2.801,319,5.789,361,4.396,403,4.221,490,4.983,501,2.651,551,5.141,1041,6.534,1084,5.534,1087,7.181,1088,7.181,1089,4.715,1090,7.345,1091,7.181,1092,4.142,1093,6.534,1094,4.983,1095,6.534]],["t/153",[5,1.257,42,1.074,80,1.42,98,2.289,136,3.449,199,2.448,202,2.007,253,4.112,304,3.449,312,3.389,335,2.268,344,1.998,394,2.783,435,4.148,478,3.333,501,2.248,503,3.179,514,2.047,582,3.351,995,3.651,1084,7.121,1092,3.512,1096,3.998,1097,5.179,1098,5.541,1099,6.09,1100,5.918,1101,4.693,1102,5.541,1103,4.106,1104,8.182,1105,8.182,1106,5.319,1107,8.182,1108,8.182,1109,6.09,1110,6.09]],["t/155",[42,1.822,114,3.942,136,4.999,426,6.542,697,6.803,788,4.913,1090,7.115,1111,8.827]],["t/157",[2,3.037,31,1.502,84,1.928,117,1.245,178,1.764,187,3.084,202,1.913,248,3.973,253,4.386,519,4.701,535,5.328,542,3.894,572,1.944,644,2.665,656,4.135,995,3.327,1106,2.988,1112,5.818,1113,7.489,1114,5.55,1115,8.012,1116,6.191,1117,5.55,1118,3.973,1119,4.72,1120,4.277,1121,5.328,1122,4.277,1123,3.973,1124,3.742,1125,4.72,1126,5.55,1127,5.049,1128,5.55,1129,4.72,1130,5.55,1131,5.55,1132,5.55,1133,4.72,1134,5.55,1135,5.55,1136,5.55,1137,5.55]],["t/159",[31,1.473,42,1.336,65,1.907,69,1.309,72,3.265,78,3.671,80,1.564,95,2.209,104,2.432,117,1.504,125,1.847,128,3.17,129,1.574,149,1.005,166,2.489,178,1.731,183,1.042,184,1.908,185,1.815,198,1.612,199,1.042,223,1.83,224,0.762,247,1.538,252,1.538,253,4.071,258,2.932,266,1.252,274,3.265,295,1.143,296,2.089,302,1.612,311,3.265,314,1.359,317,3.408,335,1.298,343,1.515,348,2.46,349,2.352,350,2.028,356,2.349,398,2.722,418,3.351,435,1.766,474,1.372,487,1.766,499,1.876,503,1.819,516,2.432,543,2.722,558,1.742,572,1.908,573,2.685,574,2.685,575,2.98,582,2.431,597,2.352,598,2.352,661,2.133,724,3.671,776,3.778,823,1.973,996,2.685,997,5.545,1033,1.346,1092,4.743,1100,3.488,1138,3.265,1139,5.834,1140,2.685,1141,3.17,1142,2.685,1143,2.808,1144,4.52,1145,3.484,1146,2.685,1147,4.799,1148,3.484,1149,3.484,1150,3.484,1151,3.17,1152,2.963,1153,5.404,1154,3.484,1155,3.484,1156,3.17,1157,3.484,1158,4.955,1159,4.976,1160,3.031,1161,2.048,1162,3.201,1163,7.58,1164,5.446]],["t/162",[33,3.408,280,5.281,321,5.182,327,2.069,934,3.539,1165,8.175,1166,5.5]],["t/164",[114,3.074,201,3.961,206,2.155,329,2.259,368,3.541,402,3.947,427,3.971,461,4.215,470,3.971,690,4.777,772,5.318,841,5.55,977,4.047,1167,4.308,1168,6.264,1169,6.264,1170,5.55,1171,5.306,1172,5.306,1173,6.264,1174,4.777,1175,5.55,1176,6.264,1177,5.55,1178,4.308,1179,5.855,1180,4.215,1181,5.855,1182,3.35,1183,5.55,1184,6.264,1185,6.264,1186,5.55]],["t/166",[5,0.797,21,1.33,33,1.464,42,0.68,65,2.112,69,1.451,80,0.9,104,3.193,117,1.604,125,3.79,129,1.384,135,1.412,149,2.308,150,2.534,151,3.032,152,3.534,166,3.268,169,2.868,173,1.786,175,1.676,177,1.685,178,1.227,183,1.764,192,1.55,195,1.854,199,1.155,201,1.724,221,2.694,223,1.297,224,1.289,243,2.415,252,1.704,254,2.602,261,2.415,266,1.388,267,1.685,308,1.808,327,1.646,331,2.415,341,2.365,344,1.934,353,3.616,359,1.376,401,1.903,408,1.985,425,1.598,454,1.903,465,2.44,467,1.93,475,3.608,478,2.112,483,2.046,487,1.957,489,4.369,501,2.176,514,1.981,520,2.663,522,2.269,524,3.226,607,1.614,621,3.775,663,2.269,679,3.338,757,2.678,770,2.534,772,4.799,804,3.98,809,2.678,811,2.269,812,2.678,917,2.186,972,3.465,1033,2.278,1073,2.472,1075,2.534,1076,2.763,1092,2.226,1187,3.512,1188,4.369,1189,2.763,1190,3.283,1191,2.534,1192,2.861,1193,5.013,1194,3.338,1195,4.543,1196,5.511,1197,2.947,1198,3.281,1199,3.283,1200,4.616,1201,3.283,1202,5.363,1203,2.415,1204,5.363,1205,5.013]],["t/169",[21,2.645,31,2.571,202,2.064,323,2.297,329,2.518,340,3.892,342,3.306,379,2.645,380,2.58,418,3.838,429,3.785,511,2.136,582,3.445,603,3.245,638,2.995,675,3.948,819,5.176,934,3.023,977,4.512,982,6.085]],["t/171",[21,2.645,31,2.571,202,2.064,323,2.297,329,2.518,340,3.892,342,3.306,379,2.645,380,2.58,418,3.838,429,3.785,511,2.136,582,3.445,603,3.245,638,2.995,675,3.948,819,5.176,934,3.023,977,4.512,1029,8.645]],["t/173",[21,2.625,31,2.558,113,4.102,202,2.054,323,2.279,329,2.499,342,3.295,379,2.625,380,2.56,381,4.879,393,3.121,402,2.739,429,3.757,511,2.12,582,2.763,603,3.22,638,2.972,675,3.918,819,5.136,1027,8.042,1206,7.618,1207,5.646]],["t/175",[31,2.672,202,2.145,299,5.238,342,3.399,379,2.817,380,2.749,511,2.276,603,3.457,675,4.206,1030,8.986,1208,7.441,1209,7.441,1210,8.178]],["t/178",[3,5.413,92,2.841,222,3.279,223,2.771,233,3.769,251,3.663,326,1.838,327,1.898,341,2.727,351,4.012,418,4.122,492,6.111,1180,5.048,1211,7.012,1212,8.246,1213,6.111]],["t/180",[69,2.624,74,3.7,92,3.083,215,2.272,222,3.559,223,2.346,230,3.269,231,3.951,235,4.185,294,2.86,302,3.229,305,4.998,312,3.885,313,4.471,323,2.089,359,2.488,414,3.397,454,3.442,503,3.644,656,3.759,957,4.707,1033,2.698,1138,4.185,1139,4.471,1161,4.103,1214,4.998,1215,5.174,1216,5.937,1217,6.352,1218,4.707,1219,6.352,1220,4.185,1221,4.583,1222,6.352,1223,6.352,1224,5.627]],["t/182",[21,2.795,33,3.077,42,1.732,224,1.773,230,4.602,251,3.627,259,4,300,4.863,322,5.469,425,3.358,495,4.678,738,5.195,788,4.515,800,6.252,801,5.326]],["t/184",[5,0.717,12,0.571,31,0.691,33,0.539,42,1.179,49,1.096,50,0.715,60,2.548,69,0.959,80,1.704,84,1.472,92,0.49,98,0.534,113,1.374,114,0.635,117,1.095,124,1.967,125,0.754,129,0.995,157,0.765,163,1.018,198,1.181,199,1.039,201,2.987,206,1.087,209,2.358,211,1.409,214,1.018,218,0.933,219,1.761,222,3.663,223,1.826,224,1.462,231,1.127,233,1.587,246,1.967,248,1.018,251,1.282,255,0.778,261,0.89,262,0.577,265,1.374,266,2.273,270,0.674,273,2.651,284,2.281,294,1.423,295,1.782,296,1.53,304,1.967,306,1.445,307,1.53,311,1.53,312,0.791,313,2.224,316,2.057,320,2.94,323,0.764,326,0.569,327,0.8,329,2.075,335,1.818,341,0.844,343,0.71,344,1.139,357,1.771,359,0.507,362,1.102,375,1.967,381,0.911,382,0.529,394,1.587,395,0.986,396,1.635,397,0.89,400,0.986,401,1.259,402,2.805,418,0.711,422,0.742,427,0.82,435,1.294,438,1.096,442,2.782,447,1.771,449,1.597,454,2.679,457,1.209,460,0.89,465,1.437,467,1.276,468,3.617,470,3.407,478,1.9,483,0.754,484,1.054,506,1.827,511,0.396,514,0.478,520,3.169,538,1.079,542,1.046,553,2.988,554,0.911,566,0.635,577,0.614,603,0.601,607,0.595,608,0.836,630,0.82,632,0.852,638,0.555,661,1.562,670,0.65,675,0.731,695,1.018,738,1.635,740,0.701,750,1.209,758,1.721,766,1.146,796,2.594,797,0.742,798,1.597,799,3.054,804,0.791,807,1.892,855,0.986,903,1.146,928,0.89,932,2.856,958,0.754,969,1.676,984,1.562,985,1.967,1025,0.805,1033,0.986,1044,1.967,1092,0.82,1101,1.096,1106,1.87,1138,2.082,1139,0.911,1147,5.417,1161,1.5,1167,0.89,1175,2.057,1180,0.87,1194,0.805,1200,0.82,1203,0.89,1215,1.892,1220,2.082,1225,1.293,1226,1.209,1227,2.057,1228,1.018,1229,2.782,1230,1.096,1231,1.293,1232,4.441,1233,1.209,1234,1.293,1235,1.096,1236,1.146,1237,1.209,1238,1.018,1239,1.293,1240,1.018,1241,2.322,1242,1.293,1243,1.146,1244,1.209,1245,1.293,1246,1.293,1247,1.293,1248,3.415,1249,1.967,1250,1.054,1251,1.209,1252,2.057,1253,2.322,1254,0.89,1255,1.293,1256,1.293,1257,1.562,1258,1.209,1259,1.146,1260,1.146,1261,2.322,1262,0.933,1263,1.293,1264,0.87,1265,0.986,1266,0.742,1267,1.293,1268,1.293,1269,1.293,1270,1.293,1271,1.293,1272,1.146,1273,1.096,1274,0.911,1275,1.293,1276,1.096,1277,1.293,1278,1.209,1279,1.209,1280,1.293,1281,1.209,1282,1.293,1283,1.293,1284,1.146,1285,1.209,1286,0.986,1287,1.209,1288,1.293,1289,2.322,1290,2.409,1291,2.322,1292,2.322,1293,4.186,1294,2.322,1295,2.714,1296,1.562,1297,4.379,1298,3.16,1299,1.892,1300,1.967,1301,2.322,1302,2.322,1303,2.171,1304,2.057,1305,2.322,1306,2.057,1307,2.322,1308,3.603,1309,2.322,1310,3.855,1311,2.322,1312,1.771,1313,1.892,1314,3.855,1315,2.057,1316,2.322,1317,1.771,1318,2.322,1319,1.5,1320,2.322,1321,2.057,1322,2.322,1323,1.827,1324,1.293,1325,1.096,1326,1.293,1327,2.953,1328,1.018,1329,0.958,1330,2.322,1331,2.171,1332,1.209,1333,1.146,1334,1.018,1335,1.209,1336,1.018,1337,1.209,1338,1.293,1339,1.374,1340,1.018,1341,0.933]],["t/186",[21,1.901,64,2.285,80,1.287,84,1.917,104,3.416,117,2.234,135,2.019,166,4.709,177,2.41,183,2.627,206,1.728,215,2.858,224,1.919,252,3.378,253,2.902,258,2.972,267,2.41,270,2.617,277,5.158,323,1.651,327,1.761,331,3.454,335,2.056,339,5.308,341,2.53,343,2.129,344,1.811,359,1.967,366,3.951,501,2.037,606,2.651,607,3.2,739,4.091,811,3.244,812,3.829,1025,3.126,1196,4.253,1290,5.308,1342,5.021,1343,6.167,1344,3.829,1345,3.721,1346,5.021,1347,5.021,1348,3.951,1349,3.535,1350,5.021,1351,5.021,1352,4.787,1353,4.449]],["t/188",[2,2.908,31,2.328,76,2.429,92,1.831,95,3.022,117,1.192,166,2.429,173,2.458,175,1.511,199,1.59,202,1.869,209,2.958,223,1.786,231,2.346,233,2.429,252,2.346,253,3.264,326,1.918,328,4.243,329,2.445,340,4.728,341,2.464,342,2.757,353,3.366,379,1.831,380,2.504,382,1.979,409,3.939,418,5.42,429,2.62,478,2.908,511,1.479,514,1.786,515,3.777,516,2.373,532,3.124,543,2.657,572,1.862,573,2.62,574,2.62,575,2.908,576,2.861,597,2.295,598,2.295,603,2.246,606,3.579,638,2.073,675,2.733,740,2.62,1159,4.892,1160,2.958,1221,3.489,1345,3.583]],["t/190",[5,1.806,42,1.542,129,2.054,260,6.485,324,7.62,325,4.392,418,4.374,449,5.475]],["t/192",[5,1.205,31,2.447,42,1.03,50,1.637,95,3.226,117,1.31,173,2.702,199,1.748,202,1.965,223,1.963,252,2.579,253,3.431,326,1.302,327,1.345,328,4.46,329,2.61,340,2.961,342,1.871,379,2.012,380,2.673,382,2.175,418,5.362,441,3.502,449,3.655,511,1.625,514,1.963,515,4.033,516,2.608,543,2.92,570,3.145,572,2.046,573,2.88,574,2.88,575,3.197,576,3.145,582,2.118,597,2.522,598,2.522,603,2.469,638,2.279,675,3.004,740,2.88,1159,5.222,1160,3.251,1221,5.222,1354,3.145,1355,5.314]],["t/194",[4,3.21,13,1.537,30,1.64,31,2.026,38,1.839,42,1.101,76,1.904,80,0.972,115,2.55,117,0.934,121,2.982,173,1.927,184,2.187,185,1.389,188,1.927,202,1.627,206,1.304,215,2.032,223,1.4,224,1.637,233,3.803,253,3.155,258,2.243,261,2.606,274,2.497,284,2.243,317,2.606,321,2.402,325,1.779,326,0.928,327,0.959,329,1.366,340,2.111,342,2.666,348,1.881,349,1.799,350,1.551,353,4.383,358,2.174,359,3.704,360,2.174,365,6.037,366,2.982,379,1.435,380,1.4,382,1.551,387,2.207,414,3.038,418,4.159,429,3.079,468,2.55,474,1.64,500,2.497,501,1.537,511,1.737,516,3.344,520,3.383,546,2.734,582,1.51,603,1.76,638,1.625,659,2.497,664,2.89,675,2.142,740,3.079,797,2.174,820,2.606,821,2.174,824,2.082,848,3.21,1097,3.542,1124,2.808,1162,2.448,1339,3.362,1348,4.47,1349,2.667,1354,2.243,1356,3.789,1357,3.789,1358,3.789,1359,3.542,1360,3.542,1361,3.542,1362,3.789,1363,5.31,1364,3.357,1365,3.542]],["t/196",[5,1.467,42,0.876,80,1.935,149,1.434,151,2.557,166,2.272,183,2.482,184,3.355,187,3.636,199,2.482,209,4.617,215,1.618,222,4.307,224,1.087,253,2.696,254,3.352,266,2.982,279,3.685,314,3.236,343,1.978,350,3.09,356,3.352,394,2.272,398,3.553,418,3.553,514,1.671,542,3.709,543,4.525,544,4.792,545,3.505,997,4.792,1139,4.552,1220,4.261,1354,3.827,1366,5.268,1367,4.792,1368,3.559,1369,4.523,1370,5.477,1371,8.145,1372,3.559,1373,6.045]],["t/199",[33,3.153,74,4.407,135,3.042,167,7.141,231,3.671,302,3.846,326,1.853,327,1.914,374,5.458,512,4.34,786,5.325,788,4.627,1214,5.952,1374,8.314]],["t/201",[231,4.003,305,6.491,312,5.046,313,5.807,1138,5.436,1214,6.491]],["t/203",[42,1.831,322,4.956,374,4.873,495,5.136,788,4.956,800,6.863,801,5.847]],["t/205",[117,1.683,135,2.745,166,4.282,173,3.471,175,2.663,177,3.276,178,2.386,183,2.803,192,3.014,195,3.604,224,1.64,252,3.313,267,3.276,344,3.073,359,2.674,425,3.106,501,3.458,607,3.139,809,5.207,811,4.411,812,5.207,1348,5.372,1375,7.504,1376,7.504]],["t/207",[5,1.152,31,2.086,42,0.984,50,1.564,69,2.097,80,1.302,84,1.939,98,2.097,113,3.005,117,1.252,199,1.67,202,1.918,209,3.106,223,2.591,252,2.464,253,3.613,266,2.771,273,3.492,311,3.346,314,2.177,327,1.285,328,2.752,374,3.054,376,6.787,379,2.656,380,1.876,381,4.938,382,2.078,393,3.159,394,2.551,402,2.006,478,3.054,512,2.913,515,2.829,516,2.492,543,2.79,573,2.752,574,2.752,575,3.054,597,3.329,598,3.329,638,2.177,784,3.762,796,3.416,799,5.527,905,6.214,987,3.762,1160,3.106,1334,3.995,1337,6.556,1377,4.301,1378,5.581,1379,5.581]],["t/210",[3,4.648,21,2.439,50,1.984,69,2.661,104,3.161,141,6.441,195,4.775,224,1.548,251,2.613,255,3.874,326,2.216,327,1.63,329,2.323,341,2.341,346,3.491,351,4.394,364,5.068,418,3.539,500,4.245,501,3.333,514,2.379,529,3.94,606,3.4,658,5.456,916,4.245,1211,6.021,1266,3.696,1286,4.912,1380,6.441,1381,7.08,1382,7.08]],["t/212",[5,1.213,30,2.314,69,2.208,74,3.114,92,2.751,95,2.383,113,3.163,215,1.912,222,3.176,223,2.684,230,2.751,231,3.526,235,3.523,294,2.407,302,2.718,305,4.206,312,3.27,313,3.763,323,1.758,326,1.309,327,1.353,359,2.094,400,4.076,414,2.859,449,3.676,454,2.897,503,3.067,567,3.676,656,3.163,795,3.067,796,4.889,797,3.067,798,3.676,799,3.676,957,3.961,1033,2.27,1138,3.523,1139,3.763,1161,3.453,1214,4.206,1215,4.355,1216,4.997,1217,5.346,1218,3.961,1219,5.346,1220,3.523,1221,3.857,1222,5.346,1223,5.346,1224,4.736,1383,4.997,1384,3.857,1385,4.736,1386,4.528,1387,5.875,1388,5.875,1389,3.067,1390,4.997,1391,5.875,1392,5.875,1393,4.997]],["t/214",[21,2.795,33,3.077,42,1.732,224,1.773,230,4.602,251,3.627,259,4,300,4.863,322,5.469,425,3.358,495,4.678,738,5.195,788,4.515,800,6.252,801,5.326]],["t/216",[50,2.072,64,3.06,80,1.725,117,1.658,194,4.346,195,4.457,252,3.264,277,4.984,326,1.648,327,2.137,341,2.445,351,4.936,418,3.696,520,3.34,529,4.115,569,2.94,582,2.681,670,3.379,803,5.96,805,6.288,806,6.288,807,5.48,955,5.13,1213,5.48,1394,5.96,1395,5.698,1396,6.288]],["t/218",[5,0.717,12,0.571,31,0.691,33,0.539,42,1.179,49,1.096,50,0.715,60,2.548,69,0.959,80,1.704,84,1.472,92,0.49,98,0.534,113,1.374,114,0.635,117,1.095,124,1.967,125,0.754,129,0.995,157,0.765,163,1.018,198,1.181,199,1.039,201,2.987,206,1.087,209,2.358,211,1.409,214,1.018,218,0.933,219,1.761,222,3.663,223,1.826,224,1.462,231,1.127,233,1.587,246,1.967,248,1.018,251,1.282,255,0.778,261,0.89,262,0.577,265,1.374,266,2.273,270,0.674,273,2.651,284,2.281,294,1.423,295,1.782,296,1.53,304,1.967,306,1.445,307,1.53,311,1.53,312,0.791,313,2.224,316,2.057,320,2.94,323,0.764,326,0.569,327,0.8,329,2.075,335,1.818,341,0.844,343,0.71,344,1.139,357,1.771,359,0.507,362,1.102,375,1.967,381,0.911,382,0.529,394,1.587,395,0.986,396,1.635,397,0.89,400,0.986,401,1.259,402,2.805,418,0.711,422,0.742,427,0.82,435,1.294,438,1.096,442,2.782,447,1.771,449,1.597,454,2.679,457,1.209,460,0.89,465,1.437,467,1.276,468,3.617,470,3.407,478,1.9,483,0.754,484,1.054,506,1.827,511,0.396,514,0.478,520,3.169,538,1.079,542,1.046,553,2.988,554,0.911,566,0.635,577,0.614,603,0.601,607,0.595,608,0.836,630,0.82,632,0.852,638,0.555,661,1.562,670,0.65,675,0.731,695,1.018,738,1.635,740,0.701,750,1.209,758,1.721,766,1.146,796,2.594,797,0.742,798,1.597,799,3.054,804,0.791,807,1.892,855,0.986,903,1.146,928,0.89,932,2.856,958,0.754,969,1.676,984,1.562,985,1.967,1025,0.805,1033,0.986,1044,1.967,1092,0.82,1101,1.096,1106,1.87,1138,2.082,1139,0.911,1147,5.417,1161,1.5,1167,0.89,1175,2.057,1180,0.87,1194,0.805,1200,0.82,1203,0.89,1215,1.892,1220,2.082,1225,1.293,1226,1.209,1227,2.057,1228,1.018,1229,2.782,1230,1.096,1231,1.293,1232,4.441,1233,1.209,1234,1.293,1235,1.096,1236,1.146,1237,1.209,1238,1.018,1239,1.293,1240,1.018,1241,2.322,1242,1.293,1243,1.146,1244,1.209,1245,1.293,1246,1.293,1247,1.293,1248,3.415,1249,1.967,1250,1.054,1251,1.209,1252,2.057,1253,2.322,1254,0.89,1255,1.293,1256,1.293,1257,1.562,1258,1.209,1259,1.146,1260,1.146,1261,2.322,1262,0.933,1263,1.293,1264,0.87,1265,0.986,1266,0.742,1267,1.293,1268,1.293,1269,1.293,1270,1.293,1271,1.293,1272,1.146,1273,1.096,1274,0.911,1275,1.293,1276,1.096,1277,1.293,1278,1.209,1279,1.209,1280,1.293,1281,1.209,1282,1.293,1283,1.293,1284,1.146,1285,1.209,1286,0.986,1287,1.209,1288,1.293,1289,2.322,1290,2.409,1291,2.322,1292,2.322,1293,4.186,1294,2.322,1295,2.714,1296,1.562,1297,4.379,1298,3.16,1299,1.892,1300,1.967,1301,2.322,1302,2.322,1303,2.171,1304,2.057,1305,2.322,1306,2.057,1307,2.322,1308,3.603,1309,2.322,1310,3.855,1311,2.322,1312,1.771,1313,1.892,1314,3.855,1315,2.057,1316,2.322,1317,1.771,1318,2.322,1319,1.5,1320,2.322,1321,2.057,1322,2.322,1323,1.827,1324,1.293,1325,1.096,1326,1.293,1327,2.953,1328,1.018,1329,0.958,1330,2.322,1331,2.171,1332,1.209,1333,1.146,1334,1.018,1335,1.209,1336,1.018,1337,1.209,1338,1.293,1339,1.374,1340,1.018,1341,0.933]],["t/220",[21,1.783,59,2.519,64,2.143,80,1.208,84,1.798,104,2.312,117,2.182,135,1.894,166,4.743,177,2.26,178,1.646,183,2.538,198,2.395,206,1.621,215,2.761,223,2.459,224,1.854,252,3.23,253,2.775,258,2.787,267,2.26,270,2.455,277,4.932,296,3.104,323,1.549,327,1.684,335,1.928,339,5.075,341,2.419,343,2.036,344,1.698,351,2.519,359,1.845,366,3.706,501,1.911,579,3.305,606,2.486,607,3.06,670,2.366,739,3.837,811,3.043,812,3.592,1025,2.932,1072,3.99,1144,3.49,1196,3.99,1290,3.592,1343,5.897,1344,3.592,1345,3.49,1346,4.71,1347,4.71,1348,3.706,1349,3.316,1350,4.71,1351,4.71,1352,4.577,1353,4.173,1354,2.787,1397,5.177,1398,4.71]],["t/223",[5,0.77,21,1.285,31,1.894,42,0.658,50,1.046,70,2.588,76,1.705,80,0.87,84,2.432,92,1.285,95,3.443,113,2.009,129,0.876,157,2.009,175,1.061,188,1.726,199,2.095,201,1.666,202,1.844,209,3.896,219,1.891,222,1.484,223,1.254,231,1.647,233,1.705,251,1.377,252,3.471,253,2.655,297,1.947,327,2.064,329,1.884,331,2.334,340,3.986,341,1.234,342,3.169,346,3.452,351,1.815,353,3.162,359,1.329,379,1.285,380,1.254,382,2.607,387,1.977,393,1.529,394,1.705,409,2.765,413,1.865,426,2.765,429,1.84,450,2.193,511,1.038,514,1.254,515,2.911,516,1.666,532,2.193,538,1.577,543,1.865,558,3.5,569,3.835,572,1.307,573,1.84,574,1.84,575,2.042,576,2.009,577,1.611,578,2.076,579,1.685,590,2.219,603,1.577,606,1.792,638,1.455,670,4.098,699,3.871,796,2.284,820,2.334,821,1.947,824,2.871,978,1.815,979,2.076,1051,2.765,1059,3.173,1124,2.515,1159,5.573,1160,2.076,1221,2.449,1345,2.515,1399,3.173,1400,7.001,1401,3.007,1402,2.875,1403,2.237,1404,2.765,1405,3.443,1406,2.076,1407,2.875]],["t/225",[5,1.657,12,0.924,30,0.906,31,1.79,42,0.405,50,1.088,70,2.694,76,1.775,80,0.536,95,0.933,104,1.027,113,2.714,125,1.219,129,1.183,135,1.421,152,1.015,175,1.104,184,1.36,185,1.295,188,1.796,193,1.596,194,1.352,198,1.796,199,0.688,202,1.877,204,3.022,205,2.962,219,1.969,221,1.051,223,0.773,224,0.503,233,2.304,241,1.326,251,1.433,253,2.246,258,1.238,262,0.933,266,0.827,267,2.2,286,1.854,297,2.027,302,1.796,314,0.897,326,1.475,327,1.848,328,1.915,329,2.634,330,1.51,331,1.439,339,2.694,340,3.002,341,1.667,342,2.3,346,3.262,347,5.099,348,2.277,349,2.176,350,1.877,351,2.881,352,1.956,353,3.905,358,2.027,359,1.796,360,1.201,368,1.183,379,1.338,380,1.694,382,2.673,387,2.058,393,1.591,394,1.775,402,0.827,403,1.352,409,2.878,413,1.941,427,1.326,429,1.134,467,1.15,492,2.878,501,1.433,507,1.303,511,1.402,514,1.99,515,1.166,516,1.027,532,2.282,538,3.033,543,1.15,569,3.438,572,0.806,573,1.134,574,1.134,575,1.259,576,2.091,577,1.677,578,2.161,579,1.754,581,1.201,582,2.399,597,0.993,598,0.993,603,1.641,606,1.865,632,1.379,638,1.515,670,1.775,695,1.647,697,1.772,699,3.992,770,1.51,796,2.377,798,1.439,811,1.352,821,2.027,824,2.96,928,1.439,1021,1.303,1034,2.878,1081,1.596,1124,2.618,1138,1.379,1153,1.854,1159,2.549,1160,1.28,1167,1.439,1221,1.51,1229,1.51,1250,1.705,1345,2.618,1385,1.854,1399,3.302,1403,2.328,1404,2.878,1405,3.55,1406,2.161,1407,2.993,1408,2.78,1409,2.3,1410,2.093,1411,1.705,1412,1.956,1413,1.956,1414,6.616,1415,3.883,1416,3.302,1417,1.28,1418,2.3,1419,2.093,1420,1.166,1421,1.51]],["t/227",[5,1.806,42,1.542,129,2.054,260,6.485,324,7.62,325,4.392,346,4.315,449,5.475]],["t/229",[5,1.047,31,2.27,42,0.894,50,2.021,70,3.519,95,2.925,113,2.731,129,1.191,199,1.517,202,2.096,204,3.041,205,2.981,219,2.571,223,1.705,251,1.872,252,2.239,253,3.182,297,2.648,327,1.168,329,2.365,342,2.688,346,4.136,379,1.747,380,1.705,382,3.124,387,2.688,393,2.078,394,2.318,413,2.535,441,3.041,449,3.174,511,1.411,514,1.705,515,3.655,516,2.265,543,2.535,569,3.336,570,2.731,572,1.777,573,2.501,574,2.501,575,2.776,576,2.731,577,2.19,578,2.823,579,2.291,582,1.839,603,2.144,638,1.979,670,2.318,699,4.861,796,3.105,824,2.535,978,2.468,979,2.823,1124,3.419,1146,3.909,1159,4.733,1160,2.823,1221,4.733,1354,2.731,1355,4.615,1403,3.041,1404,3.759,1405,4.323,1406,2.823,1407,3.909,1416,4.313,1422,4.088]],["t/231",[5,1.76,30,3.358,129,2.002,199,3.029,224,1.864,233,3.897,347,6.571,811,5.012,1153,6.873,1423,8.526,1424,5.598,1425,6.873]],["t/233",[4,3.144,13,1.506,30,1.607,31,2.001,38,1.801,42,1.084,76,1.865,80,0.952,115,2.498,117,0.915,121,2.921,173,1.887,184,2.154,185,1.36,188,1.887,202,1.919,206,1.277,215,2.001,223,1.371,224,1.617,233,3.764,253,3.123,258,2.197,261,2.553,274,2.446,284,2.197,317,2.553,321,2.353,325,1.743,326,1.37,329,1.339,342,1.97,346,3.031,348,1.843,349,1.762,350,1.52,351,2.991,353,4.353,358,2.13,359,3.685,360,2.13,365,5.963,366,2.921,379,1.406,380,1.371,382,2.755,387,2.163,393,1.672,414,2.991,429,3.031,468,2.498,474,1.607,500,2.446,501,1.506,511,1.711,516,3.303,520,3.342,546,2.679,569,2.445,577,1.762,578,2.271,582,1.48,603,1.724,638,1.592,659,2.446,664,2.831,740,3.031,797,2.13,821,2.13,824,2.04,848,3.144,1097,3.47,1124,2.751,1162,2.398,1339,3.31,1348,4.401,1349,2.613,1354,2.197,1356,3.712,1357,3.712,1358,3.712,1359,3.47,1360,3.47,1361,3.47,1362,3.712,1363,5.228,1364,3.289,1365,3.47,1416,3.47]],["t/235",[4,2.535,5,1.074,13,2.384,30,1.296,42,0.918,52,3.121,65,1.8,76,1.504,80,0.767,92,1.133,115,2.014,129,1.222,131,4.24,165,1.933,173,1.522,175,0.935,178,1.046,184,2.263,185,1.097,188,1.522,199,0.984,202,1.131,206,1.03,207,2.993,215,1.694,223,1.106,224,1.138,233,2.952,252,1.452,253,2.785,258,1.771,259,1.622,262,1.334,275,2.438,277,2.218,296,1.972,297,2.717,302,1.522,311,1.972,314,1.283,321,1.897,325,1.405,326,0.733,327,0.757,328,2.567,329,1.708,339,3.611,341,1.088,342,2.069,346,3.945,348,2.351,349,2.248,350,2.406,351,3.143,353,4.026,358,1.717,359,2.851,360,1.717,361,3.186,362,1.42,366,2.355,378,4.481,382,1.939,406,2.16,413,1.644,419,2.355,429,2.567,436,1.897,449,2.058,456,2.535,473,1.933,500,1.972,507,1.863,511,0.915,514,1.106,515,1.668,516,2.884,520,1.486,522,1.933,546,2.16,569,2.569,577,1.42,580,1.54,590,1.271,607,2.701,625,2.355,638,1.283,659,1.972,713,2.218,740,1.622,787,2.73,821,1.717,937,1.692,978,3.893,1167,2.058,1229,3.417,1319,1.933,1348,2.355,1349,2.107,1364,2.652,1365,2.797,1403,1.972,1406,4.087,1408,2.355,1426,4.978,1427,6.606,1428,2.282,1429,8.001,1430,5.205,1431,5.877,1432,2.652,1433,3.289,1434,2.797,1435,2.797,1436,3.289,1437,2.993,1438,4.427,1439,2.993,1440,2.535]],["t/237",[50,2.237,69,3,80,1.862,84,2.773,195,4.674,224,1.745,326,1.779,327,2.241,341,2.64,344,2.619,351,3.884,421,5.715,480,4.786,514,2.683,582,2.895,606,3.834,664,5.538,1441,7.983,1442,7.983]],["t/239",[5,1.145,12,4.007,21,3.034,30,2.186,31,1.502,149,1.601,178,2.441,183,2.635,195,2.665,199,2.298,256,3.397,295,1.821,326,1.237,327,2.188,343,1.544,351,5.022,394,2.537,406,3.644,408,2.854,511,1.544,514,3.194,554,3.554,555,5.042,569,3.968,572,1.944,644,2.665,662,4.919,670,4.717,704,4.474,1053,6.191,1059,6.531,1061,6.987,1062,3.851,1368,3.973,1401,7.099,1443,4.277,1444,4.474,1445,5.049,1446,5.049]],["t/241",[5,1.431,42,0.847,69,1.806,80,1.898,151,2.471,166,2.196,183,2.435,184,3.45,187,3.579,199,2.435,209,4.529,215,1.564,222,4.275,224,1.05,253,3.38,254,3.239,266,2.926,279,3.561,314,3.175,343,1.93,350,3.031,351,2.338,356,3.239,398,3.467,418,2.402,514,1.615,542,3.651,543,4.455,544,4.676,545,3.42,580,2.25,581,2.508,997,5.487,1139,4.442,1220,4.158,1354,3.734,1366,5.14,1367,4.676,1368,3.439,1369,4.371,1370,5.345,1371,8.374,1372,3.439,1373,6.921]],["t/243",[184,3.724,187,3.977,209,5.158,253,3.756,350,3.452,514,2.059,542,4.058,543,4.951,544,5.539,545,4.051,572,3.724,670,4.964,997,6.249,1352,3.834,1371,9.041,1373,7.882]],["t/246",[69,3.26,135,3.173,326,2.28,582,3.145,751,7.892,934,3.416,1447,8.674,1448,8.674,1449,8.674,1450,6.429]],["t/248",[33,3.394,50,1.956,64,2.89,74,3.7,80,1.628,117,2.008,136,5.069,194,4.103,195,4.298,251,3.303,252,3.082,262,2.832,314,2.723,326,1.995,327,2.06,341,2.309,501,2.577,529,3.885,582,2.531,788,3.885,805,5.937,806,5.937,807,5.174,934,2.75,982,4.471,1047,4.707,1140,7.612,1213,5.174,1451,6.981,1452,6.352]],["t/250",[114,3.074,201,3.961,206,2.155,329,2.259,368,3.541,402,3.947,427,3.971,461,4.215,470,3.971,690,4.777,772,5.318,841,5.55,977,4.047,1167,4.308,1168,6.264,1169,6.264,1170,5.55,1171,5.306,1172,5.306,1173,6.264,1174,4.777,1175,5.55,1176,6.264,1177,5.55,1178,4.308,1179,5.855,1180,4.215,1181,5.855,1182,3.35,1183,5.55,1184,6.264,1185,6.264,1186,5.55]],["t/252",[5,0.797,21,1.33,33,1.464,42,0.68,65,2.112,69,1.451,80,0.9,104,3.193,117,1.604,125,3.79,129,1.384,135,1.412,149,2.308,150,2.534,151,3.032,152,3.534,166,3.268,169,2.868,173,1.786,175,1.676,177,1.685,178,1.227,183,1.764,192,1.55,195,1.854,199,1.155,201,1.724,221,2.694,223,1.297,224,1.289,243,2.415,252,1.704,254,2.602,261,2.415,266,1.388,267,1.685,308,1.808,327,1.646,331,2.415,341,2.365,344,1.934,353,3.616,359,1.376,401,1.903,408,1.985,425,1.598,454,1.903,465,2.44,467,1.93,475,3.608,478,2.112,483,2.046,487,1.957,489,4.369,501,2.176,514,1.981,520,2.663,522,2.269,524,3.226,607,1.614,621,3.775,663,2.269,679,3.338,757,2.678,770,2.534,772,4.799,804,3.98,809,2.678,811,2.269,812,2.678,917,2.186,972,3.465,1033,2.278,1073,2.472,1075,2.534,1076,2.763,1092,2.226,1187,3.512,1188,4.369,1189,2.763,1190,3.283,1191,2.534,1192,2.861,1193,5.013,1194,3.338,1195,4.543,1196,5.511,1197,2.947,1198,3.281,1199,3.283,1200,4.616,1201,3.283,1202,5.363,1203,2.415,1204,5.363,1205,5.013]],["t/255",[5,1.321,33,2.428,74,3.393,145,3.115,202,2.189,218,4.202,251,2.363,328,4.171,329,3.438,341,2.117,346,3.156,379,2.205,380,2.151,382,3.15,387,3.393,393,2.623,569,4.008,577,2.764,579,2.892,590,3.268,638,2.497,788,3.562,820,4.005,934,3.731,974,4.315,977,3.762,978,3.115,979,3.562,980,4.583,981,3.562,1042,4.744,1167,4.005,1172,4.933,1453,6.401,1454,4.744,1455,4.005,1456,6.401]],["t/257",[33,2.611,74,3.649,129,1.617,136,3.899,202,2.251,294,2.821,328,4.374,329,2.91,379,2.372,380,2.981,382,3.304,387,3.649,393,2.821,402,2.475,569,4.122,577,2.973,579,3.11,590,2.661,638,2.686,785,4.128,820,4.308,934,2.712,977,4.047,978,3.35,979,3.832,980,4.929,981,3.832,1042,5.103,1457,4.929,1458,4.777,1459,6.885]],["t/259",[33,2.576,74,3.6,129,1.595,136,3.846,149,1.959,202,2.118,295,2.228,328,4.336,329,2.884,341,2.246,362,2.933,374,4.812,376,4.459,379,2.34,380,2.955,381,4.35,382,2.529,387,3.6,393,2.783,402,2.441,569,4.101,579,3.068,590,2.624,638,2.649,820,4.25,977,3.992,978,3.305,979,3.78,980,4.862,981,3.78,1027,5.776,1042,5.034,1458,6.1]],["t/261",[13,1.525,42,1.461,78,2.785,80,0.963,98,2.801,117,0.927,129,0.97,131,2.712,145,3.019,152,1.824,184,2.174,202,1.348,292,4.012,321,2.382,329,2.445,343,1.149,344,2.036,350,2.311,380,1.388,402,2.23,468,3.798,476,2.957,478,2.26,510,2.476,522,2.428,569,3.532,607,1.728,611,3.513,637,4.442,644,2.98,656,2.224,685,5.931,705,2.785,787,1.746,799,3.883,824,3.725,865,3.758,1033,1.596,1037,3.513,1103,2.785,1167,2.585,1209,3.758,1329,2.785,1403,2.476,1426,3.183,1427,4.599,1434,5.277,1435,5.277,1437,3.758,1440,3.183,1460,7.452,1461,5.645,1462,3.33,1463,7.452,1464,5.645,1465,7.452,1466,4.131,1467,4.131,1468,4.131,1469,4.131,1470,7.538,1471,4.131,1472,4.782,1473,6.205,1474,4.131,1475,3.183,1476,4.131,1477,10.181,1478,4.131,1479,6.205,1480,4.131,1481,4.131,1482,7.452,1483,4.131,1484,4.131,1485,4.131,1486,4.131,1487,4.131,1488,4.131,1489,4.131,1490,5.277,1491,4.131]],["t/263",[7,5.583,11,4.926,13,2.97,119,7.321,122,7.321,123,6.201,124,6.201,125,4.265,175,2.288,215,2.619,241,4.641,363,6.843,514,2.704,795,4.2,932,5.425,1492,7.321,1493,6.486,1494,6.843,1495,8.047,1496,8.047]],["t/265",[278,7.051,514,3.075,1497,8.324,1498,7.375,1499,9.149]],["t/268",[5,1.272,30,2.428,80,1.438,117,1.383,215,3.466,224,1.803,243,3.857,251,2.275,295,2.022,302,2.852,335,2.296,402,2.965,483,3.267,487,3.125,501,2.275,567,3.857,608,3.623,661,3.774,668,4.277,737,5.465,853,4.569,1144,4.156,1230,4.751,1264,5.05,1455,3.857,1500,9.032,1501,3.857,1502,4.751,1503,8.249,1504,4.277,1505,5.561,1506,5.243,1507,4.751,1508,4.969,1509,6.114,1510,6.649,1511,5.561,1512,6.165,1513,4.569,1514,4.751]],["t/270",[5,2.19,33,3.746,224,2.319,259,4.033,291,5.674,370,5.855,408,4.206,493,5.674,494,5.674,495,4.717,496,6.592,608,4.807,1408,5.855]],["t/272",[5,0.953,31,0.767,42,0.814,53,2.486,59,1.379,64,1.911,80,0.661,84,1.604,95,1.873,98,1.065,129,1.582,145,1.379,169,1.379,173,3.432,175,1.661,177,2.016,178,1.858,183,1.381,184,2.787,185,1.539,190,2.58,192,1.138,202,1.728,204,2.768,205,2.714,206,0.887,208,1.966,215,2.193,221,1.295,223,1.552,224,1.277,230,2.162,233,1.295,253,1.751,262,1.149,265,1.526,267,2.016,268,1.966,280,1.665,297,1.479,310,3.031,326,1.302,327,1.063,329,1.917,332,1.577,337,1.577,338,6.131,342,0.908,346,2.277,348,1.28,349,2.523,350,1.055,359,1.01,360,3.05,379,0.976,380,1.552,382,1.72,393,1.161,402,1.019,414,1.379,421,2.028,430,2.41,433,2.341,465,1.911,467,1.416,474,1.819,475,1.735,478,1.551,499,2.486,500,4.04,501,2.487,503,2.41,504,1.966,505,1.91,506,2.028,507,1.605,508,3.558,510,1.699,511,1.285,512,1.479,513,2.184,514,0.952,515,2.962,516,3.009,517,1.86,518,2.028,519,1.735,520,2.086,521,2.578,522,1.665,524,1.551,526,2.284,527,2.028,528,2.028,538,1.198,542,3.04,546,1.86,549,1.966,565,2.184,566,1.265,568,2.1,569,2.324,570,1.526,571,1.91,573,2.277,574,2.277,576,1.526,577,1.224,578,1.577,579,1.28,580,1.327,581,1.479,582,1.027,1064,3.252,1264,1.735,1266,1.479,1317,1.966,1339,1.526,1389,1.479,1514,3.558,1515,5.843,1516,5.843,1517,8.39,1518,7.959,1519,2.578,1520,2.184,1521,2.833,1522,5.843,1523,2.833,1524,5.843,1525,4.617,1526,2.833,1527,2.41,1528,2.826,1529,2.41]],["t/275",[33,3.86,74,4.558,292,4.63,294,4.17,295,2.821,326,1.917,414,4.184,661,5.264,1457,6.156,1530,7.824]],["t/277",[267,4.107,785,5.64]],["t/279",[323,2.763,739,6.844,808,8.401,1531,7.443]],["t/281",[104,3.744,117,2.249,224,1.833,252,3.701,293,8.08,299,5.369,341,2.772,1188,7.43,1195,6.461,1339,5.397,1532,7.628]],["t/284",[31,1.979,50,2.05,52,3.104,98,1.946,117,1.161,129,1.215,135,1.894,166,2.366,175,1.472,177,2.26,178,1.646,183,1.549,188,3.384,202,2.002,224,1.132,236,4.403,252,2.286,266,1.861,267,2.26,292,2.787,294,2.997,299,5.905,308,2.424,326,1.154,329,1.698,341,1.712,359,3.023,375,3.99,379,1.783,380,1.74,382,2.724,387,2.744,388,3.837,393,2.121,401,2.553,403,3.043,511,1.441,514,1.74,569,2.909,577,2.235,579,2.339,582,1.877,590,2,597,3.159,598,3.159,603,2.188,637,3.706,638,2.854,663,3.043,740,2.553,770,3.399,785,3.104,792,3.592,821,2.702,824,3.657,958,2.744,1043,5.638,1162,3.043,1188,3.837,1531,4.173,1533,5.177,1534,3.706,1535,4.173,1536,4.71,1537,4.71,1538,6.656,1539,7.315,1540,4.71]],["t/286",[31,1.761,42,0.776,52,2.64,80,1.027,98,2.909,113,2.371,145,2.142,165,2.588,175,1.85,184,2.712,185,1.468,188,2.037,192,1.768,202,1.857,257,1.901,286,3.549,294,1.804,299,4.168,302,3.01,325,1.881,326,0.981,329,2.135,341,2.56,350,1.64,351,3.166,359,1.569,360,2.298,378,5.37,379,1.517,380,1.48,382,2.423,387,2.334,388,3.263,393,1.804,436,2.539,468,2.695,511,1.225,514,2.187,569,2.588,577,1.901,579,1.989,590,1.701,597,2.81,598,2.81,603,1.861,637,3.152,638,2.538,641,5.541,663,2.588,703,2.891,740,2.171,770,2.891,785,2.64,797,2.298,802,3.393,821,2.298,824,2.201,838,3.549,928,2.755,940,2.968,971,5.218,975,4.659,976,3.152,978,4.439,1065,3.055,1431,7.042,1472,3.393,1534,3.152,1541,9.123,1542,5.92,1543,6.507,1544,3.393,1545,4.387,1546,3.744,1547,3.744,1548,4.006,1549,4.659,1550,3.152,1551,3.744,1552,4.403,1553,2.695]],["t/288",[37,5.284,38,2.564,42,1.024,50,1.628,76,2.654,129,1.86,139,3.232,149,1.675,202,2.202,265,3.127,299,3.719,326,1.766,328,4.447,329,3.178,330,5.201,332,3.232,344,1.905,380,1.952,382,2.951,577,2.508,582,2.873,590,2.244,638,2.265,703,3.813,740,2.864,758,5.341,759,4.939,765,6.386,768,4.681,775,4.681,776,6.257,777,4.681,780,4.681,903,4.681,904,5.284,961,4.75,1086,3.915,1249,4.475,1273,4.475,1333,6.386,1422,4.681,1554,5.284,1555,5.807,1556,5.807,1557,5.807,1558,5.807,1559,5.807,1560,4.939]],["t/290",[5,1.356,38,1.491,50,0.947,53,1.819,80,0.788,84,1.174,95,1.37,107,3.074,117,0.758,166,3.407,173,1.563,175,0.96,177,1.475,178,2.089,183,1.59,185,1.772,198,1.563,199,1.011,200,1.913,223,2.209,224,1.437,252,3.29,259,1.666,267,2.869,294,1.384,299,3.404,302,1.563,308,1.582,326,1.185,335,1.258,342,2.757,343,0.94,344,1.108,348,2.401,349,2.295,350,2.448,353,4.524,358,2.775,359,2.656,367,4.705,384,2.344,397,2.114,401,3.675,402,1.214,429,1.666,478,1.849,501,1.962,524,1.849,538,1.428,554,2.164,566,2.935,587,2.025,597,3.5,598,3.5,607,1.413,804,1.88,811,1.986,824,1.689,1043,4.097,1101,2.603,1143,2.723,1180,3.254,1211,2.873,1344,3.688,1425,2.723,1445,3.074,1505,3.584,1531,2.723,1532,7.374,1535,5.298,1537,3.074,1538,3.074,1540,4.836,1561,2.723,1562,6.572,1563,3.074,1564,7.83,1565,3.074,1566,7.83,1567,7.83,1568,3.074,1569,3.074,1570,6.572,1571,7.658,1572,3.074,1573,3.074,1574,3.378,1575,2.164,1576,2.419,1577,5.316,1578,5.316,1579,5.979,1580,3.378]],["t/292",[5,0.987,12,1.92,30,2.722,31,2.196,42,0.843,50,1.34,80,1.612,84,2.401,96,3.224,117,1.073,152,2.111,178,1.52,183,1.431,199,2.428,209,4.517,222,4.031,223,1.607,224,1.774,235,2.867,251,1.765,255,2.617,262,1.939,309,3.685,326,1.066,342,3.022,344,1.569,351,3.363,353,2.16,368,3.555,402,1.719,454,3.408,503,2.496,511,1.923,512,3.608,518,3.423,554,3.062,567,5.079,569,3.228,590,2.671,644,2.296,785,4.144,802,5.326,846,3.423,1021,2.708,1051,3.544,1052,5.326,1053,3.854,1064,4.517,1166,2.927,1341,4.537,1417,3.846,1424,4.537,1501,2.992,1564,4.35,1572,4.35,1581,5.198,1582,4.781,1583,4.35,1584,4.781,1585,4.35,1586,4.795,1587,4.066,1588,4.35]],["t/295",[125,4.407,149,2.398,215,3.246,231,3.671,233,3.8,250,6.407,268,5.768,344,2.728,362,3.59,425,3.441,1254,5.202,1353,6.702,1408,5.952,1411,6.162,1513,6.162]],["t/297",[21,1.655,80,1.898,84,2.409,104,2.145,117,1.078,129,1.128,150,4.553,151,4.186,152,2.121,206,1.504,224,1.779,230,2.25,253,3.735,258,2.587,261,4.34,295,1.576,394,2.196,397,5.093,407,3.077,449,3.006,460,3.006,465,3.369,487,4.126,503,2.508,515,2.436,524,3.795,553,4.982,558,4.455,607,2.009,693,4.529,737,2.824,743,3.077,840,5.345,1118,6.766,1144,5.487,1354,5.088,1589,4.965,1590,7.405,1591,4.371,1592,4.086,1593,4.804,1594,3.333,1595,6.921,1596,8.139,1597,6.921,1598,8.139,1599,6.31,1600,6.935,1601,5.14,1602,6.935]],["t/299",[224,2.248,230,4.097,231,3.863,288,5.899,460,5.475,786,5.604,928,5.475,1033,3.381,1603,8.75]],["t/301",[5,0.359,21,1.052,30,2.199,31,1.104,42,0.538,53,0.937,64,0.72,69,0.654,80,0.712,84,2.136,95,1.239,115,1.065,117,1.487,129,1.152,145,0.847,149,0.502,151,2.099,169,0.847,173,2.583,175,0.868,177,0.76,178,0.971,183,0.914,184,1.719,185,1.018,187,1.227,190,2.354,192,0.699,195,1.467,196,2.119,198,1.413,199,0.521,202,1.336,204,1.831,205,1.795,206,0.545,215,1.817,218,2.005,219,1.548,223,1.027,224,1.344,230,3.297,233,0.795,248,1.246,253,3.413,257,0.752,258,1.644,265,0.937,267,0.76,268,2.832,277,1.173,280,1.023,284,0.937,296,1.043,297,0.908,310,5.063,312,0.969,326,0.388,327,0.401,329,1.339,332,0.969,337,0.969,342,0.558,344,0.571,346,1.506,348,0.786,349,0.752,359,0.62,360,2.13,362,0.752,368,2.099,379,0.6,380,1.027,382,1.137,393,0.713,398,0.87,400,1.207,402,0.626,421,1.246,425,2.031,430,4.026,433,0.882,460,3.07,465,2.545,467,0.87,474,0.685,499,0.937,500,1.831,501,1.506,503,3.21,504,1.207,505,1.173,506,1.246,507,0.986,508,2.354,510,1.043,511,1.554,512,0.908,513,1.341,514,0.585,515,1.548,516,2.191,517,1.143,518,1.246,519,1.87,520,0.786,525,3.636,534,1.403,538,0.736,542,2.885,545,0.858,547,1.29,550,2.187,551,1.246,558,2.453,560,5.714,561,1.48,566,2.191,569,1.623,570,1.644,571,6.067,572,0.61,573,0.858,574,0.858,575,0.952,576,0.937,577,0.752,578,0.969,579,0.786,580,0.815,581,0.908,582,0.631,606,1.467,614,4.509,632,1.043,657,0.986,745,3.512,757,1.207,762,1.29,763,3.713,795,0.908,823,0.986,836,3.687,840,2.354,958,1.619,981,2.731,984,1.065,1004,4.957,1011,2.779,1014,1.831,1033,1.18,1058,1.403,1062,2.119,1094,1.207,1118,5.041,1119,2.597,1120,1.341,1122,2.354,1226,1.48,1250,1.29,1254,1.089,1276,1.341,1304,1.403,1339,0.937,1354,0.937,1389,1.594,1590,6.031,1591,3.713,1594,1.207,1599,1.583,1601,2.264,1604,3.054,1605,1.74,1606,1.74,1607,1.74,1608,6.149,1609,2.462,1610,2.597,1611,5.229,1612,3.713,1613,1.583,1614,3.054,1615,2.779,1616,1.74,1617,3.054,1618,1.74,1619,1.74,1620,3.29,1621,1.583,1622,1.29,1623,1.74,1624,1.583,1625,3.054,1626,2.059,1627,3.636,1628,4.464,1629,1.74,1630,1.74]],["t/304",[5,1.383,42,1.536,80,1.563,84,2.328,125,3.552,215,2.181,224,1.905,230,4.082,231,2.958,262,2.718,295,2.198,300,5.225,311,4.017,314,2.614,368,3.446,373,3.667,422,5.056,423,4.77,425,2.774,481,6.717,529,3.729,566,3.892,928,4.193,931,5.699,984,4.102,1162,3.939,1389,4.55,1420,3.397,1455,4.193,1513,4.966,1631,6.097,1632,6.701,1633,6.097,1634,5.164,1635,6.097]],["t/306",[5,2.159,33,3.673,92,2.728,134,6.103,224,2.287,259,3.905,262,3.212,291,5.495,370,5.67,408,4.073,493,5.495,494,5.495,495,4.567,496,6.384,1636,7.92,1637,7.92,1638,7.92]],["t/308",[5,0.717,12,0.81,21,0.695,30,1.801,31,0.94,42,0.612,53,1.87,64,1.437,80,0.471,84,1.588,95,1.409,117,0.779,125,1.069,129,1.438,145,0.982,169,0.982,173,2.832,175,1.902,177,2.371,178,1.946,183,1.039,184,2.772,185,1.158,187,1.836,190,3.244,192,0.81,194,1.186,195,0.969,202,1.453,204,2.082,205,2.041,206,1.087,215,1.768,221,1.587,223,1.826,224,1.795,230,0.945,233,0.922,240,1.716,247,0.891,253,1.317,255,1.104,261,1.262,262,0.818,264,1.716,265,1.086,267,1.516,268,1.4,269,1.292,280,1.186,295,0.662,297,1.053,310,6.083,326,1.019,327,0.799,329,1.5,332,1.933,335,0.751,337,1.123,342,0.646,344,0.662,346,1.712,348,0.911,349,1.5,359,0.719,360,2.387,368,1.786,379,0.695,380,1.167,382,1.293,393,0.827,401,0.995,402,1.248,414,0.982,421,1.444,422,2.835,423,2.973,425,2.248,430,4.545,433,1.76,435,1.023,436,3.133,465,2.769,474,1.368,499,1.086,500,3.257,501,2.005,503,1.813,504,1.4,505,1.36,506,1.444,507,1.967,508,2.676,510,1.209,511,1.272,512,1.813,513,1.555,514,0.678,515,1.76,516,2.425,517,1.324,518,1.444,519,1.235,520,0.911,522,1.186,523,2.676,524,1.104,525,5.31,526,2.799,527,2.486,528,1.444,529,2.544,530,2.953,531,1.551,538,0.853,542,3.1,545,2.254,560,5.25,564,2.676,565,1.555,566,2.987,568,1.495,569,1.818,570,1.086,571,3.082,572,0.707,573,0.995,574,0.995,575,1.104,576,1.086,577,0.871,578,1.123,579,0.911,580,1.626,581,1.813,582,0.732,625,1.444,661,1.235,823,1.143,984,1.235,992,1.835,1250,1.495,1264,3.325,1266,1.053,1339,1.086,1389,1.053,1420,1.023,1511,2.341,1520,2.676,1589,1.444,1627,4.026,1628,4.942,1639,3.685,1640,3.888,1641,6.884,1642,1.36,1643,4.572,1644,2.017,1645,2.486,1646,2.676,1647,1.555,1648,2.017,1649,5.207,1650,1.716,1651,1.36,1652,2.017,1653,1.835,1654,2.017]],["t/311",[292,4.972,323,2.763,327,2.126,758,6.225]],["t/313",[267,4.107,640,6.972]],["t/315",[323,2.788,739,6.908,1531,7.512]],["t/317",[202,2.35,340,3.589,341,2.341,379,2.439,380,2.379,384,4.912,387,3.752,388,5.247,389,5.707,390,6.441,391,6.021,392,5.247,515,4.578,606,3.4,675,3.641,978,3.445,1553,4.334,1655,8.216,1656,10.355,1657,7.08,1658,8.216,1659,7.08,1660,7.08]],["t/319",[24,2.475,31,2.79,42,0.823,92,1.609,114,2.085,117,1.796,124,5.236,149,1.96,190,1.788,202,2.118,262,2.756,299,5.632,340,2.367,341,3.09,344,1.532,379,1.609,380,1.57,382,2.53,394,2.135,402,1.679,425,1.933,474,2.676,511,2.447,597,2.934,598,2.017,603,3.717,606,2.243,637,3.343,638,3.124,661,2.859,675,2.402,725,3.764,758,3.148,759,5.778,760,4.249,761,4.249,764,7.286,765,5.477,766,3.764,767,4.249,768,3.764,773,4.249,774,4.249,775,3.764,776,4.714,777,3.764,778,4.249,779,4.249,780,3.764,781,4.249,782,4.249,1327,5.778,1331,5.778,1333,6.455,1585,4.249,1655,6.182,1656,7.286,1661,4.67,1662,6.794,1663,4.249,1664,4.67,1665,4.67]],["t/321",[30,3.262,31,2.241,42,1.093,50,1.738,80,1.447,84,2.878,117,1.391,152,2.739,178,1.972,183,1.856,222,4.243,224,1.811,235,3.719,262,2.516,309,4.78,342,1.987,344,2.035,368,4.26,402,2.23,454,4.085,503,3.238,511,2.305,512,4.324,518,4.441,567,5.183,640,4.597,644,2.979,1021,3.513,1064,5.19,1417,4.61,1424,5.438,1501,3.881,1581,5.305,1583,5.644,1586,5.747,1587,5.275,1588,5.644]],["t/323",[35,5.365,42,1.173,136,3.77,169,3.239,175,2.745,200,3.77,326,1.483,342,2.133,353,3.92,359,3.093,384,4.618,515,4.399,685,4.765,713,4.488,1033,2.572,1344,4.618,1563,6.056,1565,6.056,1566,9.9,1567,9.9,1568,6.056,1571,9.425,1573,6.056,1575,4.263,1576,4.765]],["t/326",[1663,8.401,1666,9.234,1667,9.234,1668,8.401]],["t/328",[20,5.369,50,2.35,224,1.833,274,5.026,297,4.376,326,1.868,553,5.132,664,5.817,786,5.369,1073,6.42,1669,7.628,1670,4.835,1671,8.525]],["t/330",[908,5.887,1672,8.559]],["t/334",[60,3.803,62,6.629,139,5.608,215,3.28,231,3.217,302,3.37,304,4.126,306,5.707,325,3.112,329,2.39,487,3.694,686,4.783,786,5.89,907,4.912,1161,4.282,1296,4.46,1493,5.873,1673,6.629,1674,9.168,1675,4.912,1676,5.216,1677,6.629,1678,5.615,1679,6.629]],["t/336",[30,3.389,31,2.328,50,2.614,54,4.284,80,1.738,117,1.671,178,3.237,211,2.156,215,2.425,222,2.113,223,3.135,230,4.368,235,3.186,241,3.065,247,3.29,302,2.458,307,3.186,368,3.832,442,3.489,454,2.62,460,4.663,511,2.595,524,2.908,567,3.325,606,3.579,644,3.579,908,3.325,1014,3.186,1057,4.095,1064,2.958,1161,3.124,1162,3.124,1177,4.284,1178,3.325,1198,4.147,1352,3.325,1389,4.868,1417,4.147,1633,4.835,1675,3.583,1676,3.804,1680,3.939,1681,6.006,1682,5.523,1683,4.284,1684,4.519,1685,4.835,1686,4.095]],["t/338",[60,4.038,297,4.983,311,4.638,402,2.781,406,5.079,487,3.922,554,4.955,566,3.454,724,5.215,795,4.038,1142,5.962,1144,5.215,1352,4.841,1674,7.038,1675,5.215,1678,5.962,1681,6.236,1687,7.038,1688,7.736,1689,7.736,1690,7.736,1691,6.579,1692,6.236,1693,7.736]],["t/340",[5,0.588,11,1.744,30,2.663,31,1.829,42,0.502,50,1.895,59,1.387,80,1.736,84,1.611,117,1.517,139,4.44,149,0.822,178,2.674,187,1.144,192,1.144,202,1.008,211,3.556,215,3.033,218,1.871,219,2.352,222,2.689,223,2.827,224,1.282,226,1.643,230,3.166,243,1.783,247,1.258,251,2.165,253,2.225,257,2.003,262,1.156,263,2.297,266,1.667,295,0.935,302,1.318,306,1.614,307,1.708,314,1.112,327,0.656,344,1.522,362,2.003,368,3.017,397,1.783,403,1.675,422,2.421,423,3.21,425,1.92,433,1.445,435,1.445,454,1.405,460,3.671,461,1.744,470,1.643,474,1.122,483,1.51,499,1.534,503,1.487,511,2.22,516,2.071,520,1.287,524,3.21,538,2.858,542,1.168,547,2.112,567,1.783,590,1.792,597,2.003,598,2.003,606,1.369,644,2.228,724,1.921,755,2.781,762,2.112,823,1.614,824,1.424,851,1.559,908,1.783,969,1.871,996,2.196,1014,1.708,1057,2.196,1064,1.586,1106,2.498,1160,1.586,1162,3.448,1178,2.903,1198,3.265,1213,2.112,1254,1.783,1266,1.487,1274,1.825,1352,3.671,1385,2.297,1389,3.529,1417,3.265,1594,1.977,1597,2.423,1675,3.127,1676,3.321,1681,6.779,1682,3.438,1684,2.423,1685,2.593,1686,2.196,1691,3.945,1694,2.423,1695,4.989,1696,3.974,1697,4.639,1698,4.639,1699,2.85,1700,2.423,1701,2.297,1702,2.85,1703,2.297,1704,2.593,1705,2.112,1706,2.85,1707,2.85,1708,2.85,1709,2.85,1710,2.196,1711,4.639,1712,2.423]],["t/343",[5,1.402,42,1.197,95,2.755,149,1.959,224,2.392,230,4.117,262,2.755,269,4.35,294,2.783,295,2.228,300,4.072,308,3.181,309,7.514,321,3.917,362,2.933,422,3.545,423,3.717,520,3.068,549,6.1,561,5.776,566,3.033,666,4.35,667,4.158,956,5.475,957,4.579,958,3.6,1254,4.25,1420,3.443,1713,6.792,1714,6.179,1715,6.792,1716,5.776,1717,6.792,1718,6.179]],["t/345",[5,2.197,21,2.841,33,3.764,224,2.328,259,4.066,291,5.721,370,5.903,408,4.241,493,5.721,494,5.721,495,4.756,496,6.647]],["t/347",[5,0.415,31,1.466,33,0.762,42,0.61,53,1.863,64,1.432,84,1.583,95,1.404,104,0.897,117,0.451,125,1.065,129,1.679,145,0.978,149,1.315,157,1.082,169,0.978,173,2.825,175,1.898,177,1.99,178,1.942,183,1.035,184,2.339,185,1.154,187,2.176,190,2.891,192,1.39,202,1.45,204,2.075,205,2.034,206,0.629,215,1.763,221,1.582,223,1.821,224,1.335,230,1.621,233,0.918,253,3.297,265,1.082,267,1.511,268,1.394,280,1.181,294,1.418,295,0.659,297,1.049,310,5.844,321,1.159,326,1.016,327,0.797,329,1.495,332,2.537,335,0.748,337,1.118,342,0.644,346,1.706,348,0.908,349,0.868,359,0.716,360,2.379,379,0.692,380,1.163,382,1.289,393,0.823,401,0.991,402,0.722,414,0.978,421,1.438,422,2.379,423,2.494,425,1.432,430,2.828,433,1.754,435,2.311,436,1.996,460,2.852,465,2.242,474,1.363,481,1.548,499,1.082,500,3.248,501,1.999,503,1.806,504,1.394,505,1.355,506,1.438,507,1.138,508,2.667,510,2.733,511,0.963,512,1.806,513,1.548,514,1.532,515,1.754,516,2.419,517,1.319,518,1.438,519,2.118,520,2.059,522,1.181,523,2.667,524,1.894,525,5.299,526,2.789,527,3.878,528,1.438,529,1.926,530,1.709,532,2.034,538,2.29,542,1.868,543,1.73,545,1.706,558,1.73,560,4.96,564,3.513,566,1.545,568,1.489,569,1.813,570,1.082,571,3.073,572,1.212,573,2.248,574,2.248,575,1.894,576,1.082,577,0.868,578,1.118,579,0.908,580,0.941,581,1.049,582,0.729,621,1.287,662,2.216,666,4.837,667,4.623,693,1.118,823,1.138,1118,4.373,1119,3.876,1120,1.548,1122,1.548,1240,1.438,1264,2.118,1266,1.049,1450,1.489,1511,1.355,1520,1.548,1528,1.23,1612,1.828,1613,1.828,1639,1.62,1641,1.828,1678,1.548,1694,3.876,1718,4.147,1719,7.149,1720,3.461,1721,1.62,1722,2.009,1723,1.548,1724,2.009,1725,4.929,1726,2.009,1727,3.461,1728,3.461,1729,2.009,1730,2.009,1731,2.009,1732,4.558]],["t/350",[13,2.855,136,4.381,566,3.454,567,4.841,590,3.689,705,5.215,706,5.079,1172,7.357,1696,4.547,1733,9.421,1734,8.686,1735,8.686,1736,7.736,1737,9.547,1738,9.547,1739,7.736,1740,7.736]],["t/353",[20,5.604,39,7.441,42,1.542,50,2.452,441,5.246,934,3.446,1741,7.961,1742,8.75,1743,7.053,1744,8.75]],["t/357",[5,1.717,57,5.308,84,2.168,98,2.346,125,3.308,175,2.365,199,1.867,215,2.707,219,3.164,224,2.181,233,2.853,250,4.81,251,2.304,253,2.367,258,3.361,261,5.205,265,3.361,267,3.631,268,4.33,296,4.987,325,2.666,333,6.307,334,5.308,362,2.695,425,3.443,438,4.81,483,3.308,487,4.217,514,2.098,586,4.468,762,4.626,795,3.258,1254,5.205,1296,3.821,1745,5.679,1746,6.241,1747,6.241,1748,6.241,1749,5.679,1750,6.241,1751,4.626,1752,3.821]],["t/359",[11,3.797,38,3.657,50,1.738,108,4.304,117,1.391,157,3.34,175,1.763,178,1.972,206,2.919,215,2.696,222,2.467,223,2.085,224,2.267,226,3.577,262,2.516,300,3.719,301,5.275,302,2.869,306,3.513,429,3.059,456,4.78,472,4.072,529,3.452,566,3.699,823,3.513,984,3.797,1329,4.182,1339,5.359,1389,5.195,1421,5.438,1475,4.78,1589,6.677,1642,6.287,1680,4.597,1683,5,1753,6.203,1754,5.275]],["t/361",[12,0.753,31,1.866,50,1.211,59,0.912,84,1.132,92,0.646,98,1.224,114,0.837,117,0.42,121,1.342,129,0.44,149,1.247,157,1.009,175,0.533,178,1.642,183,0.561,184,1.141,185,0.625,187,3.075,195,0.9,196,1.3,199,0.975,202,1.271,215,0.61,222,0.745,223,2.455,224,1.852,226,1.879,230,0.878,233,2.361,235,1.953,253,3.933,255,1.025,258,1.009,260,3.203,265,2.781,266,0.674,267,0.818,277,1.263,280,1.101,283,1.444,295,1.418,312,2.875,313,2.087,314,0.731,333,1.263,348,3.115,349,3.306,350,2.851,362,0.809,396,3.308,408,0.964,415,2.332,429,0.924,430,3.813,433,1.652,435,1.652,436,2.979,438,2.511,449,2.039,454,3.775,460,1.173,465,0.776,472,1.23,484,1.389,487,2.191,501,0.692,511,1.628,516,0.837,522,1.101,531,1.455,536,1.3,538,0.792,542,3.374,543,4.116,544,3.483,545,4.06,551,2.332,566,3.556,582,0.68,586,1.342,614,4.678,644,2.481,646,2.039,657,1.061,662,1.2,666,5.273,743,1.2,795,0.978,797,1.701,823,1.061,981,2.875,995,1.123,1014,1.123,1092,1.081,1100,1.2,1106,1.009,1112,4.222,1113,1.594,1142,1.444,1143,1.51,1160,1.813,1198,1.043,1228,1.342,1235,1.444,1254,2.039,1266,1.701,1276,2.511,1315,1.51,1317,1.3,1352,2.704,1403,1.123,1592,1.594,1621,2.964,1683,1.51,1725,6.645,1755,1.874,1756,1.705,1757,1.594,1758,2.964,1759,3.981,1760,1.594,1761,1.594,1762,1.594,1763,1.705,1764,4.7,1765,1.705,1766,1.594,1767,1.705,1768,1.705,1769,1.389,1770,1.705,1771,1.594,1772,1.705,1773,1.705,1774,1.705,1775,3.258,1776,1.874,1777,1.874,1778,1.874,1779,8.234,1780,5.166,1781,7.963,1782,4.322,1783,1.874,1784,1.705,1785,5.166,1786,1.874,1787,1.874,1788,5.851,1789,5.166,1790,1.874,1791,1.342,1792,1.874,1793,1.705]],["t/363",[38,3.524,42,1.407,117,1.791,129,1.874,206,2.499,215,3.168,220,5.538,224,1.745,361,4.887,425,3.304,661,4.887,986,6.435,1329,5.382,1352,4.995,1494,6.789,1529,6.789,1589,5.715,1634,6.152,1642,5.382,1794,7.983]],["t/365",[2,0.865,5,1.297,31,2.143,38,1.67,42,0.495,64,0.654,76,0.723,80,0.369,84,0.549,114,0.706,117,0.849,129,1.231,149,1.513,152,0.698,157,0.851,175,1.491,178,0.503,183,0.473,184,2.474,185,0.527,187,0.635,188,3.664,196,1.097,199,1.371,202,2.262,206,1.184,209,4.535,215,0.913,219,0.802,220,1.947,222,1.822,224,1.374,226,3.025,253,4.062,259,0.78,260,1.172,272,1.345,273,0.989,283,1.218,295,0.921,304,0.895,312,3.497,313,3.718,314,0.617,315,1.172,316,1.274,323,0.473,330,1.842,335,0.589,347,1.218,348,0.714,349,0.683,350,2.63,362,1.634,396,1.013,397,0.989,401,2.259,407,1.013,413,0.79,423,0.865,441,0.948,462,1.438,472,1.038,484,1.172,487,0.802,511,2.133,531,0.706,536,1.097,538,0.668,542,4.179,543,0.79,544,1.066,551,1.132,566,0.706,581,0.825,590,1.084,644,0.759,646,0.989,657,1.589,658,1.218,661,0.968,918,1.438,969,1.038,995,0.948,1033,0.611,1051,2.08,1052,4.473,1100,2.934,1106,0.851,1112,5.23,1113,1.345,1121,1.097,1125,1.345,1142,1.218,1160,0.88,1162,0.929,1198,0.88,1228,1.132,1235,1.218,1238,2.009,1266,0.825,1276,2.163,1329,1.066,1352,2.367,1389,0.825,1420,2.322,1494,2.386,1529,1.345,1589,2.708,1634,1.218,1642,2.551,1680,1.172,1681,3.693,1696,5.122,1759,1.218,1760,1.345,1761,1.345,1762,9.137,1764,4.771,1765,1.438,1766,1.345,1767,1.438,1768,1.438,1769,2.08,1770,1.438,1771,1.345,1772,1.438,1791,3.279,1793,4.168,1795,1.218,1796,2.806,1797,2.553,1798,5.244,1799,5.244,1800,5.244,1801,5.244,1802,1.581,1803,1.581,1804,1.581,1805,1.581,1806,1.581,1807,1.581,1808,2.806,1809,1.581,1810,1.438,1811,3.05,1812,1.438,1813,1.842,1814,1.345,1815,1.581,1816,1.581,1817,1.581,1818,1.581,1819,1.581,1820,2.386,1821,1.438,1822,1.581,1823,4.581,1824,4.965,1825,1.581,1826,1.581,1827,1.581]],["t/368",[247,4.077,323,2.763,1828,9.234,1829,9.234]],["t/370",[30,1.773,134,3.469,169,2.191,210,6.387,211,1.826,214,4.736,284,2.424,511,2.182,517,2.956,667,2.756,686,6.839,853,3.337,870,8.859,1064,3.681,1402,3.469,1424,5.674,1586,3.124,1830,4.502,1831,4.502,1832,8.377,1833,4.502,1834,7.841,1835,4.502,1836,4.502,1837,4.502,1838,4.502,1839,4.096,1840,4.502,1841,4.502,1842,4.502,1843,4.502,1844,4.502,1845,4.502,1846,4.502,1847,4.502,1848,4.502,1849,4.502,1850,4.502,1851,4.502,1852,4.502,1853,4.502,1854,4.502,1855,4.502,1856,4.502,1857,4.502,1858,4.502,1859,4.502,1860,4.502,1861,4.502,1862,4.502,1863,4.502,1864,4.502,1865,4.502,1866,4.502,1867,4.502,1868,4.502,1869,4.502,1870,4.502,1871,4.502,1872,4.502,1873,4.502,1874,4.502,1875,4.502,1876,4.502,1877,4.502,1878,4.502,1879,4.502,1880,4.502,1881,4.502,1882,4.502,1883,4.502,1884,4.502,1885,4.502,1886,4.502,1887,4.502,1888,4.502,1889,4.502,1890,4.502,1891,4.502,1892,4.502,1893,4.502,1894,4.502]],["t/374",[13,3.019,53,4.403,171,7.32,221,3.738,295,2.683,408,4.206,465,4.088,553,5.006,582,2.966,728,6.303,908,5.117,1895,6.955,1896,6.303,1897,8.178,1898,7.441,1899,6.061]],["t/376",[5,1.299,12,1.271,13,1.168,30,1.988,47,2.346,50,0.887,65,1.732,76,2.307,171,5.326,173,2.335,175,1.79,177,1.382,184,3.076,185,2.099,187,3.869,190,3.361,192,1.271,202,0.687,203,4.293,206,0.991,211,2.047,247,1.397,267,1.382,275,2.346,342,2.813,361,1.937,373,1.732,402,1.138,418,3.924,419,2.266,429,1.561,430,5.028,441,1.897,463,2.551,465,3.773,487,1.604,501,1.168,503,1.652,511,1.405,531,3.209,539,2.879,540,2.879,551,2.266,582,1.148,587,4.707,614,5.358,615,5.144,629,1.761,652,5.144,657,1.792,686,2.078,701,2.078,938,2.879,972,1.86,981,4.369,987,2.134,1011,3.566,1020,7.991,1123,2.266,1167,4.912,1354,1.704,1406,1.761,1420,1.604,1421,2.078,1428,2.196,1438,2.691,1544,3.89,1635,2.879,1645,2.266,1646,2.439,1680,2.346,1752,1.937,1900,7.752,1901,3.165,1902,4.593,1903,3.165,1904,4.593,1905,8.366,1906,4.593,1907,6.538,1908,3.614,1909,5.355,1910,3.165,1911,2.691,1912,7.185,1913,5.048,1914,5.048]],["t/378",[5,2.069,42,1.479,50,1.771,117,1.881,149,2.419,171,4.684,173,2.924,206,1.978,221,2.889,248,4.525,283,4.871,304,4.75,312,3.517,314,2.466,332,3.517,394,2.889,428,5.375,441,3.789,465,3.472,475,5.134,488,5.75,501,2.333,503,3.299,520,2.855,553,3.869,582,2.292,795,3.299,1033,3.241,1103,4.261,1229,4.149,1257,3.869,1285,5.375,1406,3.517,1412,5.375,1752,3.869,1915,4.684,1916,5.375,1917,5.095,1918,6.32,1919,6.32,1920,6.32,1921,6.32,1922,6.32,1923,5.75]],["t/381",[1924,6.735,1925,9.407]],["t/383",[10,3.021,20,5.195,50,2.754,149,2.34,247,3.581,297,4.234,326,2.19,327,2.263,630,4.678,1220,4.863,1455,5.076,1670,4.678,1924,5.807,1926,6.899,1927,8.112,1928,8.112]],["t/385",[10,3.642,46,5.425,92,2.772,224,2.303,329,2.64,402,2.893,626,4.404,772,4.824,950,7.809,959,6.201,1220,4.824,1686,6.201,1929,6.201,1930,7.321,1931,5.583]],["t/389",[5,1.622,42,1.385,59,3.823,116,5.297,132,4.532,133,4.532,135,3.526,191,7.149,266,2.824,307,5.779,674,6.682,713,5.297,1455,6.031,1926,6.682,1932,7.149,1933,7.857,1934,7.857,1935,6.334,1936,7.149,1937,6.682]],["t/391",[33,3.103,50,1.707,64,2.521,110,4.106,116,4.106,135,2.228,169,3.981,192,2.446,202,2.146,247,2.689,251,2.248,257,2.63,292,3.279,294,2.495,323,1.822,326,2.059,328,4.556,374,3.333,379,2.098,382,3.047,393,2.495,499,3.279,569,2.422,577,2.63,582,2.208,590,2.353,638,2.376,776,4.225,934,2.398,972,3.579,974,6.229,984,3.728,985,4.693,1166,3.728,1502,4.693,1938,4.909,1939,5.541,1940,8.407,1941,4.909,1942,5.179,1943,6.09,1944,9.24,1945,6.09,1946,6.09]],["t/393",[31,2.269,80,1.474,95,2.564,117,1.418,166,2.889,169,4.081,183,2.509,202,1.373,223,2.819,239,4.385,252,2.79,314,2.466,326,1.409,327,1.455,340,3.204,350,2.354,379,2.177,391,5.375,436,3.645,511,1.759,538,3.545,572,2.938,589,5.655,603,2.671,638,2.466,713,4.261,982,5.372,1221,4.149,1502,4.871,1701,5.095,1947,9.414,1948,10.027,1949,4.684,1950,6.32,1951,10.027,1952,6.32,1953,5.095,1954,6.32]],["t/395",[5,1.661,50,2.255,110,5.425,114,3.593,169,4.758,206,2.519,257,4.55,259,3.968,323,2.407,335,2.997,984,4.926,985,6.201,1040,7.321,1502,6.201,1940,7.321,1955,5.761,1956,8.047]],["t/397",[5,1.56,64,3.896,72,5.643,80,1.764,92,2.605,116,6.345,129,1.775,166,3.456,175,2.149,177,3.301,198,3.498,713,6.345,772,4.533,934,2.978,1033,3.637,1140,5.827,1942,6.43,1957,7.561,1958,7.561,1959,7.561,1960,7.561,1961,7.561,1962,7.561]],["t/400",[5,1.515,21,2.528,38,3.24,42,1.294,53,3.952,60,3.831,129,1.723,149,2.117,215,2.389,233,3.355,235,4.4,243,4.592,274,4.4,314,2.863,322,4.085,336,5.656,422,3.831,423,4.016,454,3.619,495,5.328,801,4.818,907,4.948,1218,4.948,1284,5.916,1296,4.493,1377,5.656,1963,6.677,1964,5.092,1965,6.242,1966,6.242,1967,4.948]],["t/402",[13,3.303,33,2.648,42,1.578,60,3.644,64,2.89,117,1.566,149,2.013,167,4.998,187,2.804,206,2.185,235,4.185,256,4.274,291,4.844,314,2.723,323,2.089,326,1.556,327,1.607,397,4.368,406,4.583,423,5.406,425,2.89,454,3.442,512,3.644,542,2.86,566,3.117,958,3.7,1146,5.38,1161,4.103,1218,4.707,1296,4.274,1367,4.707,1963,6.352,1968,6.981,1969,4.844,1970,6.352]],["t/404",[30,3.183,31,2.477,187,2.402,201,4.088,224,2.308,329,1.962,423,5.01,456,8.135,512,4.779,529,5.095,542,2.45,566,4.714,937,5.043,984,3.661,1162,4.751,1296,5.605,1389,4.779,1417,3.328,1500,8.33,1769,4.433,1969,4.149,1971,6.515,1972,8.083,1973,5.086,1974,5.981]],["t/406",[5,1.08,31,1.415,53,3.968,64,3.05,92,1.802,95,2.122,129,1.73,169,2.545,183,1.565,187,2.101,190,2.002,192,2.101,202,2.121,215,2.398,223,1.758,224,1.143,252,2.309,253,3.842,263,4.217,326,1.901,327,1.964,329,2.799,337,2.911,342,1.676,346,3.634,359,1.864,360,2.73,379,1.802,380,2.477,382,2.744,393,2.143,394,2.391,402,1.88,413,2.615,465,2.165,499,2.816,514,1.758,515,3.736,516,2.336,543,3.684,545,2.579,566,2.336,569,3.393,572,1.833,573,2.579,574,2.579,575,2.863,576,2.816,577,2.259,578,2.911,579,2.363,580,2.45,958,2.772,1159,3.434,1160,4.101,1257,3.202,1975,5.231,1976,4.217,1977,6.267]],["t/409",[10,3.585,42,1.166,50,1.853,60,3.452,69,2.485,80,1.542,129,1.553,162,7.348,262,2.682,266,2.377,302,3.997,314,3.371,321,3.814,335,2.463,364,4.734,373,3.619,395,4.588,519,4.048,547,4.901,646,4.138,771,5.096,797,3.452,851,3.619,961,5.18,1086,4.458,1319,3.887,1420,3.352,1421,4.341,1967,4.458,1978,6.612,1979,6.612,1980,6.612,1981,6.016,1982,6.016,1983,6.659,1984,6.612,1985,4.588,1986,6.016,1987,6.612,1988,4.901]],["t/411",[5,1.249,10,2.254,12,2.431,31,2.492,42,1.067,50,1.696,80,1.412,104,2.703,129,1.421,145,2.945,187,3.273,202,1.315,289,4.081,401,2.985,465,2.505,472,3.974,474,2.384,519,4.988,542,3.339,543,4.605,545,2.985,590,2.339,597,2.614,598,2.614,666,5.9,701,3.974,734,5.148,877,4.486,972,4.789,995,3.629,1033,2.339,1092,3.491,1096,3.974,1106,4.387,1147,4.333,1160,5.127,1571,5.148,1601,4.486,1626,4.081,1721,4.879,1988,6.039,1989,8.148,1990,6.053,1991,8.148,1992,4.879]],["t/413",[5,1.097,10,2.775,12,2.134,31,2.016,42,0.937,50,1.489,80,1.738,104,3.327,129,1.248,145,2.586,187,2.993,201,2.373,202,1.154,206,1.664,289,3.583,334,4.519,343,1.479,356,3.583,394,2.429,401,2.62,465,2.2,467,3.725,472,3.489,474,2.093,528,3.804,542,3.053,543,4.302,545,2.62,582,1.927,590,2.053,597,2.295,598,2.295,646,3.325,666,5.511,701,4.892,706,4.892,734,4.519,877,5.523,972,5.058,995,3.186,1033,2.053,1092,4.297,1096,3.489,1100,3.404,1106,2.861,1112,3.253,1121,5.17,1147,3.804,1349,3.404,1519,4.835,1601,3.939,1646,4.095,1988,5.523,1992,4.284,1993,7.451,1994,8.605,1995,5.314,1996,9.327,1997,5.314]],["t/415",[5,1.828,10,3.299,31,2.094,59,3.766,80,2.066,102,3.894,117,2.247,149,1.619,178,1.784,192,2.254,295,1.841,343,2.154,398,2.805,467,2.805,478,3.071,522,3.299,555,6.577,582,2.035,607,2.347,701,3.684,797,2.929,840,4.325,972,3.299,1092,5.973,1198,3.123,1443,4.325,1601,4.159,1700,4.773,1988,6.566,1998,6.827,1999,5.612,2000,5.612,2001,8.858,2002,8.06,2003,4.524,2004,4.524,2005,5.612,2006,7.041,2007,5.612,2008,5.612,2009,4.773,2010,6.238]],["t/418",[53,3.894,60,3.776,69,2.718,84,2.513,92,2.492,215,2.354,222,3.64,223,2.431,224,2.001,229,5.574,233,3.306,235,4.337,243,4.526,322,4.026,422,4.778,447,5.018,454,3.567,472,4.749,483,3.834,514,2.431,566,4.088,704,5.83,1033,2.795,1218,4.876,1511,4.876,1966,6.151,2011,7.233,2012,7.233,2013,7.233,2014,7.233]],["t/420",[5,1.609,53,4.198,175,2.216,222,3.1,223,2.62,224,2.097,231,3.442,322,4.339,333,5.256,408,4.01,422,4.07,477,6.63,483,4.132,492,5.778,495,4.496,566,3.481,801,6.298,1296,4.773,2015,7.796,2016,7.796,2017,7.093,2018,7.796]],["t/422",[31,1.372,53,3.882,64,2.984,95,2.057,129,1.693,169,2.468,183,1.517,190,1.942,192,2.037,202,2.096,211,2.925,215,2.347,223,1.705,224,1.997,252,2.239,253,3.913,326,1.87,327,1.931,329,2.752,337,2.823,342,1.625,346,3.555,359,1.808,360,2.648,379,1.747,380,2.423,382,2.685,393,2.078,394,3.296,402,1.823,413,2.535,422,2.648,499,2.731,514,1.705,515,3.655,516,2.265,543,3.604,545,2.501,566,4.079,569,3.336,572,1.777,573,2.501,574,2.501,575,2.776,576,2.731,577,2.19,578,2.823,579,2.291,580,2.375,958,2.688,1159,3.33,1160,4.669,1257,3.105,1389,2.648,1976,4.088,2019,5.072]],["t/424",[189,5.588,2020,9.32,2021,9.32]],["t/427",[42,1.333,92,2.605,152,3.338,206,2.946,323,2.262,325,3.23,425,3.13,505,5.097,549,5.246,656,4.071,788,4.208,793,4.628,1182,5.218,1394,6.095,1505,5.097,1670,4.361,1824,5.604,1899,5.604,1967,5.097,2022,5.604,2023,6.879,2024,6.879,2025,6.43,2026,6.095]],["t/429",[13,3.12,572,2.962,590,4.159,684,7.467,687,7.692,1696,5.922,2027,8.568,2028,8.454,2029,8.454]],["t/431",[5,1.508,21,2.086,35,3.223,42,1.067,76,1.828,84,1.389,117,0.897,149,1.153,157,2.153,173,1.85,175,1.137,184,2.121,185,2.019,187,3.517,190,2.318,192,1.606,193,2.774,199,1.812,202,1.587,206,1.895,253,3.901,267,1.746,325,1.708,335,2.255,348,2.735,349,2.615,425,1.655,429,1.972,430,3.161,507,2.265,514,2.035,538,1.69,542,1.638,543,3.027,544,4.082,558,1.999,566,1.786,570,2.153,572,1.401,590,2.34,607,1.672,656,2.153,684,7.305,701,2.625,824,3.027,1004,4.881,1011,3.429,1014,2.397,1112,4.473,1118,6.269,1129,3.401,1133,3.401,1160,2.225,1161,2.35,1182,2.946,1354,2.153,1389,2.087,1505,2.696,1611,5.149,1626,2.696,1814,3.401,1908,4.335,2030,3.999,2031,3.638,2032,3.638,2033,7.307,2034,6.055,2035,3.401,2036,3.999,2037,7.307,2038,8.382,2039,3.638,2040,5.89,2041,5.89,2042,3.223,2043,3.223,2044,3.999,2045,3.999,2046,3.401,2047,3.999,2048,3.999]],["t/434",[139,5.313,184,3.628,185,2.579,187,3.107,206,2.422,414,3.764,572,2.71,599,5.611,657,4.381,981,4.305,1011,5.407,1178,4.841,1182,3.764,1272,6.236,2022,5.734,2049,7.038,2050,7.038,2051,7.736,2052,6.579,2053,7.736]],["t/436",[15,1.587,16,1.587,17,1.587,30,3.434,31,0.637,139,1.31,184,3.653,185,1.709,187,3.83,188,4.787,202,2.161,211,1.606,214,1.685,332,1.31,368,4.484,384,1.633,501,0.869,511,2.426,535,1.633,542,3.323,572,3.055,589,5.468,599,1.384,656,1.267,686,1.545,795,1.229,854,2.748,981,2.204,1011,5.635,1056,2.142,1057,1.814,1106,3.236,1115,6.609,1228,1.685,1295,1.508,1417,1.31,1581,1.508,1824,5.384,1900,5.111,2038,10.24,2040,3.192,2041,3.192,2049,2.142,2050,4.664,2052,3.368,2054,3.368,2055,3.368,2056,3.368,2057,3.368,2058,2.002,2059,3.368,2060,4.664,2061,6.1,2062,6.1,2063,6.1,2064,6.897,2065,6.1,2066,6.1,2067,6.1,2068,6.1,2069,2.354,2070,2.002,2071,4.845,2072,1.897,2073,1.814,2074,2.354,2075,4.359,2076,3.603,2077,4.359,2078,2.354]],["t/440",[11,2.593,31,1.146,39,3.602,42,1.334,45,3.602,65,2.318,69,1.592,70,2.939,76,1.936,98,2.376,144,5.752,175,1.204,177,2.76,178,1.346,183,1.267,221,1.936,238,3.139,247,1.87,257,3.267,262,1.718,275,3.139,286,5.096,295,1.39,314,1.652,321,2.443,323,1.267,325,3.232,343,2.334,361,2.593,364,3.032,372,3.602,407,2.713,425,3.131,427,2.443,429,2.089,501,3.313,517,4.151,583,3.458,585,1.79,626,2.318,629,4.21,630,4.363,659,2.539,693,2.357,787,2.672,804,2.357,826,3.854,901,3.264,916,2.539,993,4.686,1044,3.264,1096,5.893,1192,6.218,1230,4.872,1252,3.414,1274,4.049,1295,2.713,1299,3.139,1312,2.939,1336,3.032,1367,5.1,1457,3.032,1670,2.443,1705,5.607,1812,3.854,1915,3.139,1917,3.414,2079,4.235,2080,4.235,2081,6.322,2082,5.752,2083,4.235,2084,4.235,2085,4.235,2086,4.235,2087,4.235,2088,3.854,2089,5.752,2090,4.235,2091,3.854,2092,3.854,2093,4.235,2094,3.854,2095,4.235,2096,4.235,2097,3.854,2098,3.414,2099,4.235]],["t/442",[38,2.722,42,1.454,60,3.218,72,3.696,92,2.124,117,1.383,129,1.447,149,2.379,177,4.059,199,1.844,238,4.569,257,3.562,262,2.501,283,4.751,295,2.022,323,2.782,325,2.633,329,2.022,343,2.964,403,3.623,461,3.774,470,3.555,555,5.416,583,2.818,626,5.088,787,2.605,973,4.047,1014,3.696,1057,4.751,1062,4.277,1151,9.032,1178,3.857,1182,3,1295,3.948,1312,4.277,1384,4.047,1620,4.969,2100,6.165,2101,6.165,2102,5.609]],["t/444",[5,0.909,20,2.821,24,2.334,25,2.696,26,2.891,31,0.724,38,2.873,42,0.471,50,2.17,59,1.301,60,3.397,76,1.222,78,1.803,80,1.31,88,1.856,95,1.085,108,3.056,115,1.637,117,0.6,125,1.418,129,1.318,133,1.543,149,2.755,160,3.056,175,1.252,177,3.868,178,0.85,182,1.856,198,1.237,199,1.318,219,1.356,221,1.222,224,1.227,238,4.161,239,1.856,247,1.181,257,1.902,266,2.587,270,1.268,302,1.237,306,1.515,314,1.718,319,3.55,322,2.451,326,1.251,327,1.782,335,1.64,341,0.884,343,0.744,360,1.396,362,2.81,403,2.589,425,1.107,450,1.572,473,1.572,487,1.356,511,0.744,532,2.589,555,4.724,570,3.023,579,1.208,581,2.299,583,3.289,622,2.969,626,5.322,629,1.488,632,2.64,644,2.115,646,3.513,703,3.686,743,2.821,787,1.13,886,2.433,901,2.061,924,2.156,932,4.388,959,2.061,993,5.333,1033,1.033,1102,4.007,1166,1.637,1207,1.982,1254,4.073,1287,2.275,1319,2.589,1336,1.915,1396,2.275,1402,2.061,1470,4.007,1475,2.061,1504,1.856,1513,1.982,1678,2.061,1680,3.264,1917,2.156,1967,1.803,1982,2.433,1998,3.394,2098,3.55,2103,4.404,2104,2.675,2105,2.433,2106,2.675,2107,5.614,2108,4.404,2109,3.394,2110,2.675,2111,7.196,2112,2.675,2113,1.756,2114,2.675,2115,1.713,2116,2.433,2117,2.675,2118,2.675,2119,2.675,2120,2.275,2121,2.675,2122,2.675,2123,2.061,2124,2.675,2125,2.675,2126,2.675,2127,2.433,2128,2.675,2129,2.675,2130,2.675,2131,2.675,2132,2.675,2133,2.675,2134,2.675,2135,2.675,2136,2.675,2137,2.675,2138,2.675,2139,2.275,2140,2.675,2141,5.614,2142,2.433,2143,2.275,2144,2.675,2145,2.275,2146,2.675,2147,2.675]],["t/447",[5,1.45,10,2.821,20,2.719,21,1.463,24,1.356,25,1.566,26,1.68,42,0.451,50,0.717,52,1.534,64,1.059,69,0.962,76,3.983,80,1.269,84,2.44,88,1.775,95,1.038,104,1.142,117,0.574,129,0.601,145,1.245,149,1.827,157,1.377,165,3.723,178,2.408,183,1.27,192,1.027,195,1.229,198,1.184,199,2.102,202,1.743,206,0.801,255,1.4,256,3.877,262,1.038,266,0.92,296,1.534,311,1.534,314,1.656,318,1.972,321,1.476,326,1.566,327,1.617,328,2.093,329,0.839,341,0.846,343,1.181,344,0.839,379,0.881,380,0.86,382,1.581,387,1.356,393,1.048,395,2.945,403,1.504,414,2.066,465,1.059,472,1.68,473,1.504,501,0.944,511,0.712,514,1.829,531,1.142,569,1.688,572,1.906,577,1.105,579,1.156,580,1.198,581,1.335,583,4.214,590,1.64,607,2.649,608,2.495,615,1.832,621,1.639,626,2.978,628,1.972,629,4.216,630,2.448,690,1.775,695,3.039,726,2.062,770,1.68,787,2.969,797,1.335,820,1.601,823,1.449,824,4.012,849,2.062,889,4.628,934,1.008,939,1.832,940,1.725,961,1.534,974,1.725,975,1.832,976,1.832,977,1.504,991,6.391,993,3.147,998,2.176,1031,2.176,1042,1.896,1096,1.68,1125,2.176,1167,1.601,1203,1.601,1254,1.601,1274,1.639,1319,1.504,1328,1.832,1420,1.297,1458,1.775,1624,2.328,1701,2.062,1703,2.062,1723,1.972,1811,2.062,1908,3.895,2098,2.062,2109,3.272,2120,2.176,2139,4.628,2143,2.176,2148,2.558,2149,5.974,2150,5.386,2151,5.441,2152,2.558,2153,4.245,2154,2.062,2155,5.441,2156,1.896,2157,2.558,2158,4.245,2159,2.558,2160,2.328,2161,2.328,2162,2.328,2163,2.558,2164,2.328,2165,2.558,2166,3.863,2167,5.386,2168,3.863,2169,2.558,2170,2.558,2171,2.328,2172,2.558,2173,2.328,2174,2.558,2175,2.558,2176,2.176,2177,1.972]],["t/449",[21,1.639,24,5.202,25,6.008,38,3.041,50,1.334,80,1.607,98,1.788,114,2.125,117,1.545,129,2.211,149,1.372,150,3.124,152,2.101,173,2.201,183,1.424,206,2.534,238,5.105,241,2.744,255,2.604,257,2.055,262,1.93,266,1.711,270,2.256,295,2.26,326,1.061,327,1.864,335,2.565,343,1.917,344,1.561,425,1.97,475,2.913,478,2.604,514,1.599,626,2.604,632,2.853,737,2.797,762,3.527,787,3.979,789,3.407,907,3.208,961,2.853,1034,3.527,1240,3.407,1286,3.302,1306,3.836,1319,2.797,1420,2.412,1462,5.552,1527,4.047,1642,3.208,1670,2.744,1899,5.105,1967,5.457,2109,6.837,2178,4.759,2179,4.33,2180,4.759,2181,4.047,2182,6.888,2183,4.759,2184,4.047,2185,4.33,2186,4.759,2187,4.33,2188,4.759,2189,4.33,2190,3.527,2191,4.759,2192,3.836]],["t/451",[38,2.881,50,1.829,54,5.261,73,5.55,80,1.522,117,1.464,129,1.532,150,4.285,165,3.836,202,1.417,206,2.682,257,2.818,259,3.218,343,1.816,413,3.262,433,3.308,467,3.262,474,3.374,520,2.948,565,5.029,583,3.916,787,2.758,824,3.262,1329,4.4,2043,5.261,2167,8.133,2193,6.526,2194,9.563,2195,5.938,2196,6.526,2197,5.55,2198,9.563,2199,8.567,2200,5.261,2201,8.701,2202,6.526,2203,6.526]],["t/453",[5,1.674,110,5.469,149,2.34,173,3.753,178,2.579,184,2.842,185,2.704,407,5.195,501,3.627,583,4.492,589,5.469,694,7.381,948,5.469,958,4.299,999,8.941,2204,8.112]],["t/455",[5,0.957,21,0.982,26,4.439,38,1.258,42,0.502,50,0.799,59,2.257,69,1.071,76,2.12,80,0.665,84,0.99,99,1.825,108,1.977,110,3.127,117,0.639,135,1.697,136,1.614,149,0.822,150,1.871,157,2.498,175,1.668,177,3.483,178,1.475,179,1.825,183,2.227,184,2.607,185,0.95,190,1.776,192,1.144,195,1.369,198,1.318,199,1.388,218,1.871,231,1.258,241,3.383,247,1.258,256,1.744,257,2.533,262,1.156,269,2.971,270,1.351,274,1.708,281,2.297,295,0.935,297,2.421,314,1.112,325,2.506,326,0.635,335,1.728,343,1.881,373,1.559,402,1.667,429,2.287,430,2.421,433,2.974,435,1.445,447,1.977,456,2.196,458,2.593,474,1.122,490,3.218,493,1.977,501,1.712,514,0.958,531,1.272,565,2.196,570,1.534,572,2.795,580,1.334,583,3.844,585,1.961,629,5.045,646,3.671,664,1.977,787,2.858,907,1.921,930,3.438,934,1.122,937,2.386,939,4.84,940,1.921,949,1.977,950,2.112,953,2.112,954,4.2,955,1.977,965,5.011,966,5.011,967,2.04,968,2.112,1000,3.739,1001,6.151,1010,2.423,1021,2.627,1094,1.977,1144,1.921,1162,2.726,1192,3.438,1264,1.744,1313,2.112,1319,2.726,1354,1.534,1368,2.04,1420,2.352,1651,1.921,1705,2.112,1752,1.744,1895,2.423,1915,3.438,1938,2.297,1966,2.423,2092,2.593,2105,2.593,2177,2.196,2179,2.593,2185,2.593,2205,2.85,2206,2.85,2207,2.593,2208,2.85,2209,4.639,2210,2.85,2211,2.85,2212,2.85,2213,2.85,2214,2.85,2215,2.85,2216,2.85,2217,2.85,2218,2.85,2219,2.423,2220,2.85,2221,2.196,2222,4.639,2223,4.639,2224,2.85,2225,2.85,2226,2.85,2227,2.85,2228,2.85,2229,2.85,2230,2.85,2231,3.945,2232,2.593,2233,2.85,2234,2.85,2235,2.85,2236,2.85,2237,2.85]],["t/458",[97,4.488,188,3.079,202,2.222,294,3.556,326,1.483,328,4.761,359,2.372,379,2.293,380,2.237,382,3.232,393,2.727,569,3.451,577,2.874,579,3.007,590,3.353,597,2.874,598,2.874,638,2.597,737,3.912,740,3.282,785,3.991,821,3.475,824,3.327,841,4.165,1096,5.697,1249,5.13,1273,5.13,1472,5.13,1492,6.056,1560,5.661,2238,8.678,2239,6.056,2240,6.656,2241,6.656,2242,4.765]],["t/461",[42,1.49,151,4.348,294,4.128,295,2.774,326,1.884,327,1.946,623,5.7,789,6.053,793,5.175,2243,8.454,2244,7.19,2245,7.692,2246,8.454]],["t/463",[10,3.19,92,2.248,98,2.453,185,2.176,199,1.953,273,4.084,323,2.861,342,2.745,348,2.948,349,2.818,350,2.431,353,4.763,358,3.407,367,4.672,745,6.133,810,5.261,815,7.285,822,5.55,836,3.913,837,5.55,838,7.709,839,5.55,843,5.261,846,4.672,849,5.261,850,5.55,851,3.571,852,5.55,853,4.837,854,4.528,855,4.528,856,5.029,1033,2.522,1929,5.029,2247,5.938,2248,5.938,2249,5.938]],["t/465",[10,2.439,60,2.319,80,1.528,99,4.195,114,1.984,178,1.412,185,1.481,190,1.7,199,1.329,202,0.965,223,2.201,224,2.002,284,3.527,295,1.457,312,2.472,323,1.329,342,2.751,348,2.007,349,1.918,350,1.654,353,4.476,358,2.319,367,3.18,397,2.78,484,3.292,545,2.19,549,3.082,566,1.984,590,2.531,644,2.133,686,2.916,745,5.57,810,3.581,816,5.57,822,3.778,836,2.663,837,3.778,838,7.381,839,3.778,843,5.28,844,4.042,845,5.959,850,5.57,858,8.716,900,2.916,978,3.187,979,2.472,1003,3.927,1033,2.531,1051,3.292,1052,5.996,1106,3.527,1190,3.778,1240,3.18,1383,3.778,1511,2.995,1791,3.18,1895,5.57,1955,3.18,2009,3.778,2035,3.778,2145,3.778,2250,4.689,2251,5.959,2252,4.442,2253,4.442,2254,4.442,2255,4.442,2256,4.442,2257,6.55,2258,4.442,2259,6.55,2260,3.778,2261,3.423,2262,5.048]],["t/468",[5,1.855,42,1.747,88,4.878,175,1.999,215,3.4,241,4.054,262,2.852,269,4.502,270,3.333,274,4.215,373,3.847,454,3.467,487,3.564,607,2.94,792,4.878,916,4.215,961,4.215,1086,4.74,1290,4.878,1420,3.564,1752,4.304,1773,6.396,1774,6.396,2263,7.345,2264,5.979,2265,5.979,2266,6.396,2267,8.179,2268,7.03]],["t/470",[2,2.279,5,0.86,21,1.435,31,2.026,38,1.839,42,1.32,64,1.724,80,2.079,129,1.466,166,1.904,198,1.927,202,1.627,215,2.032,222,2.978,223,1.4,224,1.819,226,2.402,230,1.95,252,1.839,253,3.155,262,2.533,263,5.033,265,2.243,273,2.606,343,1.159,422,3.909,423,4.099,433,3.165,435,3.165,439,8.109,474,2.459,516,1.86,531,1.86,538,3.516,542,3.069,543,3.121,544,4.209,545,4.395,573,2.054,574,2.054,580,1.95,581,2.174,667,4.585,714,4.47,726,3.357,789,2.982,995,2.497,1043,4.812,1044,6.411,1112,2.55,1118,2.982,1160,2.318,1266,2.174,1417,4.96,1528,2.55,1675,2.808,1696,4.402,1752,2.55,1810,3.789,1821,3.789,2269,8.319,2270,8.319,2271,8.319,2272,4.165,2273,8.319,2274,4.165,2275,4.165]],["t/473",[11,4.85,117,1.777,125,3.078,149,1.675,151,2.987,152,2.564,175,2.564,177,2.535,178,1.846,183,1.737,184,2.776,185,1.936,206,1.818,247,2.564,267,2.535,295,1.905,318,4.475,344,1.905,350,2.163,394,2.654,441,3.482,538,2.454,572,2.034,657,3.289,662,3.719,714,7.259,830,4.939,1003,4.75,1011,3.289,1015,3.813,1033,2.244,1122,4.475,1266,3.031,1339,3.127,1405,5.808,1545,5.341,1553,3.555,1622,4.304,1923,5.284,2156,4.304,2276,5.807,2277,8.254,2278,5.284,2279,5.284,2280,4.475,2281,5.807,2282,5.807,2283,4.681]],["t/475",[42,1.542,80,2.041,117,1.963,657,4.955,664,6.071,699,5.899,714,6.264,1405,5.246,1645,6.264,2284,7.441]],["t/477",[10,3.678,42,1.442,80,1.908,117,1.835,178,2.6,582,2.966,629,4.552,644,3.928,958,4.335,1123,5.855,1405,4.903,2279,8.986,2284,6.955,2285,8.986,2286,5.238]],["t/479",[5,1.572,10,2.837,42,1.343,117,1.709,192,3.06,202,2.234,262,3.09,314,2.972,389,7.623,392,5.646,413,4.727,531,3.402,699,5.136,797,3.977,978,3.707,1262,5.002,1405,6.165,1534,5.454,1622,7.009,2284,6.479]],["t/481",[202,2.265,389,7.769,392,5.824,978,5.289,979,4.373,1023,6.055,1024,6.682,1405,4.711,1534,5.625,1553,4.81,1622,5.824,1751,5.824,2109,6.055,2278,8.769,2287,9.638]],["t/485",[5,0.959,42,1.644,50,1.898,60,2.426,69,1.747,80,1.084,117,1.043,129,2.06,149,1.341,152,2.052,157,3.646,175,2.271,178,1.478,199,1.391,222,1.849,223,1.562,241,3.905,247,2.052,251,1.716,252,2.052,266,1.671,274,2.787,295,1.525,314,2.641,319,3.747,326,1.509,327,1.07,335,2.522,341,1.537,344,1.525,373,2.544,426,3.445,442,4.445,449,2.909,454,3.339,467,2.324,483,2.464,534,3.747,553,2.845,558,2.324,582,1.686,795,2.426,841,2.909,908,2.909,929,4.229,961,2.787,987,3.134,1032,4.229,1070,3.445,1123,3.328,1174,6.471,1180,2.845,1198,2.587,1290,3.225,1319,4.695,1334,3.328,1335,3.953,1352,4.237,1354,3.646,1366,3.445,1401,3.747,1411,3.445,1420,3.433,1595,3.953,1645,3.328,2190,3.445,2263,6.913,2288,3.953,2289,4.229,2290,5.458,2291,6.161,2292,6.771,2293,4.648,2294,4.648,2295,4.648,2296,4.648,2297,4.648,2298,4.229]],["t/487",[5,1.257,30,2.398,42,1.074,59,2.963,92,2.098,98,2.289,117,1.366,129,1.43,149,1.756,150,3.998,215,1.982,224,2.159,230,2.852,231,2.689,243,3.811,273,3.811,274,3.651,288,4.106,291,4.225,295,1.998,300,5.54,335,2.268,422,3.179,429,3.003,463,4.909,483,3.228,492,4.513,511,1.695,542,2.495,566,2.719,644,2.925,667,3.728,907,4.106,1174,4.225,1389,4.823,1420,3.087,1642,4.106,1645,4.36,1651,4.106,1964,4.225,1969,4.225,1973,5.179,2299,4.909,2300,6.09,2301,6.09,2302,6.09,2303,6.09,2304,5.541,2305,6.09,2306,6.09,2307,6.09,2308,4.909,2309,4.909]],["t/489",[30,1.544,31,1.614,76,1.792,175,1.115,184,3.585,185,1.988,187,2.395,190,3.639,192,1.574,200,2.22,202,1.568,221,1.792,224,0.857,230,1.836,253,3.881,258,2.111,265,4.344,300,2.35,310,4.74,348,2.694,349,3.748,350,2.221,368,3.068,433,3.66,435,3.66,436,2.261,474,2.349,511,1.66,516,1.751,523,3.021,525,5.351,536,2.72,537,3.16,542,3.746,545,3.56,560,5.598,564,3.021,568,2.906,571,5.439,572,1.373,573,1.933,574,1.933,575,2.145,581,2.046,706,3.916,736,2.807,836,4.328,900,2.574,995,2.35,1011,4.089,1112,4.419,1520,3.021,1575,2.511,1576,2.807,1627,7.045,1639,3.16,1640,3.334,1642,2.643,1696,5.898,1703,3.16,1757,3.334,1759,3.021,1969,2.72,2310,3.567,2311,2.906,2312,3.567,2313,3.334,2314,3.92]],["t/491",[50,1.414,76,2.307,175,1.435,179,3.232,183,1.51,184,2.931,185,1.682,190,3.489,192,2.027,202,1.56,203,4.292,209,3.998,221,2.307,265,2.717,342,3.3,343,1.404,367,5.143,430,3.75,433,3.642,435,3.642,474,2.829,571,4.843,587,5.465,703,3.313,736,3.613,836,3.026,978,3.496,1003,5.465,1020,8.514,1021,4.069,1174,3.501,1544,3.889,1575,5.358,1576,5.143,1627,6.755,1791,5.143,1907,6.536,1908,3.613,1911,6.11,2261,5.536,2262,7.024,2313,6.11,2315,3.889,2316,5.046,2317,5.536,2318,4.591,2319,5.046]],["t/493",[31,1.091,42,0.711,76,1.842,78,2.718,80,0.94,135,1.475,166,1.842,175,1.146,184,1.412,185,1.344,187,2.446,190,1.543,192,1.619,199,1.206,201,1.8,202,0.876,223,1.355,252,1.78,265,3.28,266,1.449,326,0.898,339,4.226,342,3.44,348,3.317,349,3.171,350,2.735,353,4.335,358,3.833,359,1.436,366,2.886,367,5.257,378,5.095,396,2.582,436,3.513,450,2.369,516,1.8,538,1.704,571,2.718,736,2.886,755,2.417,836,2.417,900,2.646,978,4.276,979,2.243,1046,3.428,1064,2.243,1100,3.901,1174,4.226,1198,2.243,1274,2.582,1343,4.91,1348,4.361,1364,3.249,1432,3.249,1544,4.695,1545,4.107,1575,4.703,1576,4.361,1627,4.515,1904,5.542,1906,5.542,1911,6.96,2317,7.395,2318,7.446,2320,4.031,2321,3.667,2322,5.542,2323,7.343,2324,8.787,2325,3.106,2326,4.031,2327,3.428,2328,7.343]],["t/495",[7,2.648,30,1.503,31,2.153,113,2.055,188,3.68,202,2.277,209,2.124,219,1.934,222,1.518,294,1.563,326,1.302,327,1.345,329,1.252,337,3.252,340,1.934,341,1.262,346,2.881,350,2.176,379,2.013,380,1.964,382,2.963,387,3.097,393,1.563,413,1.908,418,4.855,430,3.05,436,3.37,474,1.503,511,1.976,531,1.704,569,2.824,571,2.573,572,1.337,573,1.882,574,1.882,576,2.055,577,1.648,578,2.124,579,2.639,587,3.503,588,2.828,589,3.939,597,3.066,598,1.648,603,2.469,606,2.806,614,3.742,638,2.279,675,1.963,684,4.331,707,9.245,711,6.46,712,5.316,723,3.472,724,2.573,725,4.71,740,2.881,796,2.336,820,3.656,821,3.05,978,2.843,979,3.252,981,2.124,1003,2.288,1174,4.054,1352,2.388,1528,2.336,1575,2.444,1611,3.245,1627,4.331,1696,3.434,2310,5.316,2313,3.245,2322,5.316,2329,3.816,2330,3.816,2331,3.816,2332,3.816,2333,2.732,2334,3.816,2335,3.816,2336,3.816,2337,3.816,2338,3.816]],["t/498",[4,5.615,13,2.689,30,2.87,31,1.971,33,2.763,42,1.284,129,1.711,159,7.087,226,4.202,251,2.689,278,5.615,292,3.923,294,2.985,323,2.18,343,2.027,371,5.055,585,3.079,654,6.037,655,5.873,703,4.783,928,4.559,937,3.747,990,5.055,1367,4.912,1955,5.216,1964,5.055,2290,5.873,2339,6.196,2340,7.286,2341,6.629,2342,6.629]],["t/500",[92,2.888,206,3.138,323,3.324,343,2.333,359,2.988,398,4.191,425,3.47,2042,6.758,2343,6.002,2344,7.628,2345,7.628]],["t/503",[26,3.903,42,1.419,50,1.666,59,2.893,60,4.765,69,2.234,92,2.048,96,4.008,117,1.334,149,1.715,249,5.056,255,3.253,295,1.95,307,4.826,314,2.319,320,4.125,335,2.214,454,3.97,501,2.194,607,2.486,626,4.405,629,3.309,736,4.256,884,4.792,924,4.792,1014,4.826,1086,4.008,1161,4.732,1182,4.76,1203,3.72,1297,4.406,1428,4.125,1651,4.008,1745,5.409,1752,3.639,1955,4.256,1983,4.582,2161,5.409,2346,5.945,2347,5.945,2348,5.409,2349,5.945,2350,5.409,2351,5.945,2352,6.489,2353,8.05,2354,5.945,2355,4.792,2356,5.409,2357,5.409,2358,5.409]],["t/505",[5,1.855,21,2.422,76,3.213,98,2.642,149,2.028,157,3.785,206,2.201,224,1.965,231,3.104,274,4.215,288,4.74,315,5.21,323,2.103,335,2.618,336,5.418,497,6.396,937,4.623,1182,4.374,1251,5.979,1313,5.21,1670,4.054,1716,7.645,1915,5.21,1917,5.667,1964,4.878,2022,5.21,2031,6.396,2359,5.667,2360,7.03,2361,7.03,2362,7.03,2363,6.396,2364,7.03]],["t/507",[5,1.061,15,1.594,16,1.594,17,1.594,30,1.566,31,1.631,84,1.787,173,1.094,175,0.672,178,1.264,184,3.145,185,1.325,187,3.606,188,1.839,199,1.189,202,1.836,206,1.887,227,2.152,253,4.25,265,3.921,266,1.429,295,0.776,314,1.551,330,2.61,349,1.717,350,2.245,362,1.021,368,2.045,407,1.515,454,1.166,467,1.987,480,2.384,505,1.594,511,1.431,519,1.448,520,1.796,566,1.775,572,0.829,590,2.991,615,1.693,644,2.895,652,6.428,706,3.377,788,2.213,995,1.418,1011,4.384,1051,2.947,1052,5.181,1112,5.175,1121,5.052,1122,1.823,1129,5.717,1133,2.011,1167,2.488,1182,1.934,1198,2.213,1200,1.364,1325,1.823,1394,3.205,1404,1.753,1820,6.911,1824,5.397,2022,1.753,2040,6.814,2041,4.859,2054,5.127,2055,5.127,2056,4.374,2057,6.584,2058,2.011,2059,6.584,2064,4.374,2070,3.381,2267,2.152,2365,3.617,2366,2.365,2367,8.126,2368,3.617,2369,3.976,2370,3.976,2371,2.365,2372,2.365,2373,2.365,2374,5.143,2375,2.365,2376,2.365,2377,2.365,2378,6.028,2379,3.976,2380,2.365,2381,2.365,2382,5.143,2383,2.365,2384,2.365,2385,2.365,2386,3.976,2387,2.365,2388,2.011,2389,3.976]],["t/509",[26,5.079,42,1.364,211,3.138,306,4.381,307,4.638,325,4.078,361,4.736,454,3.815,629,4.305,656,5.14,795,4.038,884,6.236,901,5.962,1182,3.764,1417,4.305,2075,8.119,2076,7.038,2077,8.119,2390,7.736,2391,7.736,2392,6.579]],["t/512",[5,0.729,12,1.419,13,2.497,42,0.971,50,0.99,52,2.118,92,1.217,95,1.433,117,0.793,129,1.293,145,1.719,149,1.019,175,1.004,178,1.123,181,3.712,182,2.451,183,2.024,184,2.9,185,1.178,190,3.626,199,1.057,209,1.966,251,2.032,266,1.27,267,1.543,294,2.256,308,3.577,323,1.057,342,2.934,343,1.532,351,3.291,401,1.742,407,2.263,430,3.987,465,1.462,474,2.168,500,2.118,501,2.032,572,3.072,573,1.742,574,1.742,583,1.615,590,3.389,597,3.298,598,3.298,614,5.616,629,1.966,646,2.211,654,5.435,669,2.848,681,3.215,682,3.215,683,5.009,684,4.081,688,3.215,798,5.73,802,4.243,940,3.712,941,2.848,946,2.619,947,2.848,948,2.382,953,2.619,955,2.451,958,1.873,971,5.912,973,3.615,981,3.765,1065,5.299,1265,2.451,1328,6.556,1502,2.723,1528,2.163,1549,3.942,1550,2.529,1795,2.723,2393,2.848,2394,3.005,2395,8.055,2396,2.848,2397,2.619,2398,3.533]],["t/514",[33,1.943,42,1.28,80,1.694,98,2.729,117,1.149,149,1.478,166,2.342,188,2.37,190,2.78,202,2.185,206,1.604,215,2.364,223,1.722,247,2.262,251,2.68,296,3.072,326,1.142,329,1.681,337,2.852,343,2.696,346,4.16,354,3.949,359,1.826,379,1.765,380,1.722,382,2.705,393,2.099,450,3.012,453,4.358,467,2.561,483,2.716,524,3.974,528,3.668,548,4.358,569,2.888,577,2.213,666,4.651,667,4.446,668,3.555,676,4.662,690,3.555,691,4.13,740,2.527,787,3.069,812,3.555,821,2.675,823,2.902,824,2.561,916,3.072,975,3.668,976,3.668,1264,3.137,1266,3.791,1313,3.798,1349,3.282,1404,3.798,1422,4.13,1458,3.555,2149,4.358,2343,3.668,2394,4.358,2399,4.662,2400,4.358,2401,6.607,2402,5.124,2403,5.124]],["t/516",[33,1.904,42,1.603,80,1.946,84,1.744,97,3.385,98,1.887,113,2.703,129,1.179,149,2.065,150,3.296,188,3.311,202,1.975,233,2.295,237,3.296,266,2.999,292,4.492,294,2.933,299,4.585,325,2.145,326,1.595,329,1.647,341,1.66,343,2.675,344,2.348,359,2.551,379,1.73,380,1.688,382,2.666,393,2.057,468,3.074,531,2.242,569,2.847,577,2.168,582,1.821,585,2.122,604,3.721,608,2.951,609,3.484,632,3.01,654,5.477,656,2.703,663,4.903,671,4.27,740,2.476,743,3.216,785,5.001,792,4.967,821,2.621,824,2.51,975,3.595,976,3.595,1422,4.047,1454,3.721,1535,4.047,1536,4.568,2154,4.047,2394,4.27,2401,6.513,2404,5.021,2405,5.021,2406,5.021,2407,5.021]],["t/519",[13,2.923,129,1.859,202,1.72,572,2.775,656,4.264,684,5.87,1015,6.869,1182,5.304,1366,5.87,2022,7.178,2027,8.237,2408,9.685,2409,7.92,2410,7.92]],["t/521",[5,0.973,10,1.756,12,1.893,21,1.624,24,3.626,25,4.188,31,1.275,42,1.419,64,1.951,80,1.1,84,1.638,96,3.178,117,1.806,129,1.606,139,2.623,149,1.36,160,3.271,201,2.105,208,3.271,238,3.494,304,2.67,323,1.41,325,2.922,335,2.548,384,3.271,433,2.39,435,2.39,465,2.832,467,3.42,483,2.498,487,2.39,511,1.312,514,1.584,606,2.264,623,4.612,656,5.674,662,3.019,673,3.271,757,4.746,770,6.158,786,3.019,854,3.271,1096,4.491,1182,4.76,1250,3.494,1336,5.764,1384,3.095,1692,3.8,1741,4.289,1908,3.375,2027,6.847,2173,4.289,2357,4.289,2411,4.009,2412,4.289,2413,4.289,2414,4.714,2415,4.714,2416,8.901,2417,4.714,2418,4.289,2419,4.009,2420,4.714,2421,4.714,2422,4.714,2423,4.714,2424,4.714,2425,4.714]],["t/523",[30,3.302,31,1.286,184,3.63,185,1.584,187,3.838,188,4.681,190,0.813,202,2.105,211,1.472,224,0.464,231,0.938,304,1.203,331,1.329,335,0.791,350,1.352,368,4.312,436,1.225,503,1.895,507,1.203,511,2.333,535,1.474,542,3.175,572,2.937,589,5.224,590,2.659,686,2.383,819,1.432,981,2.02,1011,5.488,1106,3.027,1178,2.271,1182,2.736,1228,1.521,1236,1.712,1295,1.361,1312,1.474,1508,1.712,1820,3.087,1824,5.1,1900,4.781,2022,2.69,2040,2.926,2041,2.926,2052,3.087,2054,3.087,2055,3.087,2056,3.087,2057,3.087,2058,1.807,2059,3.087,2060,4.324,2061,5.746,2062,5.746,2063,5.746,2064,6.59,2065,5.746,2066,5.746,2067,5.746,2068,5.746,2070,1.807,2071,4.532,2072,1.712,2395,4.781,2413,5.115,2426,5.622,2427,3.63,2428,2.124,2429,5.115,2430,2.124,2431,2.124,2432,5.622,2433,3.63,2434,3.63,2435,3.63,2436,2.926,2437,2.124,2438,3.63,2439,11.222,2440,3.63,2441,2.124,2442,2.124,2443,2.124,2444,2.124]],["t/526",[5,1.293,10,1.558,21,1.441,50,2.104,74,2.217,92,1.441,117,1.405,129,0.982,157,2.252,219,3.175,247,3.315,262,1.696,284,2.252,295,2.463,314,2.443,321,2.412,322,2.328,326,1.396,327,1.442,333,2.82,335,2.333,341,3.304,344,1.372,373,3.427,404,3.919,405,4.011,480,2.508,522,2.458,607,1.749,643,3.805,702,2.994,797,2.183,851,2.289,908,2.617,930,3.1,969,4.112,988,3.805,1033,1.616,1094,2.902,1138,5.353,1194,4.252,1197,4.857,1237,5.326,1238,4.484,1257,2.56,1296,2.56,1321,3.371,1390,3.557,1428,5.784,1475,3.223,1513,3.1,1651,5.062,1752,2.56,1915,3.1,1930,3.805,1931,2.902,1983,3.223,2192,3.371,2359,3.371,2445,4.182,2446,5.049,2447,3.805,2448,6.72,2449,4.182,2450,3.557,2451,4.182,2452,4.182,2453,8.337,2454,4.182,2455,6.263,2456,4.182,2457,7.508,2458,4.182,2459,4.182,2460,4.182,2461,3.805,2462,4.182,2463,4.182,2464,4.182,2465,4.182,2466,2.82,2467,4.182]],["t/528",[10,1.769,12,1.907,31,1.861,42,0.837,50,0.822,59,2.311,80,1.108,98,1.102,151,1.508,190,2.29,201,2.12,202,1.641,211,1.19,226,1.692,251,1.753,266,1.707,295,0.962,308,1.374,314,1.144,326,0.654,327,1.583,329,1.963,330,3.118,341,2.498,362,1.267,380,1.596,436,1.692,511,1.321,538,2.007,546,1.926,550,2.1,582,1.064,590,2.657,597,2.051,598,2.051,603,2.007,630,1.692,638,1.852,675,2.442,679,5.02,690,3.295,701,3.118,755,2.847,795,1.531,797,2.479,851,2.599,900,4.515,916,4.529,934,1.155,937,1.508,990,2.035,1034,4.434,1045,2.174,1064,1.632,1197,3.438,1354,1.579,1372,3.4,1386,3.66,1695,5.848,1752,1.795,1937,2.494,1992,3.828,2004,2.364,2317,3.66,2446,2.364,2468,4.749,2469,8.559,2470,5.543,2471,6.873,2472,5.983,2473,2.669,2474,2.669,2475,2.669,2476,2.669,2477,2.364,2478,2.364,2479,8.085,2480,4.749,2481,4.038,2482,8,2483,4.749,2484,4.038,2485,5.543,2486,5.097,2487,5.3,2488,7.538,2489,4.038,2490,6.257,2491,4.32,2492,4.32,2493,3.828,2494,3.828,2495,4.749,2496,4.038,2497,2.669,2498,6.877,2499,6.877,2500,2.1,2501,2.933]],["t/530",[10,1.954,11,2.034,12,3.229,21,1.145,31,1.998,34,2.462,38,1.467,42,0.586,76,1.519,80,0.775,129,0.78,135,1.919,149,2.319,175,2.286,183,0.994,185,1.108,190,2.489,192,1.334,202,1.604,206,1.04,211,1.348,231,1.467,239,4.51,247,1.467,251,1.936,270,1.575,273,2.079,275,2.462,280,3.083,306,1.882,311,1.992,314,1.296,323,0.994,326,0.74,327,2.25,329,1.721,342,2.083,344,1.09,348,1.501,349,1.435,350,1.237,353,3.632,358,1.734,362,1.435,373,1.818,380,1.763,397,2.079,465,2.172,474,1.308,511,1.46,514,1.117,520,1.501,538,2.217,572,1.164,585,1.404,586,2.378,599,1.953,603,2.217,638,2.046,659,1.992,663,1.953,670,4.239,675,2.698,786,2.128,797,2.738,836,1.992,916,3.145,917,2.971,935,2.462,958,3.446,961,1.992,977,3.083,1022,2.678,1033,2.027,1045,2.462,1064,1.849,1067,3.023,1072,2.56,1074,2.462,1075,2.181,1076,3.756,1077,2.378,1078,2.678,1079,4.229,1080,4.229,1081,2.305,1138,1.992,1156,3.023,1197,4.636,1207,4.818,1385,2.678,1450,2.462,1675,3.537,1939,3.023,2368,7.314,2469,3.023,2470,4.229,2471,5.915,2473,3.023,2474,3.023,2475,3.023,2476,3.023,2502,2.825,2503,2.825,2504,2.678,2505,2.678,2506,5.246,2507,5.246,2508,6.501,2509,2.678]],["t/533",[84,3.332,135,2.852,224,2.097,251,3.541,252,3.442,302,3.607,326,2.316,327,1.795,341,2.578,797,5.007,1073,6.654,1207,7.11,1646,6.008,1926,6.63,2510,6.63]],["t/535",[42,1.231,69,2.624,80,1.628,84,2.425,129,1.639,152,3.082,163,6.407,178,2.219,224,1.526,251,2.577,314,2.723,322,5.497,326,1.556,327,1.607,483,3.7,487,3.539,957,4.707,1073,5.732,1103,4.707,1266,4.672,1368,4.998,1676,4.998,1931,6.209,2511,9.878,2512,6.981,2513,8.949,2514,5.937,2515,5.937,2516,8.949]],["t/537",[5,0.717,31,2.547,84,1.206,113,1.869,183,1.039,185,1.157,190,2.079,198,1.606,202,1.891,215,1.768,224,1.187,252,2.398,253,3.302,258,2.924,289,2.341,314,1.354,323,1.625,326,1.491,327,1.54,328,3.298,339,3.768,341,1.796,343,0.966,348,3.418,349,3.267,350,2.491,351,5.118,353,3.418,358,3.949,379,1.196,380,2.248,382,2.023,393,1.423,418,4.352,476,2.486,511,2.105,516,3.378,538,1.467,542,2.225,569,2.66,572,1.216,577,1.499,578,3.023,579,1.568,580,1.626,587,2.082,588,2.573,589,2.341,590,1.342,597,1.499,598,1.499,603,3.198,638,2.119,675,2.793,758,3.661,798,3.398,799,2.173,978,2.643,1003,3.256,1073,5.259,1319,2.041,1328,3.888,1345,2.341,1354,1.869,1553,2.125,1675,2.341,1791,2.486,2261,2.676,2262,4.185,2327,2.953,2510,4.619,2515,2.953,2517,6.689,2518,4.619,2519,7.565,2520,3.472,2521,4.941,2522,5.431,2523,5.431,2524,5.431,2525,5.431]],["t/539",[5,1.304,31,2.269,42,1.114,129,1.484,132,3.645,133,3.645,175,1.797,183,1.891,188,2.924,198,2.924,202,1.373,259,3.117,289,4.261,314,2.466,325,2.7,326,1.409,327,1.455,341,2.09,343,1.759,351,4.081,380,2.124,404,3.955,405,4.048,418,3.159,476,4.525,511,1.759,538,2.671,603,2.671,638,2.466,657,3.579,675,3.251,755,3.789,821,3.299,978,3.075,1003,5.029,1073,5.372,1319,3.715,1386,4.871,1675,4.261,1791,4.525,2261,4.871,2262,6.464,2466,4.261,2515,5.375,2521,5.75,2526,5.375,2527,5.75,2528,5.75,2529,5.375]],["t/542",[13,2.771,24,2.847,42,0.947,50,1.505,76,2.455,92,1.85,117,1.941,129,2.032,139,2.989,149,2.496,171,6.945,175,1.527,178,1.708,195,2.58,230,2.515,247,2.371,266,1.931,318,4.139,343,1.495,344,1.762,371,3.727,428,4.568,501,3.459,503,2.804,582,1.948,622,5.061,908,3.361,969,3.526,1274,3.44,1359,4.568,1360,4.568,1366,3.981,1403,5.189,1406,5.215,1420,2.723,1497,4.887,1675,3.621,1678,4.139,2109,4.139,2123,4.139,2400,4.568,2530,4.887,2531,4.568,2532,5.371,2533,4.568,2534,5.371,2535,4.139,2536,4.33,2537,5.371,2538,5.371,2539,5.371,2540,5.371,2541,5.371,2542,5.371,2543,5.371,2544,5.371,2545,5.371,2546,5.371,2547,4.887,2548,5.371,2549,5.371,2550,3.727,2551,4.139]],["t/544",[5,1.304,12,2.538,115,3.869,117,1.418,165,3.715,175,1.797,177,2.759,183,1.891,195,3.035,201,2.822,204,3.789,205,3.715,206,2.626,256,3.869,257,4.065,302,2.924,323,3.365,325,2.7,357,4.385,399,5.095,465,2.616,606,3.035,795,3.299,948,4.261,1015,4.149,1367,5.655,1377,4.871,1384,4.149,1406,6.091,1444,5.095,1705,4.684,1949,4.684,2552,5.75,2553,5.75,2554,5.75,2555,4.684]],["t/546",[5,1.365,42,1.166,50,1.853,80,2.015,114,3.858,115,4.048,117,1.483,183,1.978,185,2.204,201,2.953,206,2.705,304,3.745,323,2.585,325,3.691,335,2.463,399,6.965,402,2.377,430,4.51,465,3.577,487,3.352,501,2.441,527,4.734,652,6.186,987,4.458,1233,5.623,1367,4.458,1406,5.68,1752,4.048,1949,4.901,2299,5.33,2556,8.757,2557,6.016,2558,6.612]],["t/548",[5,1.12,59,2.642,165,3.191,184,3.685,185,1.81,195,2.608,202,1.179,212,5.606,295,1.781,335,2.022,350,3.242,362,2.345,572,2.65,590,2.098,606,2.608,1003,4.535,1015,4.966,1101,4.184,1545,5.868,1553,4.63,1949,4.024,2043,4.377,2156,5.606,2277,7.255,2280,5.829,2550,6.868,2555,4.024,2559,8.266,2560,8.646,2561,4.377,2562,5.429,2563,4.617,2564,7.589,2565,8.704,2566,4.377,2567,6.097]],["t/550",[42,1.412,129,1.096,175,1.328,177,2.039,181,4.581,184,3.416,185,1.557,202,1.014,212,6.518,295,1.532,344,1.532,350,2.983,465,1.933,474,2.676,531,2.085,572,2.38,590,1.805,607,1.953,795,2.438,980,4.864,1003,4.073,1011,3.848,1015,4.46,1384,3.066,1406,2.599,1545,6.952,1553,4.159,1908,4.864,2156,5.036,2277,6.777,2280,5.236,2325,3.599,2550,7.155,2559,7.756,2560,8.112,2561,3.764,2563,7.479,2564,5.477,2566,3.764,2567,5.477,2568,7.479,2569,4.67,2570,6.811,2571,9.345]],["t/552",[13,1.716,42,0.504,129,0.671,175,1.322,177,1.248,181,1.927,183,0.855,184,3.521,185,1.55,187,1.867,189,4.789,193,1.983,201,2.076,202,1.01,210,2.909,211,2.747,212,6.726,221,1.306,257,2.008,302,1.322,321,1.648,331,1.788,344,0.938,350,3.136,413,2.324,465,1.183,474,2.935,531,1.276,572,2.799,590,1.797,980,4.208,1003,4.06,1011,4.221,1015,5.244,1406,2.588,1454,2.118,1462,2.304,1545,7.016,1553,4.146,1908,4.848,2042,2.304,2156,5.019,2277,6.763,2280,5.219,2325,3.583,2550,7.146,2555,2.118,2559,7.938,2560,3.748,2561,3.748,2563,6.794,2564,3.748,2566,3.748,2567,5.459,2568,4.999,2570,2.43,2572,6.781,2573,9.264,2574,2.858,2575,8.42,2576,4.23,2577,2.6,2578,2.858,2579,4.649,2580,5.878,2581,6.772]],["t/554",[12,1.73,13,1.59,42,0.759,50,1.795,52,2.583,69,2.406,117,1.436,178,1.37,184,1.509,193,2.989,194,2.532,195,4.712,196,2.989,198,1.993,202,0.936,212,6.27,221,1.969,247,1.902,255,2.358,314,1.681,323,1.289,344,1.413,350,1.605,435,2.184,472,2.828,474,1.697,499,3.448,510,2.583,529,2.398,582,1.562,590,2.474,644,2.069,942,3.473,987,2.905,1085,3.664,1162,2.532,1353,3.473,1367,2.905,1384,4.204,1403,2.583,1406,5.032,1440,3.32,1444,5.161,1455,2.696,1545,6.095,1752,2.637,1797,3.92,2120,3.664,2289,3.92,2299,3.473,2333,3.084,2509,5.161,2550,6.807,2552,3.92,2553,6.953,2554,3.92,2555,3.193,2559,3.32,2561,3.473,2566,7.288,2567,5.161,2582,4.308,2583,3.473,2584,7.642,2585,8.226,2586,4.308,2587,3.92,2588,4.308,2589,4.308,2590,4.308,2591,4.308,2592,9.475,2593,8.46,2594,7.642]],["t/556",[2,1.792,13,1.208,184,3.969,185,2.661,187,2.941,189,5.532,210,2.716,211,2.103,350,3.663,572,3.591,660,1.603,1000,1.519,1003,5.696,1011,5.038,1015,6.237,1545,6.862,1553,5.816,2156,7.042,2277,8.309,2280,7.322,2325,3.996,2556,5.342,2557,2.979,2559,8.091,2560,7.553,2564,2.639,2568,6.229,2570,1.603,2572,1.715,2573,8.525,2576,3.949,2577,3.949,2595,5.186,2596,4.341,2597,4.341,2598,5.342,2599,3.274,2600,1.884,2601,1.884]],["t/559",[50,1.865,80,2.024,104,2.972,117,1.947,125,3.528,129,1.563,135,2.435,166,3.042,169,4.222,178,2.116,215,2.166,223,3.245,224,2.111,266,2.393,321,3.839,417,5.13,424,4.765,644,3.197,921,5.661,1112,4.075,1152,5.661,1215,4.933,1455,4.165,1594,4.618,1626,4.488,1653,6.056,1953,5.365,2602,7.38,2603,7.896,2604,6.656,2605,6.656,2606,6.656,2607,6.656,2608,6.656,2609,5.661,2610,6.656,2611,6.656]],["t/561",[5,0.832,31,1.648,53,2.17,64,1.669,76,1.842,80,1.909,92,1.389,102,2.797,113,2.17,117,1.366,169,1.961,173,1.865,175,1.146,183,1.206,192,1.619,194,2.369,195,1.936,198,1.865,199,2.197,202,2.084,215,1.983,219,2.043,223,1.355,224,0.881,253,1.529,261,3.812,266,2.19,267,1.76,277,2.718,295,1.322,326,0.898,327,0.928,328,3.621,329,2.409,337,2.243,342,1.291,343,1.122,344,1.322,346,3.004,379,1.389,380,1.355,382,2.735,393,1.652,402,1.449,413,2.015,414,1.961,415,2.886,461,2.468,470,2.325,511,1.122,515,2.043,516,2.72,519,2.468,524,2.206,531,1.8,538,1.704,547,2.988,569,3.255,572,1.412,576,2.17,577,1.741,578,2.243,579,1.821,580,1.888,581,2.104,582,1.462,590,1.558,597,1.741,598,1.741,603,1.704,638,1.572,725,3.249,755,2.417,792,2.797,796,2.468,1089,2.646,1092,2.325,1143,3.249,1274,2.582,1592,5.181,1594,2.797,1626,2.718,1682,2.988,1721,3.249,1749,5.542,2200,3.249,2555,2.988,2602,8.402,2609,3.428,2612,7.343,2613,4.031,2614,5.542,2615,3.428,2616,8.787,2617,6.092,2618,4.031,2619,4.031,2620,4.031,2621,4.031,2622,4.031]],["t/564",[13,3.346,75,6.987,221,4.144,359,3.231,1021,5.135,2623,9.067]],["t/566",[231,4.077,1021,5.23,1214,6.611,2624,9.234]],["t/568",[33,3.378,42,1.57,230,4.17,251,3.287,322,5.782,425,3.686,788,4.956]],["t/570",[21,2.636,50,1.547,60,2.881,64,2.285,69,2.875,84,1.917,117,1.97,150,3.623,166,4.334,169,3.722,183,2.289,188,2.553,195,2.651,224,1.206,237,3.623,266,1.984,295,1.811,326,1.23,353,2.493,357,3.829,359,3.838,402,1.984,414,4.272,453,4.694,465,3.167,468,3.379,474,2.174,478,3.02,480,3.309,529,4.258,661,3.379,693,3.072,811,4.497,841,3.454,848,4.253,901,4.253,1124,5.158,1138,3.309,1203,3.454,1254,3.454,1339,2.972,1361,6.506,1363,4.694,1462,4.449,1561,7.078,1998,4.253,2514,4.694,2625,5.519,2626,5.021,2627,5.519,2628,4.694,2629,5.021]],["t/572",[69,2.976,92,2.728,125,4.197,166,3.62,167,5.67,175,2.251,223,2.662,262,3.212,323,2.369,344,2.598,359,2.822,371,5.495,408,4.073,480,4.748,514,2.662,739,5.87,812,5.495,986,6.384,990,5.495,1579,7.205,2630,7.92,2631,7.92]],["t/574",[13,2.441,42,1.166,74,2.386,95,1.826,98,2.947,117,1.484,149,1.298,157,2.424,166,3.023,173,3.06,174,3.829,175,1.88,177,3.423,178,1.431,183,2.586,184,2.317,185,1.501,202,0.978,204,2.699,205,2.646,219,2.282,226,2.596,236,3.829,241,2.596,251,1.662,252,1.988,253,2.974,257,3.386,258,2.424,262,1.826,267,2.888,270,2.135,287,4.096,301,3.829,302,2.083,323,1.347,326,1.003,327,1.036,329,1.477,342,1.442,343,1.253,348,2.034,349,1.944,350,2.464,353,2.034,359,3.08,367,3.223,373,2.464,418,2.251,425,1.864,429,2.22,465,1.864,467,2.251,483,2.386,490,3.124,507,2.55,516,2.01,538,1.903,570,2.424,662,2.883,740,2.22,900,2.956,961,2.699,1000,3.629,1153,3.629,1158,4.096,1198,2.506,1319,2.646,1421,2.956,1432,6.321,1609,3.629,1670,2.596,2032,4.096,2098,3.629,2632,4.502,2633,4.502,2634,9.207,2635,8.643,2636,6.615,2637,4.502,2638,6.615,2639,6.615,2640,4.502]],["t/577",[10,3.317,199,2.664,323,2.664,804,4.956,972,5.234,1033,3.441,1751,6.6,2242,6.375]],["t/579",[10,3.232,12,3.485,21,2.293,33,2.525,64,2.755,74,3.528,92,2.99,108,4.618,199,1.991,323,3.455,374,3.643,470,5.005,582,3.147,693,4.83,934,2.622,1033,2.572,1120,5.13,1265,4.618,1811,5.365,2242,6.913,2641,6.656,2642,6.656,2643,8.678,2644,6.213,2645,6.056,2646,4.165]],["t/581",[5,1.943,12,2.538,33,2.397,50,1.771,72,3.789,95,3.402,202,1.822,237,4.149,326,1.409,327,1.455,341,2.09,342,3.016,351,3.075,374,3.459,461,3.869,470,3.645,499,3.403,532,4.93,632,5.029,644,3.035,795,3.299,932,4.261,934,2.489,1033,2.442,1034,4.684,1049,4.385,1050,5.095,1070,4.684,1191,5.506,1208,7.631,1227,5.095,1410,5.75,1450,4.684,2242,4.525,2647,6.32,2648,6.32,2649,5.375,2650,7.133,2651,5.75,2652,6.32,2653,6.32,2654,6.32,2655,6.32]],["t/584",[1924,6.799]],["t/586",[10,3.425,21,2.51,104,3.253,108,5.055,135,2.665,297,3.803,473,4.282,699,4.912,701,4.783,804,6.202,819,4.912,1033,3.894,1323,5.216,1670,4.202,1811,5.873,1924,5.216,2116,6.629,2646,4.559,2656,7.286,2657,9.196,2658,6.629,2659,7.286,2660,7.286,2661,6.629]],["t/588",[2,4.476,42,1.442,64,3.385,127,7.961,250,6.303,408,4.206,450,4.807,494,5.674,804,4.552,916,4.903,1033,3.16,1670,4.717,2662,6.955,2663,8.178,2664,8.178,2665,8.178,2666,6.592]],["t/590",[24,4.638,127,7.053,326,1.95,327,2.367,364,6.264,704,7.053,937,5.288,2667,7.053]],["t/593",[251,3.147,308,3.993,326,1.9,327,1.963,341,2.82,404,5.335,405,5.461,417,6.571,633,5.916,1025,4.829,1180,5.219,2466,5.748,2530,7.758]],["t/595",[42,1.001,76,2.594,80,1.324,92,2.687,95,2.302,98,3.606,104,3.483,114,2.534,183,1.698,199,1.698,251,2.095,266,2.04,317,3.551,327,1.307,341,2.579,343,1.579,344,1.862,356,3.826,357,6.183,394,2.594,402,2.04,403,4.584,404,4.88,405,4.995,409,4.207,474,2.235,477,4.827,478,4.268,511,1.579,657,3.214,740,2.799,755,3.403,762,4.207,821,2.963,956,4.575,957,3.826,1025,4.417,1064,3.159,1180,5.455,1344,3.938,1609,4.575,1670,3.273,2003,4.575,2352,4.575,2466,5.258,2529,4.827,2668,5.164,2669,5.676,2670,5.676,2671,5.676,2672,4.575,2673,5.164,2674,5.164,2675,4.827,2676,4.827,2677,5.164]],["t/597",[42,1.59,76,2.654,80,1.355,92,2.001,95,2.356,98,2.978,104,2.593,114,2.593,132,3.349,133,3.349,183,1.737,188,2.686,199,1.737,251,2.143,317,3.634,323,1.737,325,2.481,341,2.62,356,3.915,357,5.497,394,2.654,403,3.413,404,4.958,405,5.074,413,2.903,418,2.903,478,3.178,554,3.719,581,3.031,657,3.289,740,2.864,755,3.482,821,3.031,907,3.915,956,4.681,957,5.341,1180,3.555,1386,4.475,1609,4.681,1670,3.349,2127,5.284,2352,4.681,2466,5.341,2526,4.939,2527,5.284,2528,5.284,2529,4.939,2668,5.284,2672,4.681,2673,5.284,2674,5.284,2675,4.939,2676,4.939,2677,5.284,2678,4.939,2679,5.807,2680,5.807,2681,4.939,2682,5.807]],["t/600",[13,2.833,31,2.077,129,1.802,202,1.667,211,3.114,226,4.427,499,4.133,501,2.833,542,4.228,545,3.785,679,4.348,1649,8.08,1696,6.065,2683,7.677,2684,7.677,2685,7.677,2686,7.677,2687,7.677,2688,7.677,2689,8.08]],["t/602",[135,3.093,226,4.876,470,4.876,724,5.7,755,5.069,996,6.515,1203,5.29,1547,7.19,1712,7.19,2690,8.454,2691,8.454,2692,9.166,2693,8.454]],["t/604",[13,3.776,189,5.2,433,4.397,572,3.039,2395,8.699,2694,8.699,2695,8.674,2696,8.674]],["t/606",[84,3.285,184,3.313,187,3.06,200,4.315,542,3.121,572,3.603,587,5.67,1514,7.288,1701,7.623,2026,6.141,2697,8.604,2698,9.456,2699,7.618,2700,9.456,2701,7.618,2702,7.618,2703,7.618]],["t/608",[80,1.923,202,1.791,206,2.581,535,6.886,629,4.589,670,4.867,1417,4.589,1507,6.354,2598,9.03,2704,7.502,2705,9.925,2706,8.246]],["t/610",[5,1.472,31,1.352,38,2.206,42,1.257,50,1.999,104,2.231,175,2.028,177,3.114,183,2.134,184,2.499,185,1.666,199,1.495,201,2.231,202,2.084,226,2.881,237,3.28,239,3.466,241,2.881,253,3.639,262,2.027,320,3.466,344,1.639,408,2.57,418,2.498,441,4.276,493,3.466,536,4.949,537,5.75,538,3.015,542,4.088,545,2.464,570,2.69,590,1.931,995,2.995,1021,2.83,1106,2.69,1323,7.518,1504,3.466,1696,5.865,1703,4.027,1761,6.066,2071,4.027,2072,4.027,2195,4.546,2707,7.569,2708,7.133,2709,4.996,2710,7.133,2711,4.546,2712,6.49,2713,4.996,2714,4.996,2715,4.996,2716,4.996]],["t/613",[50,2.22,69,2.976,80,1.847,117,1.776,129,1.859,194,4.655,195,3.803,247,3.496,326,2.159,327,2.23,341,3.203,351,3.853,480,4.748,670,4.427,1213,5.87,1259,6.384,2509,6.384,2672,6.384]],["t/615",[5,1.272,42,1.087,69,2.317,80,1.438,129,1.447,149,1.778,190,2.36,192,2.476,194,4.849,201,2.753,202,1.339,247,3.642,248,4.413,326,1.374,327,1.899,328,3.04,329,2.706,341,3.283,344,2.022,425,2.552,487,3.125,493,4.277,511,1.715,512,3.218,531,2.753,570,3.319,670,4.868,900,4.047,984,3.774,1248,4.969,1258,7.015,1259,4.969,1260,4.969,1349,3.948,1420,3.125,1504,4.277,1507,4.751,1670,3.555,2672,4.969,2717,6.165,2718,6.165,2719,5.609,2720,6.165,2721,8.249]],["t/617",[5,1.178,59,2.777,65,3.124,95,3.625,175,1.623,178,1.815,194,3.355,262,2.315,269,3.656,270,2.707,278,4.399,302,2.64,314,2.227,325,2.438,326,1.272,327,1.803,340,3.969,341,2.589,342,2.864,351,4.349,353,3.537,359,2.034,378,3.96,402,2.052,447,5.433,475,3.494,507,3.233,512,2.979,514,1.918,553,3.494,569,2.27,580,2.673,581,4.087,670,4.606,713,3.848,798,4.9,799,3.572,928,3.572,1014,3.422,1297,4.231,1328,4.086,1399,4.854,1420,2.894,1421,3.747,1651,3.848,2176,4.854,2184,4.854,2298,5.193,2509,4.601,2722,8.132,2723,5.708,2724,5.708]],["t/619",[5,1.56,21,2.605,104,3.376,183,2.262,194,4.444,254,5.097,269,4.842,297,3.947,325,3.23,341,2.5,373,4.138,402,2.718,448,6.43,487,3.833,514,2.541,581,3.947,670,4.302,693,4.208,772,4.533,1196,5.827,1420,4.771,1421,4.964,2725,7.561,2726,7.561,2727,6.095,2728,7.561]],["t/621",[569,3.672,2727,7.443,2729,9.234,2730,8.401]],["t/623",[59,3.915,65,4.404,326,1.793,327,2.252,346,3.968,351,4.758,418,4.023,581,4.2,670,3.678,789,5.761,917,4.557,994,7.321,1045,5.964,1264,4.926,2123,6.201,2722,7.321,2727,6.486,2730,7.321]],["t/626",[5,1.716,50,2.33,92,2.864,152,3.671,178,2.643,199,2.487,582,3.015,630,5.753,646,5.202,916,4.985,1033,3.213,1070,6.162,1089,5.458,1395,6.407,1721,6.702]],["t/628",[5,1.823,10,3.289,38,3.019,42,1.557,47,5.068,50,1.916,115,4.186,117,1.534,135,3.231,149,1.972,152,3.019,199,2.046,224,2.138,262,2.774,270,3.242,296,4.1,314,2.668,326,1.524,327,1.574,403,4.019,519,4.186,607,2.86,630,3.944,685,4.895,792,4.744,804,3.806,917,3.873,972,4.019,1200,3.944,1272,5.512,1389,3.569,1680,5.068,2731,6.221,2732,5.512,2733,6.838,2734,6.838]],["t/630",[5,1.712,33,1.886,50,2.325,64,2.058,95,2.016,129,1.167,149,1.434,174,4.228,175,1.413,178,1.58,185,1.657,192,1.997,198,2.3,202,1.544,224,1.554,237,3.264,259,2.451,308,3.885,326,1.584,327,1.145,342,2.658,343,1.383,348,2.246,349,2.147,350,1.851,353,4.089,358,2.595,359,1.772,374,2.721,413,2.485,425,2.058,511,2.519,512,4.33,531,2.22,570,2.677,576,3.827,582,1.803,659,2.98,737,2.922,743,3.184,811,2.922,841,5.191,934,1.958,937,5.123,1050,4.007,1075,3.264,1077,3.559,1089,3.264,1090,5.729,1191,4.666,1199,7.055,1200,4.785,1262,3.264,1395,3.831,1501,3.111,1938,4.007,2735,6.467,2736,4.007,2737,6.045,2738,4.523,2739,4.971,2740,4.971]],["t/632",[30,2.21,31,2.094,199,1.679,202,1.924,212,7.425,255,3.071,267,2.45,342,2.48,344,1.841,362,2.423,368,2.886,474,3.945,511,2.465,542,3.913,543,4.428,545,3.816,582,2.035,590,2.169,606,2.695,877,6.566,1053,4.524,1064,5.575,1089,3.684,1112,4.738,1191,3.684,1417,3.123,1626,5.218,1696,5.207,1704,5.106,2492,5.106,2735,5.106,2737,9.621,2738,5.106]],["t/634",[64,3.441,80,1.939,117,1.865,308,3.893,343,2.314,450,5.863,607,3.477,841,5.202,1025,4.709,1089,5.458,1100,6.388,1266,4.34,1345,5.605,2741,8.314]],["t/636",[10,3.259,50,2.452,129,2.054,199,2.618,519,5.356,531,3.907,855,6.071,856,6.743,1425,7.053,2742,7.961]],["t/639",[5,1.482,12,2.884,52,4.306,60,3.749,92,3.139,95,2.913,129,1.686,323,2.149,335,2.675,343,2.785,585,4.23,662,4.599,787,3.851,851,3.93,973,5.982,987,4.842,1014,4.306,1043,5.534,1281,6.107,1319,4.221,1405,4.306,1408,5.141,1622,5.323,2535,5.534,2743,6.534,2744,7.181,2745,7.181,2746,7.181]],["t/641",[42,1.074,52,3.651,98,2.289,102,4.225,149,1.756,184,2.866,185,2.03,190,3.132,257,3.533,308,2.852,343,1.695,344,1.998,360,3.179,433,3.087,435,3.087,465,2.521,474,2.398,570,3.279,572,2.866,585,2.574,597,2.63,598,2.63,787,2.574,803,4.909,823,3.449,934,2.398,939,4.36,940,4.106,948,4.106,949,4.225,950,4.513,954,4.36,965,6.064,966,6.064,967,4.36,968,4.513,971,5.516,984,3.728,1047,4.106,1065,5.677,1170,4.909,1329,4.106,1549,6.615,1550,5.857,1839,5.541,2355,4.909,2397,6.064,2535,4.693]],["t/643",[175,2.027,177,3.113,184,3.178,185,2.377,190,3.473,267,3.113,308,3.339,360,3.722,433,3.615,435,3.615,474,2.808,572,3.178,597,3.079,598,3.079,607,2.982,934,2.808,939,5.105,944,8.253,945,6.487,949,4.947,950,5.285,954,5.105,965,6.723,966,6.723,967,5.105,968,5.285,971,4.807,1047,4.807,1065,4.947,1170,5.747]],["t/646",[5,1.76,42,1.503,145,4.149,152,3.764,175,2.424,343,2.373,585,3.604,787,3.604,1033,3.295,1224,6.873,2046,7.251,2747,7.758,2748,8.526]],["t/648",[69,1.64,80,1.018,95,1.77,104,1.949,183,1.306,184,2.983,185,1.455,200,2.472,202,0.948,270,2.07,342,3.05,349,3.325,350,2.868,358,4.02,398,2.182,414,4.143,427,2.517,480,2.617,580,2.044,585,3.255,679,2.472,851,2.389,953,3.235,971,7.277,978,3.747,979,4.286,981,4.286,990,3.028,1003,4.617,1015,5.056,1016,8.096,1047,5.192,1065,5.343,1195,3.364,1553,3.958,1620,7.673,2397,5.707,2749,4.365,2750,4.365,2751,8.514,2752,10.907,2753,5.211,2754,4.365,2755,4.365,2756,7.701,2757,6.465,2758,4.365,2759,3.518,2760,4.365]],["t/650",[139,4.87,184,3.065,187,4.129,190,3.35,304,4.955,934,3.446,949,6.071,2761,8.75,2762,8.75]],["t/653",[21,1.747,33,2.735,65,2.776,92,2.89,95,3.705,108,3.519,114,2.265,117,1.138,208,5.82,220,3.519,222,3.838,251,1.872,252,2.239,288,3.419,302,3.335,308,4.519,326,1.13,335,2.685,343,2.334,374,2.776,398,4.193,414,3.508,467,3.604,478,3.946,510,3.041,558,3.604,585,4.238,596,5.002,606,4.387,784,3.419,787,3.047,789,3.631,851,4.999,911,6.132,1152,4.313,1300,6.465,1367,3.419,1646,3.909,2231,4.313,2315,3.909,2343,3.631,2743,4.615,2763,6.56,2764,6.132,2765,7.21,2766,5.072,2767,4.615,2768,5.072]],["t/655",[5,1.356,38,2.9,42,1.517,54,5.295,129,1.542,152,2.9,199,1.965,202,1.869,211,2.665,221,3.003,257,2.837,297,3.429,332,3.656,342,2.105,362,2.837,394,3.003,402,2.361,403,3.861,549,4.558,572,3.014,593,4.313,595,7.441,596,4.558,961,3.938,1008,5.977,1899,4.869,2221,5.062,2763,5.977,2764,5.587,2769,9.221,2770,5.295,2771,5.295]],["t/657",[72,5.156,98,3.232,135,3.146,273,5.381,288,5.798,343,2.393,424,6.156,585,3.635,607,3.597,730,6.374,784,5.798,2772,7.824]],["t/659",[199,2.212,202,1.606,211,4.115,221,3.379,279,5.48,332,4.115,342,2.369,344,2.426,398,3.696,465,3.06,572,3.252,593,4.854,595,7.343,754,6.879,755,4.433,1227,5.96,2615,6.288,2649,6.288,2770,5.96,2771,5.96,2773,7.393,2774,7.393]],["t/661",[50,1.6,69,2.145,72,4.694,117,1.756,135,2.864,149,2.258,202,1.701,211,2.315,221,2.609,256,3.494,269,3.656,285,5.193,302,3.622,314,2.227,332,3.177,335,2.126,342,1.829,343,2.487,344,1.873,572,2.743,585,2.412,593,3.747,595,6.834,730,6.624,757,3.96,987,3.848,1025,3.233,1085,4.854,1189,4.086,1319,3.355,1420,2.894,1421,3.747,1651,3.848,1896,4.399,1998,4.399,2207,5.193,2221,4.399,2244,4.854,2333,4.086,2650,7.601,2770,4.601,2771,4.601,2772,7.124,2775,5.193,2776,5.708,2777,5.708,2778,7.83,2779,8.132,2780,4.601]],["t/663",[30,2.138,31,1.469,72,6.305,98,2.041,117,1.218,139,3.022,175,1.544,184,2.65,185,1.81,187,3.038,190,2.896,198,3.499,266,1.952,270,3.587,302,2.512,308,2.543,314,2.118,326,1.686,327,2.004,335,2.022,343,2.105,433,2.752,435,2.752,474,2.138,520,2.453,538,2.295,597,2.345,598,2.345,686,3.564,730,6.452,787,2.295,789,3.887,792,3.767,949,3.767,973,3.564,996,4.184,1025,3.075,1220,3.255,1279,4.617,1354,4.073,1501,3.397,1549,3.887,1550,3.887,1581,3.477,1712,4.617,2181,4.617,2397,4.024,2535,5.829,2779,4.94,2781,5.429,2782,5.429,2783,5.429,2784,5.429,2785,4.617,2786,5.429,2787,7.564,2788,7.564,2789,5.429,2790,5.429]],["t/666",[2,3.178,42,1.397,50,1.628,59,2.826,80,1.355,125,4.199,129,2.275,166,2.654,198,2.686,201,2.593,215,2.579,221,2.654,223,1.952,224,2.118,237,5.201,241,3.349,266,2.088,284,4.266,295,2.959,302,2.686,335,2.163,362,2.508,398,2.903,400,4.029,422,3.031,423,3.178,424,4.157,442,3.813,534,4.681,585,4.094,702,4.157,743,5.074,1014,3.482,1161,3.413,1197,4.508,1229,3.813,1354,3.127,1421,3.813,1586,4.029,2102,5.284,2461,5.284,2791,5.807,2792,5.807,2793,4.939,2794,5.807,2795,5.807,2796,5.807,2797,5.284,2798,4.939]],["t/668",[5,1.374,60,3.475,98,2.502,129,1.563,175,1.892,183,1.991,201,2.972,202,1.446,211,2.7,215,2.166,222,2.647,224,1.455,231,2.939,239,4.618,284,3.584,295,2.184,327,1.532,328,3.282,329,2.184,380,2.917,394,3.042,402,2.393,422,3.475,423,3.643,424,4.765,442,4.37,520,3.007,553,4.075,693,3.704,743,4.263,786,4.263,1033,2.572,1106,4.672,1161,3.912,1178,4.165,1229,4.37,1243,5.365,1244,5.661,1297,4.933,1384,4.37,2221,5.13,2264,5.661,2799,6.056,2800,6.656]],["t/670",[178,2.558,224,1.759,237,5.283,326,1.793,327,1.853,426,5.964,514,2.704,529,4.478,558,4.023,585,4.133,599,4.73,644,3.865,823,4.557,1033,3.109,2799,7.321,2801,7.321,2802,6.843,2803,7.537]],["t/672",[31,1.987,80,0.94,98,2.289,99,2.582,104,2.72,139,3.39,175,1.732,183,1.206,184,1.412,187,3.854,190,1.543,200,2.283,202,0.876,222,1.603,223,1.355,224,1.332,326,0.898,342,2.353,343,1.122,351,2.964,401,1.988,430,3.18,538,1.704,542,2.496,545,1.988,546,2.646,569,1.603,582,2.663,583,1.842,597,1.741,598,1.741,614,5.241,670,1.842,679,2.283,706,4.821,724,2.718,784,2.718,851,2.206,881,8.161,934,1.588,937,3.133,949,2.797,971,4.951,981,3.39,995,2.417,997,5.517,1047,2.718,1062,2.797,1065,2.797,1100,2.582,1106,3.954,1112,2.468,1139,3.901,1197,3.045,1200,3.513,1372,2.886,1549,4.361,1550,2.886,1589,2.886,1696,3.58,1710,3.106,2396,4.91,2397,2.988,2753,6.597,2780,3.249,2803,8.07,2804,5.542,2805,5.442,2806,6.681,2807,7.343,2808,3.667,2809,5.542,2810,5.542,2811,3.428,2812,3.667,2813,3.667]],["t/674",[31,2.068,80,1.005,98,2.406,99,2.759,104,2.859,139,3.564,175,1.225,183,1.289,184,1.509,187,3.94,190,1.649,200,2.44,202,0.936,223,1.448,224,0.942,326,0.96,342,2.448,343,1.199,351,3.116,401,2.124,430,3.342,538,1.821,542,1.765,545,2.124,546,2.828,569,1.713,582,2.322,583,1.969,597,1.86,598,1.86,614,5.418,670,1.969,679,4.328,706,5.017,724,2.905,784,2.905,851,2.358,881,7.689,934,1.697,937,3.293,949,2.989,971,5.152,981,3.564,997,5.704,1047,2.905,1062,2.989,1065,2.989,1100,2.759,1106,4.115,1112,2.637,1139,4.101,1197,2.154,1200,2.485,1372,3.084,1549,4.584,1550,3.084,1589,3.084,1710,3.32,2396,3.473,2397,3.193,2500,3.084,2753,5.161,2780,3.473,2803,7.936,2804,3.92,2805,4.746,2806,6.953,2808,3.92,2809,5.826,2810,5.826,2811,3.664,2812,3.92,2813,3.92,2814,7.642]],["t/677",[5,1.989,50,2.202,80,1.833,129,1.845,246,6.055,304,4.45,343,2.187,585,4.074,908,4.917,1103,5.297,1182,4.69,1297,5.824,1419,7.149,2356,7.149,2436,6.334,2719,7.149,2797,7.149,2815,7.857,2816,7.857,2817,7.857]],["t/679",[98,2.041,114,2.424,129,1.275,136,3.075,149,1.566,206,1.7,220,3.767,247,2.397,300,3.255,304,4.284,323,1.624,325,3.718,333,3.66,335,3.242,397,3.397,407,3.477,425,2.247,483,2.878,501,2.004,505,3.66,517,4.966,608,4.446,610,5.606,656,4.073,788,3.022,793,5.329,934,2.138,958,2.878,970,7.403,1103,5.099,1165,6.882,1182,4.581,1186,4.377,1299,4.024,1366,4.024,1394,4.377,1670,3.131,1716,7.403,1824,4.024,2026,4.377,2075,6.433,2221,4.184,2486,5.606,2678,4.617,2742,4.94,2818,6.882,2819,7.564,2820,5.429,2821,7.564,2822,6.882,2823,7.564,2824,7.564]],["t/681",[98,2.234,99,3.808,129,1.89,145,2.893,149,1.715,198,2.75,202,1.291,211,3.265,256,3.639,257,3.476,295,1.95,317,3.72,325,2.54,331,3.72,342,1.905,343,2.24,344,1.95,514,1.998,528,4.256,549,4.125,552,5.409,572,2.82,593,3.903,595,7.294,596,4.125,610,4.406,656,3.201,754,4.406,755,3.564,934,2.341,937,3.058,958,3.151,1094,4.125,1116,8.494,1182,3.917,1266,3.103,1329,4.008,1899,4.406,2769,6.846,2770,4.792,2771,4.792,2818,5.409,2825,7.324]],["t/684",[76,2.509,84,1.907,98,2.063,175,2.167,184,3.067,185,1.83,190,3.804,192,2.204,200,3.109,265,2.955,349,3.291,358,3.978,401,2.707,425,2.272,510,3.291,512,2.865,514,1.845,531,2.451,542,3.876,811,3.226,889,4.668,980,3.93,986,4.424,1015,5.004,1016,8.044,1116,8.67,1182,4.602,1183,4.424,1368,3.93,1417,4.242,2392,4.668,2825,4.994,2826,8.755,2827,8.755,2828,4.068,2829,4.994,2830,5.489,2831,7.621,2832,9.459,2833,8.755,2834,5.489]],["t/686",[5,1.127,21,1.881,24,2.893,42,0.962,69,2.052,76,2.495,84,1.896,88,3.788,98,2.052,117,1.225,129,1.282,173,2.525,178,1.735,199,1.633,202,2.05,206,1.709,211,2.214,257,2.357,295,2.491,311,3.273,326,1.692,327,1.748,328,3.744,329,2.491,332,3.038,342,1.749,344,1.791,362,3.279,380,1.835,402,1.962,406,3.584,414,2.656,531,2.438,555,3.584,580,2.556,585,2.307,590,2.934,595,6.195,596,3.788,626,2.987,754,4.046,755,3.273,954,3.908,965,5.627,966,5.627,1116,7.037,1181,4.643,1182,3.694,1183,4.4,1417,3.038,1458,3.788,1700,4.643,2392,4.643,2769,6.457,2829,4.967,2835,5.459,2836,5.459,2837,4.967,2838,5.459,2839,5.459]],["t/689",[5,1.016,10,3.356,50,2.312,104,2.198,114,2.198,117,1.104,129,1.657,149,2.38,201,2.198,240,4.186,272,4.186,273,3.08,295,2.315,314,3.218,325,2.103,335,1.833,373,2.694,396,3.153,470,2.839,475,3.013,476,3.524,511,1.37,622,3.319,630,2.839,644,2.364,916,2.951,934,1.939,1034,5.231,1106,3.8,1178,4.416,1194,5.104,1197,5.229,1238,3.524,1293,3.793,1317,3.415,1323,3.524,1377,3.793,1389,3.684,1417,2.74,1424,3.232,1428,4.897,1454,3.648,1504,3.415,1513,3.648,1575,3.153,1676,3.524,1752,3.013,1832,4.479,1915,3.648,1964,3.415,1983,3.793,2043,3.968,2192,3.968,2450,4.186,2531,4.186,2644,3.524,2793,6.002,2805,3.648,2840,4.922,2841,4.922,2842,4.922,2843,7.057,2844,4.922,2845,4.479,2846,4.922,2847,4.922,2848,4.922,2849,4.922,2850,3.232,2851,4.922,2852,4.922]],["t/691",[5,1.635,10,3.776,11,3.555,12,2.332,38,2.564,84,2.752,152,2.564,157,3.127,183,1.737,199,2.37,208,4.029,224,1.971,257,2.508,343,2.205,467,2.903,514,1.952,550,5.672,570,3.127,590,3.485,606,2.789,607,3.314,679,5.487,1121,4.029,1266,3.031,1339,3.127,1372,5.672,1695,4.939,1992,4.681,2315,4.475,2477,7.269,2478,7.269,2485,6.386,2500,4.157,2853,5.807,2854,7.923,2855,7.923,2856,7.923,2857,5.807,2858,5.807,2859,7.923,2860,5.284]],["t/693",[42,1.166,135,2.419,149,2.492,183,1.978,185,2.204,323,1.978,326,1.474,327,1.522,342,2.768,344,2.169,348,2.987,349,2.855,350,2.463,353,4.784,358,3.452,474,2.604,663,3.887,670,3.022,836,3.964,917,3.745,935,4.901,958,3.505,1022,5.33,1072,5.096,1074,4.901,1075,4.341,1076,6.186,1077,4.734,1078,5.33,1079,6.965,1080,6.965,1081,4.588,1197,3.305,1207,4.901,1450,4.901,2503,5.623,2504,5.33,2505,5.33]],["t/697",[30,3.509,33,3.379,53,3.733,76,3.169,80,1.617,84,2.408,114,3.096,117,1.555,121,4.963,129,1.628,211,2.812,247,3.061,274,4.156,310,4.551,335,2.582,422,3.619,423,3.794,511,2.74,545,4.393,566,3.096,657,3.926,667,4.244,1179,5.896,1339,3.733,1581,4.44,2861,8.91,2862,8.91,2863,8.958,2864,8.91,2865,6.308]],["t/699",[15,5.748,16,5.748,17,5.748,21,3.488,22,6.873,23,7.251,42,1.503,76,3.897,117,1.913,151,4.385,2866,8.526,2867,8.526]],["t/702",[12,0.793,13,1.258,30,2.379,31,1.448,49,2.626,50,0.553,69,0.742,145,1.658,184,3.412,185,1.136,187,1.806,190,2.313,202,1.162,206,1.067,214,2.44,220,1.369,224,0.431,253,3.735,258,1.063,309,1.521,310,3.514,341,0.653,348,1.539,349,2.311,350,0.735,368,2.313,378,6.832,402,0.709,430,5.468,433,2.28,435,2.28,436,3.484,454,0.973,474,1.342,511,1.251,516,0.881,523,1.521,525,5.251,536,1.369,537,1.591,542,4.148,545,1.68,560,3.12,564,1.521,566,0.881,568,1.463,615,3.219,644,0.948,670,0.902,738,3.428,836,1.183,851,1.08,854,1.369,995,3.209,998,1.678,1011,4.759,1062,4.192,1118,1.413,1127,6.013,1290,1.369,1315,2.747,1339,1.063,1424,1.296,1498,1.591,1520,1.521,1626,4.073,1639,1.591,1640,1.678,1649,1.678,1650,1.678,1694,1.678,1757,1.678,1759,1.521,1769,1.463,1784,3.1,1931,1.369,1937,2.898,1969,3.713,2006,1.796,2283,4.314,2311,1.463,2312,1.796,2551,1.521,2645,1.796,2658,1.796,2689,4.551,2805,1.463,2868,1.974,2869,1.974,2870,1.974,2871,1.974,2872,1.974,2873,1.974,2874,5.352,2875,5.352,2876,6.041,2877,6.041,2878,5.352,2879,6.041,2880,5.352,2881,6.041,2882,4.497,2883,1.974,2884,1.974,2885,3.408,2886,3.1,2887,3.1,2888,3.408,2889,3.408,2890,3.408,2891,3.408,2892,3.408,2893,1.974,2894,3.824,2895,4.497,2896,3.408,2897,6.041,2898,1.974,2899,4.497,2900,1.796,2901,1.974,2902,1.974,2903,1.974,2904,3.408,2905,4.497,2906,3.408,2907,1.974,2908,1.974,2909,3.408,2910,1.974,2911,3.408,2912,3.408,2913,1.974,2914,3.408,2915,1.974,2916,1.974,2917,1.974,2918,4.497,2919,4.497,2920,1.796,2921,3.408,2922,1.974]],["t/705",[5,1.402,13,2.507,24,4.66,25,4.158,69,2.552,74,3.6,84,2.359,92,2.34,116,4.579,231,2.999,280,3.992,295,2.228,323,2.032,495,3.917,512,3.545,607,2.841,626,4.812,685,6.294,697,5.234,699,5.928,728,5.234,737,3.992,1028,5.776,1166,4.158,1420,3.443,1427,5.034,1677,6.179,2333,6.98,2667,5.475,2923,6.179,2924,6.792,2925,6.792,2926,6.792,2927,6.179,2928,6.792,2929,6.792,2930,6.792]],["t/707",[5,1.264,13,3.032,24,3.247,31,2.223,38,2.705,74,3.247,84,2.128,92,2.111,96,4.131,116,4.131,118,6.622,149,1.767,256,3.751,259,3.021,266,2.202,295,2.01,323,1.833,344,2.01,371,4.251,373,4.496,454,3.021,511,1.705,512,4.838,531,2.736,582,2.222,623,4.131,626,3.353,697,4.722,705,4.131,993,4.541,1166,3.751,1257,3.751,1336,6.635,1420,3.106,1426,4.722,1443,4.722,1634,4.722,2150,5.211,2358,5.574,2411,5.211,2412,5.574,2419,5.211,2587,5.574,2923,7.475,2931,6.127,2932,6.127,2933,5.574,2934,6.127,2935,6.127,2936,6.127]],["t/714",[13,2.946,129,1.874,178,3.094,256,4.887,364,5.715,599,4.692,626,4.368,705,5.382,726,6.435,823,4.521,1426,6.152,2162,7.263,2197,8.277,2937,9.552,2938,7.983,2939,7.983,2940,7.983]],["t/716",[13,2.67,30,3.605,118,5.83,151,3.72,178,2.299,270,3.43,368,4.708,441,4.337,511,2.547,555,4.749,580,3.387,611,7.785,626,5.009,705,4.876,1166,4.428,1186,5.83,1257,4.428,1931,5.018,2160,6.581,2759,5.83,2941,7.233,2942,7.233,2943,7.233,2944,9.154,2945,7.233,2946,7.233,2947,7.233,2948,6.581]],["t/718",[5,1.127,10,3.251,21,1.881,38,2.41,42,0.962,50,1.53,69,2.052,74,2.893,84,1.896,92,1.881,121,3.908,129,1.783,149,1.574,178,2.775,192,2.192,256,6.072,266,1.962,280,3.209,344,2.864,406,3.584,429,2.692,511,1.519,514,1.835,531,2.438,555,4.985,580,3.556,623,3.68,626,4.155,705,3.68,706,3.584,834,4.967,1166,3.342,1230,4.207,1254,3.416,1299,4.046,1321,4.4,1336,3.908,1899,4.046,1931,3.788,1985,5.268,2242,3.908,2248,4.967,2249,4.967,2285,4.967,2333,3.908,2355,4.4,2411,4.643,2419,4.643,2711,4.967,2948,4.967,2949,5.459,2950,7.592,2951,7.592,2952,5.459,2953,5.459,2954,5.459,2955,5.459,2956,5.459,2957,8.73,2958,5.459]],["t/720",[13,2.632,38,3.148,50,2.542,59,3.469,69,2.68,80,1.663,97,4.807,98,2.68,104,3.184,129,1.674,149,2.056,270,3.381,281,5.747,295,2.339,314,2.781,546,4.681,743,5.81,795,3.722,930,5.285,1257,4.365,1304,5.747,2264,6.064,2304,6.487,2536,5.747,2759,5.747,2927,6.487,2959,7.13,2960,7.13,2961,7.13,2962,6.487,2963,7.13,2964,7.13,2965,6.487,2966,7.13]],["t/723",[5,2.048,152,3.64,199,2.467,222,3.947,251,3.043,259,4.066,327,1.898,341,2.727,413,4.122,797,4.304,936,7.502,1089,5.413,1197,4.122,2448,6.647,2967,7.012]],["t/725",[92,2.963,95,3.488,416,7.824,524,4.706,877,6.374,1089,5.646,1626,5.798,1682,6.374,2486,6.374,2487,6.627,2968,8.6,2969,7.313]],["t/727",[5,0.559,12,2.276,30,1.754,31,0.733,42,0.478,69,1.019,72,2.67,80,1.039,84,0.942,92,0.934,98,1.019,183,0.811,188,2.06,192,1.089,200,2.522,202,1.692,221,1.239,222,1.771,223,2.205,224,1.584,235,1.625,289,1.828,326,0.992,327,1.025,342,1.427,351,2.167,353,4.141,402,1.601,414,1.319,427,1.563,450,2.617,511,1.577,512,2.324,514,0.911,520,1.225,524,3.101,538,1.882,542,1.825,545,1.337,566,1.988,569,2.254,597,3.845,598,3.845,606,1.302,659,1.625,679,4.869,701,1.78,724,3.002,730,2.009,737,1.593,755,2.67,757,1.881,840,2.089,851,3.101,870,2.305,877,2.009,969,2.923,982,1.736,997,3.002,1033,1.047,1064,3.652,1089,4.759,1090,5.289,1092,1.563,1100,2.852,1106,4.629,1191,5.846,1195,2.089,1197,3.623,1198,1.509,1200,3.784,1205,3.787,1228,1.941,1372,1.941,1403,1.625,1587,2.305,1597,2.305,1682,2.009,1696,3.331,1710,2.089,1754,2.305,2010,6.281,2071,2.185,2072,2.185,2486,3.3,2487,4.367,2488,5.58,2489,2.305,2493,3.589,2494,3.589,2496,2.305,2615,2.305,2736,3.589,2753,2.185,2780,2.185,2969,2.305,2970,2.711,2971,2.711,2972,4.453,2973,2.711,2974,2.711,2975,2.711,2976,2.711,2977,10.479,2978,2.466,2979,2.711,2980,5.667,2981,2.711,2982,2.711,2983,2.466,2984,2.711,2985,2.711,2986,2.711,2987,2.711,2988,2.711,2989,2.711,2990,2.711,2991,2.466,2992,2.711,2993,2.711]],["t/729",[33,2.743,175,2.602,230,3.387,251,3.896,274,4.337,326,2.238,327,1.665,341,2.392,395,5.018,424,6.553,685,7.557,795,4.778,798,4.526,799,4.526,972,5.38,1248,5.83,1390,6.151,1411,6.785,2448,5.83,2994,7.233,2995,7.233]],["t/732",[64,3.153,98,2.863,129,1.789,173,3.524,175,2.166,182,5.286,183,2.279,251,2.812,267,4.129,359,2.715,414,4.601,501,2.812,514,2.56,668,5.286,737,4.478,809,5.286,946,5.646,1265,5.286,1751,7.009,2996,6.479,2997,6.479,2998,6.931,2999,6.931,3000,6.479]],["t/734",[12,1.858,95,2.737,98,1.739,139,2.575,183,1.384,184,3.068,185,1.542,187,3.904,189,5.827,190,3.721,202,1.005,350,1.723,351,3.876,358,2.415,359,1.649,398,4.377,414,4.26,430,5.369,436,2.668,467,2.313,474,1.822,510,2.774,536,3.21,558,2.313,614,6.826,668,3.21,700,3.935,798,2.895,961,2.774,978,4.883,979,3.756,981,5.181,1003,5.25,1004,3.73,1046,3.935,1328,3.312,1339,2.491,1544,3.566,1545,4.55,2535,3.566,2996,3.935,3000,3.935,3001,6.14,3002,4.627,3003,4.627,3004,6.14,3005,6.748,3006,4.627,3007,6.748,3008,4.627]],["t/736",[31,1.916,42,1.592,80,1.154,113,2.663,129,1.161,139,4.604,188,3.276,190,2.711,202,2.224,210,4.432,211,2.873,219,2.508,288,3.335,296,2.966,326,1.102,328,4.08,329,1.623,337,2.753,343,1.971,346,3.492,354,3.812,379,1.704,380,1.663,382,3.081,387,2.622,393,2.027,398,2.473,413,2.473,450,2.908,454,2.439,511,1.377,569,4.073,576,2.663,577,2.136,578,2.753,579,3.199,590,1.911,603,2.091,606,2.376,607,2.069,638,1.93,666,5.299,667,5.064,668,3.432,691,3.987,740,2.439,796,3.028,820,3.095,821,2.582,978,4.395,979,5.027,1106,2.663,1218,3.335,1413,4.207,2997,4.207,3001,4.501,3009,4.947,3010,4.947,3011,4.947]],["t/738",[42,1.128,70,4.441,80,1.493,92,2.205,98,3.179,117,1.436,188,2.961,210,4.005,211,2.596,215,2.753,251,2.363,257,2.764,264,5.444,300,5.071,323,1.915,327,1.474,335,2.384,343,2.804,344,2.775,359,2.281,397,4.005,414,3.115,419,4.583,425,2.65,454,3.156,505,4.315,580,2.998,581,3.341,617,4.583,656,3.446,666,5.417,667,5.178,1146,4.933,1177,5.16,1218,4.315,1509,4.744,1511,4.315,1514,4.933,1751,4.744,2315,4.933,3012,6.401,3013,6.401,3014,6.401]],["t/741",[34,5,42,1.189,59,3.282,117,1.513,215,2.196,224,1.914,229,6.746,233,3.083,235,4.044,239,4.68,243,4.221,266,2.425,322,3.754,325,2.882,333,4.548,370,4.829,398,3.372,402,3.147,422,3.521,423,3.692,454,3.326,514,2.267,520,3.047,1218,4.548,1509,5,1510,7.834,1511,5.902,1679,6.138,2017,6.138,2200,5.438,2245,6.138,2626,6.138,2628,5.737,3015,6.746,3016,6.746,3017,6.138,3018,6.746,3019,6.746]],["t/743",[53,3.952,92,2.528,95,2.977,117,1.646,175,2.086,222,2.919,224,1.604,231,3.24,402,2.638,408,3.775,419,5.254,487,3.721,495,4.233,501,2.709,608,4.314,610,5.44,656,3.952,801,6.065,1144,4.948,1161,4.314,1200,4.233,1286,5.092,1296,4.493,1506,6.242,1508,5.916,1509,6.847,1510,5.916,2629,6.677,3020,7.339,3021,7.339]],["t/745",[31,1.252,53,3.633,64,2.793,95,1.877,125,2.452,129,1.87,169,2.251,183,1.384,190,1.771,192,1.858,201,2.066,202,2.022,215,2.196,223,1.555,224,1.914,252,2.043,253,3.806,326,1.775,327,1.834,329,2.613,337,2.575,342,1.482,346,3.328,359,1.649,360,2.415,379,1.594,380,2.268,382,2.513,393,1.896,394,3.085,402,1.663,413,2.313,465,1.915,474,1.822,478,2.532,487,2.346,499,2.491,514,2.268,515,3.421,516,2.066,543,3.373,545,2.281,566,3.557,569,3.168,572,1.621,573,2.281,574,2.281,575,2.532,576,2.491,577,1.998,578,2.575,579,2.09,580,3.16,666,4.322,667,4.131,668,3.21,691,3.73,958,2.452,1159,3.038,1160,4.433,1257,2.832,1509,5.904,1510,5.44,1514,3.566,1692,3.73,1976,3.73,2828,5.002,3022,4.627]],["t/748",[5,1.159,11,2.218,30,3.299,31,1.519,33,2.129,42,0.99,50,1.015,74,1.92,84,1.258,97,2.442,98,1.361,117,1.542,201,1.618,206,2.423,211,1.469,215,1.179,220,2.513,224,2.23,231,1.599,252,1.599,259,1.786,280,3.3,284,3.7,327,0.834,429,1.786,489,2.685,511,1.912,520,2.536,529,2.016,545,2.768,558,1.811,566,3.457,570,3.022,615,5.542,738,2.32,823,2.052,907,2.442,937,3.981,958,1.92,1028,3.081,1070,2.685,1123,2.593,1200,2.089,1264,3.436,1334,2.593,1339,4.77,1344,2.513,1389,5.54,1417,3.124,1498,6.24,1501,2.267,1505,2.442,1575,2.32,1576,4.019,1586,2.513,1642,2.442,1769,2.685,1964,2.513,1969,2.513,1971,6.24,1973,4.774,2026,2.92,2035,4.774,2154,2.92,2308,2.92,2309,6.24,2352,4.525,2359,2.92,2429,5.107,2547,3.296,2828,2.685,2894,5.845,3023,6.24,3024,3.623,3025,7.62,3026,5.614,3027,3.623,3028,3.296,3029,3.623,3030,3.623,3031,3.623,3032,6.873,3033,3.296,3034,3.623,3035,3.623,3036,3.623]],["t/750",[42,1.701,149,1.463,187,3.369,188,2.346,201,2.265,202,1.822,206,1.588,211,2.057,215,2.73,224,1.109,265,3.882,266,2.592,323,2.157,327,1.168,328,3.555,330,4.733,337,4.013,344,1.664,359,3.574,360,3.763,380,1.705,402,3.284,510,4.323,520,2.291,590,1.96,740,2.501,821,2.648,824,2.535,846,5.162,969,4.733,1025,4.083,1103,4.861,1106,3.882,1243,6.762,1266,2.648,1274,4.618,1303,4.313,1389,2.648,1413,6.132,1575,4.618,1642,3.419,1977,7.769,2822,6.56,3037,5.072,3038,7.21,3039,7.21,3040,9.135,3041,5.072]],["t/752",[5,2.049,30,2.428,33,2.338,117,2.085,129,1.937,152,2.722,183,1.844,198,2.852,199,2.468,208,4.277,221,2.818,224,1.348,233,2.818,295,2.022,326,1.838,327,2.14,342,1.975,343,1.715,359,2.197,378,4.277,433,3.125,474,2.428,511,1.715,553,3.774,570,3.319,679,3.491,743,3.948,937,3.171,1025,3.491,1033,2.382,1354,3.319,1401,4.969,1575,6.628,1576,5.906,2263,4.569,2291,5.609,2675,5.243,2676,5.243,3023,4.969,3025,7.505,3042,6.165,3043,6.165]],["t/754",[359,3.261,1274,5.86,1575,5.86,2526,7.781,2801,8.324]],["t/756",[30,3.171,31,2.178,38,2.625,42,1.048,117,1.334,151,3.058,199,1.779,202,2.22,205,3.494,206,1.861,211,2.411,224,1.76,266,2.894,317,3.72,325,2.54,368,4.14,403,3.494,495,3.429,511,2.24,516,4.368,520,2.686,538,2.513,542,3.74,548,5.056,607,2.486,1064,3.309,1070,4.406,1171,4.582,1352,3.72,1417,3.309,1424,3.903,1581,3.808,1705,7.576,2555,4.406,2802,5.056,3044,5.945,3045,5.945,3046,5.056,3047,9.3,3048,8.05]],["t/758",[2,4.016,42,1.294,53,3.952,64,3.038,149,2.117,157,3.952,199,2.196,202,1.594,209,4.085,211,2.977,215,2.389,222,2.919,224,1.604,266,2.638,326,1.636,327,1.69,342,2.351,415,5.254,520,3.315,573,3.619,574,3.619,580,3.437,581,3.831,582,2.661,1528,4.493,1705,5.44,1771,6.242,1977,6.242,3046,6.242,3047,6.677,3049,6.677,3050,7.339]],["t/761",[84,1.78,113,5.692,115,4.446,129,2.275,136,2.902,179,3.282,183,1.533,224,2.262,233,2.342,284,3.91,307,5.502,311,3.072,312,5.107,447,3.555,504,5.039,520,3.281,532,3.012,550,6.57,608,3.012,909,4.662,937,4.339,1124,4.896,1299,6.802,1312,6.367,1339,2.759,1420,2.598,1455,3.206,2187,4.662,2531,6.176,2603,4.662,2644,3.668,2798,4.358,3051,5.124,3052,5.124,3053,5.124,3054,7.262,3055,7.262,3056,5.124,3057,5.124,3058,5.124,3059,5.124,3060,5.124,3061,5.124,3062,5.124,3063,8.436,3064,4.662,3065,4.662]],["t/763",[31,2.943,211,4.149,542,3.554,599,5.098,1528,5.31,1696,5.098,2311,6.429,3066,8.674]],["t/765",[31,2.943,211,4.149,542,3.554,599,5.098,1528,5.31,1696,5.098,2311,6.429,2920,7.892]],["t/767",[3,5.159,13,2.9,200,4.45,201,3.509,211,3.187,284,4.231,307,4.711,465,3.252,514,2.641,542,3.219,693,4.373,937,4.957,963,5.625,1528,4.81,1696,4.618,2311,7.144,2666,6.334,3067,9.638,3068,7.857,3069,7.857]],["t/770",[5,1.584,38,3.389,42,1.353,50,2.151,201,3.428,206,2.403,327,1.767,341,3.142,408,3.948,427,4.427,429,3.785,441,4.603,512,4.007,572,2.689,659,4.603,772,6.187,1189,5.496,1300,5.916,1504,5.326,2091,6.984,3070,7.677,3071,7.677,3072,7.677]],["t/772",[175,2.344,202,1.791,326,1.838,327,1.898,328,4.066,329,3.256,344,2.705,380,2.771,402,2.964,590,3.186,608,4.846,772,4.944,934,3.248,977,4.846,1189,5.903,3073,8.246]],["t/774",[5,1.213,11,3.597,42,1.036,73,4.997,92,2.024,95,2.383,113,3.163,145,2.859,178,1.868,185,1.959,190,3.057,221,2.685,224,1.746,233,2.685,341,1.943,342,2.559,348,2.654,349,2.537,350,2.188,353,5.006,358,3.067,359,2.094,413,2.937,427,3.389,435,2.979,474,3.573,507,3.327,538,2.483,558,2.937,798,3.676,811,3.453,836,3.523,848,6.154,967,4.206,1074,4.355,1075,3.857,1077,4.206,1081,5.541,1188,6.724,1189,4.206,1191,3.857,1198,3.27,1339,3.163,1501,4.997,1553,3.597,2736,6.437,3074,5.346]],["t/776",[5,1.451,42,1.239,69,2.642,80,1.64,104,3.139,129,1.651,259,3.467,295,2.949,315,5.21,326,1.567,327,2.07,342,2.252,343,1.956,351,3.421,413,3.514,490,4.878,670,4.934,693,5.003,804,5.003,934,2.769,1033,2.717,1045,5.21,1213,5.21,1325,5.418,1970,6.396,1981,6.396,2123,5.418,2388,5.979,2727,5.667,3075,6.396]],["t/778",[5,1.08,33,3.842,42,0.922,50,1.466,59,2.545,69,2.769,80,1.22,117,1.173,134,4.031,135,1.914,149,2.125,152,3.253,178,2.343,199,2.205,221,2.391,224,1.611,239,3.629,241,3.017,247,3.253,251,1.931,270,3.494,292,2.816,295,1.716,314,2.041,320,3.629,327,1.204,335,1.948,361,3.202,362,2.259,373,2.863,374,2.863,396,3.35,425,3.834,448,4.449,490,3.629,499,2.816,511,1.456,585,2.211,644,2.512,771,4.031,911,4.449,928,3.273,934,2.06,1021,4.173,1086,4.968,1182,4.151,1295,5.464,1312,5.113,1341,6.081,1411,3.877,1501,3.273,1508,4.217,1651,3.527,1670,3.017,1687,4.759,1723,4.031,1983,4.031,2190,3.877,2265,4.449,3076,5.231,3077,4.759]],["t/780",[5,1.374,11,2.781,30,3.419,31,1.229,33,2.526,42,1.39,69,1.707,80,1.553,129,1.067,149,1.31,175,1.291,177,1.983,183,1.359,185,1.514,199,1.359,206,1.422,209,2.528,211,1.843,219,2.303,223,1.527,224,1.723,230,2.127,253,3.292,255,2.486,257,2.875,259,2.24,295,1.49,317,2.843,327,1.046,335,1.692,342,2.133,344,1.49,348,2.052,349,1.962,350,1.692,353,4.362,358,2.371,362,2.875,394,3.044,401,2.24,408,2.336,415,3.252,420,6.058,441,2.724,450,2.67,480,2.724,543,2.271,554,2.909,572,1.592,573,2.24,574,2.24,575,2.486,607,1.9,632,2.724,836,2.724,934,2.623,984,2.781,1058,3.662,1074,3.367,1075,2.982,1077,3.252,1160,2.528,1162,2.67,1198,2.528,1201,6.703,1266,2.371,1317,3.152,1354,2.446,1389,4.115,1969,3.152,2142,4.133,2177,3.501,2628,3.863,2662,5.663,2802,3.863,2837,4.133,3065,4.133,3078,4.543,3079,4.543,3080,6.659,3081,6.659,3082,6.659,3083,6.659]],["t/783",[30,1.607,31,1.104,33,3.922,42,1.304,50,1.723,59,1.985,80,1.434,117,1.659,201,1.822,206,1.277,219,2.068,224,1.344,226,2.353,231,1.801,235,5.296,247,3.266,251,2.73,262,1.655,270,3.904,281,3.289,292,2.197,295,2.427,300,3.686,306,4.189,314,1.592,317,2.553,321,2.353,323,1.221,324,3.024,336,5.701,362,1.762,374,2.233,408,2.098,414,1.985,422,2.13,423,2.233,425,1.689,442,2.679,483,2.163,507,2.311,529,2.271,554,2.613,617,2.921,667,2.498,930,4.557,934,3.657,937,3.162,1014,2.446,1021,2.311,1142,3.144,1162,2.398,1197,3.073,1203,2.553,1214,2.921,1264,2.498,1266,2.13,1296,3.763,1317,2.831,1319,2.398,1342,3.712,1354,2.197,1389,4.298,1396,3.47,1438,3.47,1455,2.553,1594,2.831,1645,4.401,1683,3.289,1896,3.144,1916,3.47,1949,3.024,1964,2.831,1967,2.751,1971,3.289,2123,3.144,2189,3.712,2190,3.024,2232,3.712,2263,3.024,2309,3.289,2894,3.47,2962,3.712,3084,4.08,3085,4.08,3086,4.08,3087,4.08,3088,4.08,3089,4.08,3090,4.08,3091,4.08,3092,3.47,3093,4.08,3094,4.08,3095,4.08]],["t/785",[5,1.952,33,3.587,74,5.012,226,4.394,251,2.812,275,5.646,292,5.092,294,3.875,295,2.499,302,3.524,306,5.356,361,4.664,374,4.169,819,5.136,923,8.604,934,3.724,3096,7.618,3097,7.618,3098,7.618]],["t/787",[50,1.6,59,2.777,69,2.145,80,1.331,84,2.72,102,3.96,117,1.28,135,2.088,219,2.894,222,2.27,223,3.004,224,1.248,233,2.609,247,2.52,251,2.107,306,3.233,314,2.227,322,4.358,336,7.412,341,1.888,373,3.124,429,2.815,447,5.433,450,5.653,522,3.355,581,2.979,607,2.387,658,4.399,807,4.231,851,3.124,934,3.084,961,3.422,990,3.96,1411,4.231,1420,2.894,1475,4.399,1504,3.96,1651,3.848,1896,4.399,1931,3.96,2190,4.231,2265,4.854,2299,4.601,2321,5.193,3099,5.708,3100,5.708,3101,5.708,3102,5.708,3103,5.708,3104,5.708,3105,5.708,3106,5.708,3107,5.708,3108,5.708,3109,5.708,3110,5.708,3111,5.193,3112,5.708,3113,5.708]],["t/790",[33,2.868,80,1.764,95,3.067,323,3.365,326,2.098,327,1.741,341,3.113,480,4.533,670,4.684,758,5.097,772,5.643,1021,4.282,1192,5.604,1220,5.643,1733,6.879,2388,6.43,3092,6.43]],["t/792",[31,1.438,34,3.939,69,1.997,80,1.24,117,1.671,152,2.346,206,1.664,237,3.489,257,3.218,305,3.804,323,3.287,326,1.184,327,1.715,343,2.969,368,2.733,398,3.725,425,3.084,450,4.38,461,3.253,487,3.777,558,3.725,583,2.429,584,5.17,585,2.246,610,3.939,656,2.861,787,2.246,917,3.01,963,3.804,973,3.489,1021,3.01,1025,3.01,1033,2.053,1062,3.687,1069,4.519,1139,3.404,1144,3.583,1178,3.325,1182,4.779,1224,4.284,1300,4.095,1428,3.687,1505,3.583,1620,4.284,2073,4.095,2088,4.835,2333,3.804,2343,3.804,2514,4.519,3114,5.314,3115,5.314,3116,5.314,3117,4.835,3118,5.314,3119,5.314]],["t/794",[10,3.931,222,3.64,259,3.567,308,4.287,323,3.38,326,1.612,327,2.107,463,5.83,795,3.776,917,4.097,935,5.361,1025,4.097,1138,4.337,1194,4.097,1197,5.02,1929,5.574,2446,5.83,2644,5.178,2732,5.83,3120,6.151]],["t/796",[10,2.997,92,2.772,221,3.678,323,3.279,326,1.793,327,2.252,582,2.918,917,4.557,1025,4.557,1033,4.071,1120,6.201,2242,5.761,2646,5.035,2661,7.321]],["t/798",[84,2.795,178,2.558,199,2.407,206,2.519,222,3.2,224,1.759,259,3.968,323,3.152,630,4.641,804,4.478,1089,5.283,1112,4.926,1197,4.023,1200,4.641,1323,5.761,1395,6.201,1626,5.425,3121,8.047]],["t/800",[152,3.764,224,2.213,323,3.029,326,1.9,327,2.487,1033,3.295,2805,6.319,3122,6.873,3123,8.526]],["t/802",[72,5.112,92,2.937,166,4.628,169,4.927,323,3.232,582,3.092,713,5.748,1341,5.598,1942,7.251]],["t/804",[196,5.866,206,2.647,224,1.848,259,4.169,323,3.22,326,1.884,327,1.946,504,6.99,572,2.962,955,5.866,3124,7.692]],["t/806",[5,0.812,21,2.785,33,2.269,42,1.533,53,2.119,74,3.836,92,2.061,114,2.671,133,5.281,135,2.958,149,1.135,167,2.818,175,1.119,198,1.821,206,1.232,220,2.731,224,1.308,247,1.738,251,3.21,262,1.596,292,3.896,293,3.173,294,2.965,295,1.291,296,2.36,304,3.388,322,2.19,323,2.602,333,4.033,335,1.466,341,2.674,361,2.409,362,1.7,374,3.274,406,2.584,414,3.934,415,2.818,483,2.086,487,1.995,495,3.45,517,2.584,522,2.313,585,3.059,605,2.731,641,2.818,644,1.89,654,2.584,657,2.229,706,2.584,728,3.033,787,1.663,793,2.409,799,2.463,801,3.928,910,5.443,930,2.917,934,3.863,970,3.347,1014,2.36,1021,2.229,1026,3.033,1050,3.173,1166,4.43,1229,2.584,1286,2.731,1295,4.635,1312,2.731,1332,3.347,1407,3.033,1461,5.443,1743,3.173,2046,3.347,2089,3.581,2190,2.917,2192,3.173,2333,4.283,2502,3.347,2551,4.61,2667,3.173,2967,3.347,3125,3.936,3126,3.173,3127,3.581,3128,3.936,3129,3.581,3130,3.581,3131,3.347,3132,3.581,3133,3.936]],["t/809",[60,2.979,117,1.28,149,1.646,158,5.193,184,2,185,1.903,187,3.145,215,2.548,224,1.712,230,3.667,251,2.107,253,2.97,335,2.126,348,4.345,349,4.352,350,3.582,374,4.285,394,2.609,433,4.531,435,2.894,454,2.815,532,3.355,542,2.339,543,2.853,544,3.848,545,2.815,661,3.494,736,4.086,819,3.848,1033,2.206,1138,3.422,1262,3.747,1490,8.571,1561,4.601,1756,5.193,1758,5.193,1759,6.034,1760,4.854,1762,6.659,1763,5.193,2024,5.193,3134,5.708,3135,5.708,3136,5.708,3137,5.708,3138,7.124]],["t/811",[42,1.628,139,5.139,344,3.029,3139,9.234]],["t/814",[13,2.77,98,2.82,135,2.745,163,5.372,175,2.133,222,3.726,224,1.64,231,3.313,269,4.806,284,4.04,295,2.462,335,2.795,374,4.107,402,2.698,424,5.372,442,4.927,472,4.927,514,2.522,932,5.059,969,4.927,1197,3.751,1235,5.783,1260,6.049,1421,4.927,1443,5.783,2450,6.382,3092,6.382,3140,7.504]],["t/816",[5,1.234,13,2.207,31,2.187,64,2.476,92,2.06,98,2.248,129,1.404,145,2.91,149,1.725,175,1.7,201,2.671,202,2.13,206,1.872,215,1.947,222,2.378,253,2.268,307,3.586,329,2.652,344,1.962,376,6.93,379,2.06,380,2.01,381,3.83,382,2.227,385,4.433,386,4.433,393,2.45,394,2.734,402,2.905,413,2.99,465,2.476,511,1.664,515,3.032,516,2.671,579,2.702,603,2.528,638,2.333,693,3.328,754,4.433,770,3.926,937,3.076,1296,3.661,1349,3.83,1490,5.086,1754,5.086,1967,5.449,2644,4.282,3141,8.083,3142,5.981,3143,5.441]],["t/818",[80,1.892,117,1.82,178,3.124,222,4.205,223,2.726,224,2.148,450,4.768,566,3.622,823,4.594,1511,5.469,1527,6.899,2900,7.381,3143,7.381,3144,8.112,3145,8.112]],["t/820",[5,1.041,30,3.295,31,1.365,33,1.914,38,2.228,110,3.402,117,1.876,129,1.185,206,1.58,219,2.558,224,1.57,308,2.363,368,2.595,371,3.501,442,3.313,467,2.523,511,2.68,524,2.762,535,3.501,538,2.133,542,3.427,567,3.158,629,2.809,670,3.284,819,3.402,1064,2.809,1144,3.402,1264,5.121,1296,3.089,1389,4.758,1417,2.809,1424,3.313,1506,4.292,1507,3.889,1561,4.068,1581,3.232,1650,4.292,1916,4.292,1969,3.501,1971,4.068,2283,5.791,2309,4.068,2359,5.791,2502,4.292,2649,4.292,2689,4.292,2704,4.591,2775,6.536,2828,3.74,2887,7.611,3111,4.591,3131,4.292,3146,5.046,3147,5.046,3148,5.046,3149,5.046,3150,5.046,3151,5.046,3152,5.046,3153,5.046,3154,5.046,3155,5.046,3156,5.046,3157,5.046,3158,5.046,3159,5.046,3160,5.046,3161,5.046,3162,5.046,3163,4.292,3164,5.046,3165,5.046]],["t/822",[5,1.504,10,2.713,12,2.926,24,3.862,50,2.042,59,3.545,193,5.055,229,5.615,242,6.629,304,4.126,362,3.146,520,3.291,855,5.055,1086,4.912,1092,4.202,1284,5.873,1334,5.216,1393,6.196,1417,4.055,1569,6.629,2250,5.216,2436,5.873,2694,6.196,2793,6.196,2978,6.629,3166,6.629,3167,7.286,3168,7.286,3169,7.286,3170,7.286,3171,7.286,3172,7.286,3173,7.286]],["t/824",[20,4.917,42,1.675,92,2.645,135,2.808,160,5.326,304,4.348,322,5.288,341,2.539,685,5.496,703,5.04,772,4.603,1086,5.176,1094,5.326,1194,4.348,1393,6.529,1428,5.326,3126,6.188,3127,6.984,3132,6.984,3174,7.677,3175,7.677,3176,7.677,3177,7.677,3178,7.677]],["t/826",[2,3.416,10,3.098,64,3.872,74,3.308,84,2.168,117,1.4,129,1.465,152,2.756,219,3.164,221,4.276,224,1.364,259,3.078,262,2.532,295,2.729,306,3.535,326,1.391,480,3.742,493,4.33,797,3.258,917,3.535,935,4.626,1023,4.81,1103,4.208,1140,4.81,1194,3.535,1197,4.677,1278,5.308,1647,7.209,1985,4.33,1986,5.679,2250,4.468,2436,5.031,2477,5.031,2478,5.031,2500,4.468,2803,4.81,3130,5.679,3179,6.241,3180,6.241,3181,6.241,3182,5.031,3183,5.308,3184,6.241,3185,6.241,3186,6.241,3187,6.241]],["t/828",[5,1.881,10,3.115,12,2.885,50,1.414,69,1.897,95,2.914,104,2.253,114,2.253,135,1.846,145,2.455,149,1.455,152,2.228,166,2.307,169,3.496,192,2.027,193,3.501,198,2.334,199,1.51,208,3.501,221,4.166,222,2.857,223,1.696,255,2.762,259,3.543,289,3.402,304,2.858,326,1.125,327,1.654,341,1.669,408,3.695,465,2.089,475,3.089,480,3.026,514,2.415,520,2.28,531,2.253,599,2.966,633,3.501,659,3.026,679,2.858,702,3.613,713,3.402,917,4.069,934,1.988,935,3.74,974,3.402,982,3.232,1033,1.95,1047,3.402,1086,3.402,1098,4.591,1194,4.069,1197,4.182,1198,2.809,1377,3.889,1647,7.024,2477,4.068,2478,4.068,2481,4.292,2500,3.613,3017,4.591,3182,4.068,3183,4.292,3188,5.046,3189,5.046,3190,7.611,3191,4.292,3192,5.046,3193,5.046]],["t/830",[10,2.98,12,2.949,31,0.89,34,3.858,49,2.535,52,3.121,72,3.121,80,1.507,92,1.793,95,2.111,104,2.324,117,1.647,129,0.772,146,1.933,151,1.692,152,1.452,166,2.379,169,3.143,178,1.655,199,0.984,200,1.863,206,1.629,221,4.224,223,3.106,224,0.719,257,3.171,260,2.438,266,1.182,270,1.56,296,1.972,308,4.174,326,1.16,327,0.757,330,2.16,343,0.915,353,1.486,396,2.107,398,1.644,401,1.622,402,1.871,450,3.059,465,3.04,467,1.644,475,2.014,483,1.743,511,0.915,514,1.106,520,2.351,538,1.39,550,2.355,558,2.602,566,1.469,572,1.152,630,1.897,633,5.095,659,1.972,679,1.863,690,5.095,695,2.355,701,2.16,736,2.355,737,3.059,830,2.797,841,2.058,851,4.019,951,2.058,959,2.535,972,1.933,974,2.218,982,2.107,1033,2.011,1189,2.355,1191,2.16,1197,4.253,1200,1.897,1286,2.282,1398,2.993,1594,2.282,1610,2.797,1615,2.993,1631,2.993,1647,6.557,1686,2.535,1929,2.535,1985,2.282,2003,2.652,2010,2.652,2154,2.652,2283,2.652,2481,2.797,2482,4.427,2484,4.427,2485,4.196,2486,4.787,2487,4.011,2493,2.652,2494,2.652,2650,2.797,2651,2.993,2969,2.797,2991,2.993,3163,2.797,3166,2.993,3182,4.196,3190,5.877,3191,4.427,3194,3.289,3195,3.289,3196,3.289,3197,3.289,3198,3.289,3199,3.289,3200,3.289,3201,3.289,3202,3.289]],["t/832",[5,0.485,10,1.906,12,0.943,30,1.557,31,1.069,42,0.697,80,1.194,92,0.809,117,0.887,149,1.14,178,1.256,183,0.703,185,0.783,188,2.367,195,1.128,196,1.629,200,1.33,202,1.676,206,1.237,218,1.542,224,0.864,237,2.595,270,2.426,284,1.264,295,0.77,308,3.398,326,1.492,327,1.542,329,0.77,330,2.595,335,0.875,341,1.307,342,3.222,348,2.711,349,2.592,350,2.235,353,4.143,358,1.226,365,3.186,379,0.809,380,1.328,382,1.472,387,2.095,393,0.962,402,0.844,461,1.438,468,1.438,470,1.354,474,0.925,511,1.67,520,1.061,524,2.8,538,1.67,550,1.681,553,1.438,569,1.572,577,1.014,579,1.061,590,0.907,603,0.993,606,2.882,638,1.542,644,1.128,662,1.504,670,3.703,675,1.208,679,3.792,690,2.742,714,1.681,737,1.38,740,1.949,754,1.741,755,1.408,772,3.068,820,2.473,821,2.063,841,1.47,849,3.186,851,2.8,853,1.741,854,1.629,855,2.742,856,3.046,900,1.542,931,1.997,974,1.583,977,2.323,978,3.942,979,4.509,982,2.531,1033,0.907,1042,2.929,1047,4.514,1075,1.542,1081,1.629,1100,1.504,1172,1.81,1180,1.438,1188,1.741,1191,5.066,1193,3.361,1197,4.05,1198,1.307,1203,1.47,1343,3.186,1386,1.81,1594,1.629,1682,1.741,1710,1.81,1929,3.943,1985,1.629,2003,1.893,2010,3.186,2250,1.681,2260,3.361,2288,1.997,2317,1.81,2327,1.997,2482,6.89,2484,4.352,2485,1.893,2486,3.793,2487,3.943,2488,5.104,2489,1.997,2490,3.596,2493,1.893,2494,1.893,2496,1.997,2497,2.137,2505,1.893,2614,2.137,2692,2.137,2694,3.361,2736,3.186,3049,2.137,3074,2.137,3163,1.997,3191,1.997,3203,2.348,3204,2.348,3205,3.596,3206,2.348,3207,2.348,3208,2.348,3209,2.348,3210,2.348,3211,2.348,3212,2.348,3213,2.348]],["t/834",[114,3.907,136,4.955,149,2.524,343,2.435,344,2.871,823,4.955,1033,3.381,2504,7.053,3182,7.053,3183,7.441]],["t/836",[10,2.138,42,1.386,80,1.339,117,1.288,135,2.1,149,2.781,179,5.034,183,1.718,185,1.914,206,1.797,295,1.883,297,2.997,323,1.718,325,2.452,326,1.279,327,1.322,342,2.519,344,1.883,348,2.593,349,2.479,350,2.138,353,4.711,358,2.997,394,2.624,427,3.311,474,2.261,633,3.983,663,5.269,670,2.624,836,3.442,917,3.251,1022,6.336,1072,4.424,1074,4.255,1075,3.769,1076,5.628,1077,4.11,1078,4.627,1079,7.226,1080,7.226,1081,3.983,1194,3.251,1197,2.87,1207,4.255,1450,4.255,2503,4.882,2504,4.627,2505,4.627,2805,5.826,2811,4.882]],["t/839",[5,1.831,21,3.381,82,6.264,129,1.617,163,4.929,224,1.505,247,3.04,307,5.318,395,4.777,459,5.103,908,4.308,917,5.024,1197,3.442,1262,5.823,1341,6.443,2731,9.43,3028,6.264,3214,6.885,3215,8.87,3216,8.87,3217,6.885,3218,6.885,3219,6.264,3220,6.885,3221,6.885,3222,6.885,3223,6.885,3224,6.885]],["t/841",[42,1.385,129,1.845,317,4.917,329,2.578,343,2.682,344,2.578,376,5.159,459,5.824,468,4.81,579,3.549,702,5.625,1262,6.845,1340,5.625,1341,5.159,2609,6.682,3225,8.404,3226,7.149,3227,7.857]],["t/843",[202,2.257,253,3.379,376,5.849,379,2.388,380,2.33,381,4.44,382,2.582,385,5.138,386,5.138,393,2.841,459,5.138,515,3.515,516,3.096,582,2.514,597,2.994,598,2.994,638,2.704,900,4.551,905,5.588,1064,3.858,1262,5.849,1340,4.963,1424,4.551,1581,4.44,3225,5.588,3226,6.308,3228,9.779,3229,5.896,3230,5.896,3231,6.308]],["t/845",[202,2.375,209,4.085,376,6.065,379,2.528,380,2.467,381,4.7,382,2.733,385,5.44,386,5.44,393,3.007,573,3.619,574,3.619,638,2.863,1064,4.085,1262,4.818,1424,4.818,1528,4.493,1581,4.7,2518,6.242,3225,5.916,3229,6.242,3230,6.242,3231,6.677,3232,9.199,3233,6.677]],["t/847",[42,1.556,129,2.072,317,5.523,329,2.896,468,5.403,702,6.319,1340,6.319,1341,6.785]],["t/849",[117,1.599,149,2.056,202,2.281,223,2.396,253,3.441,376,5.955,379,2.456,380,2.396,381,4.567,382,2.655,385,5.285,386,5.285,393,2.921,459,5.285,515,3.615,516,3.184,582,2.586,597,3.079,598,3.079,638,2.781,900,4.681,905,5.747,1262,5.955,1340,5.105,1341,4.681,3225,5.747,3228,9.553]],["t/851",[98,3.247,117,1.938,202,2.3,209,3.68,222,3.828,224,1.445,329,2.835,376,5.673,379,2.278,380,2.222,381,4.235,382,2.463,385,4.901,386,4.901,393,2.709,394,3.022,573,3.261,574,3.261,638,2.579,937,3.401,1340,6.186,1341,6.319,1528,4.048,1769,7.564,2518,5.623,3229,5.623,3230,5.623,3232,8.757,3233,6.016]],["t/854",[5,1.461,42,1.248,50,2.531,104,3.161,175,2.013,177,3.091,178,2.871,222,3.954,224,1.974,326,2.013,327,2.289,441,4.245,490,6.265,507,4.01,547,5.247,558,3.539,622,4.773,784,6.704,786,4.534,846,6.465,1408,5.068,1896,5.456,3234,7.08,3235,6.021,3236,7.08]],["t/857",[2,3.538,5,0.901,12,1.753,31,1.749,42,1.14,69,1.64,80,1.508,117,1.727,166,2.955,178,1.388,202,1.849,215,2.104,222,1.736,223,1.467,224,1.413,252,3.4,254,2.943,258,3.481,266,1.569,328,3.797,329,1.432,340,2.213,341,2.138,343,1.215,356,2.943,378,6.307,379,1.504,380,1.467,382,1.626,398,2.182,413,2.182,418,4.925,467,2.182,474,2.546,503,3.375,511,1.215,516,3.439,542,1.788,558,2.182,573,3.797,574,3.797,575,2.389,576,2.35,590,2.498,603,1.845,638,1.703,675,2.245,846,3.125,978,2.124,979,2.429,1017,5.498,1180,3.958,1220,2.617,1257,2.672,1339,4.146,1389,2.278,1501,2.731,1528,3.958,2536,3.518,3237,9.09,3238,5.882,3239,3.971,3240,7.006,3241,3.971,3242,5.882,3243,3.971,3244,3.971,3245,3.971,3246,5.882,3247,5.882,3248,7.006]],["t/859",[2,2.909,5,1.356,12,1.357,31,1.438,38,1.491,42,1.159,50,1.842,64,1.398,69,1.27,70,2.344,80,1.24,113,1.819,117,1.672,129,0.793,166,2.43,175,0.96,177,1.475,178,1.074,188,1.563,198,1.563,202,1.869,215,1.73,219,1.713,222,2.614,223,1.135,224,1.629,251,1.247,252,3.29,253,1.281,254,2.278,258,2.862,266,1.911,270,1.602,297,1.763,308,1.582,329,1.744,341,1.758,342,2.106,343,0.94,346,1.666,356,2.278,359,1.204,379,1.164,380,1.135,382,2.448,387,1.791,393,1.384,394,1.544,398,1.689,413,2.657,415,2.419,467,1.689,474,2.094,476,2.419,501,1.247,503,2.775,511,0.94,515,1.713,516,2.935,524,1.849,538,1.428,542,1.384,558,2.657,569,2.614,573,3.241,574,3.241,575,1.849,576,1.819,577,1.459,578,1.88,579,1.526,580,1.582,581,1.763,590,2.054,599,1.986,603,1.428,638,1.318,699,3.584,784,2.278,796,2.068,809,2.344,820,2.114,821,1.763,824,2.657,846,2.419,978,1.644,979,1.88,1017,4.521,1124,2.278,1180,3.254,1220,2.025,1240,2.419,1257,2.068,1339,3.539,1389,1.763,1402,2.603,1403,2.025,1404,2.504,1405,3.187,1406,1.88,1407,2.603,1501,2.114,1528,3.254,1634,2.603,1909,2.873,2176,2.873,2355,2.723,2491,3.074,2536,2.723,2666,2.723,3238,4.836,3239,3.074,3240,5.979,3241,3.074,3242,4.836,3243,3.074,3244,3.074,3245,3.074,3246,4.836,3247,4.836,3248,5.979,3249,3.378,3250,3.378,3251,3.378,3252,3.378,3253,3.378,3254,3.378,3255,3.378]],["t/862",[13,2.689,42,1.284,114,3.253,159,7.087,175,2.071,294,2.985,295,2.39,323,2.18,335,2.713,343,2.027,362,3.146,401,3.593,585,3.079,609,5.055,641,6.583,655,5.873,663,5.405,793,4.46,1408,5.216,1427,6.816,1898,6.629,1955,5.216,2023,6.629,2263,6.816,2290,5.873,2339,6.196,3077,6.629,3256,7.286]],["t/864",[92,2.75,114,3.565,117,1.791,305,5.715,323,2.912,327,1.838,343,2.708,398,3.991,663,4.692,686,5.241,963,5.715,1178,4.995,1671,6.789,2343,5.715,2344,7.263,2345,7.263,2886,7.263,3117,7.263,3257,7.983]],["t/866",[6,7.505,10,2.296,13,2.275,50,1.728,116,4.156,133,5.362,154,5.609,206,1.93,266,2.216,270,2.923,408,4.243,476,4.413,487,3.125,511,2.296,948,4.156,1049,4.277,1162,3.623,1166,3.774,1178,3.857,1402,7.165,1457,6.656,1671,7.015,2097,5.609,2113,4.047,2115,5.283,2164,5.609,2470,6.649,3258,6.165,3259,6.165,3260,4.969,3261,5.243,3262,10.65,3263,9.297,3264,9.297,3265,6.165,3266,5.609,3267,6.165]],["t/868",[30,3.096,42,1.012,84,1.994,92,1.978,117,1.288,129,1.348,187,2.305,195,3.775,200,3.251,201,2.563,224,1.255,253,2.177,323,2.352,326,1.279,343,2.187,359,2.046,461,3.514,473,5.269,512,2.997,519,3.514,535,3.983,579,2.593,585,2.426,737,3.374,793,3.514,851,3.142,934,3.531,937,2.952,951,3.592,958,3.043,961,3.442,993,4.255,1023,4.424,1084,4.424,1096,3.769,1121,3.983,1182,2.793,1370,4.424,1658,5.223,1752,3.514,1813,3.769,1953,4.627,2025,4.882,2113,5.885,2115,5.741,2286,3.677,2348,5.223,2644,4.11,2764,4.882,2850,5.161,3126,4.627,3260,6.336,3268,4.627,3269,5.741,3270,5.741,3271,5.741]],["t/870",[3,3.747,80,1.331,117,2.157,151,4.027,169,3.81,183,1.708,192,2.292,251,2.107,257,2.465,270,2.707,279,4.231,315,4.231,327,1.803,344,1.873,357,3.96,398,2.853,409,4.231,465,2.363,467,2.853,473,4.602,501,2.107,511,1.588,580,4.185,664,3.96,693,4.974,797,4.665,934,2.248,951,3.572,1025,3.233,1123,4.086,1182,3.81,1194,3.233,1265,3.96,1344,3.96,1345,3.848,1813,5.868,1965,4.854,2073,4.399,2113,3.747,2115,3.656,2242,4.086,2286,3.656,2315,6.034,2678,4.854,2850,5.141,2865,5.193,3235,4.854,3260,4.601,3261,4.854,3268,4.601,3272,5.193,3273,5.708,3274,5.708]],["t/872",[3,5.805,10,1.855,13,1.414,21,2.258,26,2.515,30,0.891,31,0.612,34,1.678,42,0.675,59,1.101,65,1.239,69,1.44,70,1.57,72,1.357,76,1.035,80,0.894,84,1.331,96,1.526,98,0.851,99,1.45,115,1.386,117,0.859,129,0.9,135,0.828,145,1.101,146,2.928,149,1.105,151,1.164,152,1.691,167,1.62,171,2.84,173,1.047,175,0.643,176,2.059,179,1.45,192,0.909,199,0.677,201,2.224,204,2.297,205,2.252,206,0.709,211,0.918,215,1.621,222,0.9,224,0.495,230,1.06,231,0.999,251,2.163,254,1.526,257,2.531,262,0.918,277,1.526,282,2.059,284,1.219,302,2.304,303,2.059,323,1.49,326,0.504,327,0.882,329,1.257,335,0.843,341,0.749,344,0.743,353,1.022,359,1.775,368,1.97,372,3.258,395,1.57,402,0.814,404,1.416,408,1.164,425,0.937,427,1.305,459,1.678,465,1.586,468,1.386,473,3.445,474,1.509,501,2.163,504,1.57,510,2.297,511,1.386,531,1.011,532,1.33,535,1.57,551,1.62,582,0.821,623,2.583,654,1.486,656,3.832,670,1.035,714,1.62,757,2.658,795,1.182,797,2,884,1.825,916,1.357,917,1.282,934,2.986,951,1.416,963,1.62,990,1.57,1023,2.953,1024,3.258,1033,1.48,1064,1.26,1076,2.743,1081,1.57,1139,1.45,1182,1.101,1192,2.84,1194,2.17,1197,3.277,1238,1.62,1286,1.57,1295,3.754,1317,1.57,1349,2.454,1405,2.297,1428,3.456,1455,1.416,1457,1.62,1505,1.526,1534,1.62,1601,1.678,1676,3.566,1692,1.825,1734,2.059,1735,2.059,1813,2.515,1953,3.088,1965,1.925,2002,2.059,2039,2.059,2077,3.258,2082,2.059,2113,1.486,2115,1.45,2177,1.744,2286,1.45,2288,3.258,2317,1.744,2341,2.059,2365,2.059,2416,3.486,2418,3.486,2446,1.825,2447,2.059,2551,2.953,2583,3.088,2646,3.117,2732,1.825,2759,1.825,2798,1.925,2803,1.744,2845,2.059,2850,5.453,2933,2.059,2983,2.059,3131,1.925,3138,3.486,3260,7.6,3261,1.925,3268,1.825,3272,3.486,3275,2.264,3276,2.264,3277,2.264,3278,2.264,3279,2.264,3280,2.264,3281,2.264,3282,7.582,3283,2.264,3284,2.264,3285,2.059,3286,2.264,3287,4.981,3288,2.264,3289,2.264,3290,3.486,3291,2.264,3292,2.264,3293,2.264,3294,3.831,3295,2.264,3296,3.831,3297,5.332,3298,2.264,3299,2.264,3300,2.264,3301,2.264,3302,2.059,3303,3.831,3304,2.264]],["t/874",[3,2.746,10,2.333,12,1.68,21,2.158,33,1.586,60,2.183,76,1.912,80,1.461,92,2.158,97,2.82,114,1.868,117,1.405,146,2.458,149,1.206,169,2.035,179,2.679,195,2.009,201,1.868,215,1.361,222,1.663,223,1.406,233,1.912,251,1.544,257,1.806,292,3.372,294,2.566,312,3.486,323,3.057,326,1.396,327,1.442,329,1.372,359,2.676,425,1.731,460,2.617,461,2.56,470,2.412,473,5.508,481,3.223,499,2.252,582,1.517,585,2.647,654,2.746,659,2.508,693,4.179,738,2.679,793,2.56,795,2.183,811,2.458,823,2.369,934,2.467,951,2.617,963,2.994,1084,3.223,1093,3.805,1174,2.902,1182,3.047,1194,2.369,1198,2.328,1203,2.617,1220,2.508,1221,2.746,1240,2.994,1252,3.371,1266,2.183,1344,4.345,1345,2.82,1370,3.223,1383,3.557,1384,2.746,1403,2.508,1406,2.328,1427,4.642,1443,3.223,1454,3.1,1505,2.82,1586,2.902,1622,3.1,1813,4.112,1909,3.557,1955,2.994,2025,3.557,2073,3.223,2113,2.746,2115,2.679,2247,3.805,2250,2.994,2251,3.805,2286,2.679,2585,3.805,2644,4.484,2646,2.617,2850,2.746,2996,3.557,3305,2.994,3306,4.182,3307,3.223,3308,4.182,3309,3.805,3310,3.805,3311,4.182,3312,4.182]],["t/876",[117,1.366,146,3.579,165,3.579,177,2.659,198,2.817,211,2.47,222,3.675,224,1.789,291,4.225,323,1.822,460,3.811,473,6.058,489,4.513,499,3.279,501,2.248,585,2.574,674,5.179,693,3.389,787,3.458,793,3.728,942,4.909,951,3.811,1146,4.693,1147,4.36,1182,2.963,1293,4.693,1295,5.24,1308,5.179,1323,6.615,1384,3.998,1586,4.225,1813,3.998,2113,3.998,2115,3.9,2286,3.9,2646,3.811,2707,5.541,2712,5.541,2737,5.179,2850,3.998,3122,4.909,3126,4.909,3305,4.36,3307,4.693,3313,6.09,3314,6.09,3315,6.09,3316,6.09,3317,6.09]],["t/878",[3,3.685,5,0.748,10,2.56,12,2.254,42,1.212,64,1.5,92,1.248,104,1.618,117,0.813,135,2.054,145,1.763,146,2.129,149,1.619,151,1.863,165,2.129,168,3.296,169,3.344,175,1.596,178,1.152,179,2.32,188,1.676,199,1.084,206,1.757,262,1.469,266,1.302,270,2.662,292,1.95,294,2.3,295,1.188,308,3.922,323,1.084,325,1.547,326,1.251,327,1.292,335,1.349,342,2.839,353,4.314,359,2.985,374,1.982,403,2.129,473,5.208,511,1.008,524,3.072,531,1.618,532,3.3,538,1.531,553,2.218,560,2.513,583,2.566,606,1.74,607,1.515,670,3.538,679,3.179,693,2.016,740,1.786,772,2.172,793,2.218,804,3.124,821,1.891,824,1.811,851,3.072,934,3.049,951,2.267,963,4.019,972,2.129,978,2.731,979,3.124,982,2.32,1033,2.656,1095,3.296,1171,2.792,1197,3.436,1198,2.016,1200,2.089,1221,2.378,1507,2.792,1586,2.513,1813,2.378,1938,2.92,1985,2.513,1988,2.685,2004,2.92,2009,4.774,2113,2.378,2115,3.595,2250,2.593,2260,4.774,2286,2.32,2550,2.513,2583,2.92,2646,2.267,2850,5.082,2860,5.107,3046,3.081,3205,5.107,3305,2.593,3307,2.792,3318,3.296,3319,3.623,3320,6.873,3321,5.614]],["t/880",[5,1.717,12,2.006,42,1.257,64,2.068,117,1.121,146,2.937,177,2.181,179,3.2,196,3.466,199,1.495,206,1.564,215,2.322,257,2.157,262,2.027,323,1.495,343,2.315,376,3.28,392,3.703,473,5.64,499,2.69,532,2.937,558,2.498,567,3.126,585,3.835,605,3.466,641,3.577,654,3.28,693,2.781,714,3.577,784,3.368,787,3.015,793,3.058,874,4.546,921,4.249,942,5.75,951,3.126,973,5.461,1058,4.027,1092,2.881,1121,4.949,1123,3.577,1295,3.2,1334,6.496,1384,3.28,1405,4.988,1444,5.75,1551,4.249,1610,4.249,1813,3.28,2004,4.027,2113,3.28,2115,3.2,2286,3.2,2602,4.249,2646,3.126,2666,4.027,2747,4.546,2850,3.28,3023,4.027,3064,4.546,3124,4.546,3235,4.249,3305,3.577,3307,3.85,3322,4.996,3323,4.996,3324,4.996,3325,4.027,3326,4.996,3327,4.996,3328,4.546,3329,4.996]],["t/882",[5,1.37,10,1.684,12,1.816,42,1.17,52,2.711,65,2.475,115,2.768,132,4.534,133,4.534,145,2.2,146,2.658,175,1.286,177,1.974,183,2.591,204,2.711,205,2.658,215,2.559,222,3.834,258,2.435,327,1.041,343,1.258,346,2.23,359,2.365,402,1.626,404,4.153,405,4.25,473,5.422,501,1.669,503,2.361,532,4.621,567,2.83,621,2.896,660,3.846,663,2.658,693,3.694,785,2.711,787,2.805,788,2.517,793,2.768,851,2.475,934,1.781,948,3.049,951,2.83,1014,2.711,1021,2.561,1049,3.138,1103,3.049,1147,3.238,1166,2.768,1370,3.485,1403,2.711,1406,3.694,1439,4.115,1440,3.485,1454,3.352,1464,4.115,1518,4.115,1546,3.846,1691,3.846,1795,3.485,1813,2.969,1924,3.238,2113,6.056,2115,5.035,2286,2.896,2466,3.049,2500,3.238,2550,3.138,2646,2.83,2850,4.357,3122,3.645,3305,3.238,3307,3.485,3325,3.645,3328,4.115,3330,6.637,3331,4.522,3332,4.522,3333,4.115,3334,4.522,3335,4.522]],["t/884",[2,2.734,10,2.656,60,2.608,72,2.995,80,1.165,92,1.721,114,2.231,117,1.6,132,4.114,133,4.114,135,1.828,146,2.937,179,3.2,199,1.495,206,1.564,229,3.85,231,2.206,251,1.844,292,2.69,323,1.495,325,3.047,326,1.113,327,1.915,328,3.517,329,2.34,341,2.359,343,1.39,374,2.734,392,3.703,404,5.205,405,5.328,473,5.333,501,1.844,693,2.781,793,3.058,799,3.126,951,3.126,957,3.368,1073,3.2,1092,2.881,1121,3.466,1182,2.431,1191,4.683,1238,3.577,1293,3.85,1325,3.85,1395,3.85,1403,2.995,1405,2.995,1406,3.97,1440,3.85,1505,3.368,1581,3.2,1813,5.461,1988,3.703,2073,3.85,2115,4.568,2263,3.703,2286,3.2,2466,3.368,2510,4.249,2646,3.126,2681,4.249,2828,3.703,2850,4.683,2863,4.546,3297,4.546,3305,3.577,3325,4.027,3336,4.996,3337,4.996,3338,4.996,3339,4.996]],["t/886",[116,5.7,331,5.29,473,5.922,776,5.866,951,5.29,1166,5.175,1581,5.415,2286,5.415,2697,7.692,3302,7.692,3305,6.053,3340,10.075]],["t/889",[1,6.63,194,4.582,206,3.003,380,2.62,940,5.256,941,6.284,1265,6.655,1432,6.284,1766,6.63,1902,7.093,1941,6.284,2311,5.778,2785,6.63,3341,7.796,3342,7.796,3343,7.796,3344,7.796,3345,9.592,3346,7.796,3347,7.093,3348,7.796]],["t/891",[1,4.249,5,1.98,12,2.006,38,2.206,42,1.599,50,1.999,80,1.165,114,2.231,129,1.173,165,2.937,173,2.311,178,2.645,183,1.495,195,3.995,199,2.715,202,1.549,259,2.464,266,2.564,280,2.937,311,2.995,335,1.861,364,3.577,373,3.903,399,4.027,402,1.796,404,3.126,405,3.2,465,2.953,511,1.39,512,2.608,514,1.679,522,2.937,532,2.937,585,2.112,659,2.995,787,3.015,797,2.608,824,2.498,932,3.368,978,2.431,1171,3.85,1229,3.28,1403,4.988,1406,3.97,1458,7.126,1504,3.466,1941,4.027,1949,3.703,1967,3.368,2094,4.546,2149,8.734,2219,4.249,2396,4.027,2466,3.368,2470,4.027,2550,4.949,2583,4.027,2646,3.126,3266,4.546,3325,4.027]],["t/894",[2,2.389,10,1.626,42,0.769,50,1.223,80,1.018,129,1.518,149,1.259,175,1.838,178,1.388,181,2.943,182,3.028,183,1.934,184,3.452,185,2.155,187,3.823,189,5.105,190,3.259,266,1.569,267,1.906,323,1.306,343,1.215,401,2.152,407,2.795,430,3.375,465,1.807,500,2.617,501,2.386,572,2.265,583,1.995,594,3.125,609,3.028,614,4.141,621,2.795,629,2.429,634,3.364,639,3.712,641,6.095,646,2.731,651,3.712,652,6.508,663,2.565,670,3.52,745,3.125,841,2.731,843,3.518,852,3.712,853,3.235,854,3.028,855,3.028,856,3.364,940,4.359,941,3.518,946,3.235,947,3.518,948,2.943,953,3.235,955,3.028,958,2.313,971,5.74,973,2.865,981,2.429,997,5.192,1011,3.662,1472,3.364,1546,3.712,1547,3.712,1548,7.006,1549,4.629,1550,3.125,1551,3.712,1795,3.364,1985,3.028,2145,3.712,2393,3.518,3349,4.365,3350,4.365,3351,4.365,3352,6.465,3353,6.465]],["t/896",[13,2.194,31,2.178,42,1.048,50,1.666,139,3.309,149,1.715,165,4.732,188,2.75,189,3.564,202,2.125,210,3.72,211,2.411,270,2.819,294,2.436,323,1.779,341,1.966,359,2.119,379,2.048,380,1.998,382,2.998,387,3.151,388,4.406,393,2.436,511,1.654,538,2.513,569,3.201,577,2.567,594,4.256,597,3.941,598,3.476,600,4.792,603,2.513,638,3.14,639,6.846,641,5.763,657,3.367,737,3.494,740,2.932,785,4.826,787,2.513,821,3.103,824,2.972,975,4.256,976,4.256,995,3.564,1405,3.564,1534,4.256,1542,5.409,2551,4.582,3354,5.945]],["t/899",[1924,6.735,3355,9.407]],["t/901",[135,3.146,149,2.48,175,2.445,224,1.88,297,4.489,790,7.313,937,5.234,1073,5.508,1670,4.96,1924,6.156,2667,6.932]],["t/903",[908,5.887,1672,8.559]],["t/906",[7,3.767,10,2.817,20,3.477,22,4.377,92,2.606,127,6.097,160,3.767,224,1.903,284,2.923,297,2.834,329,1.781,362,2.345,371,3.767,402,1.952,408,2.792,450,3.191,485,4.94,494,3.767,510,3.255,538,2.295,626,4.764,728,4.184,776,3.767,788,3.022,908,3.397,912,6.882,916,3.255,932,3.66,1161,4.446,1167,3.397,1194,3.075,1220,3.255,1236,4.377,1266,2.834,1412,4.617,1455,3.397,1493,4.377,1647,4.184,1668,4.94,1669,4.94,1670,3.131,1676,3.887,1684,4.617,1814,4.617,1931,3.767,1985,3.767,2197,7.403,2250,3.887,2350,6.882,2662,4.617,3290,4.94,3333,4.94,3356,5.429,3357,5.429,3358,5.429,3359,5.429,3360,5.429,3361,5.429,3362,7.564,3363,5.429,3364,5.429,3365,7.564,3366,5.429,3367,5.429,3368,5.429,3369,5.429]],["t/909",[5,1.264,33,2.324,104,2.736,129,1.439,149,1.767,152,3.627,199,1.833,224,1.339,231,2.705,251,2.261,278,4.722,292,5.561,293,4.939,314,2.39,326,1.366,327,1.891,341,2.717,396,3.924,427,3.534,482,5.574,489,4.541,582,2.222,636,5.574,907,4.131,916,3.673,924,4.939,928,3.834,1025,3.47,1472,6.331,2177,4.722,2219,5.211,2448,4.939,2500,4.386,2967,5.211,3370,6.127,3371,6.127,3372,6.127,3373,6.127,3374,6.127,3375,8.215,3376,8.215,3377,6.127,3378,6.127,3379,6.127,3380,6.127,3381,6.127,3382,6.127,3383,6.127,3384,6.127]],["t/911",[5,1.634,113,4.264,223,2.662,224,1.731,231,3.496,305,5.67,307,4.748,312,4.408,313,5.072,324,5.87,400,5.495,795,4.134,796,5.929,797,4.134,798,4.956,799,4.956,1138,4.748,1214,5.67,1215,5.87,3385,7.92,3386,7.92]],["t/913",[33,3.102,42,1.741,224,1.788,230,4.625,259,4.033,292,5.317,300,4.903,322,5.496,425,3.385,495,4.717,738,5.238,788,4.552,800,6.303,801,5.369]],["t/915",[136,5.044,295,2.922,326,1.985,785,6.228,1140,6.863,1203,5.572,1530,8.102]],["t/917",[2,3.768,42,1.214,50,2.486,84,2.392,129,1.617,159,6.836,183,2.06,226,3.971,247,3.04,294,2.821,306,3.899,308,4.154,343,1.916,414,4.316,549,4.777,558,3.442,585,3.749,599,4.047,605,4.777,609,4.777,610,7.273,655,5.55,703,4.52,928,4.308,937,3.541,1498,5.55,1501,4.308,1645,4.929,1964,4.777,2290,5.55,2339,5.855,2342,6.264,2393,5.55,3219,6.264]],["t/919",[92,2.963,206,3.186,323,3.243,343,2.393,398,4.299,425,3.56,790,7.313,2042,6.932,2343,6.156]],["t/921",[531,4.201,605,6.527]],["t/925",[31,1.549,64,1.538,98,2.152,104,1.66,129,1.344,135,1.36,145,1.808,173,2.649,175,1.057,182,2.579,183,1.713,184,2.969,185,1.909,187,3.595,188,3.231,189,4.705,190,2.192,192,1.493,202,1.704,210,2.326,211,1.508,231,1.641,257,1.605,262,1.508,267,2.5,292,3.083,294,1.523,299,5.734,300,3.433,323,1.713,326,1.276,327,0.856,328,3.444,343,1.593,344,1.879,359,2.489,379,1.28,380,1.249,382,2.133,384,2.579,387,1.97,388,2.755,393,1.523,414,3.398,419,2.661,430,2.989,501,1.372,511,1.034,514,1.249,569,3.121,577,1.605,579,1.679,590,2.213,594,4.099,603,1.571,608,2.185,617,2.661,638,2.234,656,3.083,668,3.973,671,3.161,737,2.185,740,1.833,785,2.228,809,4.846,821,1.94,824,2.862,842,3.382,917,2.105,946,2.755,972,2.185,978,2.786,1011,3.956,1249,2.864,1265,2.579,1273,2.864,1501,2.326,1534,2.661,1535,2.996,1553,3.505,1560,3.161,1714,3.382,1751,4.244,2997,5.94,2998,3.382,2999,3.382,3000,4.87,3004,3.382,3309,5.21,3387,5.726,3388,3.717,3389,9.631,3390,3.717]],["t/928",[50,1.647,129,1.875,149,1.695,175,1.67,178,1.868,181,3.961,182,4.076,183,2.389,184,3.679,185,2.662,187,4.217,189,5.836,190,3.057,266,2.112,267,2.565,323,1.758,401,2.897,407,3.763,465,2.432,500,3.523,501,2.948,583,2.685,594,4.206,605,6.295,629,3.27,634,4.528,646,3.676,652,7.288,946,4.355,947,4.736,948,3.961,953,4.355,955,4.076,958,3.114,1011,4.523,1795,4.528,2393,4.736,2785,6.792,3347,5.346,3391,5.875]],["t/930",[166,3.126,190,2.618,202,2.245,223,2.298,247,3.019,326,1.524,343,1.903,379,2.356,382,3.289,393,2.802,569,3.89,577,2.953,585,2.89,587,4.1,604,5.068,605,4.744,740,3.372,785,5.295,787,3.732,916,4.1,1031,5.815,1266,4.61,1313,5.068,1458,4.744,1941,5.512,2343,4.895,2399,6.221,2400,5.815,3392,6.221,3393,6.838,3394,6.838,3395,6.838,3396,6.838]],["t/932",[10,2.734,12,2.09,21,1.793,24,2.758,25,3.185,33,1.974,117,1.167,149,1.501,165,4.315,178,1.654,199,1.557,202,1.595,321,3.001,325,3.136,326,1.16,343,1.448,344,1.707,350,1.938,382,1.938,514,1.749,520,2.351,529,2.896,572,2.572,579,2.351,583,3.889,585,3.103,587,3.12,588,3.857,589,3.508,597,3.17,598,2.247,600,4.195,607,2.176,628,4.01,630,3.001,662,3.333,703,3.416,715,4.734,719,4.734,787,3.596,804,2.896,824,4.619,1182,2.532,1197,2.601,1349,3.333,1446,4.734,1458,5.903,2139,4.425,2150,4.425,2166,4.734,2167,4.425,2168,4.734,2171,4.734,2181,4.425,2201,9.455,3392,4.734,3397,5.204,3398,5.204,3399,5.204,3400,5.204,3401,5.204,3402,5.204,3403,5.204,3404,7.342,3405,5.204]],["t/935",[3,4.313,5,1.356,7,4.558,13,3.176,14,4.558,15,4.429,16,4.429,17,4.429,35,5.295,42,1.158,123,5.062,131,5.648,132,3.789,135,3.147,142,5.977,143,5.295,147,5.587,149,1.895,178,2.088,413,3.284,429,3.239,494,4.558,507,3.72,632,3.938,659,5.158,673,4.558,771,5.062,787,2.776,788,3.656,804,3.656,990,4.558,1094,4.558,1166,4.021,1306,5.295,1425,5.295,1935,5.295,2200,5.295,2231,5.587,2533,5.587,3406,6.569,3407,6.569,3408,6.569,3409,6.569,3410,6.569]],["t/938",[132,5.84,133,5.84,135,3.119,215,2.775,404,5.335,405,5.461,957,5.748,1049,5.916,2466,5.748,2681,7.251,3023,6.873]],["t/940",[132,5.136,133,5.136,135,3.258,327,2.05,404,5.572,405,5.704,1049,6.179,1073,5.704]],["t/942",[21,3.241,135,3.441]],["t/944",[132,5.229,133,5.229,135,3.317,230,4.246,425,3.753,1049,6.291]],["t/946",[21,3.241,135,3.441]],["t/948",[21,3.241,135,3.441]],["t/950",[10,2.859,132,6.391,133,6.391,135,3.476,804,5.288,972,4.512,1033,2.966,1138,4.603,1194,6.107,1200,4.427,1932,6.984,3120,6.529,3285,6.984]],["t/952",[10,3.23,959,6.685,1096,5.695,1194,5.793,1493,6.992,1686,6.685,2239,7.892,2732,6.992,3120,7.377,3411,8.674]],["t/954",[13,2.97,21,2.772,64,4.048,97,5.425,99,5.154,129,1.889,131,5.283,132,4.641,133,4.641,135,3.854,323,2.407,580,3.768,581,4.2,632,4.824,1049,5.583,1264,4.926,3412,8.047]],["t/957",[5,1.753,47,4.775,92,2.219,114,2.877,129,1.513,131,5.576,152,2.844,215,3.288,221,2.945,224,1.408,230,4.731,262,2.613,294,2.64,300,5.093,335,2.399,373,3.525,422,4.434,423,3.525,503,4.96,514,2.165,566,2.877,608,3.787,622,4.343,656,3.469,673,4.47,787,2.723,1216,5.479,1257,3.944,1368,4.612,1420,4.306,1509,4.775,1511,4.343,1955,4.612,2184,5.479,2266,5.861,3413,6.442,3414,6.442,3415,6.442]],["t/959",[5,1.549,64,3.106,80,1.75,135,3.736,269,4.806,295,2.462,302,3.471,320,5.207,335,2.795,363,6.382,373,4.107,490,5.207,494,5.207,673,5.207,787,3.172,788,4.176,1420,3.804,1998,7.871,2244,6.382,2363,6.827,2965,6.827,3416,7.504,3417,7.504,3418,7.504,3419,7.504]],["t/961",[26,3.124,30,1.874,42,0.839,43,6.884,46,5.982,50,1.334,99,5.682,101,6.837,118,3.836,132,4.669,135,3.703,206,1.49,215,1.549,289,3.208,323,2.937,325,2.033,368,2.447,425,1.97,427,4.669,511,1.324,529,2.648,555,3.124,705,5.457,731,4.33,737,2.797,787,2.911,1021,3.901,1380,8.072,1457,6.352,1723,3.667,1935,6.525,1967,3.208,2143,5.857,2533,5.857,3122,3.836,3310,8.072,3420,4.33,3421,4.33,3422,8.095,3423,4.759,3424,4.33,3425,8.872,3426,4.759,3427,4.759,3428,4.759,3429,8.095,3430,8.095,3431,8.095,3432,4.759,3433,4.759,3434,4.759,3435,4.759]],["t/963",[5,1.609,33,2.957,42,1.374,46,5.256,65,4.266,75,7.392,84,2.708,98,2.93,101,7.392,160,5.409,375,6.008,527,5.581,1141,7.093,1452,7.093,1743,6.284,2308,6.284,3424,7.093,3436,6.63,3437,8.727,3438,6.63,3439,7.093]],["t/965",[14,3.788,36,4.4,45,4.643,46,5.885,65,2.987,75,6.728,84,3.033,90,6.12,101,5.851,117,1.703,132,6.195,133,5.035,135,1.997,136,3.092,146,3.209,160,5.268,214,3.908,250,4.207,306,4.3,413,2.729,417,4.207,511,2.113,607,2.283,661,3.342,696,4.967,771,4.207,787,3.988,1035,7.943,1457,3.908,1554,4.967,1743,4.4,2308,4.4,3268,4.4,3420,6.908,3436,4.643,3437,9.342,3438,4.643,3439,6.908,3440,7.592,3441,5.459,3442,7.592,3443,5.459,3444,5.459,3445,4.967]],["t/967",[21,3.154,43,7.785,46,7.706,64,2.994,101,5.574,114,3.23,117,2.053,132,6.088,396,4.633,1274,4.633,1723,5.574,2828,5.361,3421,6.581,3436,6.151,3438,6.151,3446,7.233,3447,7.233,3448,7.233,3449,7.233,3450,7.233,3451,7.233]],["t/969",[13,1.773,21,1.655,24,2.546,42,1.223,52,2.88,76,3.17,80,1.121,115,2.941,117,1.556,129,2.092,131,4.553,143,3.873,149,1.386,151,2.471,175,1.366,178,1.527,183,2.075,184,2.851,185,1.602,200,3.928,262,1.949,311,2.88,325,2.052,331,3.006,344,1.576,350,2.583,360,2.508,401,2.369,425,1.989,429,3.42,500,4.879,501,1.773,510,2.88,522,2.824,531,2.145,555,4.553,569,3.237,582,1.742,587,4.158,588,3.561,626,4.877,657,2.721,787,2.931,1021,3.928,1094,3.333,1096,3.154,1229,3.154,1406,4.529,1426,3.702,1427,6.032,1434,4.086,1435,7.579,1455,3.006,1595,4.086,1935,7.184,2325,3.702,2646,3.006,3318,4.371,3452,4.804,3453,6.31,3454,6.935,3455,4.804,3456,4.804,3457,6.935,3458,6.935,3459,4.804]],["t/971",[42,1.491,80,1.493,117,1.897,131,4.202,132,4.878,133,4.878,135,3.094,137,5.824,139,4.707,162,5.444,241,3.692,266,2.301,279,4.744,343,1.781,344,2.775,398,3.2,417,4.933,470,3.692,511,2.354,524,3.503,527,4.583,597,2.764,598,2.764,673,4.441,703,4.202,1003,3.838,1553,3.918,1791,6.055,1936,5.824,2261,4.933,2262,6.518,3033,5.824,3453,5.824,3460,8.458,3461,6.401,3462,6.401,3463,8.458,3464,6.401,3465,6.401,3466,6.401]],["t/973",[7,5.367,14,5.367,15,5.215,16,5.215,17,5.215,123,5.962,143,7.695,151,3.979,192,3.107,325,3.305,514,2.6,607,3.235,644,3.715,657,4.381,695,5.538,733,7.038,1162,4.547,2937,7.038,3129,7.038,3445,8.686,3467,7.736,3468,7.736,3469,7.736]],["t/976",[60,3.977,65,4.169,84,2.647,152,4.175,215,2.48,223,2.56,224,1.665,233,4.322,235,4.568,243,5.917,247,3.363,251,2.812,288,5.136,314,2.972,419,5.454,441,4.568,475,4.664,658,5.871,738,4.879,786,4.879,1161,4.478,1218,5.136,1673,6.931,2767,6.931]],["t/978",[21,2.864,159,6.407,222,3.306,223,3.352,224,1.817,251,3.069,330,5.458,335,3.096,408,4.276,495,4.795,738,5.325,786,5.325,1290,5.768,3075,7.564,3470,8.314]],["t/980",[31,1.59,53,3.163,64,2.432,95,2.383,129,1.875,169,2.859,183,1.758,190,2.249,202,2.211,215,2.599,224,1.284,252,2.594,253,3.861,326,1.309,327,1.839,329,2.976,337,3.27,342,1.882,346,3.938,354,4.528,359,2.094,360,3.067,379,2.024,380,2.684,382,2.974,393,2.407,394,2.685,402,2.112,514,1.975,515,4.049,516,2.624,543,2.937,566,2.624,569,3.608,572,2.058,573,2.897,574,2.897,575,3.215,576,3.163,577,2.537,578,3.27,579,2.654,580,2.751,1159,3.857,1160,4.445,1976,4.736]]],"invertedIndex":[["0",{"_index":31,"t":{"5":{"position":[[69,1]]},"57":{"position":[[1716,1]]},"60":{"position":[[366,1],[368,1],[511,1]]},"66":{"position":[[422,1],[424,1]]},"69":{"position":[[65,1],[67,1],[335,1],[337,1],[499,1]]},"78":{"position":[[124,1],[232,1],[354,1]]},"80":{"position":[[189,1],[191,1],[1158,1],[1160,1],[1768,1],[1770,1]]},"86":{"position":[[238,1],[240,1]]},"104":{"position":[[426,1],[428,1]]},"132":{"position":[[187,1],[189,1]]},"134":{"position":[[3553,1],[3555,1]]},"138":{"position":[[531,1],[533,1]]},"157":{"position":[[290,1]]},"159":{"position":[[532,1],[877,1]]},"169":{"position":[[138,1],[140,1]]},"171":{"position":[[140,1],[142,1]]},"173":{"position":[[137,1],[139,1]]},"175":{"position":[[114,1],[116,1]]},"184":{"position":[[1311,1],[1313,1]]},"188":{"position":[[341,1],[496,1],[498,1]]},"192":{"position":[[222,1],[377,1],[379,1]]},"194":{"position":[[181,1],[654,1],[656,1]]},"207":{"position":[[204,1],[431,1]]},"218":{"position":[[1311,1],[1313,1]]},"223":{"position":[[406,1],[803,1],[805,1]]},"225":{"position":[[310,1],[1139,1],[1141,1],[1693,1],[1695,1]]},"229":{"position":[[225,1],[395,1],[397,1]]},"233":{"position":[[184,1],[680,1],[682,1]]},"239":{"position":[[341,1]]},"272":{"position":[[1070,1]]},"284":{"position":[[600,1],[602,1]]},"286":{"position":[[525,1],[527,1]]},"292":{"position":[[100,1],[371,1],[415,1]]},"301":{"position":[[1437,1],[1480,1],[2643,1]]},"308":{"position":[[1218,1],[2122,1]]},"319":{"position":[[59,1],[61,1],[96,1],[98,1],[242,1],[244,1],[468,1],[470,1]]},"321":{"position":[[66,1],[110,1]]},"336":{"position":[[8,1],[158,1],[168,1]]},"340":{"position":[[111,1],[231,1],[241,1],[413,1]]},"347":{"position":[[1179,1],[1502,1],[1509,1],[2287,1]]},"361":{"position":[[1029,1],[1525,1],[1629,1],[1726,1],[1827,1],[2026,1],[2531,1]]},"365":{"position":[[111,1],[136,1],[636,1],[921,1],[1156,1],[1182,1],[1583,1],[2057,1],[2533,1],[2878,1],[3115,1],[3170,1]]},"393":{"position":[[93,1],[95,1]]},"404":{"position":[[37,1],[98,1],[163,1]]},"406":{"position":[[268,1]]},"411":{"position":[[104,1],[237,1],[265,1]]},"413":{"position":[[292,1],[359,1]]},"415":{"position":[[108,1],[234,1]]},"422":{"position":[[281,1]]},"436":{"position":[[994,1]]},"440":{"position":[[321,1]]},"444":{"position":[[271,1]]},"470":{"position":[[312,1],[598,1],[727,1]]},"489":{"position":[[835,1],[1000,1]]},"493":{"position":[[671,1]]},"495":{"position":[[384,1],[386,1],[790,1],[792,1]]},"498":{"position":[[49,1]]},"507":{"position":[[1148,1],[1386,1],[2123,1],[2135,1]]},"521":{"position":[[27,1]]},"523":{"position":[[218,1],[1260,1],[2571,1]]},"528":{"position":[[377,1],[379,1],[492,1],[494,1]]},"530":{"position":[[744,1],[746,1],[890,1],[892,1]]},"537":{"position":[[258,1],[260,1],[273,1],[275,1],[608,1],[610,1],[697,1],[699,1]]},"539":{"position":[[124,1],[126,1]]},"561":{"position":[[600,1],[602,1]]},"600":{"position":[[116,1]]},"610":{"position":[[160,1]]},"632":{"position":[[205,1],[348,1]]},"663":{"position":[[303,1]]},"672":{"position":[[342,1],[523,1],[737,1]]},"674":{"position":[[314,1],[609,1],[738,1]]},"702":{"position":[[1571,1],[1664,1],[2117,1],[2280,1]]},"707":{"position":[[40,1],[73,1]]},"727":{"position":[[1296,1]]},"736":{"position":[[132,1],[134,1]]},"745":{"position":[[281,1]]},"748":{"position":[[225,1],[260,1]]},"756":{"position":[[178,1],[295,1]]},"763":{"position":[[67,1],[69,1],[71,1]]},"765":{"position":[[73,1],[75,1],[77,1]]},"780":{"position":[[84,1]]},"783":{"position":[[105,1]]},"792":{"position":[[221,1]]},"816":{"position":[[288,1],[290,1]]},"820":{"position":[[71,1]]},"830":{"position":[[621,1]]},"832":{"position":[[1352,1],[1354,1]]},"857":{"position":[[118,1],[120,1]]},"859":{"position":[[849,1],[851,1]]},"872":{"position":[[680,1]]},"896":{"position":[[480,1],[482,1]]},"925":{"position":[[663,1],[665,1]]},"980":{"position":[[249,1]]}}}],["0x96",{"_index":2917,"t":{"702":{"position":[[1925,4]]}}}],["1",{"_index":511,"t":{"57":{"position":[[146,1],[232,1]]},"60":{"position":[[370,1],[509,1]]},"66":{"position":[[426,1]]},"69":{"position":[[69,1],[339,1],[505,1]]},"78":{"position":[[178,1],[286,1],[408,1]]},"80":{"position":[[193,1],[821,1],[1162,1],[1485,1],[1772,1],[2320,1]]},"86":{"position":[[242,1]]},"104":{"position":[[430,1]]},"120":{"position":[[345,1]]},"132":{"position":[[191,1]]},"134":{"position":[[3557,1]]},"138":{"position":[[535,1]]},"169":{"position":[[142,1]]},"171":{"position":[[144,1]]},"173":{"position":[[141,1]]},"175":{"position":[[118,1]]},"184":{"position":[[1315,1]]},"188":{"position":[[500,1]]},"192":{"position":[[381,1]]},"194":{"position":[[90,1],[658,1]]},"218":{"position":[[1315,1]]},"223":{"position":[[807,1]]},"225":{"position":[[58,1],[1143,1],[1697,1]]},"229":{"position":[[399,1]]},"233":{"position":[[90,1],[684,1]]},"235":{"position":[[301,1]]},"239":{"position":[[1,1]]},"272":{"position":[[138,1],[224,1]]},"284":{"position":[[604,1]]},"286":{"position":[[529,1]]},"292":{"position":[[373,1],[417,1]]},"301":{"position":[[108,1],[194,1],[1284,1],[1622,1],[1774,1]]},"308":{"position":[[140,1],[226,1],[1247,1]]},"319":{"position":[[63,1],[100,1],[246,1],[472,1]]},"321":{"position":[[68,1],[112,1]]},"336":{"position":[[10,1],[42,1],[160,1],[170,1]]},"340":{"position":[[113,1],[139,1],[233,1],[243,1],[313,1],[416,1]]},"347":{"position":[[142,1],[228,1]]},"361":{"position":[[846,1],[2357,1],[2477,1],[2689,1],[2733,1]]},"365":{"position":[[103,1],[128,1],[377,1],[403,1],[662,1],[895,1],[1821,1],[2245,1],[2299,1],[2588,1],[2823,1]]},"370":{"position":[[170,1],[426,1],[477,1]]},"376":{"position":[[125,1],[148,1]]},"393":{"position":[[97,1]]},"436":{"position":[[1186,1],[1289,1],[1543,1],[1546,1],[1661,1],[1665,1],[1789,1],[1794,1],[1915,1],[1926,1]]},"444":{"position":[[283,1]]},"447":{"position":[[162,1]]},"487":{"position":[[149,1]]},"489":{"position":[[840,1],[1024,1]]},"495":{"position":[[388,1],[794,1],[1135,1]]},"507":{"position":[[1788,1],[1872,1],[1935,1]]},"521":{"position":[[131,1]]},"523":{"position":[[1488,1],[1615,1],[1917,1],[1920,1],[2059,1],[2063,1],[2211,1],[2216,1],[2361,1],[2372,1]]},"528":{"position":[[381,1],[496,1]]},"530":{"position":[[748,1],[894,1]]},"537":{"position":[[262,1],[277,1],[612,1],[701,1]]},"539":{"position":[[128,1]]},"561":{"position":[[604,1]]},"595":{"position":[[113,1]]},"615":{"position":[[49,1]]},"630":{"position":[[199,1],[204,1],[434,1],[440,1]]},"632":{"position":[[167,1],[172,1],[208,1]]},"689":{"position":[[238,1]]},"697":{"position":[[65,1],[67,1],[81,1]]},"702":{"position":[[1092,1],[1371,1],[2770,1]]},"707":{"position":[[54,1]]},"716":{"position":[[85,1],[119,1]]},"718":{"position":[[227,1]]},"727":{"position":[[1592,1],[1859,1],[1864,1]]},"736":{"position":[[136,1]]},"748":{"position":[[289,1],[376,1],[425,1]]},"752":{"position":[[16,1]]},"756":{"position":[[181,1],[298,1]]},"778":{"position":[[55,1]]},"816":{"position":[[292,1]]},"820":{"position":[[17,1],[69,1],[196,1],[218,1],[286,1]]},"830":{"position":[[623,1]]},"832":{"position":[[1356,1],[1667,1],[1672,1],[2143,1]]},"857":{"position":[[122,1]]},"859":{"position":[[853,1]]},"866":{"position":[[115,1],[149,1]]},"870":{"position":[[10,1]]},"872":{"position":[[10,1],[12,1],[1035,1]]},"878":{"position":[[12,1]]},"891":{"position":[[0,1]]},"896":{"position":[[484,1]]},"925":{"position":[[667,1]]},"961":{"position":[[237,1]]},"965":{"position":[[169,1],[171,1]]},"971":{"position":[[26,1],[59,1]]}}}],["10",{"_index":211,"t":{"25":{"position":[[428,2],[499,2],[517,2]]},"60":{"position":[[172,2],[587,2]]},"66":{"position":[[228,2]]},"69":{"position":[[92,2],[516,2],[650,2]]},"75":{"position":[[148,2]]},"80":{"position":[[799,2],[1463,2],[2298,2]]},"102":{"position":[[350,2]]},"184":{"position":[[193,2],[1152,2],[1931,2]]},"218":{"position":[[193,2],[1152,2],[1931,2]]},"336":{"position":[[23,2]]},"340":{"position":[[338,2],[821,2],[824,2],[864,2],[872,2],[935,2],[939,2],[950,2]]},"370":{"position":[[164,2]]},"376":{"position":[[553,2],[881,2]]},"422":{"position":[[466,2],[489,2]]},"436":{"position":[[938,2],[1037,2]]},"509":{"position":[[51,2]]},"523":{"position":[[1186,2],[1315,2]]},"528":{"position":[[281,2]]},"530":{"position":[[648,2]]},"552":{"position":[[62,2],[868,2],[1589,2],[1632,2]]},"556":{"position":[[865,2],[1667,2],[2607,2],[3251,2]]},"600":{"position":[[79,2]]},"655":{"position":[[305,2]]},"659":{"position":[[116,2],[121,2],[225,2]]},"661":{"position":[[429,2]]},"668":{"position":[[182,2]]},"681":{"position":[[223,2],[509,2]]},"686":{"position":[[328,2]]},"697":{"position":[[83,2]]},"736":{"position":[[585,2],[626,2]]},"738":{"position":[[51,2]]},"748":{"position":[[236,2]]},"750":{"position":[[349,2]]},"756":{"position":[[161,2]]},"758":{"position":[[47,2]]},"763":{"position":[[56,2],[73,2]]},"765":{"position":[[59,2],[70,2]]},"767":{"position":[[168,2]]},"780":{"position":[[317,2]]},"872":{"position":[[363,2]]},"876":{"position":[[12,2]]},"896":{"position":[[507,2]]},"925":{"position":[[175,2]]}}}],["100",{"_index":686,"t":{"80":{"position":[[817,3],[1481,3],[2316,3]]},"120":{"position":[[1696,3],[1814,3],[1959,3]]},"334":{"position":[[38,3]]},"370":{"position":[[38,3],[59,3],[118,3],[322,3],[326,3],[356,3],[383,3],[420,3],[438,3]]},"376":{"position":[[1576,3]]},"436":{"position":[[976,3]]},"465":{"position":[[250,3]]},"523":{"position":[[1236,3],[2696,3]]},"663":{"position":[[336,3]]},"864":{"position":[[4,3]]}}}],["1000",{"_index":755,"t":{"102":{"position":[[345,4]]},"340":{"position":[[943,4],[968,4]]},"493":{"position":[[191,4]]},"528":{"position":[[900,4],[1598,4]]},"539":{"position":[[245,4]]},"561":{"position":[[206,4]]},"595":{"position":[[84,4]]},"597":{"position":[[149,4]]},"602":{"position":[[89,4]]},"659":{"position":[[109,4]]},"681":{"position":[[216,4]]},"686":{"position":[[321,4]]},"727":{"position":[[766,4],[1595,4]]},"832":{"position":[[2146,4]]}}}],["10000",{"_index":1272,"t":{"184":{"position":[[583,5]]},"218":{"position":[[583,5]]},"434":{"position":[[123,5]]},"628":{"position":[[78,5]]}}}],["1000m",{"_index":444,"t":{"50":{"position":[[26,6]]}}}],["1000nt",{"_index":1873,"t":{"370":{"position":[[288,6]]}}}],["100mb",{"_index":2251,"t":{"465":{"position":[[16,5],[263,5]]},"874":{"position":[[328,5]]}}}],["1024",{"_index":1106,"t":{"153":{"position":[[163,4],[168,4],[267,4],[272,4]]},"157":{"position":[[266,4]]},"184":{"position":[[43,4],[183,4],[188,4]]},"218":{"position":[[43,4],[183,4],[188,4]]},"340":{"position":[[331,4],[358,4]]},"361":{"position":[[905,4]]},"365":{"position":[[1880,4]]},"411":{"position":[[132,4],[139,4]]},"413":{"position":[[161,4]]},"436":{"position":[[1063,4],[1405,4],[1440,4],[1475,4]]},"465":{"position":[[240,4],[245,4]]},"523":{"position":[[1347,4],[1755,4],[1796,4],[1837,4]]},"610":{"position":[[48,4]]},"668":{"position":[[168,4],[175,4]]},"672":{"position":[[359,4],[366,4],[530,4]]},"674":{"position":[[626,4],[633,4],[745,4]]},"689":{"position":[[22,4],[27,4]]},"727":{"position":[[438,4],[557,4],[564,4],[1183,4],[1190,4],[1433,4],[1479,4],[1486,4]]},"736":{"position":[[247,4]]},"750":{"position":[[335,4],[342,4]]}}}],["1024102410",{"_index":3037,"t":{"750":{"position":[[64,10]]}}}],["1024byte",{"_index":2979,"t":{"727":{"position":[[397,8]]}}}],["10gb",{"_index":2733,"t":{"628":{"position":[[63,4]]}}}],["10k",{"_index":1231,"t":{"184":{"position":[[67,3]]},"218":{"position":[[67,3]]}}}],["10mb",{"_index":2461,"t":{"526":{"position":[[251,4]]},"666":{"position":[[51,4]]}}}],["10w",{"_index":3117,"t":{"792":{"position":[[213,3]]},"864":{"position":[[12,3]]}}}],["11",{"_index":2864,"t":{"697":{"position":[[36,2],[95,2]]}}}],["12",{"_index":1518,"t":{"272":{"position":[[353,2],[357,2],[496,2],[500,2],[970,2],[974,2],[990,2],[994,2]]},"882":{"position":[[12,2]]}}}],["123",{"_index":967,"t":{"127":{"position":[[352,3],[628,3]]},"132":{"position":[[428,3]]},"134":{"position":[[3641,3]]},"455":{"position":[[196,3]]},"641":{"position":[[409,3]]},"643":{"position":[[293,3]]},"774":{"position":[[340,3]]}}}],["12345678",{"_index":1737,"t":{"350":{"position":[[79,8],[159,8]]}}}],["125598921",{"_index":2338,"t":{"495":{"position":[[93,9]]}}}],["127",{"_index":603,"t":{"60":{"position":[[362,3]]},"66":{"position":[[418,3]]},"69":{"position":[[61,3],[331,3]]},"80":{"position":[[185,3],[1154,3],[1764,3]]},"86":{"position":[[234,3]]},"104":{"position":[[422,3]]},"132":{"position":[[183,3]]},"134":{"position":[[3549,3]]},"138":{"position":[[527,3]]},"169":{"position":[[134,3]]},"171":{"position":[[136,3]]},"173":{"position":[[133,3]]},"175":{"position":[[110,3]]},"184":{"position":[[1307,3]]},"188":{"position":[[492,3]]},"192":{"position":[[373,3]]},"194":{"position":[[650,3]]},"218":{"position":[[1307,3]]},"223":{"position":[[799,3]]},"225":{"position":[[1135,3],[1689,3]]},"229":{"position":[[391,3]]},"233":{"position":[[676,3]]},"284":{"position":[[596,3]]},"286":{"position":[[521,3]]},"319":{"position":[[55,3],[92,3],[238,3],[464,3]]},"393":{"position":[[89,3]]},"495":{"position":[[380,3],[786,3]]},"528":{"position":[[373,3],[488,3]]},"530":{"position":[[740,3],[886,3]]},"537":{"position":[[254,3],[269,3],[604,3],[693,3]]},"539":{"position":[[120,3]]},"561":{"position":[[596,3]]},"736":{"position":[[128,3]]},"816":{"position":[[284,3]]},"832":{"position":[[1348,3]]},"857":{"position":[[114,3]]},"859":{"position":[[845,3]]},"896":{"position":[[476,3]]},"925":{"position":[[659,3]]}}}],["128",{"_index":1881,"t":{"370":{"position":[[339,3]]}}}],["13",{"_index":2865,"t":{"697":{"position":[[98,2]]},"870":{"position":[[12,2]]}}}],["15",{"_index":876,"t":{"120":{"position":[[1578,2]]}}}],["150",{"_index":2922,"t":{"702":{"position":[[2776,3]]}}}],["16",{"_index":2697,"t":{"606":{"position":[[2,2],[106,2]]},"886":{"position":[[12,2]]}}}],["17",{"_index":2886,"t":{"702":{"position":[[977,2],[2337,2]]},"864":{"position":[[22,3]]}}}],["18",{"_index":2069,"t":{"436":{"position":[[744,2]]}}}],["188",{"_index":1878,"t":{"370":{"position":[[312,3]]}}}],["1h",{"_index":138,"t":{"18":{"position":[[3,2]]}}}],["1mb",{"_index":1238,"t":{"184":{"position":[[129,3]]},"218":{"position":[[129,3]]},"365":{"position":[[1379,3],[1408,3]]},"526":{"position":[[239,3],[275,3]]},"689":{"position":[[229,3]]},"872":{"position":[[347,3]]},"884":{"position":[[80,3]]}}}],["1w",{"_index":2437,"t":{"523":{"position":[[342,2]]}}}],["2",{"_index":30,"t":{"5":{"position":[[67,1]]},"42":{"position":[[16,1]]},"44":{"position":[[11,1]]},"78":{"position":[[122,1],[230,1],[352,1]]},"120":{"position":[[362,1]]},"142":{"position":[[506,1],[508,1]]},"194":{"position":[[533,1]]},"212":{"position":[[63,1]]},"225":{"position":[[370,1]]},"231":{"position":[[4,1]]},"233":{"position":[[539,1]]},"235":{"position":[[865,1]]},"239":{"position":[[184,1]]},"268":{"position":[[124,1]]},"292":{"position":[[375,1],[419,1]]},"301":{"position":[[1297,1],[1440,1],[1485,1],[1633,1],[1811,1]]},"308":{"position":[[1187,1],[1221,1],[1275,1]]},"321":{"position":[[70,1],[114,1]]},"336":{"position":[[12,1],[162,1],[172,1]]},"340":{"position":[[115,1],[235,1],[245,1],[419,1]]},"370":{"position":[[172,1]]},"376":{"position":[[141,1],[563,1]]},"404":{"position":[[57,1],[165,1]]},"436":{"position":[[1208,1],[1313,1],[1567,1],[1570,1],[1687,1],[1691,1],[1817,1],[1822,1],[1948,1],[1959,1]]},"487":{"position":[[137,1]]},"489":{"position":[[876,1]]},"495":{"position":[[1196,1]]},"498":{"position":[[47,1]]},"507":{"position":[[1875,1],[1979,1]]},"523":{"position":[[1516,1],[1645,1],[1947,1],[1950,1],[2091,1],[2095,1],[2245,1],[2250,1],[2400,1],[2411,1]]},"632":{"position":[[211,1]]},"663":{"position":[[5,1]]},"697":{"position":[[61,1],[63,1]]},"702":{"position":[[1179,1],[1373,1],[2147,1],[2199,1],[2926,1]]},"716":{"position":[[87,1],[121,1]]},"727":{"position":[[1883,1],[1888,1]]},"748":{"position":[[211,1],[325,1],[380,1],[437,1],[471,1]]},"752":{"position":[[28,1]]},"756":{"position":[[184,1],[301,1]]},"780":{"position":[[377,1],[440,1],[461,1],[561,1]]},"783":{"position":[[54,1]]},"820":{"position":[[67,1],[168,1],[238,1]]},"832":{"position":[[1691,1],[1696,1]]},"868":{"position":[[10,1],[12,1]]},"872":{"position":[[1081,1]]},"961":{"position":[[244,1]]}}}],["20",{"_index":210,"t":{"25":{"position":[[424,2],[495,2]]},"60":{"position":[[176,2],[633,2]]},"66":{"position":[[232,2]]},"69":{"position":[[97,2],[520,2],[658,2]]},"75":{"position":[[156,2]]},"370":{"position":[[137,2],[167,2],[179,2],[226,2],[248,2],[251,2],[303,2],[393,2]]},"552":{"position":[[767,2],[1020,2]]},"556":{"position":[[1819,2],[2752,2],[3396,2]]},"736":{"position":[[588,2],[629,2]]},"738":{"position":[[54,2]]},"896":{"position":[[512,2]]},"925":{"position":[[178,2]]}}}],["200",{"_index":1832,"t":{"370":{"position":[[11,3],[77,3],[81,3],[155,3],[428,3]]},"689":{"position":[[155,3]]}}}],["20000",{"_index":2734,"t":{"628":{"position":[[84,5]]}}}],["2000m",{"_index":1176,"t":{"164":{"position":[[117,6]]},"250":{"position":[[117,6]]}}}],["200w",{"_index":1387,"t":{"212":{"position":[[43,4]]}}}],["2011",{"_index":3372,"t":{"909":{"position":[[46,4]]}}}],["2022",{"_index":3305,"t":{"874":{"position":[[5,4]]},"876":{"position":[[5,4]]},"878":{"position":[[5,4]]},"880":{"position":[[5,4]]},"882":{"position":[[5,4]]},"884":{"position":[[5,4]]},"886":{"position":[[5,4]]}}}],["2023",{"_index":3268,"t":{"868":{"position":[[5,4]]},"870":{"position":[[5,4]]},"872":{"position":[[5,4]]},"965":{"position":[[164,4]]}}}],["21",{"_index":3306,"t":{"874":{"position":[[12,2]]}}}],["2147483647",{"_index":3036,"t":{"748":{"position":[[407,10]]}}}],["224",{"_index":3231,"t":{"843":{"position":[[386,3]]},"845":{"position":[[241,3]]}}}],["23",{"_index":2686,"t":{"600":{"position":[[22,2]]}}}],["234762506",{"_index":9,"t":{"3":{"position":[[23,9]]}}}],["25",{"_index":874,"t":{"120":{"position":[[1570,2]]},"880":{"position":[[12,2]]}}}],["255",{"_index":1769,"t":{"361":{"position":[[777,3]]},"365":{"position":[[1354,3],[1752,3]]},"404":{"position":[[39,3]]},"702":{"position":[[1476,3]]},"748":{"position":[[397,3]]},"851":{"position":[[272,3],[276,3],[280,3],[284,3]]}}}],["28",{"_index":3336,"t":{"884":{"position":[[12,2]]}}}],["298",{"_index":3433,"t":{"961":{"position":[[283,3]]}}}],["2g",{"_index":485,"t":{"53":{"position":[[41,2]]},"906":{"position":[[110,2]]}}}],["2gb",{"_index":3168,"t":{"822":{"position":[[35,3]]}}}],["2mb",{"_index":2464,"t":{"526":{"position":[[294,3]]}}}],["3",{"_index":368,"t":{"44":{"position":[[13,1]]},"164":{"position":[[126,1]]},"225":{"position":[[827,1]]},"250":{"position":[[126,1]]},"292":{"position":[[377,1],[421,1]]},"301":{"position":[[1115,1],[1315,1],[1355,1]]},"304":{"position":[[53,1]]},"308":{"position":[[1169,1],[1613,1]]},"321":{"position":[[72,1],[116,1]]},"336":{"position":[[14,1],[164,1]]},"340":{"position":[[117,1],[237,1],[422,1]]},"436":{"position":[[1230,1],[1337,1],[1591,1],[1594,1],[1713,1],[1717,1],[1845,1],[1850,1],[1981,1],[1992,1]]},"489":{"position":[[159,1],[763,1]]},"507":{"position":[[1842,1],[1878,1]]},"523":{"position":[[1544,1],[1675,1],[1977,1],[1980,1],[2123,1],[2127,1],[2279,1],[2284,1],[2439,1],[2450,1]]},"632":{"position":[[214,1]]},"702":{"position":[[944,1],[2285,1],[2889,1]]},"716":{"position":[[89,1],[123,1]]},"756":{"position":[[187,1],[304,1]]},"792":{"position":[[236,1]]},"820":{"position":[[65,1]]},"872":{"position":[[428,1],[1112,1]]},"961":{"position":[[251,1]]}}}],["30",{"_index":214,"t":{"25":{"position":[[446,2]]},"184":{"position":[[557,2]]},"218":{"position":[[557,2]]},"370":{"position":[[201,2],[374,2]]},"436":{"position":[[2065,2]]},"702":{"position":[[263,2],[2041,2]]},"965":{"position":[[92,2]]}}}],["3000m",{"_index":1169,"t":{"164":{"position":[[34,6]]},"250":{"position":[[34,6]]}}}],["300m",{"_index":2848,"t":{"689":{"position":[[159,5]]}}}],["30px",{"_index":882,"t":{"120":{"position":[[1666,4],[1803,4],[1843,4],[1947,4]]}}}],["31",{"_index":1974,"t":{"404":{"position":[[167,2]]}}}],["33",{"_index":1861,"t":{"370":{"position":[[223,2]]}}}],["3d",{"_index":3314,"t":{"876":{"position":[[40,2]]}}}],["4",{"_index":1417,"t":{"225":{"position":[[1347,1]]},"292":{"position":[[379,1],[423,1]]},"321":{"position":[[74,1],[118,1]]},"336":{"position":[[16,1],[166,1]]},"340":{"position":[[119,1],[239,1],[425,1]]},"404":{"position":[[123,1]]},"436":{"position":[[2043,1]]},"470":{"position":[[238,1],[338,1],[342,1],[462,1],[493,1]]},"509":{"position":[[67,1]]},"608":{"position":[[80,1]]},"632":{"position":[[217,1]]},"684":{"position":[[311,1],[609,1]]},"686":{"position":[[308,1]]},"689":{"position":[[96,1]]},"748":{"position":[[384,1],[452,1]]},"756":{"position":[[347,1]]},"820":{"position":[[63,1]]},"822":{"position":[[33,1]]}}}],["40",{"_index":2430,"t":{"523":{"position":[[184,2]]}}}],["400",{"_index":1843,"t":{"370":{"position":[[114,3]]}}}],["400w",{"_index":3146,"t":{"820":{"position":[[22,4]]}}}],["403",{"_index":2254,"t":{"465":{"position":[[310,3]]}}}],["40374647",{"_index":2335,"t":{"495":{"position":[[68,8]]}}}],["404",{"_index":827,"t":{"120":{"position":[[356,3]]}}}],["5",{"_index":1064,"t":{"142":{"position":[[504,1]]},"272":{"position":[[366,1],[947,1],[963,1]]},"292":{"position":[[381,1],[407,1],[435,1]]},"321":{"position":[[76,1],[102,1],[130,1]]},"336":{"position":[[144,1]]},"340":{"position":[[639,1]]},"370":{"position":[[69,1],[479,1]]},"493":{"position":[[198,1]]},"528":{"position":[[267,1]]},"530":{"position":[[634,1]]},"595":{"position":[[75,1]]},"632":{"position":[[281,1],[320,1],[374,1],[483,1],[522,1]]},"727":{"position":[[466,1],[514,1],[571,1],[1493,1]]},"756":{"position":[[350,1]]},"820":{"position":[[61,1]]},"843":{"position":[[390,1]]},"845":{"position":[[245,1]]},"872":{"position":[[430,1]]}}}],["50",{"_index":870,"t":{"120":{"position":[[1548,2]]},"370":{"position":[[51,2],[99,2],[107,2],[237,2],[240,2],[263,2],[272,2],[401,2],[466,2]]},"727":{"position":[[1197,2]]}}}],["5000",{"_index":1208,"t":{"175":{"position":[[120,4]]},"581":{"position":[[120,4],[264,4]]}}}],["505554090",{"_index":123,"t":{"12":{"position":[[156,9]]},"94":{"position":[[36,9]]},"263":{"position":[[52,9]]},"935":{"position":[[156,9]]},"973":{"position":[[29,9]]}}}],["50m",{"_index":2847,"t":{"689":{"position":[[136,4]]}}}],["512kb",{"_index":1316,"t":{"184":{"position":[[1087,5],[1866,5]]},"218":{"position":[[1087,5],[1866,5]]}}}],["5aa5",{"_index":2883,"t":{"702":{"position":[[760,4]]}}}],["5gb",{"_index":1392,"t":{"212":{"position":[[65,3]]}}}],["5mb",{"_index":2981,"t":{"727":{"position":[[472,3]]}}}],["6",{"_index":1424,"t":{"231":{"position":[[2,1]]},"292":{"position":[[383,1],[437,1]]},"321":{"position":[[78,1],[132,1]]},"370":{"position":[[365,1],[367,1],[454,1],[456,1]]},"689":{"position":[[98,1]]},"702":{"position":[[2289,1]]},"756":{"position":[[353,1]]},"820":{"position":[[59,1]]},"843":{"position":[[392,1]]},"845":{"position":[[247,1]]}}}],["60",{"_index":2614,"t":{"561":{"position":[[213,2],[227,2]]},"832":{"position":[[2003,2]]}}}],["60px",{"_index":894,"t":{"120":{"position":[[1988,4]]}}}],["64",{"_index":1228,"t":{"184":{"position":[[48,2]]},"218":{"position":[[48,2]]},"361":{"position":[[900,2]]},"365":{"position":[[1875,2]]},"436":{"position":[[1070,2]]},"523":{"position":[[1354,2]]},"727":{"position":[[1440,2]]}}}],["6455",{"_index":3378,"t":{"909":{"position":[[64,4]]}}}],["64k",{"_index":1235,"t":{"184":{"position":[[101,3]]},"218":{"position":[[101,3]]},"361":{"position":[[796,3]]},"365":{"position":[[1771,3]]},"814":{"position":[[21,3]]}}}],["65535",{"_index":1973,"t":{"404":{"position":[[100,5]]},"487":{"position":[[164,5]]},"748":{"position":[[239,5],[401,5]]}}}],["66",{"_index":1834,"t":{"370":{"position":[[26,2],[191,2],[409,2]]}}}],["666",{"_index":1846,"t":{"370":{"position":[[128,3]]}}}],["7",{"_index":1581,"t":{"292":{"position":[[83,1],[385,1],[439,1]]},"321":{"position":[[80,1],[134,1]]},"436":{"position":[[2021,1]]},"663":{"position":[[3,1]]},"697":{"position":[[34,1]]},"756":{"position":[[356,1]]},"820":{"position":[[57,1]]},"843":{"position":[[394,1]]},"845":{"position":[[249,1]]},"884":{"position":[[10,1]]},"886":{"position":[[10,1]]}}}],["7219",{"_index":742,"t":{"102":{"position":[[134,4]]}}}],["7705",{"_index":676,"t":{"80":{"position":[[195,4]]},"514":{"position":[[566,4]]}}}],["7706",{"_index":604,"t":{"60":{"position":[[372,4]]},"66":{"position":[[428,4]]},"80":{"position":[[1164,4],[1774,4]]},"86":{"position":[[244,4]]},"516":{"position":[[337,4]]},"930":{"position":[[213,4]]}}}],["7788",{"_index":2518,"t":{"537":{"position":[[165,4],[245,4]]},"845":{"position":[[107,4]]},"851":{"position":[[138,4]]}}}],["7789",{"_index":638,"t":{"69":{"position":[[71,4],[341,4]]},"120":{"position":[[213,4]]},"129":{"position":[[182,4]]},"132":{"position":[[193,4]]},"134":{"position":[[3559,4]]},"138":{"position":[[537,4]]},"169":{"position":[[144,4]]},"171":{"position":[[146,4]]},"173":{"position":[[143,4]]},"184":{"position":[[1317,4]]},"188":{"position":[[502,4]]},"192":{"position":[[383,4]]},"194":{"position":[[660,4]]},"207":{"position":[[296,4]]},"218":{"position":[[1317,4]]},"223":{"position":[[809,4]]},"225":{"position":[[1145,4],[1699,4]]},"229":{"position":[[401,4]]},"233":{"position":[[686,4]]},"235":{"position":[[1035,4]]},"255":{"position":[[188,4]]},"257":{"position":[[179,4]]},"259":{"position":[[184,4]]},"284":{"position":[[228,4],[606,4]]},"286":{"position":[[254,4],[531,4]]},"288":{"position":[[233,4]]},"319":{"position":[[65,4],[102,4],[248,4]]},"391":{"position":[[237,4]]},"393":{"position":[[99,4]]},"458":{"position":[[211,4]]},"495":{"position":[[390,4],[796,4]]},"528":{"position":[[383,4],[498,4]]},"530":{"position":[[750,4],[896,4]]},"537":{"position":[[264,4],[614,4]]},"539":{"position":[[130,4]]},"561":{"position":[[606,4]]},"736":{"position":[[138,4]]},"816":{"position":[[294,4]]},"832":{"position":[[92,4],[1358,4]]},"843":{"position":[[228,4]]},"845":{"position":[[254,4]]},"849":{"position":[[246,4]]},"851":{"position":[[291,4]]},"857":{"position":[[124,4]]},"859":{"position":[[855,4]]},"896":{"position":[[136,4],[486,4]]},"925":{"position":[[359,4],[669,4]]}}}],["7790",{"_index":578,"t":{"57":{"position":[[1840,4]]},"223":{"position":[[828,4]]},"225":{"position":[[1164,4],[1718,4]]},"229":{"position":[[420,4]]},"233":{"position":[[705,4]]},"272":{"position":[[1638,4]]},"301":{"position":[[2767,4]]},"308":{"position":[[2246,4]]},"347":{"position":[[2411,4]]},"406":{"position":[[378,4]]},"422":{"position":[[391,4]]},"495":{"position":[[409,4]]},"537":{"position":[[279,4],[703,4]]},"561":{"position":[[625,4]]},"736":{"position":[[157,4]]},"745":{"position":[[391,4]]},"859":{"position":[[874,4]]},"980":{"position":[[359,4]]}}}],["7794",{"_index":1206,"t":{"173":{"position":[[109,4]]}}}],["8",{"_index":567,"t":{"57":{"position":[[1258,1]]},"120":{"position":[[1351,1]]},"212":{"position":[[48,1]]},"268":{"position":[[122,1]]},"292":{"position":[[98,1],[387,1],[441,1]]},"321":{"position":[[82,1],[136,1]]},"336":{"position":[[150,1]]},"340":{"position":[[223,1]]},"350":{"position":[[100,1]]},"820":{"position":[[102,1]]},"880":{"position":[[10,1]]},"882":{"position":[[10,1]]}}}],["80",{"_index":1332,"t":{"184":{"position":[[1382,2]]},"218":{"position":[[1382,2]]},"806":{"position":[[475,2]]}}}],["800mb",{"_index":3169,"t":{"822":{"position":[[46,5]]}}}],["85",{"_index":872,"t":{"120":{"position":[[1560,2]]}}}],["88",{"_index":1849,"t":{"370":{"position":[[147,2]]}}}],["8848",{"_index":3402,"t":{"932":{"position":[[324,4]]}}}],["8s",{"_index":3118,"t":{"792":{"position":[[223,2]]}}}],["9",{"_index":1586,"t":{"292":{"position":[[389,1],[443,1]]},"321":{"position":[[84,1],[138,1]]},"370":{"position":[[211,1]]},"666":{"position":[[79,1]]},"748":{"position":[[227,1]]},"874":{"position":[[10,1]]},"876":{"position":[[10,1]]},"878":{"position":[[10,1]]}}}],["98",{"_index":1882,"t":{"370":{"position":[[343,2]]}}}],["99",{"_index":134,"t":{"16":{"position":[[36,2]]},"55":{"position":[[6,2]]},"306":{"position":[[6,2]]},"370":{"position":[[213,2]]},"778":{"position":[[194,2]]}}}],["998",{"_index":3435,"t":{"961":{"position":[[292,3]]}}}],["9mb",{"_index":2794,"t":{"666":{"position":[[81,3]]}}}],["9s",{"_index":3119,"t":{"792":{"position":[[238,2]]}}}],["_",{"_index":2495,"t":{"528":{"position":[[1046,1],[1744,1]]}}}],["__",{"_index":1662,"t":{"319":{"position":[[25,2],[30,2]]}}}],["ab",{"_index":3349,"t":{"894":{"position":[[157,2]]}}}],["abc",{"_index":968,"t":{"127":{"position":[[369,3],[645,3]]},"132":{"position":[[434,3]]},"134":{"position":[[3647,3]]},"455":{"position":[[217,3]]},"641":{"position":[[426,3]]},"643":{"position":[[310,3]]}}}],["absolut",{"_index":878,"t":{"120":{"position":[[1592,8]]}}}],["accesstyp",{"_index":1944,"t":{"391":{"position":[[354,10],[373,10],[394,10]]}}}],["account",{"_index":965,"t":{"127":{"position":[[311,7],[342,7],[587,7],[618,7]]},"134":{"position":[[506,7],[853,7],[1351,7],[1627,7],[1849,7],[2125,7],[2580,7],[2823,7],[3082,7],[3325,7]]},"455":{"position":[[152,7],[184,7],[315,7],[824,7]]},"641":{"position":[[277,7],[399,7]]},"643":{"position":[[155,7],[283,7]]},"686":{"position":[[376,7],[387,7]]}}}],["action",{"_index":1547,"t":{"286":{"position":[[700,6]]},"602":{"position":[[20,6]]},"894":{"position":[[150,6]]}}}],["adapt",{"_index":439,"t":{"48":{"position":[[277,7],[304,7]]},"470":{"position":[[26,7],[151,7],[373,7],[574,7],[730,7]]}}}],["adapterconsoleapp",{"_index":2868,"t":{"702":{"position":[[61,17]]}}}],["adapterfilt",{"_index":3242,"t":{"857":{"position":[[301,13],[317,13]]},"859":{"position":[[195,13],[211,13]]}}}],["add",{"_index":188,"t":{"25":{"position":[[107,3],[388,3],[418,3],[449,3]]},"80":{"position":[[771,3],[790,3],[808,3],[1435,3],[1454,3],[1472,3],[2270,3],[2289,3],[2307,3]]},"91":{"position":[[195,3],[257,3],[330,3]]},"120":{"position":[[301,3]]},"194":{"position":[[759,3]]},"223":{"position":[[975,3]]},"225":{"position":[[1311,3],[1865,3]]},"233":{"position":[[805,3]]},"235":{"position":[[1118,3]]},"284":{"position":[[333,3],[453,3]]},"286":{"position":[[417,3]]},"365":{"position":[[2211,3],[2265,3],[2319,3],[2499,3],[2554,3],[2609,3],[2789,3],[2844,3],[2899,3],[3081,3],[3136,3],[3191,3]]},"436":{"position":[[1182,3],[1204,3],[1226,3],[1284,3],[1308,3],[1332,3],[1392,3],[1427,3],[1462,3],[1539,3],[1563,3],[1587,3],[1657,3],[1683,3],[1709,3],[1784,3],[1812,3],[1840,3],[1911,3],[1944,3],[1977,3]]},"458":{"position":[[247,3]]},"495":{"position":[[588,3],[966,3],[1130,3],[1191,3]]},"507":{"position":[[1174,3],[1411,3]]},"514":{"position":[[330,3]]},"516":{"position":[[453,3],[526,3]]},"523":{"position":[[1484,3],[1512,3],[1540,3],[1610,3],[1640,3],[1670,3],[1742,3],[1783,3],[1824,3],[1913,3],[1943,3],[1973,3],[2055,3],[2087,3],[2119,3],[2206,3],[2240,3],[2274,3],[2357,3],[2396,3],[2435,3]]},"539":{"position":[[195,3]]},"570":{"position":[[142,3]]},"597":{"position":[[99,3]]},"727":{"position":[[1854,3],[1878,3]]},"736":{"position":[[439,3],[581,3]]},"738":{"position":[[47,3]]},"750":{"position":[[504,3]]},"832":{"position":[[212,3],[1662,3],[1686,3]]},"859":{"position":[[1021,3]]},"878":{"position":[[395,3]]},"896":{"position":[[315,3]]},"925":{"position":[[171,3],[462,3],[509,3]]}}}],["addcommand",{"_index":3004,"t":{"734":{"position":[[396,10],[452,10]]},"925":{"position":[[827,10]]}}}],["addconsolelogg",{"_index":820,"t":{"120":{"position":[[251,16]]},"138":{"position":[[573,16]]},"194":{"position":[[709,16]]},"223":{"position":[[891,16]]},"255":{"position":[[226,16]]},"257":{"position":[[217,16]]},"259":{"position":[[220,16]]},"447":{"position":[[414,16]]},"495":{"position":[[538,16],[916,16]]},"736":{"position":[[389,16]]},"832":{"position":[[143,16],[1431,16]]},"859":{"position":[[937,16]]}}}],["addcontrol",{"_index":1467,"t":{"261":{"position":[[448,14]]}}}],["addfastbinaryconvert",{"_index":2048,"t":{"431":{"position":[[882,22]]}}}],["addfilelogg",{"_index":1042,"t":{"138":{"position":[[595,13]]},"255":{"position":[[248,13]]},"257":{"position":[[239,13]]},"259":{"position":[[242,13]]},"447":{"position":[[436,13]]},"832":{"position":[[165,13],[1453,13]]}}}],["addfold",{"_index":2241,"t":{"458":{"position":[[275,9]]}}}],["addlic",{"_index":3458,"t":{"969":{"position":[[489,10],[659,10]]}}}],["addoper",{"_index":2974,"t":{"727":{"position":[[216,12]]}}}],["addorupd",{"_index":2738,"t":{"630":{"position":[[186,11]]},"632":{"position":[[154,11]]}}}],["addplugin",{"_index":3393,"t":{"930":{"position":[[248,9]]}}}],["addproxytyp",{"_index":2194,"t":{"451":{"position":[[30,12],[189,12],[248,12]]}}}],["addrpcpars",{"_index":3398,"t":{"932":{"position":[[160,12]]}}}],["addswaggergen",{"_index":1468,"t":{"261":{"position":[[475,13]]}}}],["addtargetcli",{"_index":2521,"t":{"537":{"position":[[547,15],[636,15]]},"539":{"position":[[62,15]]}}}],["addtcpservic",{"_index":1436,"t":{"235":{"position":[[959,13]]}}}],["addwstouchrpc",{"_index":1460,"t":{"261":{"position":[[84,13],[233,13],[356,13]]}}}],["ag",{"_index":2052,"t":{"434":{"position":[[60,3]]},"436":{"position":[[738,3],[869,3]]},"523":{"position":[[48,3],[178,3]]}}}],["agv",{"_index":3415,"t":{"957":{"position":[[126,3]]}}}],["alladapt",{"_index":3243,"t":{"857":{"position":[[331,10]]},"859":{"position":[[225,10]]}}}],["android",{"_index":2345,"t":{"500":{"position":[[35,7]]},"864":{"position":[[51,7]]}}}],["answer",{"_index":845,"t":{"120":{"position":[[859,6],[2276,6]]},"465":{"position":[[325,6],[745,6]]}}}],["aop",{"_index":1224,"t":{"180":{"position":[[101,3]]},"212":{"position":[[171,3]]},"646":{"position":[[52,3]]},"792":{"position":[[89,3]]}}}],["ap",{"_index":2588,"t":{"554":{"position":[[238,3]]}}}],["apach",{"_index":28,"t":{"5":{"position":[[52,6]]}}}],["api",{"_index":1472,"t":{"261":{"position":[[542,3],[857,3]]},"286":{"position":[[694,3]]},"458":{"position":[[301,3]]},"894":{"position":[[144,3]]},"909":{"position":[[93,3],[165,3]]}}}],["apiserv",{"_index":639,"t":{"69":{"position":[[76,9],[482,9],[603,9]]},"894":{"position":[[110,9]]},"896":{"position":[[265,9],[491,9]]}}}],["app",{"_index":1477,"t":{"261":{"position":[[663,3],[722,3],[768,3],[786,3],[876,3],[913,3],[979,3],[997,3],[1021,3]]}}}],["append",{"_index":2259,"t":{"465":{"position":[[569,6],[617,6]]}}}],["appendlin",{"_index":859,"t":{"120":{"position":[[1202,10],[1247,10],[1283,10],[1319,10],[1374,10],[1430,10],[1467,10],[1503,10],[1622,10],[1730,10],[1870,10],[2046,10],[2082,10],[2119,10]]}}}],["appendvalu",{"_index":3048,"t":{"756":{"position":[[270,11],[322,11]]}}}],["appmessag",{"_index":180,"t":{"25":{"position":[[24,10],[84,10],[144,10]]}}}],["appmesseng",{"_index":197,"t":{"25":{"position":[[222,12],[247,12],[273,12],[286,12],[305,12],[321,12],[394,12],[465,12]]}}}],["arg",{"_index":589,"t":{"60":{"position":[[60,4]]},"66":{"position":[[127,4]]},"393":{"position":[[297,3],[383,3]]},"436":{"position":[[545,3],[599,3],[612,3],[673,3],[1890,3],[1922,3],[1955,3],[1988,3]]},"453":{"position":[[71,4]]},"495":{"position":[[138,4],[187,4]]},"523":{"position":[[584,3],[952,3],[965,3],[982,3],[2330,3],[2368,3],[2407,3],[2446,3]]},"537":{"position":[[26,4]]},"932":{"position":[[64,4]]}}}],["array",{"_index":1821,"t":{"365":{"position":[[1986,5]]},"470":{"position":[[275,5]]}}}],["arrayseg",{"_index":1761,"t":{"361":{"position":[[443,12]]},"365":{"position":[[1532,12]]},"610":{"position":[[428,12],[528,12]]}}}],["articl",{"_index":2336,"t":{"495":{"position":[[77,7]]}}}],["asget",{"_index":752,"t":{"102":{"position":[[289,5]]}}}],["asp",{"_index":1461,"t":{"261":{"position":[[115,3],[320,3]]},"806":{"position":[[406,3],[427,3]]}}}],["aspnetcor",{"_index":1427,"t":{"235":{"position":[[18,10],[45,10],[95,10],[122,10],[181,10],[1197,10],[1246,10]]},"261":{"position":[[25,10],[52,10]]},"705":{"position":[[93,10]]},"862":{"position":[[39,10],[119,10]]},"874":{"position":[[120,10],[239,10]]},"969":{"position":[[181,10],[280,10],[384,10]]}}}],["assert",{"_index":212,"t":{"25":{"position":[[433,6],[504,6]]},"548":{"position":[[212,6],[241,6]]},"550":{"position":[[435,6],[464,6],[493,6],[547,6]]},"552":{"position":[[562,6],[591,6],[620,6],[674,6],[728,6],[772,6],[1649,6],[1672,6],[1702,6]]},"554":{"position":[[490,6],[512,6],[694,6],[716,6]]},"632":{"position":[[248,6],[285,6],[405,6],[446,6],[487,6]]}}}],["async",{"_index":2985,"t":{"727":{"position":[[590,5]]}}}],["attribut",{"_index":2748,"t":{"646":{"position":[[37,9]]}}}],["auto",{"_index":1249,"t":{"184":{"position":[[270,4],[611,4]]},"218":{"position":[[270,4],[611,4]]},"288":{"position":[[183,4]]},"458":{"position":[[161,4]]},"925":{"position":[[309,4]]}}}],["await",{"_index":1372,"t":{"196":{"position":[[307,5]]},"241":{"position":[[260,5]]},"528":{"position":[[1086,5],[1783,5]]},"672":{"position":[[1049,5]]},"674":{"position":[[954,5]]},"691":{"position":[[96,5],[274,5]]},"727":{"position":[[749,5]]}}}],["azur",{"_index":1892,"t":{"370":{"position":[[460,5]]}}}],["b",{"_index":189,"t":{"25":{"position":[[122,1],[138,1],[182,1],[198,1]]},"69":{"position":[[95,1],[502,1],[654,1]]},"75":{"position":[[152,1]]},"80":{"position":[[795,1],[1459,1],[2294,1]]},"146":{"position":[[9,1]]},"424":{"position":[[0,1]]},"552":{"position":[[65,1],[806,1],[931,1],[1064,1],[1068,1],[1158,1]]},"556":{"position":[[913,1],[965,1],[969,1],[1054,1],[1730,1],[1863,1],[1867,1],[1957,1],[2663,1],[2796,1],[2800,1],[2890,1],[3307,1],[3440,1],[3444,1],[3534,1]]},"604":{"position":[[49,1]]},"734":{"position":[[349,1],[418,1],[479,1],[604,1],[700,1],[798,1]]},"894":{"position":[[242,1],[258,1],[359,1],[858,1]]},"896":{"position":[[510,1]]},"925":{"position":[[849,1],[865,1],[955,1],[1034,1]]},"928":{"position":[[181,1],[197,1],[278,1],[346,1]]}}}],["baidu",{"_index":1331,"t":{"184":{"position":[[1353,5],[1372,5]]},"218":{"position":[[1353,5],[1372,5]]},"319":{"position":[[721,5],[749,5]]}}}],["base",{"_index":358,"t":{"40":{"position":[[318,4]]},"42":{"position":[[226,4]]},"146":{"position":[[322,4]]},"194":{"position":[[496,4]]},"225":{"position":[[576,4],[786,4]]},"233":{"position":[[502,4]]},"235":{"position":[[597,4]]},"290":{"position":[[956,4],[1266,4]]},"463":{"position":[[302,4]]},"465":{"position":[[813,4]]},"493":{"position":[[688,4],[814,4],[1257,4]]},"530":{"position":[[394,4]]},"537":{"position":[[450,4],[1027,4],[1227,4],[1458,4]]},"630":{"position":[[479,4]]},"648":{"position":[[430,4],[754,4],[1106,4]]},"684":{"position":[[395,4],[740,4]]},"693":{"position":[[294,4]]},"734":{"position":[[179,4]]},"774":{"position":[[404,4]]},"780":{"position":[[467,4]]},"832":{"position":[[1237,4]]},"836":{"position":[[384,4]]}}}],["becach",{"_index":1614,"t":{"301":{"position":[[748,8],[1000,8]]}}}],["benchmark",{"_index":2427,"t":{"523":{"position":[[102,9],[2480,9]]}}}],["betweenand",{"_index":3335,"t":{"882":{"position":[[294,10]]}}}],["big",{"_index":3069,"t":{"767":{"position":[[109,3]]}}}],["bigendian",{"_index":3066,"t":{"763":{"position":[[37,9]]}}}],["bigfixedheadercustomdatahandlingadapt",{"_index":509,"t":{"57":{"position":[[101,39]]}}}],["binari",{"_index":1573,"t":{"290":{"position":[[375,6]]},"323":{"position":[[149,6]]}}}],["bio",{"_index":3385,"t":{"911":{"position":[[33,3]]}}}],["bit",{"_index":3149,"t":{"820":{"position":[[50,3]]}}}],["block",{"_index":2273,"t":{"470":{"position":[[665,5],[692,5],[715,5],[752,5]]}}}],["blog",{"_index":2331,"t":{"495":{"position":[[51,4]]}}}],["bobo",{"_index":1830,"t":{"370":{"position":[[0,4]]}}}],["bodi",{"_index":310,"t":{"34":{"position":[[267,4],[274,4]]},"57":{"position":[[427,4],[1665,4],[1710,4],[1733,4]]},"120":{"position":[[1480,4],[2096,4]]},"272":{"position":[[476,4],[489,4]]},"301":{"position":[[1532,4],[1626,4],[1692,4],[1829,4],[1836,4],[1985,4],[2019,4],[2592,4],[2637,4],[2660,4]]},"308":{"position":[[412,4],[863,4],[929,4],[949,4],[992,4],[1004,4],[1043,4],[1050,4],[2071,4],[2116,4],[2139,4],[2395,4],[2446,4],[2467,4],[2535,4]]},"347":{"position":[[418,4],[632,4],[698,4],[718,4],[761,4],[773,4],[812,4],[819,4],[1045,4],[1467,4],[2236,4],[2281,4],[2304,4]]},"489":{"position":[[602,4],[614,4],[660,4]]},"697":{"position":[[101,4]]},"702":{"position":[[2718,4],[2730,4],[2764,4],[2826,4]]}}}],["bodylength",{"_index":525,"t":{"57":{"position":[[391,10],[563,10],[901,10]]},"301":{"position":[[1453,10],[1493,10],[1651,10],[1698,10]]},"308":{"position":[[376,10],[497,10],[565,10],[591,10],[1024,10],[1198,10],[2493,10]]},"347":{"position":[[382,10],[507,10],[575,10],[601,10],[793,10],[929,10],[1489,10]]},"489":{"position":[[536,10],[634,10],[773,10]]},"702":{"position":[[606,10],[702,10],[724,10],[931,10],[2210,10],[2750,10],[2876,10]]}}}],["bool",{"_index":433,"t":{"48":{"position":[[175,4]]},"57":{"position":[[764,4],[854,4]]},"127":{"position":[[293,4],[569,4]]},"132":{"position":[[360,4],[388,4]]},"134":{"position":[[3614,4]]},"272":{"position":[[512,4],[594,4]]},"301":{"position":[[995,4]]},"308":{"position":[[966,4],[1094,4]]},"340":{"position":[[366,4]]},"347":{"position":[[735,4],[863,4]]},"361":{"position":[[110,4],[157,4]]},"451":{"position":[[61,4]]},"455":{"position":[[134,4],[297,4],[806,4]]},"470":{"position":[[69,4],[96,4]]},"489":{"position":[[178,4],[576,4],[704,4]]},"491":{"position":[[303,4],[561,4]]},"521":{"position":[[346,4]]},"604":{"position":[[44,4]]},"641":{"position":[[234,4]]},"643":{"position":[[137,4]]},"663":{"position":[[224,4]]},"702":{"position":[[283,4],[1982,4],[2692,4]]},"752":{"position":[[111,4]]},"809":{"position":[[135,4],[350,4],[458,4]]}}}],["boolean",{"_index":1007,"t":{"134":{"position":[[478,7],[819,7],[1323,7],[1655,7],[1697,7],[1815,7],[2179,7],[2522,7],[2851,7],[2893,7],[3018,7],[3379,7]]}}}],["break",{"_index":1571,"t":{"290":{"position":[[282,5],[352,5],[547,5],[630,5],[659,5],[688,5],[704,5]]},"323":{"position":[[97,5],[126,5],[157,5],[187,5],[216,5],[245,5],[261,5]]},"411":{"position":[[270,5]]}}}],["breakpointresum",{"_index":3210,"t":{"832":{"position":[[1802,16]]}}}],["breaktrigg",{"_index":3244,"t":{"857":{"position":[[362,12]]},"859":{"position":[[256,12]]}}}],["broadcast",{"_index":3214,"t":{"839":{"position":[[2,9]]}}}],["bucket",{"_index":1205,"t":{"166":{"position":[[494,6],[542,6]]},"252":{"position":[[494,6],[542,6]]},"727":{"position":[[145,6],[1010,6]]}}}],["buffer",{"_index":543,"t":{"57":{"position":[[658,6],[724,6]]},"159":{"position":[[524,6],[869,6]]},"188":{"position":[[333,6]]},"192":{"position":[[214,6]]},"196":{"position":[[139,6],[227,6],[357,6],[403,6]]},"207":{"position":[[196,6]]},"223":{"position":[[398,6]]},"225":{"position":[[302,6]]},"229":{"position":[[217,6]]},"241":{"position":[[92,6],[180,6],[310,6],[408,6]]},"243":{"position":[[111,6],[187,6],[307,6],[388,6]]},"347":{"position":[[1073,6],[1342,6]]},"361":{"position":[[299,6],[593,6],[968,6],[1021,6],[1404,6],[1423,6],[1517,6],[1621,6],[1819,6],[1921,6],[2018,6]]},"365":{"position":[[2049,6]]},"406":{"position":[[260,6],[563,6]]},"411":{"position":[[114,6],[229,6],[240,6]]},"413":{"position":[[143,6],[322,6],[351,6]]},"422":{"position":[[273,6],[547,6]]},"431":{"position":[[267,6],[333,6]]},"470":{"position":[[175,6],[286,6]]},"632":{"position":[[358,6],[396,6],[417,6]]},"745":{"position":[[273,6],[618,6]]},"780":{"position":[[432,6]]},"809":{"position":[[318,6]]},"980":{"position":[[241,6]]}}}],["bufferlength",{"_index":1681,"t":{"336":{"position":[[29,12],[131,12]]},"338":{"position":[[0,12]]},"340":{"position":[[72,12],[126,12],[210,12],[298,12],[316,12],[342,12],[522,12]]},"365":{"position":[[317,12],[576,12],[835,12],[1096,12]]}}}],["bug",{"_index":2113,"t":{"444":{"position":[[254,3]]},"866":{"position":[[92,3]]},"868":{"position":[[71,3],[107,3],[139,3]]},"870":{"position":[[141,3]]},"872":{"position":[[103,3]]},"874":{"position":[[487,3]]},"876":{"position":[[207,3]]},"878":{"position":[[206,3]]},"880":{"position":[[342,3]]},"882":{"position":[[289,3],[312,3],[330,3],[354,3],[372,3]]}}}],["build",{"_index":3049,"t":{"758":{"position":[[96,5]]},"832":{"position":[[300,5]]}}}],["buildwithtcptouchrpccli",{"_index":3208,"t":{"832":{"position":[[1547,26]]}}}],["buildwithtcptouchrpcservic",{"_index":3203,"t":{"832":{"position":[[266,27]]}}}],["button",{"_index":892,"t":{"120":{"position":[[1896,6]]}}}],["byhexstringtobyt",{"_index":2699,"t":{"606":{"position":[[37,18]]}}}],["byhexstringtoint32",{"_index":2703,"t":{"606":{"position":[[141,18]]}}}],["byte",{"_index":542,"t":{"57":{"position":[[651,4],[875,4]]},"157":{"position":[[64,4],[261,4],[326,4],[563,4]]},"184":{"position":[[35,4],[175,4]]},"196":{"position":[[132,4],[220,4],[350,4],[396,4]]},"218":{"position":[[35,4],[175,4]]},"241":{"position":[[85,4],[173,4],[303,4],[401,4]]},"243":{"position":[[104,4],[180,4],[300,4],[381,4]]},"272":{"position":[[469,4],[534,4],[618,4],[1016,4],[1103,4]]},"301":{"position":[[1340,4],[1448,4],[1467,4],[1685,4],[2012,4],[2100,4],[2192,4],[2285,4]]},"308":{"position":[[615,4],[683,4],[734,4],[803,4],[856,4],[922,4],[985,4],[1115,4]]},"340":{"position":[[404,4]]},"347":{"position":[[625,4],[691,4],[754,4]]},"361":{"position":[[292,4],[456,4],[586,4],[688,4],[931,4],[1314,4],[1397,4],[2051,4],[2228,4],[2287,4],[2608,4]]},"365":{"position":[[261,4],[347,4],[372,4],[398,4],[520,4],[606,4],[631,4],[657,4],[779,4],[865,4],[890,4],[916,4],[1040,4],[1126,4],[1151,4],[1177,4],[1545,4],[1663,4],[1906,4],[2121,4],[2236,4],[2290,4],[2409,4],[2524,4],[2579,4],[2699,4],[2814,4],[2869,4],[2991,4],[3106,4],[3161,4]]},"402":{"position":[[37,4]]},"404":{"position":[[0,4]]},"411":{"position":[[107,4],[127,4]]},"413":{"position":[[136,4],[156,4]]},"431":{"position":[[260,4]]},"436":{"position":[[138,4],[231,4],[344,4],[1058,4],[1367,4],[1400,4],[1435,4],[1470,4]]},"470":{"position":[[127,4],[261,4],[528,4]]},"487":{"position":[[153,4]]},"489":{"position":[[499,4],[595,4],[725,4],[1046,4],[1121,4],[1415,4]]},"523":{"position":[[697,4],[820,4],[913,4],[1342,4],[1711,4],[1750,4],[1791,4],[1832,4]]},"537":{"position":[[1109,4],[1306,4]]},"600":{"position":[[56,4],[74,4],[84,4]]},"606":{"position":[[30,4]]},"610":{"position":[[25,4],[43,4],[412,4],[441,4],[510,4],[541,4]]},"632":{"position":[[178,4],[196,4],[351,4],[369,4]]},"672":{"position":[[578,4],[873,4]]},"674":{"position":[[793,4]]},"684":{"position":[[197,4],[285,4],[533,4],[583,4]]},"702":{"position":[[577,4],[626,4],[650,4],[675,4],[787,4],[1006,4],[1120,4],[1207,4],[1289,4],[1397,4],[1502,4],[1766,4],[1870,4],[1952,4],[2003,4],[2151,4],[2360,4],[2406,4],[2449,4],[2494,4],[2542,4],[2711,4],[2942,4]]},"727":{"position":[[1160,4],[1178,4]]},"756":{"position":[[169,4],[286,4],[338,4]]},"763":{"position":[[0,4]]},"765":{"position":[[0,4]]},"767":{"position":[[114,4]]},"809":{"position":[[311,4]]},"820":{"position":[[220,4],[233,4],[281,4]]},"857":{"position":[[469,4]]},"859":{"position":[[363,4]]}}}],["byte1",{"_index":3150,"t":{"820":{"position":[[77,5]]}}}],["byte10",{"_index":3162,"t":{"820":{"position":[[183,6]]}}}],["byte2",{"_index":3153,"t":{"820":{"position":[[116,5]]}}}],["byte3",{"_index":3154,"t":{"820":{"position":[[122,5]]}}}],["byte4",{"_index":3155,"t":{"820":{"position":[[128,5]]}}}],["byte5",{"_index":3156,"t":{"820":{"position":[[134,5]]}}}],["byte6",{"_index":3157,"t":{"820":{"position":[[140,5]]}}}],["byte7",{"_index":3158,"t":{"820":{"position":[[146,5]]}}}],["byte8",{"_index":3159,"t":{"820":{"position":[[152,5]]}}}],["byte9",{"_index":3161,"t":{"820":{"position":[[177,5]]}}}],["byteblock",{"_index":253,"t":{"32":{"position":[[34,9],[66,9],[132,9],[215,9]]},"34":{"position":[[256,9]]},"57":{"position":[[1443,9],[1513,9]]},"151":{"position":[[25,9],[123,9]]},"153":{"position":[[25,9],[76,9],[117,9],[144,9],[213,9],[324,9],[349,9]]},"157":{"position":[[7,9],[17,9],[33,9],[48,9],[80,9],[111,9],[143,9],[168,9],[229,9],[274,9],[343,9],[380,9],[420,9],[464,9],[509,9],[583,9]]},"159":{"position":[[28,9],[94,9],[190,9],[216,9],[274,9],[306,9],[412,9],[422,9],[514,9],[535,9],[722,9],[732,9],[771,9],[859,9],[880,9],[896,9]]},"186":{"position":[[215,9],[268,9]]},"188":{"position":[[246,9],[323,9],[344,9]]},"192":{"position":[[127,9],[204,9],[225,9]]},"194":{"position":[[327,9],[372,9],[382,9],[396,9]]},"196":{"position":[[173,9],[183,9]]},"207":{"position":[[74,9],[126,9],[186,9],[207,9]]},"220":{"position":[[222,9],[275,9]]},"223":{"position":[[311,9],[388,9],[409,9]]},"225":{"position":[[167,9],[177,9],[292,9],[313,9]]},"229":{"position":[[130,9],[207,9],[228,9]]},"233":{"position":[[333,9],[378,9],[388,9],[402,9]]},"235":{"position":[[738,9],[783,9],[793,9],[807,9]]},"241":{"position":[[126,9],[136,9],[349,9],[359,9]]},"243":{"position":[[46,9],[56,9],[237,9],[247,9]]},"272":{"position":[[1334,9],[1404,9]]},"297":{"position":[[28,9],[41,9],[152,9],[203,9],[244,9],[316,9]]},"301":{"position":[[441,9],[508,9],[645,9],[708,9],[974,9],[984,9],[1092,9],[1175,9],[1300,9],[1321,9],[1506,9],[1542,9],[1636,9],[1666,9],[2398,9],[2468,9]]},"308":{"position":[[1855,9],[1925,9]]},"340":{"position":[[537,9],[624,9],[644,9]]},"347":{"position":[[884,9],[894,9],[1063,9],[1093,9],[1108,9],[1216,9],[1276,9],[1332,9],[1350,9],[1390,9],[2016,9],[2086,9]]},"357":{"position":[[168,9]]},"361":{"position":[[231,9],[241,9],[802,9],[812,9],[828,9],[864,9],[874,9],[890,9],[914,9],[952,9],[1011,9],[1032,9],[1242,9],[1374,9],[1384,9],[1413,9],[1439,9],[2396,9],[2406,9],[2422,9],[2441,9],[2503,9],[2572,9],[2795,9],[2842,9],[2852,9],[2887,9],[2917,9]]},"365":{"position":[[276,9],[286,9],[302,9],[355,9],[381,9],[407,9],[446,9],[470,9],[535,9],[545,9],[561,9],[614,9],[640,9],[666,9],[705,9],[729,9],[794,9],[804,9],[820,9],[873,9],[899,9],[925,9],[964,9],[988,9],[1055,9],[1065,9],[1081,9],[1134,9],[1160,9],[1186,9],[1225,9],[1249,9],[1777,9],[1787,9],[1803,9],[1839,9],[1849,9],[1865,9],[1889,9],[1965,9],[2039,9],[2060,9]]},"406":{"position":[[90,9],[173,9],[250,9],[271,9],[536,9],[553,9]]},"422":{"position":[[80,9],[102,9],[186,9],[263,9],[284,9],[520,9],[537,9]]},"431":{"position":[[302,9],[342,9],[400,9],[432,9],[499,9],[509,9],[584,9],[599,9],[624,9],[656,9]]},"470":{"position":[[402,9],[476,9],[655,9],[677,9]]},"489":{"position":[[931,9],[941,9],[954,9],[1029,9],[1087,9],[1153,9],[1163,9],[1179,9],[1205,9],[1224,9]]},"507":{"position":[[260,9],[270,9],[295,9],[316,9],[337,9],[358,9],[399,9],[479,9],[533,9],[580,9],[665,9],[719,9],[746,9],[847,9],[857,9],[892,9],[925,9],[959,9],[991,9],[1028,9],[1079,9],[1178,9],[1231,9],[1298,9],[1415,9],[1438,9],[1598,9],[1608,9],[1621,9],[1675,9],[1685,9],[1708,9],[2030,9],[2040,9],[2054,9],[2085,9],[2108,9],[2190,9]]},"537":{"position":[[1160,9],[1170,9],[1260,9],[1388,9],[1398,9],[1511,9]]},"561":{"position":[[92,9]]},"574":{"position":[[484,9],[494,9],[559,9]]},"610":{"position":[[92,9],[102,9],[116,9],[145,9],[218,9]]},"702":{"position":[[2054,9],[2064,9],[2080,9],[2101,9],[2120,9],[2169,9],[2309,9],[2365,9],[2411,9],[2454,9],[2499,9],[2547,9],[2585,9],[2628,9],[2790,9],[2800,9],[2816,9],[2835,9],[2893,9],[2947,9]]},"745":{"position":[[80,9],[102,9],[186,9],[263,9],[284,9],[591,9],[608,9]]},"780":{"position":[[336,9],[422,9],[445,9],[539,9]]},"809":{"position":[[231,9],[241,9]]},"816":{"position":[[183,9]]},"843":{"position":[[88,9],[135,9]]},"849":{"position":[[106,9],[153,9]]},"859":{"position":[[60,9]]},"868":{"position":[[147,9]]},"980":{"position":[[48,9],[70,9],[154,9],[231,9],[252,9]]}}}],["byteblock1",{"_index":1104,"t":{"153":{"position":[[127,10],[191,10]]}}}],["byteblock2",{"_index":1108,"t":{"153":{"position":[[223,10],[295,10]]}}}],["byteblock3",{"_index":1110,"t":{"153":{"position":[[334,10]]}}}],["bytemanag",{"_index":3289,"t":{"872":{"position":[[510,11]]}}}],["bytepool",{"_index":1084,"t":{"149":{"position":[[45,8],[64,8]]},"151":{"position":[[4,8]]},"153":{"position":[[0,8],[37,8],[236,8]]},"868":{"position":[[227,8]]},"874":{"position":[[468,8]]}}}],["bytes",{"_index":1105,"t":{"153":{"position":[[154,8],[258,8]]}}}],["bytesvalu",{"_index":1136,"t":{"157":{"position":[[570,10]]}}}],["bytevalu",{"_index":1126,"t":{"157":{"position":[[331,9]]}}}],["c",{"_index":685,"t":{"80":{"position":[[813,1],[1477,1],[2312,1]]},"261":{"position":[[489,1],[496,1],[803,1],[810,1]]},"323":{"position":[[44,1]]},"628":{"position":[[57,1]]},"705":{"position":[[47,1],[122,1]]},"729":{"position":[[0,1],[21,1],[46,1],[70,1]]},"824":{"position":[[2,1]]}}}],["c8",{"_index":2889,"t":{"702":{"position":[[1089,2],[1176,2]]}}}],["cach",{"_index":1591,"t":{"297":{"position":[[21,5]]},"301":{"position":[[416,5],[1140,5],[1589,5]]}}}],["cachetimeout",{"_index":469,"t":{"50":{"position":[[203,12]]}}}],["cachetimeouten",{"_index":466,"t":{"50":{"position":[[174,18]]}}}],["call",{"_index":584,"t":{"60":{"position":[[17,4]]},"69":{"position":[[17,4]]},"80":{"position":[[47,4]]},"125":{"position":[[21,4]]},"132":{"position":[[25,4]]},"144":{"position":[[31,4]]},"146":{"position":[[47,4],[75,4]]},"792":{"position":[[56,4],[70,4]]}}}],["callcontext",{"_index":971,"t":{"127":{"position":[[735,11]]},"286":{"position":[[827,11],[846,11],[944,11]]},"512":{"position":[[517,11],[692,11],[723,11],[807,11],[938,11],[1017,11]]},"641":{"position":[[258,11],[308,11]]},"643":{"position":[[192,11]]},"648":{"position":[[113,11],[306,11],[392,11],[445,11],[534,11],[605,11],[689,11],[768,11],[864,11],[956,11],[1040,11],[1127,11]]},"672":{"position":[[96,11],[301,11],[376,11]]},"674":{"position":[[68,11],[273,11],[321,11]]},"894":{"position":[[430,11],[579,11],[625,11],[693,11]]}}}],["caller",{"_index":1065,"t":{"142":{"position":[[538,6]]},"286":{"position":[[858,6]]},"512":{"position":[[735,6],[819,6],[950,6],[1029,6]]},"641":{"position":[[85,6],[320,6]]},"643":{"position":[[204,6]]},"648":{"position":[[318,6],[617,6],[968,6]]},"672":{"position":[[388,6]]},"674":{"position":[[333,6]]}}}],["cancel",{"_index":2780,"t":{"661":{"position":[[340,6]]},"672":{"position":[[636,6]]},"674":{"position":[[851,6]]},"727":{"position":[[1521,6]]}}}],["cancellationtoken",{"_index":2650,"t":{"581":{"position":[[138,17],[273,17]]},"661":{"position":[[86,17],[133,17],[287,17]]},"830":{"position":[[700,17]]}}}],["cancellationtokensourc",{"_index":2778,"t":{"661":{"position":[[205,23],[247,23]]}}}],["canreadlen",{"_index":1612,"t":{"301":{"position":[[451,10],[1102,10],[1516,10]]},"347":{"position":[[1118,10]]}}}],["cansendrequestinfo",{"_index":1757,"t":{"361":{"position":[[162,18]]},"489":{"position":[[183,18]]},"702":{"position":[[288,18]]}}}],["cansetdatahandlingadapt",{"_index":434,"t":{"48":{"position":[[180,25]]}}}],["cansplicingsend",{"_index":1756,"t":{"361":{"position":[[115,15]]},"809":{"position":[[140,15]]}}}],["case",{"_index":1566,"t":{"290":{"position":[[198,4],[289,4],[359,4],[554,4],[637,4],[666,4]]},"323":{"position":[[75,4],[104,4],[133,4],[164,4],[194,4],[223,4]]}}}],["catch",{"_index":2261,"t":{"465":{"position":[[757,5]]},"491":{"position":[[477,5],[735,5]]},"537":{"position":[[714,5]]},"539":{"position":[[288,5]]},"971":{"position":[[139,5]]}}}],["certif",{"_index":780,"t":{"104":{"position":[[475,11]]},"122":{"position":[[84,11]]},"288":{"position":[[336,11]]},"319":{"position":[[517,11]]}}}],["certificatevalidationcallback",{"_index":778,"t":{"104":{"position":[[434,29]]},"319":{"position":[[476,29]]}}}],["chain",{"_index":781,"t":{"104":{"position":[[488,5]]},"319":{"position":[[530,5]]}}}],["channel",{"_index":2803,"t":{"670":{"position":[[24,7],[40,7]]},"672":{"position":[[490,7],[498,7],[560,7],[596,7],[740,7],[748,7],[833,7],[851,7],[887,7],[941,7],[998,7]]},"674":{"position":[[435,7],[443,7],[462,7],[492,7],[639,7],[647,7],[775,7],[811,7],[905,7]]},"826":{"position":[[8,7]]},"872":{"position":[[82,7]]}}}],["channelid",{"_index":2806,"t":{"672":{"position":[[135,9],[318,9],[475,9]]},"674":{"position":[[107,9],[290,9],[420,9]]}}}],["channelno",{"_index":2904,"t":{"702":{"position":[[1402,9],[2481,9]]}}}],["channelstatu",{"_index":2810,"t":{"672":{"position":[[680,13],[703,13]]},"674":{"position":[[552,13],[575,13]]}}}],["char",{"_index":2366,"t":{"507":{"position":[[99,4]]}}}],["charset",{"_index":863,"t":{"120":{"position":[[1337,7]]}}}],["checkstatu",{"_index":2480,"t":{"528":{"position":[[636,11],[1350,11]]}}}],["chenqiang",{"_index":1891,"t":{"370":{"position":[[444,9]]}}}],["class",{"_index":185,"t":{"25":{"position":[[50,5]]},"40":{"position":[[85,5]]},"42":{"position":[[39,5]]},"48":{"position":[[67,5]]},"57":{"position":[[486,5],[1102,5]]},"120":{"position":[[629,5]]},"127":{"position":[[150,5],[417,5]]},"134":{"position":[[934,5],[2242,5]]},"138":{"position":[[254,5]]},"146":{"position":[[130,5]]},"159":{"position":[[339,5],[649,5]]},"194":{"position":[[104,5]]},"225":{"position":[[86,5],[442,5]]},"233":{"position":[[104,5]]},"235":{"position":[[315,5]]},"272":{"position":[[386,5],[774,5]]},"286":{"position":[[565,5]]},"290":{"position":[[808,5],[1103,5]]},"301":{"position":[[233,5],[1924,5]]},"308":{"position":[[426,5],[1418,5]]},"347":{"position":[[432,5],[1718,5]]},"361":{"position":[[44,5]]},"365":{"position":[[194,5]]},"376":{"position":[[33,5],[197,5],[683,5]]},"431":{"position":[[162,5],[756,5]]},"434":{"position":[[28,5]]},"436":{"position":[[27,5],[593,5],[810,5]]},"453":{"position":[[65,5]]},"455":{"position":[[84,5]]},"463":{"position":[[36,5]]},"465":{"position":[[35,5]]},"473":{"position":[[51,5]]},"489":{"position":[[28,5],[405,5]]},"491":{"position":[[96,5]]},"493":{"position":[[60,5]]},"507":{"position":[[6,5],[1501,5]]},"512":{"position":[[105,5]]},"523":{"position":[[16,5],[389,5],[946,5]]},"530":{"position":[[162,5]]},"537":{"position":[[331,5]]},"546":{"position":[[199,5]]},"548":{"position":[[279,5]]},"550":{"position":[[610,5]]},"552":{"position":[[828,5],[1766,5]]},"556":{"position":[[45,5],[97,5],[289,5],[481,5],[825,5],[1295,5],[1627,5],[2209,5],[2567,5],[3211,5]]},"574":{"position":[[411,5]]},"610":{"position":[[362,5]]},"630":{"position":[[283,5]]},"641":{"position":[[109,5]]},"643":{"position":[[58,5]]},"648":{"position":[[7,5]]},"663":{"position":[[103,5]]},"684":{"position":[[112,5]]},"693":{"position":[[62,5]]},"702":{"position":[[133,5],[519,5]]},"734":{"position":[[56,5]]},"774":{"position":[[59,5]]},"780":{"position":[[161,5]]},"809":{"position":[[73,5]]},"832":{"position":[[380,5]]},"836":{"position":[[112,5]]},"894":{"position":[[104,5],[804,5]]},"925":{"position":[[764,5],[979,5]]},"928":{"position":[[114,5],[292,5]]},"969":{"position":[[435,5]]}}}],["client",{"_index":342,"t":{"40":{"position":[[39,6]]},"42":{"position":[[124,6],[162,6],[244,6]]},"57":{"position":[[1435,6]]},"60":{"position":[[72,6],[121,6]]},"66":{"position":[[139,6],[194,6]]},"69":{"position":[[288,6],[317,6],[349,6],[401,6],[415,6],[457,6],[577,6]]},"75":{"position":[[112,6]]},"102":{"position":[[11,6],[38,6],[262,6],[312,6]]},"120":{"position":[[730,6],[2338,6]]},"132":{"position":[[94,6],[128,6],[230,6],[374,6]]},"134":{"position":[[999,6],[1014,6],[1023,6],[1051,6],[1428,6],[1504,6],[1532,6],[1676,6],[1926,6],[2002,6],[2030,6],[2153,6],[2558,6],[2700,6],[2728,6],[2872,6],[3060,6],[3202,6],[3230,6],[3353,6],[3460,6],[3494,6],[3596,6],[3628,6]]},"138":{"position":[[438,6],[472,6],[717,6]]},"142":{"position":[[66,6]]},"146":{"position":[[220,6],[337,6]]},"169":{"position":[[45,6],[79,6],[181,6]]},"171":{"position":[[46,6],[81,6],[183,6]]},"173":{"position":[[29,6],[57,6],[161,6]]},"175":{"position":[[17,6],[50,6],[140,6]]},"188":{"position":[[117,6],[173,6],[238,6]]},"192":{"position":[[119,6]]},"194":{"position":[[269,6],[516,6],[558,6],[584,6]]},"223":{"position":[[151,6],[201,6],[254,6],[303,6],[425,6],[449,6],[474,6],[510,6],[648,6]]},"225":{"position":[[908,6],[958,6],[1011,6],[1462,6],[1512,6],[1565,6]]},"229":{"position":[[122,6],[244,6],[268,6]]},"233":{"position":[[275,6],[522,6]]},"235":{"position":[[529,6],[614,6],[680,6]]},"272":{"position":[[1326,6]]},"290":{"position":[[134,6],[608,6],[922,6],[981,6],[1215,6],[1291,6]]},"292":{"position":[[23,7],[32,6],[150,6],[244,7],[297,7]]},"301":{"position":[[2390,6]]},"308":{"position":[[1847,6]]},"321":{"position":[[1,6]]},"323":{"position":[[24,6]]},"347":{"position":[[2008,6]]},"376":{"position":[[992,6],[1124,6],[1169,6],[1220,6],[1336,6],[1431,6],[1472,6]]},"406":{"position":[[165,6]]},"422":{"position":[[178,6]]},"463":{"position":[[117,6],[313,6]]},"465":{"position":[[117,6],[648,6],[780,6],[825,6]]},"491":{"position":[[12,6],[335,6],[382,6],[500,6],[593,6],[640,6],[758,6]]},"493":{"position":[[367,6],[405,6],[469,6],[567,6],[647,6],[705,6],[773,6],[834,6],[850,6],[946,6],[1072,6],[1238,6],[1277,6]]},"512":{"position":[[798,6],[856,6],[878,6],[1008,6],[1062,6],[1084,6],[1097,6]]},"530":{"position":[[252,6],[409,6],[960,6]]},"561":{"position":[[84,6]]},"574":{"position":[[370,6]]},"581":{"position":[[12,6],[68,6],[217,6]]},"617":{"position":[[200,6],[226,6],[238,6]]},"630":{"position":[[147,6],[382,6],[500,6]]},"632":{"position":[[65,6],[115,6]]},"648":{"position":[[352,6],[362,6],[651,6],[661,6],[1002,6],[1012,6]]},"655":{"position":[[257,6]]},"659":{"position":[[177,6]]},"661":{"position":[[381,6]]},"672":{"position":[[671,6],[758,6],[976,6]]},"674":{"position":[[543,6],[657,6],[883,6]]},"681":{"position":[[461,6]]},"686":{"position":[[344,6]]},"693":{"position":[[152,6],[309,6]]},"727":{"position":[[1124,6],[1923,6]]},"745":{"position":[[178,6]]},"752":{"position":[[130,6]]},"758":{"position":[[13,6]]},"774":{"position":[[153,6],[423,6]]},"776":{"position":[[45,6]]},"780":{"position":[[264,6],[495,6]]},"832":{"position":[[509,6],[596,6],[632,6],[758,6],[831,6],[866,6],[1002,6],[1037,6],[1071,6],[1150,6],[1191,6],[1223,6],[1257,6],[1297,6],[1577,6],[2242,6],[2398,6],[2429,6]]},"836":{"position":[[202,6],[399,6]]},"859":{"position":[[52,6],[148,6],[442,6]]},"878":{"position":[[479,6],[512,6],[547,6],[632,6],[680,6],[715,6]]},"980":{"position":[[146,6]]}}}],["client1",{"_index":3184,"t":{"826":{"position":[[127,7]]}}}],["client2",{"_index":3186,"t":{"826":{"position":[[149,7]]}}}],["clientcertif",{"_index":773,"t":{"104":{"position":[[262,18]]},"319":{"position":[[304,18]]}}}],["clientdisconnectedeventarg",{"_index":2327,"t":{"493":{"position":[[781,27]]},"537":{"position":[[879,27]]},"832":{"position":[[1158,27]]}}}],["clientfactori",{"_index":2469,"t":{"528":{"position":[[44,13],[59,13],[207,13],[518,13],[567,13],[622,13],[1092,13],[1281,13],[1336,13],[1789,13]]},"530":{"position":[[574,13]]}}}],["clientid",{"_index":1400,"t":{"223":{"position":[[593,8],[636,8],[681,8]]}}}],["clientoperationeventarg",{"_index":352,"t":{"40":{"position":[[201,24]]},"42":{"position":[[132,24]]},"225":{"position":[[669,24]]}}}],["clientsslopt",{"_index":767,"t":{"104":{"position":[[102,15],[242,15]]},"319":{"position":[[284,15]]}}}],["close",{"_index":1344,"t":{"186":{"position":[[145,5]]},"220":{"position":[[152,5]]},"290":{"position":[[570,5],[615,5]]},"323":{"position":[[180,5]]},"595":{"position":[[170,5]]},"748":{"position":[[263,5]]},"870":{"position":[[176,5]]},"874":{"position":[[355,5],[368,5]]}}}],["cmd",{"_index":3012,"t":{"738":{"position":[[22,3]]}}}],["cmdid",{"_index":2879,"t":{"702":{"position":[[635,5],[1013,5],[1030,5],[1046,5],[2330,5]]}}}],["code",{"_index":2150,"t":{"447":{"position":[[114,4],[1055,5],[1192,5],[1348,5]]},"707":{"position":[[141,4]]},"932":{"position":[[497,5]]}}}],["codegener",{"_index":2167,"t":{"447":{"position":[[929,13],[1151,13],[1311,13],[1354,13]]},"451":{"position":[[16,13],[175,13],[234,13]]},"932":{"position":[[446,13]]}}}],["codestr",{"_index":2171,"t":{"447":{"position":[[1138,10]]},"932":{"position":[[433,10]]}}}],["coffe",{"_index":1835,"t":{"370":{"position":[[31,6]]}}}],["com",{"_index":124,"t":{"12":{"position":[[169,3]]},"184":{"position":[[1359,3],[1378,3]]},"218":{"position":[[1359,3],[1378,3]]},"263":{"position":[[65,3]]},"319":{"position":[[727,3],[755,3]]}}}],["command",{"_index":3000,"t":{"732":{"position":[[74,7]]},"734":{"position":[[30,7]]},"925":{"position":[[112,7],[718,7]]}}}],["complet",{"_index":2809,"t":{"672":{"position":[[604,8],[627,8]]},"674":{"position":[[819,8],[842,8]]}}}],["completedlength",{"_index":3200,"t":{"830":{"position":[[523,15]]}}}],["complexobject",{"_index":2439,"t":{"523":{"position":[[395,13],[1081,13],[1116,13],[1130,13],[1150,13],[1167,13],[1190,13],[1217,13],[1241,13],[1263,13],[1296,13],[1319,13],[1406,13],[1425,13],[1464,13],[1492,13],[1520,13],[1548,13],[1590,13],[1620,13],[1650,13],[1680,13],[1722,13],[1763,13],[1804,13],[1845,13],[1894,13],[1924,13],[1954,13],[1984,13],[2036,13],[2068,13],[2100,13],[2132,13],[2187,13],[2221,13],[2255,13],[2289,13],[2338,13],[2377,13],[2416,13],[2462,13],[2512,13],[2668,13]]}}}],["compress",{"_index":2708,"t":{"610":{"position":[[136,8],[419,8]]}}}],["config",{"_index":328,"t":{"38":{"position":[[1,6]]},"46":{"position":[[12,6]]},"129":{"position":[[102,6],[301,6]]},"188":{"position":[[423,6],[457,6],[547,6]]},"192":{"position":[[304,6],[338,6],[428,6]]},"207":{"position":[[382,6]]},"225":{"position":[[542,6],[592,6]]},"235":{"position":[[973,6],[985,6]]},"255":{"position":[[107,6],[328,6]]},"257":{"position":[[98,6],[302,6]]},"259":{"position":[[121,6],[277,6]]},"288":{"position":[[21,6],[102,6],[136,6]]},"391":{"position":[[149,6],[176,6],[268,6]]},"447":{"position":[[295,6],[709,6]]},"458":{"position":[[80,6],[114,6],[337,6]]},"537":{"position":[[81,6],[115,6],[189,6]]},"561":{"position":[[511,6],[545,6],[747,6]]},"615":{"position":[[77,6]]},"668":{"position":[[112,6]]},"686":{"position":[[11,6],[31,6]]},"736":{"position":[[43,6],[77,6],[492,6]]},"750":{"position":[[263,6],[297,6]]},"772":{"position":[[47,6]]},"857":{"position":[[45,6],[79,6],[158,6]]},"884":{"position":[[231,6],[303,6]]},"925":{"position":[[228,6],[262,6],[569,6]]}}}],["configur",{"_index":1476,"t":{"261":{"position":[[633,9]]}}}],["configurecontain",{"_index":387,"t":{"46":{"position":[[206,18]]},"120":{"position":[[223,18]]},"138":{"position":[[545,18]]},"194":{"position":[[682,18]]},"223":{"position":[[848,18]]},"225":{"position":[[1184,18],[1738,18]]},"229":{"position":[[440,18]]},"233":{"position":[[728,18]]},"255":{"position":[[198,18]]},"257":{"position":[[189,18]]},"259":{"position":[[192,18]]},"284":{"position":[[238,18]]},"286":{"position":[[264,18]]},"317":{"position":[[237,18]]},"447":{"position":[[386,18]]},"495":{"position":[[510,18],[888,18]]},"736":{"position":[[361,18]]},"832":{"position":[[115,18],[1403,18]]},"859":{"position":[[894,18]]},"896":{"position":[[146,18]]},"925":{"position":[[369,18]]}}}],["configureplugin",{"_index":821,"t":{"120":{"position":[[275,16]]},"194":{"position":[[733,16]]},"223":{"position":[[947,16]]},"225":{"position":[[1283,16],[1837,16]]},"233":{"position":[[779,16]]},"235":{"position":[[1092,16]]},"284":{"position":[[307,16]]},"286":{"position":[[391,16]]},"458":{"position":[[221,16]]},"495":{"position":[[562,16],[940,16]]},"514":{"position":[[304,16]]},"516":{"position":[[427,16]]},"539":{"position":[[138,16]]},"595":{"position":[[34,16]]},"597":{"position":[[74,16]]},"736":{"position":[[413,16]]},"750":{"position":[[478,16]]},"832":{"position":[[186,16],[1474,16]]},"859":{"position":[[993,16]]},"878":{"position":[[370,16]]},"896":{"position":[[289,16]]},"925":{"position":[[437,16]]}}}],["configurerpcstor",{"_index":975,"t":{"129":{"position":[[192,17]]},"138":{"position":[[616,17]]},"286":{"position":[[67,17],[333,17]]},"447":{"position":[[457,17]]},"514":{"position":[[221,17]]},"516":{"position":[[347,17]]},"896":{"position":[[223,17]]}}}],["configureservic",{"_index":1434,"t":{"235":{"position":[[884,17]]},"261":{"position":[[212,17],[268,17]]},"969":{"position":[[601,17]]}}}],["connect",{"_index":340,"t":{"40":{"position":[[20,10]]},"46":{"position":[[428,10]]},"60":{"position":[[401,7]]},"66":{"position":[[457,7]]},"69":{"position":[[356,7]]},"80":{"position":[[237,7],[1215,7],[1918,7]]},"86":{"position":[[274,7]]},"102":{"position":[[144,7]]},"132":{"position":[[237,7]]},"134":{"position":[[3603,7]]},"138":{"position":[[724,7]]},"169":{"position":[[188,7]]},"171":{"position":[[190,7]]},"188":{"position":[[10,10],[21,9],[103,9],[566,7]]},"192":{"position":[[447,7]]},"194":{"position":[[781,7]]},"223":{"position":[[46,10],[57,9],[137,10],[188,9]]},"225":{"position":[[894,10],[945,9],[1448,10],[1499,9]]},"317":{"position":[[366,7]]},"319":{"position":[[579,7]]},"393":{"position":[[107,7]]},"495":{"position":[[1015,7]]},"617":{"position":[[130,10],[186,10]]},"857":{"position":[[179,7]]}}}],["connectasync",{"_index":1210,"t":{"175":{"position":[[147,12]]}}}],["connectw",{"_index":1543,"t":{"286":{"position":[[545,9],[798,9]]}}}],["consol",{"_index":597,"t":{"60":{"position":[[181,7],[224,7],[412,7]]},"66":{"position":[[237,7],[280,7],[468,7]]},"69":{"position":[[367,7],[525,7],[665,7]]},"75":{"position":[[163,7]]},"80":{"position":[[248,7],[401,7],[536,7],[698,7],[943,7],[1226,7],[1361,7],[1589,7],[1929,7],[2007,7],[2098,7],[2191,7],[2373,7]]},"91":{"position":[[438,7],[461,7]]},"102":{"position":[[355,7]]},"120":{"position":[[875,7]]},"159":{"position":[[551,7],[950,7]]},"188":{"position":[[360,7]]},"192":{"position":[[241,7]]},"207":{"position":[[138,7],[314,7]]},"225":{"position":[[329,7]]},"284":{"position":[[539,7],[572,7]]},"286":{"position":[[458,7],[497,7]]},"290":{"position":[[220,7],[311,7],[406,7],[478,7],[579,7]]},"319":{"position":[[590,7],[654,7]]},"340":{"position":[[975,7],[1030,7]]},"411":{"position":[[293,7]]},"413":{"position":[[383,7]]},"458":{"position":[[354,7]]},"495":{"position":[[1309,7],[1413,7],[1501,7]]},"512":{"position":[[765,7],[891,7],[976,7],[1148,7]]},"528":{"position":[[966,7],[1664,7]]},"537":{"position":[[215,7]]},"561":{"position":[[371,7]]},"641":{"position":[[357,7]]},"643":{"position":[[241,7]]},"663":{"position":[[403,7]]},"672":{"position":[[1071,7]]},"674":{"position":[[976,7]]},"727":{"position":[[369,7],[447,7],[669,7],[775,7],[837,7],[1040,7],[1299,7],[1687,7],[1976,7]]},"843":{"position":[[117,7]]},"849":{"position":[[135,7]]},"896":{"position":[[409,7],[446,7],[518,7]]},"932":{"position":[[505,7],[534,7]]},"971":{"position":[[162,7]]}}}],["consoleact",{"_index":707,"t":{"91":{"position":[[0,13],[14,13],[34,13],[69,13],[98,13],[181,13],[243,13],[316,13],[375,13],[420,13]]},"495":{"position":[[195,13],[209,13],[229,13],[1060,13],[1089,13],[1116,13],[1177,13],[1355,13],[1395,13],[1458,13]]}}}],["consoleaction_onexcept",{"_index":712,"t":{"91":{"position":[[98,25]]},"495":{"position":[[1089,25],[1458,25]]}}}],["consoleapp2",{"_index":2223,"t":{"455":{"position":[[573,11],[664,11]]}}}],["consolelogg",{"_index":1534,"t":{"284":{"position":[[285,13]]},"286":{"position":[[311,13]]},"479":{"position":[[85,13]]},"481":{"position":[[57,13]]},"872":{"position":[[610,13]]},"896":{"position":[[193,13]]},"925":{"position":[[415,13]]}}}],["constructor",{"_index":2557,"t":{"546":{"position":[[159,11]]},"556":{"position":[[2546,11],[3166,11]]}}}],["cont",{"_index":1568,"t":{"290":{"position":[[214,4]]},"323":{"position":[[91,4]]}}}],["contain",{"_index":2550,"t":{"542":{"position":[[200,9]]},"548":{"position":[[80,9],[90,9],[106,9],[119,9],[175,9]]},"550":{"position":[[144,9],[154,9],[170,9],[183,9],[236,9],[289,9],[342,9],[398,9]]},"552":{"position":[[165,9],[175,9],[191,9],[204,9],[257,9],[310,9],[363,9],[416,9],[469,9],[525,9],[1461,9],[1471,9],[1487,9],[1500,9],[1545,9],[1607,9]]},"554":{"position":[[333,9],[343,9],[359,9],[372,9],[425,9],[463,9],[575,9]]},"878":{"position":[[55,9]]},"882":{"position":[[274,9]]},"891":{"position":[[243,9],[263,9]]}}}],["contentlen",{"_index":2253,"t":{"465":{"position":[[229,10]]}}}],["contentlength",{"_index":1717,"t":{"343":{"position":[[94,13]]}}}],["context",{"_index":838,"t":{"120":{"position":[[770,7],[822,7],[933,7],[983,7],[1059,7],[1090,7],[2144,7],[2259,7]]},"286":{"position":[[956,7]]},"463":{"position":[[157,7],[197,7],[273,7]]},"465":{"position":[[157,7],[213,7],[281,7],[418,7],[698,7]]}}}],["converttocod",{"_index":2168,"t":{"447":{"position":[[943,13],[1165,13]]},"932":{"position":[[460,13]]}}}],["copi",{"_index":1810,"t":{"365":{"position":[[1322,4]]},"470":{"position":[[281,4]]}}}],["core",{"_index":2551,"t":{"542":{"position":[[229,4]]},"702":{"position":[[18,4]]},"806":{"position":[[414,4],[435,4]]},"872":{"position":[[505,4],[536,4]]},"896":{"position":[[381,4]]}}}],["count",{"_index":1820,"t":{"365":{"position":[[1640,5],[2011,5]]},"507":{"position":[[498,5],[684,5],[1071,5],[1127,5],[1155,5],[1290,5],[1365,5],[1393,5]]},"523":{"position":[[225,5],[2578,5]]}}}],["crc",{"_index":1649,"t":{"308":{"position":[[2427,3],[2451,3],[2472,3],[2508,3],[2540,3]]},"600":{"position":[[35,3],[100,3]]},"702":{"position":[[2295,3]]}}}],["crc1",{"_index":2685,"t":{"600":{"position":[[17,4]]}}}],["crc16",{"_index":2689,"t":{"600":{"position":[[47,5],[104,5]]},"702":{"position":[[684,5],[1877,5],[1894,5],[2919,5]]},"820":{"position":[[272,5]]}}}],["createchannel",{"_index":2811,"t":{"672":{"position":[[765,13]]},"674":{"position":[[664,13]]},"836":{"position":[[337,13]]}}}],["createclientfactori",{"_index":2472,"t":{"528":{"position":[[158,19],[583,19],[1297,19]]}}}],["createloopact",{"_index":2489,"t":{"528":{"position":[[883,16],[1581,16]]},"727":{"position":[[1574,16]]},"832":{"position":[[2125,16]]}}}],["createproxi",{"_index":2215,"t":{"455":{"position":[[434,11]]}}}],["createtcptoucerpcservic",{"_index":2971,"t":{"727":{"position":[[63,24]]}}}],["createtcptouchrpccli",{"_index":2990,"t":{"727":{"position":[[1133,23]]}}}],["createtest",{"_index":1699,"t":{"340":{"position":[[475,12]]}}}],["createwebapicli",{"_index":648,"t":{"69":{"position":[[252,18],[424,18]]}}}],["createxmlrpcrpcpars",{"_index":3392,"t":{"930":{"position":[[59,21]]},"932":{"position":[[190,21]]}}}],["cref",{"_index":1004,"t":{"134":{"position":[[290,4],[353,4],[430,4],[626,4],[689,4],[766,4],[1128,4],[1191,4],[1268,4],[2320,4],[2383,4],[2460,4]]},"301":{"position":[[397,4],[435,4],[502,4],[539,4],[602,4],[639,4]]},"431":{"position":[[77,4],[117,4]]},"734":{"position":[[856,4]]}}}],["cs",{"_index":991,"t":{"134":{"position":[[77,2]]},"447":{"position":[[175,2],[244,2],[574,2],[787,2],[997,2]]}}}],["csdn",{"_index":2332,"t":{"495":{"position":[[56,4]]}}}],["csharp",{"_index":3044,"t":{"756":{"position":[[27,6]]}}}],["csproj",{"_index":3265,"t":{"866":{"position":[[122,6]]}}}],["ctorshouldbeok",{"_index":2562,"t":{"548":{"position":[[61,14]]}}}],["custombetweenanddatahandlingadapt",{"_index":1516,"t":{"272":{"position":[[97,35],[696,35],[820,35]]}}}],["custombigfixedheaderdatahandlingadapt",{"_index":563,"t":{"57":{"position":[[974,39],[1152,39]]}}}],["customdatahandlingadapt",{"_index":268,"t":{"32":{"position":[[172,25]]},"57":{"position":[[1480,25]]},"272":{"position":[[1371,25]]},"295":{"position":[[18,25]]},"301":{"position":[[77,25],[269,25],[2435,25]]},"308":{"position":[[1892,25]]},"347":{"position":[[2053,25]]},"357":{"position":[[104,25]]}}}],["customfixedheaderdatahandlingadapt",{"_index":1640,"t":{"308":{"position":[[98,36],[1338,36],[1465,36]]},"489":{"position":[[69,36]]},"702":{"position":[[171,36]]}}}],["customunfixedheaderdatahandlingadapt",{"_index":1718,"t":{"343":{"position":[[124,38]]},"347":{"position":[[98,38],[1671,38],[1767,38]]}}}],["d",{"_index":853,"t":{"120":{"position":[[1033,1]]},"268":{"position":[[133,1]]},"370":{"position":[[389,1]]},"463":{"position":[[247,1]]},"832":{"position":[[1895,1]]},"894":{"position":[[669,1]]}}}],["d1d1d1d1d1d1d1",{"_index":3459,"t":{"969":{"position":[[568,14]]}}}],["d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1",{"_index":3452,"t":{"969":{"position":[[70,36]]}}}],["data",{"_index":1696,"t":{"340":{"position":[[393,4],[678,4],[715,4],[929,4]]},"350":{"position":[[72,4]]},"365":{"position":[[268,4],[423,4],[527,4],[682,4],[786,4],[941,4],[1047,4],[1202,4],[2128,4],[2340,4],[2416,4],[2630,4],[2706,4],[2920,4],[2998,4],[3212,4]]},"429":{"position":[[29,4],[139,4]]},"470":{"position":[[535,4],[592,4],[601,4]]},"489":{"position":[[506,4],[653,4],[985,4],[1009,4],[1071,4],[1103,4],[1323,4],[1376,4],[1434,4]]},"495":{"position":[[1273,4],[1279,4]]},"600":{"position":[[63,4],[110,4],[119,4]]},"610":{"position":[[32,4],[78,4],[155,4],[162,4],[447,4],[547,4]]},"632":{"position":[[185,4],[241,4],[438,4]]},"672":{"position":[[880,4],[917,4]]},"727":{"position":[[1167,4],[1225,4],[1271,4]]},"763":{"position":[[7,4]]},"765":{"position":[[7,4]]},"767":{"position":[[121,4]]}}}],["dataadaptertest",{"_index":1697,"t":{"340":{"position":[[430,17],[457,17]]}}}],["databuff",{"_index":1788,"t":{"361":{"position":[[2119,10],[2235,10],[2301,10],[2457,10],[2669,10]]}}}],["datafram",{"_index":1564,"t":{"290":{"position":[[178,9],[254,9],[331,9],[389,9],[441,9],[517,9]]},"292":{"position":[[326,9]]}}}],["datahandlingadapt",{"_index":438,"t":{"48":{"position":[[257,19]]},"184":{"position":[[209,19]]},"218":{"position":[[209,19]]},"357":{"position":[[21,19]]},"361":{"position":[[10,19],[72,19]]}}}],["datalen",{"_index":1764,"t":{"361":{"position":[[631,7],[678,7],[838,7],[936,7]]},"365":{"position":[[1573,7],[1624,7],[1653,7],[1813,7],[1911,7]]}}}],["datalock",{"_index":1734,"t":{"350":{"position":[[35,10],[146,10]]},"872":{"position":[[768,8]]}}}],["datasecur",{"_index":1735,"t":{"350":{"position":[[48,12],[122,12]]},"872":{"position":[[779,12]]}}}],["datatyp",{"_index":1627,"t":{"301":{"position":[[1386,8],[1756,8],[2161,8],[2197,8]]},"308":{"position":[[620,8],[688,8],[712,8],[1229,8]]},"489":{"position":[[460,8],[469,8],[848,8],[860,8],[1056,8],[1303,8],[1404,8]]},"491":{"position":[[416,8],[427,8],[674,8],[685,8]]},"493":{"position":[[1209,8],[1221,8]]},"495":{"position":[[1253,8],[1264,8]]}}}],["datetim",{"_index":2056,"t":{"436":{"position":[[167,8],[1010,8]]},"507":{"position":[[1543,8],[1960,8],[2004,8]]},"523":{"position":[[849,8],[1282,8]]}}}],["debug",{"_index":2156,"t":{"447":{"position":[[525,5]]},"473":{"position":[[122,5]]},"548":{"position":[[465,5],[556,5]]},"550":{"position":[[784,5],[875,5]]},"552":{"position":[[1252,5],[1343,5],[1877,5],[1968,5]]},"556":{"position":[[131,5],[222,5],[323,5],[414,5],[667,5],[758,5],[1137,5],[1228,5],[1469,5],[1560,5],[2051,5],[2142,5],[2364,5],[2455,5],[2984,5],[3075,5],[3628,5],[3719,5]]}}}],["decompress",{"_index":2710,"t":{"610":{"position":[[207,10],[517,10]]}}}],["decompressdata2",{"_index":2709,"t":{"610":{"position":[[184,15]]}}}],["decryptd",{"_index":1740,"t":{"350":{"position":[[135,10]]}}}],["deepsearch",{"_index":2203,"t":{"451":{"position":[[290,10]]}}}],["default",{"_index":200,"t":{"25":{"position":[[260,7]]},"120":{"position":[[322,7]]},"134":{"position":[[568,7],[915,7],[1413,7],[1911,7],[2642,7],[3144,7]]},"290":{"position":[[695,7]]},"323":{"position":[[252,7]]},"489":{"position":[[810,7]]},"606":{"position":[[95,7]]},"648":{"position":[[289,7]]},"672":{"position":[[717,7]]},"674":{"position":[[589,7]]},"684":{"position":[[649,7]]},"727":{"position":[[658,7],[1661,7]]},"767":{"position":[[151,7]]},"830":{"position":[[666,7]]},"832":{"position":[[2213,7]]},"868":{"position":[[247,7]]},"969":{"position":[[154,7],[546,7]]}}}],["defaultendiantyp",{"_index":3067,"t":{"767":{"position":[[27,17],[78,17]]}}}],["defaulthttpserviceplugin",{"_index":832,"t":{"120":{"position":[[438,24]]}}}],["defaultsend",{"_index":1369,"t":{"196":{"position":[[78,11]]},"241":{"position":[[476,11]]}}}],["defaultserializationselector",{"_index":2830,"t":{"684":{"position":[[150,28]]}}}],["delay",{"_index":2986,"t":{"727":{"position":[[760,5]]}}}],["delayinvok",{"_index":2786,"t":{"663":{"position":[[229,11]]}}}],["delayrun",{"_index":2984,"t":{"727":{"position":[[505,8]]}}}],["delaysend",{"_index":1308,"t":{"184":{"position":[[1013,11],[1037,11],[1792,11],[1816,11]]},"218":{"position":[[1013,11],[1037,11],[1792,11],[1816,11]]},"876":{"position":[[159,11]]}}}],["delet",{"_index":814,"t":{"118":{"position":[[90,6]]},"120":{"position":[[593,6]]}}}],["demo",{"_index":1473,"t":{"261":{"position":[[546,4],[861,4]]}}}],["depend",{"_index":2545,"t":{"542":{"position":[[150,10]]}}}],["dependencyextens",{"_index":1911,"t":{"376":{"position":[[689,20]]},"491":{"position":[[102,20],[259,20]]},"493":{"position":[[485,20],[583,20],[866,20],[962,20]]}}}],["dependencyinject",{"_index":2325,"t":{"493":{"position":[[174,16]]},"550":{"position":[[29,16]]},"552":{"position":[[2,16],[851,16]]},"556":{"position":[[848,16],[1650,16],[2590,16],[3234,16]]},"969":{"position":[[245,19]]}}}],["dependencymethod",{"_index":2577,"t":{"552":{"position":[[900,16]]},"556":{"position":[[1699,16],[2632,16],[3276,16]]}}}],["dependencyobject",{"_index":1902,"t":{"376":{"position":[[153,16],[212,16]]},"889":{"position":[[138,16]]}}}],["dependencyparamterinject",{"_index":2568,"t":{"550":{"position":[[2,24],[74,24],[633,24],[703,24]]},"552":{"position":[[935,24],[985,24],[1790,24]]},"556":{"position":[[1318,24],[1388,24],[1734,24],[1784,24],[2667,24],[2717,24],[3311,24],[3361,24]]}}}],["dependencyproperti",{"_index":1907,"t":{"376":{"position":[[444,18],[489,18],[772,18],[817,18]]},"491":{"position":[[148,18],[199,18]]}}}],["dependencytyp",{"_index":2556,"t":{"546":{"position":[[129,14],[144,14],[173,14]]},"556":{"position":[[2516,14],[2531,14],[3136,14],[3151,14],[3180,14]]}}}],["descript",{"_index":949,"t":{"127":{"position":[[183,11],[459,11]]},"455":{"position":[[717,11]]},"641":{"position":[[142,11]]},"643":{"position":[[100,11]]},"650":{"position":[[1,11]]},"663":{"position":[[150,11]]},"672":{"position":[[156,11]]},"674":{"position":[[128,11]]}}}],["deseri",{"_index":2834,"t":{"684":{"position":[[688,11]]}}}],["deserializeparamet",{"_index":2827,"t":{"684":{"position":[[45,20],[475,20],[745,20]]}}}],["detail",{"_index":2337,"t":{"495":{"position":[[85,7]]}}}],["di",{"_index":2548,"t":{"542":{"position":[[174,2]]}}}],["dic",{"_index":2382,"t":{"507":{"position":[[1325,3],[1407,3],[1490,3]]}}}],["dic1",{"_index":2065,"t":{"436":{"position":[[400,4],[1491,4],[1534,4],[1558,4],[1582,4]]},"523":{"position":[[439,4],[1859,4],[1908,4],[1938,4],[1968,4]]}}}],["dic2",{"_index":2066,"t":{"436":{"position":[[450,4],[1606,4],[1652,4],[1678,4],[1704,4]]},"523":{"position":[[489,4],[1998,4],[2050,4],[2082,4],[2114,4]]}}}],["dic3",{"_index":2067,"t":{"436":{"position":[[503,4],[1730,4],[1779,4],[1807,4],[1835,4]]},"523":{"position":[[542,4],[2146,4],[2201,4],[2235,4],[2269,4]]}}}],["dic4",{"_index":2068,"t":{"436":{"position":[[550,4],[1863,4],[1906,4],[1939,4],[1972,4]]},"523":{"position":[[589,4],[2303,4],[2352,4],[2391,4],[2430,4]]}}}],["dictionari",{"_index":2064,"t":{"436":{"position":[[379,10],[426,10],[476,10],[529,10],[1502,10],[1617,10],[1741,10],[1874,10]]},"507":{"position":[[193,10],[1335,10],[1899,10]]},"523":{"position":[[418,10],[465,10],[515,10],[568,10],[1870,10],[2009,10],[2157,10],[2314,10]]}}}],["dirpath",{"_index":2655,"t":{"581":{"position":[[241,7]]}}}],["disconnect",{"_index":409,"t":{"46":{"position":[[405,12]]},"188":{"position":[[156,12]]},"223":{"position":[[238,12]]},"225":{"position":[[995,12],[1549,12]]},"595":{"position":[[176,10]]},"870":{"position":[[157,13]]}}}],["disopos",{"_index":2621,"t":{"561":{"position":[[485,8]]}}}],["dispos",{"_index":1100,"t":{"153":{"position":[[90,7],[202,7],[306,7]]},"159":{"position":[[633,7],[942,7]]},"361":{"position":[[2927,7]]},"365":{"position":[[480,7],[739,7],[998,7],[1259,7]]},"413":{"position":[[100,7]]},"493":{"position":[[554,7],[935,7]]},"634":{"position":[[15,7],[40,7]]},"672":{"position":[[643,7]]},"674":{"position":[[858,7]]},"727":{"position":[[1017,7],[1674,7]]},"832":{"position":[[2229,7]]}}}],["div",{"_index":866,"t":{"120":{"position":[[1516,3],[2060,3]]}}}],["dll",{"_index":2098,"t":{"440":{"position":[[311,3]]},"444":{"position":[[264,3],[645,3]]},"447":{"position":[[1242,3]]},"574":{"position":[[23,3]]}}}],["doctyp",{"_index":860,"t":{"120":{"position":[[1216,7]]}}}],["doubl",{"_index":2058,"t":{"436":{"position":[[200,6]]},"507":{"position":[[128,6]]},"523":{"position":[[882,6]]}}}],["down",{"_index":1799,"t":{"365":{"position":[[106,4],[507,4],[1025,4],[2388,4],[2968,4]]}}}],["down_go_send",{"_index":1805,"t":{"365":{"position":[[507,12]]}}}],["down_go_splicingsend",{"_index":1825,"t":{"365":{"position":[[2388,20]]}}}],["down_hold_send",{"_index":1807,"t":{"365":{"position":[[1025,14]]}}}],["down_hold_splicingsend",{"_index":1827,"t":{"365":{"position":[[2968,22]]}}}],["download",{"_index":2949,"t":{"718":{"position":[[21,8]]}}}],["downloadfil",{"_index":3351,"t":{"894":{"position":[[547,12]]}}}],["dropmulticastgroup",{"_index":3227,"t":{"841":{"position":[[76,18]]}}}],["e",{"_index":353,"t":{"40":{"position":[[226,1],[350,1]]},"42":{"position":[[157,1],[252,1]]},"120":{"position":[[759,1],[768,1],[820,1],[902,1],[931,1],[981,1],[1057,1],[1088,1],[2142,1],[2257,1],[2367,1]]},"146":{"position":[[251,1],[260,1],[292,1],[345,1]]},"166":{"position":[[272,1],[492,1],[540,1],[578,1]]},"188":{"position":[[125,1],[181,1]]},"194":{"position":[[299,1],[325,1],[337,1],[394,1],[434,1],[451,1],[524,1]]},"223":{"position":[[159,1],[209,1],[262,1]]},"225":{"position":[[694,1],[715,1],[752,1],[818,1],[916,1],[966,1],[1019,1],[1470,1],[1520,1],[1573,1]]},"233":{"position":[[305,1],[331,1],[343,1],[400,1],[440,1],[457,1],[530,1]]},"235":{"position":[[558,1],[622,1],[710,1],[736,1],[748,1],[805,1],[845,1]]},"252":{"position":[[272,1],[492,1],[540,1],[578,1]]},"290":{"position":[[163,1],[176,1],[252,1],[329,1],[387,1],[439,1],[515,1],[951,1],[989,1],[1244,1],[1299,1]]},"292":{"position":[[324,1]]},"323":{"position":[[47,1],[63,1]]},"463":{"position":[[146,1],[155,1],[195,1],[271,1],[321,1]]},"465":{"position":[[146,1],[155,1],[211,1],[279,1],[416,1],[696,1],[833,1]]},"493":{"position":[[396,1],[713,1],[809,1],[842,1],[1102,1],[1111,1],[1285,1]]},"530":{"position":[[283,1],[292,1],[327,1],[364,1],[417,1]]},"537":{"position":[[445,1],[481,1],[907,1],[1084,1]]},"570":{"position":[[180,1]]},"574":{"position":[[398,1]]},"617":{"position":[[208,1],[216,1]]},"630":{"position":[[413,1],[422,1],[446,1],[508,1]]},"693":{"position":[[183,1],[192,1],[227,1],[264,1],[317,1]]},"727":{"position":[[135,1],[143,1],[214,1],[276,1],[327,1],[913,1],[945,1],[961,1],[1008,1],[1084,1]]},"774":{"position":[[183,1],[192,1],[218,1],[254,1],[283,1],[328,1],[348,1],[376,1],[431,1]]},"780":{"position":[[294,1],[303,1],[334,1],[420,1],[443,1],[503,1]]},"830":{"position":[[308,1]]},"832":{"position":[[540,1],[545,1],[649,1],[672,1],[794,1],[817,1],[883,1],[904,1],[926,1],[1032,1],[1186,1],[1265,1]]},"836":{"position":[[233,1],[242,1],[277,1],[312,1],[354,1],[407,1]]},"872":{"position":[[948,1]]},"878":{"position":[[487,1],[564,1],[585,1],[640,1],[666,1],[732,1],[753,1],[780,1]]}}}],["easyact",{"_index":2983,"t":{"727":{"position":[[494,10]]},"872":{"position":[[796,10]]}}}],["easylogg",{"_index":390,"t":{"46":{"position":[[273,10]]},"317":{"position":[[304,10]]}}}],["easytask",{"_index":3298,"t":{"872":{"position":[[808,8]]}}}],["ee",{"_index":3281,"t":{"872":{"position":[[263,2]]}}}],["elapsedtimerpcserv",{"_index":2784,"t":{"663":{"position":[[109,20]]}}}],["emptylogg",{"_index":3291,"t":{"872":{"position":[[627,11]]}}}],["encod",{"_index":573,"t":{"57":{"position":[[1672,8]]},"159":{"position":[[490,8],[835,8]]},"188":{"position":[[299,8]]},"192":{"position":[[180,8]]},"207":{"position":[[162,8]]},"223":{"position":[[364,8]]},"225":{"position":[[268,8]]},"229":{"position":[[183,8]]},"272":{"position":[[1036,8],[1121,8]]},"301":{"position":[[2599,8]]},"308":{"position":[[2078,8]]},"347":{"position":[[1130,8],[1308,8],[2243,8]]},"406":{"position":[[226,8]]},"422":{"position":[[239,8]]},"470":{"position":[[542,8]]},"489":{"position":[[1347,8]]},"495":{"position":[[1286,8]]},"512":{"position":[[1109,8]]},"745":{"position":[[239,8]]},"758":{"position":[[50,8]]},"780":{"position":[[396,8]]},"845":{"position":[[261,8]]},"851":{"position":[[298,8]]},"857":{"position":[[515,8],[582,8],[745,8]]},"859":{"position":[[409,8],[471,8],[634,8]]},"980":{"position":[[207,8]]}}}],["encryptd",{"_index":1736,"t":{"350":{"position":[[61,10]]}}}],["end",{"_index":2918,"t":{"702":{"position":[[1957,3],[2301,3],[2935,3]]}}}],["endcod",{"_index":1522,"t":{"272":{"position":[[541,7],[745,7],[1110,7]]}}}],["endian",{"_index":3052,"t":{"761":{"position":[[10,6]]}}}],["endiantyp",{"_index":3068,"t":{"767":{"position":[[98,10]]}}}],["endif",{"_index":2159,"t":{"447":{"position":[[657,5]]}}}],["endpoint",{"_index":1490,"t":{"261":{"position":[[1038,9],[1053,9]]},"809":{"position":[[206,8],[292,8],[301,8],[404,8],[413,8]]},"816":{"position":[[173,8]]}}}],["enterpris",{"_index":3453,"t":{"969":{"position":[[143,10],[535,10]]},"971":{"position":[[115,10]]}}}],["enum",{"_index":2314,"t":{"489":{"position":[[1399,4]]}}}],["env",{"_index":1479,"t":{"261":{"position":[[688,3],[699,3]]}}}],["equal",{"_index":213,"t":{"25":{"position":[[440,5],[511,5]]},"142":{"position":[[283,6]]}}}],["equals",{"_index":1107,"t":{"153":{"position":[[173,9],[277,9]]}}}],["error",{"_index":2278,"t":{"473":{"position":[[138,5]]},"481":{"position":[[150,5],[157,5]]}}}],["estel",{"_index":1889,"t":{"370":{"position":[[414,5]]}}}],["eventbu",{"_index":1932,"t":{"389":{"position":[[0,8]]},"950":{"position":[[57,8]]}}}],["eventnam",{"_index":1954,"t":{"393":{"position":[[368,9]]}}}],["eventsend",{"_index":1951,"t":{"393":{"position":[[265,11],[277,11],[321,11],[356,11]]}}}],["everyon",{"_index":1946,"t":{"391":{"position":[[405,8]]}}}],["ex",{"_index":2262,"t":{"465":{"position":[[774,2],[804,2]]},"491":{"position":[[494,2],[524,2],[752,2],[782,2]]},"537":{"position":[[731,2],[767,2]]},"539":{"position":[[305,2],[341,2]]},"971":{"position":[[156,2],[180,2]]}}}],["exc",{"_index":3011,"t":{"736":{"position":[[663,3]]}}}],["exccommand",{"_index":3008,"t":{"734":{"position":[[898,10]]}}}],["except",{"_index":1003,"t":{"134":{"position":[[280,9],[327,9],[343,9],[404,9],[420,9],[443,9],[460,9],[616,9],[663,9],[679,9],[740,9],[756,9],[779,9],[796,9],[1118,9],[1165,9],[1181,9],[1242,9],[1258,9],[1281,9],[1298,9],[2310,9],[2357,9],[2373,9],[2434,9],[2450,9],[2473,9],[2490,9]]},"465":{"position":[[764,9],[794,9]]},"473":{"position":[[209,9],[219,9]]},"491":{"position":[[484,9],[514,9],[742,9],[772,9]]},"495":{"position":[[1484,9]]},"537":{"position":[[721,9],[757,9]]},"539":{"position":[[295,9],[331,9]]},"548":{"position":[[519,9],[529,9]]},"550":{"position":[[838,9],[848,9]]},"552":{"position":[[1306,9],[1316,9],[1931,9],[1941,9]]},"556":{"position":[[185,9],[195,9],[377,9],[387,9],[721,9],[731,9],[1191,9],[1201,9],[1523,9],[1533,9],[2105,9],[2115,9],[2418,9],[2428,9],[3038,9],[3048,9],[3682,9],[3692,9]]},"648":{"position":[[929,9],[939,9],[1170,9]]},"734":{"position":[[846,9],[862,9],[875,9],[923,9]]},"971":{"position":[[146,9]]}}}],["execut",{"_index":2751,"t":{"648":{"position":[[90,9],[435,9],[512,8],[759,8]]}}}],["executexcept",{"_index":2757,"t":{"648":{"position":[[835,15],[1111,15]]}}}],["extens",{"_index":3456,"t":{"969":{"position":[[234,10]]}}}],["f",{"_index":2924,"t":{"705":{"position":[[50,1]]}}}],["fact",{"_index":2561,"t":{"548":{"position":[[43,4]]},"550":{"position":[[103,4]]},"552":{"position":[[126,4],[1413,4]]},"554":{"position":[[294,4]]}}}],["fals",{"_index":435,"t":{"48":{"position":[[209,5]]},"50":{"position":[[290,5]]},"127":{"position":[[399,5],[675,5]]},"134":{"position":[[1543,5],[2041,5],[2739,5],[3241,5]]},"153":{"position":[[183,5],[287,5]]},"159":{"position":[[917,5]]},"184":{"position":[[810,5],[1989,5]]},"218":{"position":[[810,5],[1989,5]]},"308":{"position":[[1078,5]]},"340":{"position":[[700,5]]},"347":{"position":[[847,5],[1590,5],[1614,5]]},"361":{"position":[[134,5],[184,5]]},"455":{"position":[[247,5]]},"470":{"position":[[89,5],[120,5]]},"489":{"position":[[205,5],[688,5],[902,5]]},"491":{"position":[[538,5],[796,5]]},"521":{"position":[[520,5]]},"554":{"position":[[519,5]]},"641":{"position":[[456,5]]},"643":{"position":[[340,5]]},"663":{"position":[[444,5]]},"702":{"position":[[310,5],[2676,5],[2993,5]]},"774":{"position":[[240,5]]},"809":{"position":[[159,5]]}}}],["famili",{"_index":883,"t":{"120":{"position":[[1676,6]]}}}],["fast",{"_index":2073,"t":{"436":{"position":[[2000,4]]},"792":{"position":[[173,4]]},"870":{"position":[[113,4]]},"874":{"position":[[61,4]]},"884":{"position":[[195,4]]}}}],["fastbinari",{"_index":2818,"t":{"679":{"position":[[25,10],[78,10]]},"681":{"position":[[282,10]]}}}],["fastbinaryconvert",{"_index":2034,"t":{"431":{"position":[[83,19],[197,19]]}}}],["fastbinarydeseri",{"_index":2029,"t":{"429":{"position":[[109,21]]}}}],["fastbinaryformatt",{"_index":2047,"t":{"431":{"position":[[862,19]]}}}],["fastbinaryseri",{"_index":2028,"t":{"429":{"position":[[53,19]]}}}],["fastconvert",{"_index":2044,"t":{"431":{"position":[[705,13]]}}}],["feedbacktyp",{"_index":2769,"t":{"655":{"position":[[89,12],[104,12],[144,12],[159,12],[197,12],[212,12]]},"681":{"position":[[166,12],[181,12]]},"686":{"position":[[229,12],[244,12]]}}}],["file",{"_index":849,"t":{"120":{"position":[[961,4]]},"447":{"position":[[531,4]]},"463":{"position":[[185,4]]},"832":{"position":[[249,4],[1382,4]]}}}],["filecli",{"_index":2856,"t":{"691":{"position":[[107,10],[285,10]]}}}],["fileinfo",{"_index":2860,"t":{"691":{"position":[[325,8]]},"878":{"position":[[587,8],[755,8]]}}}],["filelogg",{"_index":392,"t":{"46":{"position":[[303,10]]},"317":{"position":[[334,10]]},"479":{"position":[[105,10]]},"481":{"position":[[77,10]]},"880":{"position":[[42,10]]},"884":{"position":[[62,10]]}}}],["filenam",{"_index":2009,"t":{"415":{"position":[[224,8]]},"465":{"position":[[588,8]]},"878":{"position":[[596,8],[764,8]]}}}],["fileoper",{"_index":2482,"t":{"528":{"position":[[711,12],[922,12],[990,12],[1016,12],[1120,12],[1425,12],[1620,12],[1688,12],[1714,12],[1817,12]]},"830":{"position":[[217,12],[230,12]]},"832":{"position":[[1701,12],[1714,12],[1733,12],[1959,12],[2168,12],[2267,12],[2294,12],[2414,12]]}}}],["fileoperationeventarg",{"_index":3204,"t":{"832":{"position":[[517,22]]}}}],["filepool",{"_index":1988,"t":{"409":{"position":[[103,8]]},"411":{"position":[[1,8],[166,8]]},"413":{"position":[[1,8],[188,8]]},"415":{"position":[[32,8],[123,8],[200,8]]},"878":{"position":[[74,8]]},"884":{"position":[[243,8]]}}}],["fileservic",{"_index":2507,"t":{"530":{"position":[[774,11],[920,11]]}}}],["filestoragestream",{"_index":3319,"t":{"878":{"position":[[84,17]]}}}],["filestream",{"_index":2973,"t":{"727":{"position":[[202,10]]}}}],["filetransf",{"_index":3190,"t":{"828":{"position":[[221,15],[237,14],[294,14]]},"830":{"position":[[95,15],[154,14],[288,15]]}}}],["filetransferstatuseventarg",{"_index":3206,"t":{"832":{"position":[[766,27]]}}}],["filter",{"_index":1619,"t":{"301":{"position":[[967,6]]}}}],["filterresult",{"_index":1590,"t":{"297":{"position":[[8,12],[81,12],[184,12]]},"301":{"position":[[403,12],[545,12],[608,12],[954,12],[1127,12],[1576,12],[1881,12]]}}}],["fin",{"_index":1574,"t":{"290":{"position":[[399,3]]}}}],["final",{"_index":1793,"t":{"361":{"position":[[2907,7]]},"365":{"position":[[460,7],[719,7],[978,7],[1239,7]]}}}],["firstordefault",{"_index":1060,"t":{"142":{"position":[[261,14]]}}}],["fixedheaderpackageadapt",{"_index":263,"t":{"32":{"position":[[103,25]]},"340":{"position":[[492,25]]},"406":{"position":[[430,25]]},"470":{"position":[[0,25],[40,25]]}}}],["fixedheadertyp",{"_index":1977,"t":{"406":{"position":[[460,15],[477,15]]},"750":{"position":[[11,15],[135,15],[412,15],[565,15]]},"758":{"position":[[109,15]]}}}],["fixedsizepackageadapt",{"_index":2019,"t":{"422":{"position":[[442,23]]}}}],["flag",{"_index":3163,"t":{"820":{"position":[[190,4]]},"830":{"position":[[490,5]]},"832":{"position":[[1780,5]]}}}],["font",{"_index":880,"t":{"120":{"position":[[1655,4],[1671,4],[1792,4],[1936,4]]}}}],["foreach",{"_index":1051,"t":{"142":{"position":[[10,7]]},"223":{"position":[[580,7]]},"292":{"position":[[276,7]]},"365":{"position":[[1586,7],[1927,7]]},"465":{"position":[[460,7]]},"507":{"position":[[506,7],[692,7]]}}}],["fortest",{"_index":3463,"t":{"971":{"position":[[71,7],[126,7]]}}}],["frameno",{"_index":2896,"t":{"702":{"position":[[1294,7],[2438,7]]}}}],["frametyp",{"_index":2891,"t":{"702":{"position":[[1125,9],[2347,9]]}}}],["framework",{"_index":2956,"t":{"718":{"position":[[160,9]]}}}],["fromfil",{"_index":852,"t":{"120":{"position":[[1022,8]]},"463":{"position":[[236,8]]},"894":{"position":[[658,8]]}}}],["fromjson",{"_index":2410,"t":{"519":{"position":[[118,8]]}}}],["fromresult",{"_index":3353,"t":{"894":{"position":[[739,10],[771,10]]}}}],["fromsecond",{"_index":3211,"t":{"832":{"position":[[1991,11]]}}}],["fromtext",{"_index":844,"t":{"120":{"position":[[839,8]]},"465":{"position":[[729,8]]}}}],["ga",{"_index":722,"t":{"91":{"position":[[335,2]]}}}],["gc",{"_index":3170,"t":{"822":{"position":[[54,2]]}}}],["gener",{"_index":2598,"t":{"556":{"position":[[51,7],[2268,7],[2284,7],[2294,7],[2335,7]]},"608":{"position":[[43,9],[92,9]]}}}],["generatorrpcmethod",{"_index":2225,"t":{"455":{"position":[[751,18]]}}}],["generatorrpcproxi",{"_index":2222,"t":{"455":{"position":[[530,17],[645,17]]}}}],["getal",{"_index":717,"t":{"91":{"position":[[166,6],[338,6],[360,6]]}}}],["getbodi",{"_index":756,"t":{"102":{"position":[[381,7]]}}}],["getbyt",{"_index":1528,"t":{"272":{"position":[[1050,8],[1135,8]]},"347":{"position":[[1144,8]]},"470":{"position":[[556,8]]},"495":{"position":[[1300,8]]},"512":{"position":[[1123,8]]},"758":{"position":[[64,8]]},"763":{"position":[[47,8]]},"765":{"position":[[50,8]]},"767":{"position":[[159,8]]},"845":{"position":[[275,8]]},"851":{"position":[[312,8]]},"857":{"position":[[529,8],[759,8]]},"859":{"position":[[423,8],[648,8]]}}}],["getbyteblock",{"_index":1109,"t":{"153":{"position":[[245,12]]}}}],["getclient",{"_index":1053,"t":{"142":{"position":[[50,10]]},"239":{"position":[[25,10],[91,10]]},"292":{"position":[[262,10]]},"632":{"position":[[74,9]]}}}],["getcomplexobject",{"_index":2440,"t":{"523":{"position":[[1095,16],[2538,16]]}}}],["getcurr",{"_index":2813,"t":{"672":{"position":[[895,10]]},"674":{"position":[[500,10]]}}}],["getdirectoryinfo",{"_index":2654,"t":{"581":{"position":[[224,16]]}}}],["getid",{"_index":1059,"t":{"142":{"position":[[252,6]]},"223":{"position":[[570,6]]},"239":{"position":[[204,6],[296,6]]}}}],["getinfo",{"_index":3334,"t":{"882":{"position":[[263,7]]}}}],["getinst",{"_index":568,"t":{"57":{"position":[[1308,11]]},"272":{"position":[[1203,11]]},"308":{"position":[[1723,11]]},"347":{"position":[[1882,11]]},"489":{"position":[[245,11]]},"702":{"position":[[352,11]]}}}],["getmd5hash",{"_index":2695,"t":{"604":{"position":[[17,10]]}}}],["getmultifilecollect",{"_index":2258,"t":{"465":{"position":[[434,22]]}}}],["getmyproperti",{"_index":1914,"t":{"376":{"position":[[1395,13],[1609,13]]}}}],["getproxycod",{"_index":2151,"t":{"447":{"position":[[128,13],[581,13],[1368,13]]}}}],["getproxyinfo",{"_index":2166,"t":{"447":{"position":[[895,12],[1072,12]]},"932":{"position":[[386,12]]}}}],["getread",{"_index":1989,"t":{"411":{"position":[[10,9],[175,9]]}}}],["getstr",{"_index":575,"t":{"57":{"position":[[1686,9]]},"159":{"position":[[504,9],[849,9]]},"188":{"position":[[313,9]]},"192":{"position":[[194,9]]},"207":{"position":[[176,9]]},"223":{"position":[[378,9]]},"225":{"position":[[282,9]]},"229":{"position":[[197,9]]},"301":{"position":[[2613,9]]},"308":{"position":[[2092,9]]},"347":{"position":[[1322,9],[2257,9]]},"406":{"position":[[240,9]]},"422":{"position":[[253,9]]},"489":{"position":[[1361,9]]},"745":{"position":[[253,9]]},"780":{"position":[[410,9]]},"857":{"position":[[596,9]]},"859":{"position":[[485,9]]},"980":{"position":[[221,9]]}}}],["getstream",{"_index":1277,"t":{"184":{"position":[[644,9]]},"218":{"position":[[644,9]]}}}],["gettyp",{"_index":980,"t":{"129":{"position":[[350,7]]},"255":{"position":[[377,7]]},"257":{"position":[[351,7]]},"259":{"position":[[326,7]]},"550":{"position":[[517,7],[571,7]]},"552":{"position":[[644,7],[698,7],[1727,7]]},"684":{"position":[[364,7]]}}}],["getvalu",{"_index":1904,"t":{"376":{"position":[[305,8],[1479,8]]},"493":{"position":[[476,8],[857,8]]}}}],["getwaitingcli",{"_index":3238,"t":{"857":{"position":[[194,16],[261,16]]},"859":{"position":[[93,16],[155,16]]}}}],["getwrit",{"_index":1993,"t":{"413":{"position":[[10,9],[197,9]]}}}],["getxmlrpcclient",{"_index":591,"t":{"60":{"position":[[81,15],[265,15]]},"66":{"position":[[148,15],[321,15]]}}}],["gite",{"_index":111,"t":{"12":{"position":[[88,5]]}}}],["github",{"_index":112,"t":{"12":{"position":[[94,6]]}}}],["go",{"_index":1800,"t":{"365":{"position":[[125,2],[253,2],[512,2],[2105,2],[2393,2]]}}}],["goon",{"_index":1599,"t":{"297":{"position":[[197,4],[299,4]]},"301":{"position":[[558,4]]}}}],["goreceiv",{"_index":1792,"t":{"361":{"position":[[2876,10]]}}}],["gosend",{"_index":1772,"t":{"361":{"position":[[1004,6]]},"365":{"position":[[2032,6]]}}}],["gotoa",{"_index":2635,"t":{"574":{"position":[[114,5],[157,5],[349,5],[625,5]]}}}],["guid",{"_index":2721,"t":{"615":{"position":[[145,4],[195,4]]}}}],["gzip",{"_index":2707,"t":{"610":{"position":[[5,4],[131,4],[202,4]]},"876":{"position":[[55,4]]}}}],["gzipdatacompressor",{"_index":2715,"t":{"610":{"position":[[318,18]]}}}],["h",{"_index":708,"t":{"91":{"position":[[49,1],[490,1]]}}}],["handl",{"_index":848,"t":{"120":{"position":[[904,7]]},"194":{"position":[[453,7]]},"233":{"position":[[459,7]]},"570":{"position":[[182,7]]},"774":{"position":[[285,7],[378,7]]}}}],["handlereceiveddata",{"_index":1153,"t":{"159":{"position":[[230,18],[393,18],[703,18]]},"225":{"position":[[148,18]]},"231":{"position":[[30,18]]},"574":{"position":[[465,18]]}}}],["handshak",{"_index":1658,"t":{"317":{"position":[[116,10],[146,10]]},"868":{"position":[[88,10]]}}}],["head",{"_index":861,"t":{"120":{"position":[[1296,4],[1444,4]]}}}],["header",{"_index":560,"t":{"57":{"position":[[882,6]]},"120":{"position":[[366,6]]},"301":{"position":[[1288,6],[1347,6],[1362,6],[1410,6],[1430,6],[1473,6],[1725,6],[1734,6],[1767,6],[1804,6],[2071,6],[2107,6]]},"308":{"position":[[1122,6],[1159,6],[1211,6],[1240,6],[1268,6],[2388,6],[2439,6],[2485,6]]},"347":{"position":[[1037,7],[1240,7],[1298,7],[1382,7],[1433,7],[1453,7],[1569,6]]},"489":{"position":[[732,6],[746,6],[827,6],[869,6]]},"702":{"position":[[2010,6],[2024,6],[2090,6]]},"878":{"position":[[198,6]]}}}],["headerlength",{"_index":564,"t":{"57":{"position":[[1017,12],[1243,12]]},"308":{"position":[[1378,12],[1597,12]]},"347":{"position":[[1253,12],[1364,12],[1407,12]]},"489":{"position":[[143,12]]},"702":{"position":[[247,12]]}}}],["headertyp",{"_index":1975,"t":{"406":{"position":[[53,10]]}}}],["heartbeatandreceiveplugin",{"_index":2322,"t":{"493":{"position":[[66,25],[209,25]]},"495":{"position":[[592,25],[970,25]]}}}],["heartbeattim",{"_index":2319,"t":{"491":{"position":[[235,14]]}}}],["heartbeattimerproperti",{"_index":2318,"t":{"491":{"position":[[174,22]]},"493":{"position":[[506,22],[604,22],[887,22],[983,22]]}}}],["height",{"_index":871,"t":{"120":{"position":[[1552,6]]}}}],["hello",{"_index":1502,"t":{"268":{"position":[[21,5]]},"391":{"position":[[346,5]]},"393":{"position":[[155,5]]},"395":{"position":[[66,5]]},"512":{"position":[[1133,5]]}}}],["help",{"_index":709,"t":{"91":{"position":[[51,4],[492,4]]}}}],["hexstr",{"_index":2700,"t":{"606":{"position":[[68,9],[172,9]]}}}],["hi",{"_index":1040,"t":{"138":{"position":[[361,2]]},"395":{"position":[[75,2]]}}}],["hold",{"_index":1801,"t":{"365":{"position":[[131,4],[769,4],[1030,4],[2681,4],[2973,4]]}}}],["host",{"_index":751,"t":{"102":{"position":[[282,4]]},"246":{"position":[[18,4]]}}}],["href",{"_index":2330,"t":{"495":{"position":[[37,4]]}}}],["html",{"_index":857,"t":{"120":{"position":[[1118,4],[1132,4],[1224,4],[1260,4],[2133,4],[2211,4]]}}}],["http",{"_index":294,"t":{"34":{"position":[[129,4],[145,4],[214,4]]},"60":{"position":[[355,4],[479,4]]},"66":{"position":[[411,4]]},"69":{"position":[[54,4]]},"78":{"position":[[182,4],[195,4]]},"80":{"position":[[984,4],[1147,4],[1193,4],[1381,4],[1609,4]]},"86":{"position":[[199,4],[227,4]]},"97":{"position":[[11,4],[26,4]]},"102":{"position":[[117,4]]},"104":{"position":[[7,5]]},"106":{"position":[[19,4]]},"110":{"position":[[16,4]]},"112":{"position":[[2,5]]},"114":{"position":[[0,4]]},"122":{"position":[[0,5],[10,4]]},"180":{"position":[[49,4]]},"184":{"position":[[1346,4],[1364,5],[1444,5]]},"212":{"position":[[119,4]]},"218":{"position":[[1346,4],[1364,5],[1444,5]]},"257":{"position":[[4,4]]},"275":{"position":[[12,4],[31,4]]},"284":{"position":[[32,4],[558,4]]},"286":{"position":[[25,4]]},"290":{"position":[[1015,4]]},"343":{"position":[[24,4]]},"347":{"position":[[991,4],[1032,4]]},"391":{"position":[[32,4]]},"458":{"position":[[32,4],[373,4]]},"461":{"position":[[1,4],[20,4]]},"495":{"position":[[43,5]]},"498":{"position":[[97,4]]},"512":{"position":[[784,4],[911,4]]},"516":{"position":[[44,4],[71,4]]},"785":{"position":[[9,4],[60,4]]},"806":{"position":[[271,4],[279,4],[350,4]]},"862":{"position":[[64,4]]},"874":{"position":[[255,4],[291,4]]},"878":{"position":[[106,4],[187,4]]},"896":{"position":[[469,4]]},"917":{"position":[[50,4]]},"925":{"position":[[611,4]]},"957":{"position":[[87,4]]}}}],["httpclient",{"_index":640,"t":{"69":{"position":[[101,10]]},"97":{"position":[[0,10]]},"102":{"position":[[0,10],[24,10]]},"116":{"position":[[45,10]]},"313":{"position":[[2,10]]},"321":{"position":[[11,10]]}}}],["httpcontext",{"_index":3352,"t":{"894":{"position":[[637,11],[705,11]]}}}],["httpcontexteventarg",{"_index":837,"t":{"120":{"position":[[738,20],[2346,20]]},"463":{"position":[[125,20]]},"465":{"position":[[125,20]]}}}],["httpmethodtyp",{"_index":1548,"t":{"286":{"position":[[719,14]]},"894":{"position":[[195,14],[271,14],[460,14]]}}}],["httppluginbas",{"_index":810,"t":{"118":{"position":[[44,14]]},"120":{"position":[[648,14]]},"463":{"position":[[55,14]]},"465":{"position":[[54,14]]}}}],["httprequest",{"_index":744,"t":{"102":{"position":[[161,11],[187,11]]}}}],["httpservic",{"_index":785,"t":{"110":{"position":[[0,11],[34,11]]},"120":{"position":[[0,11],[53,11],[97,11]]},"257":{"position":[[24,11]]},"277":{"position":[[2,11]]},"284":{"position":[[112,11]]},"286":{"position":[[138,11]]},"292":{"position":[[10,11],[217,11]]},"458":{"position":[[61,11]]},"516":{"position":[[25,11],[201,11],[227,11]]},"882":{"position":[[180,11]]},"896":{"position":[[0,11],[26,11]]},"915":{"position":[[8,11],[26,11]]},"925":{"position":[[209,11]]},"930":{"position":[[85,11],[111,11]]}}}],["httpsocketcli",{"_index":802,"t":{"116":{"position":[[19,16]]},"120":{"position":[[663,16],[713,16],[2321,16]]},"286":{"position":[[868,16]]},"292":{"position":[[42,16],[160,16]]},"512":{"position":[[745,16],[829,16]]}}}],["httpstaticpageplugin",{"_index":2238,"t":{"458":{"position":[[0,20],[251,20]]}}}],["httptouchrpcclient",{"_index":1029,"t":{"138":{"position":[[52,18]]},"171":{"position":[[27,18],[59,18]]}}}],["httptouchrpcservic",{"_index":1459,"t":{"257":{"position":[[57,19]]}}}],["i1",{"_index":2871,"t":{"702":{"position":[[103,2]]}}}],["i4",{"_index":616,"t":{"60":{"position":[[584,2],[591,2],[630,2],[637,2]]}}}],["iaplugin",{"_index":2634,"t":{"574":{"position":[[101,8],[133,8],[288,8],[323,8],[614,8]]}}}],["iapplicationbuild",{"_index":1463,"t":{"261":{"position":[[127,19],[166,19],[643,19]]}}}],["ibetweenandrequestinfo",{"_index":1515,"t":{"272":{"position":[[32,22],[306,22],[418,22]]}}}],["ibigfixedheaderrequestinfo",{"_index":502,"t":{"57":{"position":[[32,26],[322,26],[522,26]]}}}],["ical",{"_index":2746,"t":{"639":{"position":[[94,7]]}}}],["icallcontext",{"_index":2397,"t":{"512":{"position":[[679,12]]},"641":{"position":[[61,12],[245,12]]},"648":{"position":[[100,12],[521,12],[851,12]]},"663":{"position":[[241,12]]},"672":{"position":[[288,12]]},"674":{"position":[[260,12]]}}}],["iclient",{"_index":1909,"t":{"376":{"position":[[588,7],[1159,7],[1455,7]]},"859":{"position":[[1071,7]]},"874":{"position":[[268,7]]}}}],["icontain",{"_index":3308,"t":{"874":{"position":[[131,10]]}}}],["icontainerprovid",{"_index":3312,"t":{"874":{"position":[[446,18]]}}}],["id",{"_index":670,"t":{"78":{"position":[[173,2],[281,2],[403,2]]},"120":{"position":[[1520,2],[1637,2],[1763,2],[1905,2]]},"142":{"position":[[211,2],[228,2],[293,2],[342,2]]},"146":{"position":[[21,2]]},"184":{"position":[[435,2]]},"216":{"position":[[100,2]]},"218":{"position":[[435,2]]},"220":{"position":[[374,2]]},"223":{"position":[[456,2],[523,2],[545,2],[556,3],[605,3],[655,2]]},"225":{"position":[[717,2],[730,2]]},"229":{"position":[[275,2]]},"239":{"position":[[168,2],[188,2],[226,2],[236,2],[282,3],[337,3]]},"243":{"position":[[2,2],[42,2],[100,2],[176,2],[233,2],[296,2],[377,2]]},"530":{"position":[[33,2],[43,2],[88,2],[101,2],[111,2],[436,2],[517,2],[1043,2]]},"608":{"position":[[2,2],[18,2],[89,2]]},"613":{"position":[[30,2],[43,2]]},"615":{"position":[[29,2],[45,2],[68,2],[112,2],[130,2],[153,2]]},"617":{"position":[[4,2],[80,2],[114,2],[172,2],[218,2]]},"619":{"position":[[4,2],[52,2]]},"623":{"position":[[37,2]]},"672":{"position":[[1006,2]]},"674":{"position":[[913,2]]},"693":{"position":[[33,2]]},"702":{"position":[[974,2]]},"776":{"position":[[61,2],[78,2],[100,2],[119,2],[124,2]]},"790":{"position":[[20,2],[40,2],[47,2]]},"820":{"position":[[0,2],[34,2]]},"832":{"position":[[628,2],[639,2],[862,2],[873,2],[1067,2],[1078,2],[1219,2],[1230,2]]},"836":{"position":[[33,2]]},"872":{"position":[[665,2]]},"878":{"position":[[543,2],[554,2],[711,2],[722,2]]},"894":{"position":[[599,2],[609,2],[783,2]]}}}],["idatacompressor",{"_index":2712,"t":{"610":{"position":[[259,15],[387,15]]},"876":{"position":[[75,15]]}}}],["idefaultsend",{"_index":3250,"t":{"859":{"position":[[1080,14]]}}}],["idependencyobject",{"_index":1910,"t":{"376":{"position":[[604,17]]}}}],["ietf",{"_index":3374,"t":{"909":{"position":[[52,4]]}}}],["ieventobject",{"_index":1961,"t":{"397":{"position":[[64,12]]}}}],["ifastbinaryconvert",{"_index":2036,"t":{"431":{"position":[[123,20]]}}}],["ifixedheaderrequestinfo",{"_index":1639,"t":{"308":{"position":[[32,23],[310,23],[459,23]]},"347":{"position":[[32,23]]},"489":{"position":[[427,23]]},"702":{"position":[[543,23]]}}}],["igener",{"_index":2595,"t":{"556":{"position":[[17,8],[69,8],[2245,8],[2312,8]]}}}],["ihttpplugin",{"_index":808,"t":{"118":{"position":[[13,11]]},"279":{"position":[[13,11]]}}}],["iinvokeopt",{"_index":1008,"t":{"134":{"position":[[539,13],[886,13],[1384,13],[1882,13],[2613,13],[3115,13]]},"655":{"position":[[316,13]]}}}],["ijsonrpccallcontext",{"_index":3326,"t":{"880":{"position":[[253,19]]}}}],["il",{"_index":2092,"t":{"440":{"position":[[241,2]]},"455":{"position":[[366,2]]}}}],["il2cpp",{"_index":3269,"t":{"868":{"position":[[130,6]]}}}],["ilist",{"_index":1760,"t":{"361":{"position":[[437,5]]},"365":{"position":[[1526,5]]},"809":{"position":[[423,5]]}}}],["ilog",{"_index":1545,"t":{"286":{"position":[[611,4],[642,4]]},"473":{"position":[[2,4],[68,4]]},"493":{"position":[[160,4],[249,4]]},"548":{"position":[[147,4],[193,4],[294,4]]},"550":{"position":[[211,4],[264,4],[317,4],[370,4],[416,4],[625,4],[676,4],[746,4]]},"552":{"position":[[232,4],[285,4],[338,4],[391,4],[444,4],[497,4],[543,4],[843,4],[971,4],[1032,4],[1181,4],[1214,4],[1528,4],[1573,4],[1625,4],[1782,4],[1822,4]]},"554":{"position":[[397,4],[443,4],[481,4],[645,4],[685,4]]},"556":{"position":[[112,4],[304,4],[496,4],[840,4],[1310,4],[1361,4],[1431,4],[1642,4],[1770,4],[1831,4],[1980,4],[2013,4],[2224,4],[2254,4],[2321,4],[2582,4],[2703,4],[2764,4],[2913,4],[2946,4],[3226,4],[3347,4],[3408,4],[3557,4],[3590,4]]},"734":{"position":[[124,4],[164,4]]}}}],["ilogg",{"_index":1430,"t":{"235":{"position":[[373,7],[423,7]]}}}],["imessag",{"_index":176,"t":{"25":{"position":[[9,8],[72,8]]},"872":{"position":[[821,8]]}}}],["imessageobject",{"_index":3299,"t":{"872":{"position":[[831,14]]}}}],["imyrpcserv",{"_index":1001,"t":{"134":{"position":[[211,12],[954,12]]},"455":{"position":[[275,12],[394,12],[446,12],[701,12]]}}}],["includ",{"_index":2946,"t":{"716":{"position":[[54,7]]}}}],["includecallcontext",{"_index":1550,"t":{"286":{"position":[[765,18]]},"512":{"position":[[629,18]]},"641":{"position":[[25,18],[197,18]]},"663":{"position":[[196,18]]},"672":{"position":[[241,18]]},"674":{"position":[[213,18]]},"894":{"position":[[506,18]]}}}],["index",{"_index":1725,"t":{"347":{"position":[[1055,5],[1171,5],[1230,5],[1268,5]]},"361":{"position":[[2157,5],[2251,5],[2274,5],[2312,5],[2349,5],[2469,5],[2681,5],[2715,5]]}}}],["indexoffirst",{"_index":1726,"t":{"347":{"position":[[1080,12]]}}}],["info",{"_index":979,"t":{"129":{"position":[[334,4]]},"142":{"position":[[80,4]]},"223":{"position":[[439,4]]},"229":{"position":[[258,4]]},"255":{"position":[[361,4]]},"257":{"position":[[335,4]]},"259":{"position":[[310,4]]},"465":{"position":[[662,4]]},"481":{"position":[[99,4]]},"493":{"position":[[1167,4]]},"495":{"position":[[655,4],[1043,4]]},"648":{"position":[[376,4],[675,4],[1026,4]]},"734":{"position":[[435,4],[717,4]]},"736":{"position":[[538,4],[571,4],[612,4],[653,4]]},"832":{"position":[[363,4],[610,4],[845,4],[1051,4],[1205,4],[1591,4],[2256,4],[2443,4]]},"857":{"position":[[567,4]]},"859":{"position":[[456,4]]},"878":{"position":[[526,4],[694,4]]}}}],["inheritdoc",{"_index":431,"t":{"48":{"position":[[124,10]]}}}],["inithead",{"_index":746,"t":{"102":{"position":[[211,11]]}}}],["inject",{"_index":2546,"t":{"542":{"position":[[161,9]]}}}],["input",{"_index":888,"t":{"120":{"position":[[1743,5],[1883,5]]}}}],["int",{"_index":187,"t":{"25":{"position":[[103,3],[111,3],[118,3],[163,3],[171,3],[178,3],[384,3],[412,3],[455,3],[483,3]]},"57":{"position":[[666,3],[678,3],[1239,3]]},"60":{"position":[[107,3],[135,3]]},"66":{"position":[[203,3]]},"69":{"position":[[446,3],[471,3],[566,3],[591,3]]},"75":{"position":[[101,3]]},"157":{"position":[[96,3],[365,3]]},"196":{"position":[[235,3],[247,3],[411,3],[423,3]]},"241":{"position":[[188,3],[200,3],[416,3],[428,3]]},"243":{"position":[[119,3],[131,3],[315,3],[327,3]]},"301":{"position":[[1041,3],[1165,3]]},"308":{"position":[[493,3],[561,3],[1593,3]]},"340":{"position":[[294,3]]},"347":{"position":[[503,3],[571,3],[1051,3],[1249,3]]},"361":{"position":[[307,3],[319,3],[601,3],[613,3],[627,3],[1431,3],[2247,3],[2258,3],[2320,3]]},"365":{"position":[[1569,3]]},"376":{"position":[[56,3],[275,3],[463,3],[508,3],[629,3],[791,3],[836,3],[1132,3],[1391,3],[1582,3]]},"402":{"position":[[49,3]]},"404":{"position":[[108,3]]},"406":{"position":[[493,3]]},"411":{"position":[[94,3],[209,3]]},"413":{"position":[[254,3],[297,3]]},"431":{"position":[[275,3],[287,3],[489,3],[574,3],[779,3]]},"434":{"position":[[56,3]]},"436":{"position":[[50,3],[267,3],[390,3],[395,3],[437,3],[540,3],[616,3],[757,3],[865,3],[1160,3],[1513,3],[1518,3],[1628,3],[1885,3]]},"489":{"position":[[139,3],[532,3]]},"493":{"position":[[127,3],[235,3]]},"507":{"position":[[40,3],[164,3],[204,3],[1067,3],[1122,3],[1140,3],[1286,3],[1346,3],[1378,3],[1865,3],[1910,3]]},"523":{"position":[[44,3],[210,3],[429,3],[434,3],[476,3],[579,3],[620,3],[732,3],[986,3],[1038,3],[1456,3],[1881,3],[1886,3],[2020,3],[2325,3],[2563,3]]},"552":{"position":[[917,3],[1124,3]]},"556":{"position":[[899,3],[1025,3],[1716,3],[1923,3],[2649,3],[2856,3],[3293,3],[3500,3]]},"606":{"position":[[137,3]]},"650":{"position":[[60,3],[76,3]]},"663":{"position":[[272,3],[295,3]]},"672":{"position":[[269,3],[314,3],[331,3],[345,3],[515,3],[726,3],[963,3]]},"674":{"position":[[241,3],[286,3],[303,3],[598,3],[612,3],[730,3],[870,3]]},"702":{"position":[[243,3],[600,3],[698,3]]},"734":{"position":[[392,3],[407,3],[414,3],[647,3],[689,3],[696,3]]},"750":{"position":[[151,3],[428,3],[581,3]]},"809":{"position":[[326,3],[338,3]]},"868":{"position":[[158,3]]},"894":{"position":[[223,3],[231,3],[238,3],[300,3],[827,3],[854,3]]},"925":{"position":[[823,3],[838,3],[845,3],[1003,3],[1030,3],[1057,3]]},"928":{"position":[[162,3],[170,3],[177,3],[218,3],[315,3],[342,3]]}}}],["int16",{"_index":3085,"t":{"783":{"position":[[90,5]]}}}],["int32",{"_index":2702,"t":{"606":{"position":[[116,5]]}}}],["interfac",{"_index":1000,"t":{"134":{"position":[[201,9]]},"455":{"position":[[265,9],[691,9]]},"556":{"position":[[7,9]]},"574":{"position":[[313,9]]}}}],["intern",{"_index":836,"t":{"120":{"position":[[620,8]]},"146":{"position":[[121,8]]},"301":{"position":[[224,8],[1915,8],[2031,8],[2121,8],[2213,8],[2307,8]]},"463":{"position":[[27,8]]},"465":{"position":[[26,8]]},"489":{"position":[[19,8],[396,8],[1390,8]]},"491":{"position":[[80,8]]},"493":{"position":[[51,8]]},"530":{"position":[[153,8]]},"693":{"position":[[53,8]]},"702":{"position":[[124,8]]},"774":{"position":[[50,8]]},"780":{"position":[[152,8]]},"836":{"position":[[103,8]]}}}],["internalsetadapt",{"_index":437,"t":{"48":{"position":[[238,18]]}}}],["internet",{"_index":3219,"t":{"839":{"position":[[51,8]]},"917":{"position":[[13,8]]}}}],["intvalu",{"_index":1128,"t":{"157":{"position":[[369,8]]}}}],["invok",{"_index":593,"t":{"60":{"position":[[128,6]]},"69":{"position":[[464,6],[584,6]]},"80":{"position":[[305,6],[464,6],[599,6],[856,6],[1283,6],[1520,6]]},"132":{"position":[[381,6]]},"134":{"position":[[1525,6],[1683,6],[2023,6],[2721,6],[2879,6],[3223,6]]},"142":{"position":[[90,6],[390,6]]},"655":{"position":[[264,6]]},"659":{"position":[[184,6]]},"661":{"position":[[388,6]]},"681":{"position":[[468,6]]}}}],["invokeasync",{"_index":1018,"t":{"134":{"position":[[2160,11],[3360,11]]}}}],["invokeopt",{"_index":595,"t":{"60":{"position":[[147,12]]},"80":{"position":[[360,12],[495,12],[657,12],[912,12],[1320,12],[1558,12]]},"132":{"position":[[319,12],[403,12]]},"134":{"position":[[553,12],[900,12],[1398,12],[1715,12],[1896,12],[2197,12],[2627,12],[2911,12],[3129,12],[3397,12]]},"142":{"position":[[170,12],[470,12]]},"655":{"position":[[5,12],[28,12],[41,12],[60,12],[76,12],[131,12],[184,12],[290,12],[333,12]]},"659":{"position":[[3,12],[38,12],[51,12],[70,12],[86,12],[210,12]]},"661":{"position":[[120,12],[157,12],[170,12],[189,12],[274,12],[414,12]]},"681":{"position":[[49,12],[85,12],[98,12],[117,12],[134,12],[231,12],[296,12],[369,12],[494,12]]},"686":{"position":[[180,12],[193,12],[212,12],[422,12]]}}}],["invokeresult",{"_index":2752,"t":{"648":{"position":[[151,12],[164,12],[182,12],[201,12],[474,12],[572,12],[585,12],[728,12],[797,12],[902,12],[915,12],[1079,12],[1156,12]]}}}],["invokestatu",{"_index":2754,"t":{"648":{"position":[[232,12]]}}}],["io",{"_index":1252,"t":{"184":{"position":[[290,2],[632,2]]},"218":{"position":[[290,2],[632,2]]},"440":{"position":[[258,3]]},"874":{"position":[[101,2]]}}}],["ioc",{"_index":1440,"t":{"235":{"position":[[1210,3]]},"261":{"position":[[433,3]]},"554":{"position":[[156,3]]},"882":{"position":[[203,3]]},"884":{"position":[[38,3]]}}}],["iocp",{"_index":1215,"t":{"180":{"position":[[6,4]]},"184":{"position":[[960,4],[1739,4]]},"212":{"position":[[6,4]]},"218":{"position":[[960,4],[1739,4]]},"559":{"position":[[15,4]]},"911":{"position":[[28,4]]}}}],["iou",{"_index":2576,"t":{"552":{"position":[[812,3],[1025,3]]},"556":{"position":[[1824,3],[2757,3],[3401,3]]}}}],["ip",{"_index":798,"t":{"112":{"position":[[33,2]]},"184":{"position":[[463,2],[1294,2]]},"212":{"position":[[88,2]]},"218":{"position":[[463,2],[1294,2]]},"225":{"position":[[744,2]]},"512":{"position":[[471,2],[851,2],[863,2],[918,2],[1057,2],[1069,2],[1174,2]]},"537":{"position":[[956,2],[996,2]]},"617":{"position":[[104,2],[233,2]]},"729":{"position":[[37,2]]},"734":{"position":[[738,2]]},"774":{"position":[[39,2]]},"911":{"position":[[61,2]]}}}],["ipackag",{"_index":2365,"t":{"507":{"position":[[22,8],[801,8]]},"872":{"position":[[184,8]]}}}],["ipaddress",{"_index":3229,"t":{"843":{"position":[[369,9]]},"845":{"position":[[224,9]]},"851":{"position":[[255,9]]}}}],["ipendpoint",{"_index":3233,"t":{"845":{"position":[[213,10]]},"851":{"position":[[244,10]]}}}],["iphost",{"_index":382,"t":{"46":{"position":[[97,6]]},"57":{"position":[[1818,6],[1833,6]]},"102":{"position":[[109,6]]},"120":{"position":[[191,6],[206,6]]},"129":{"position":[[160,6],[175,6]]},"184":{"position":[[1274,6]]},"188":{"position":[[484,6]]},"192":{"position":[[365,6]]},"194":{"position":[[642,6]]},"207":{"position":[[289,6]]},"218":{"position":[[1274,6]]},"223":{"position":[[770,6],[785,6],[821,6]]},"225":{"position":[[1106,6],[1121,6],[1157,6],[1660,6],[1675,6],[1711,6]]},"229":{"position":[[362,6],[377,6],[413,6]]},"233":{"position":[[653,6],[668,6],[698,6]]},"235":{"position":[[1013,6],[1028,6]]},"255":{"position":[[166,6],[181,6]]},"257":{"position":[[157,6],[172,6]]},"259":{"position":[[177,6]]},"272":{"position":[[1616,6],[1631,6]]},"284":{"position":[[206,6],[221,6]]},"286":{"position":[[232,6],[247,6]]},"288":{"position":[[211,6],[226,6]]},"301":{"position":[[2745,6],[2760,6]]},"308":{"position":[[2224,6],[2239,6]]},"319":{"position":[[224,6],[708,6]]},"347":{"position":[[2389,6],[2404,6]]},"391":{"position":[[204,6],[230,6]]},"406":{"position":[[356,6],[371,6]]},"422":{"position":[[369,6],[384,6]]},"447":{"position":[[354,6],[369,6]]},"458":{"position":[[189,6],[204,6]]},"495":{"position":[[357,6],[372,6],[402,6],[778,6]]},"514":{"position":[[544,6],[559,6]]},"516":{"position":[[315,6],[330,6]]},"537":{"position":[[143,6],[158,6]]},"561":{"position":[[573,6],[588,6],[618,6]]},"736":{"position":[[105,6],[120,6],[150,6]]},"745":{"position":[[369,6],[384,6]]},"816":{"position":[[275,6]]},"832":{"position":[[70,6],[85,6]]},"843":{"position":[[221,6]]},"845":{"position":[[100,6]]},"849":{"position":[[239,6]]},"851":{"position":[[131,6]]},"857":{"position":[[106,6]]},"859":{"position":[[816,6],[831,6],[867,6]]},"896":{"position":[[114,6],[129,6]]},"925":{"position":[[337,6],[352,6]]},"930":{"position":[[191,6],[206,6]]},"932":{"position":[[317,6]]},"980":{"position":[[337,6],[352,6]]}}}],["iplugin",{"_index":2636,"t":{"574":{"position":[[146,7],[334,7]]}}}],["iprotocolplugin",{"_index":2631,"t":{"572":{"position":[[70,15]]}}}],["iremoteserv",{"_index":1002,"t":{"134":{"position":[[226,13]]}}}],["irequestinfo",{"_index":258,"t":{"32":{"position":[[76,12],[146,12],[202,12]]},"34":{"position":[[237,12]]},"159":{"position":[[433,12],[743,12]]},"186":{"position":[[279,12]]},"194":{"position":[[407,12]]},"220":{"position":[[286,12]]},"225":{"position":[[188,12]]},"233":{"position":[[413,12]]},"235":{"position":[[818,12]]},"297":{"position":[[122,12]]},"301":{"position":[[22,12],[1946,12]]},"357":{"position":[[155,12]]},"361":{"position":[[371,12]]},"489":{"position":[[327,12]]},"537":{"position":[[1181,12],[1409,12]]},"574":{"position":[[505,12]]},"702":{"position":[[436,12]]},"857":{"position":[[649,12],[778,12]]},"859":{"position":[[538,12],[667,12]]},"882":{"position":[[79,12]]}}}],["iresult",{"_index":3213,"t":{"832":{"position":[[2381,7]]}}}],["irpcactionfilt",{"_index":2747,"t":{"646":{"position":[[17,16]]},"880":{"position":[[300,16]]}}}],["irpcclient",{"_index":1010,"t":{"134":{"position":[[988,10],[1040,10],[1470,10],[1968,10],[2683,10],[3185,10]]},"140":{"position":[[127,10]]},"455":{"position":[[870,10]]}}}],["irpcpars",{"_index":1031,"t":{"138":{"position":[[92,10]]},"447":{"position":[[92,10]]},"930":{"position":[[48,10]]}}}],["irpcserv",{"_index":941,"t":{"127":{"position":[[43,10]]},"512":{"position":[[29,10]]},"889":{"position":[[232,10]]},"894":{"position":[[29,10]]}}}],["isasync",{"_index":3138,"t":{"809":{"position":[[355,7],[463,7]]},"872":{"position":[[1049,7],[1061,7]]}}}],["iscancellationrequest",{"_index":2789,"t":{"663":{"position":[[376,23]]}}}],["iscopedcontain",{"_index":2585,"t":{"554":{"position":[[124,16],[214,16],[271,16],[540,16],[593,16]]},"874":{"position":[[427,16]]}}}],["isdevelop",{"_index":1480,"t":{"261":{"position":[[703,13]]}}}],["isend",{"_index":2491,"t":{"528":{"position":[[935,5],[1633,5]]},"859":{"position":[[1096,5]]}}}],["iserverprovid",{"_index":3347,"t":{"889":{"position":[[216,15]]},"928":{"position":[[34,15]]}}}],["iservicecollect",{"_index":1435,"t":{"235":{"position":[[902,18]]},"261":{"position":[[64,18],[286,18]]},"969":{"position":[[326,18],[352,18],[505,18],[619,18]]}}}],["iserviceplugin",{"_index":3270,"t":{"868":{"position":[[190,14]]}}}],["iserviceprovid",{"_index":2589,"t":{"554":{"position":[[246,16]]}}}],["isnul",{"_index":2378,"t":{"507":{"position":[[1019,6],[1057,6],[1222,6],[1276,6]]}}}],["iso",{"_index":856,"t":{"120":{"position":[[1051,3]]},"463":{"position":[[265,3]]},"636":{"position":[[18,3]]},"832":{"position":[[1866,3],[1913,3]]},"894":{"position":[[687,3]]}}}],["isocketcli",{"_index":1046,"t":{"140":{"position":[[25,13]]},"493":{"position":[[415,13]]},"734":{"position":[[662,13]]}}}],["ispermitoper",{"_index":1081,"t":{"146":{"position":[[294,17]]},"225":{"position":[[754,17]]},"530":{"position":[[366,17]]},"693":{"position":[[266,17]]},"774":{"position":[[220,17],[350,17]]},"832":{"position":[[547,17]]},"836":{"position":[[356,17]]},"872":{"position":[[950,17]]}}}],["issuccess",{"_index":1695,"t":{"340":{"position":[[371,9],[688,9],[1004,9]]},"528":{"position":[[692,9],[1146,9],[1406,9],[1843,9]]},"691":{"position":[[347,9]]}}}],["issupport",{"_index":2422,"t":{"521":{"position":[[351,11]]}}}],["itcpclient",{"_index":2523,"t":{"537":{"position":[[857,10],[1366,10]]}}}],["itcpclientbas",{"_index":367,"t":{"42":{"position":[[109,14]]},"290":{"position":[[119,14],[907,14],[1200,14]]},"463":{"position":[[102,14]]},"465":{"position":[[102,14]]},"491":{"position":[[359,14],[617,14]]},"493":{"position":[[352,14],[758,14],[1057,14]]},"574":{"position":[[355,14]]}}}],["itcpplugin",{"_index":739,"t":{"101":{"position":[[2,10]]},"186":{"position":[[2,10]]},"220":{"position":[[2,10]]},"279":{"position":[[2,10]]},"315":{"position":[[2,10]]},"572":{"position":[[46,10]]}}}],["item",{"_index":1052,"t":{"142":{"position":[[23,4],[85,4]]},"292":{"position":[[289,4],[308,4]]},"365":{"position":[[1599,4],[1635,4],[1940,4],[1981,4],[1993,4],[2006,4]]},"465":{"position":[[473,4],[583,4],[632,4]]},"507":{"position":[[519,4],[549,4],[705,4],[735,4],[769,4]]}}}],["itemgroup",{"_index":2944,"t":{"716":{"position":[[25,9],[96,9]]}}}],["itokenplugin",{"_index":2630,"t":{"572":{"position":[[57,12]]}}}],["itouchrpc",{"_index":1077,"t":{"146":{"position":[[210,9]]},"530":{"position":[[242,9]]},"630":{"position":[[372,9]]},"693":{"position":[[142,9]]},"774":{"position":[[143,9]]},"780":{"position":[[254,9]]},"836":{"position":[[192,9]]}}}],["itouchrpcplugin",{"_index":1187,"t":{"166":{"position":[[13,15]]},"252":{"position":[[13,15]]}}}],["itransientrpcserv",{"_index":945,"t":{"127":{"position":[[94,19]]},"643":{"position":[[28,19]]}}}],["iudpsessionplugin",{"_index":1375,"t":{"205":{"position":[[13,17]]}}}],["iunfixedheaderrequestinfo",{"_index":1720,"t":{"347":{"position":[[314,25],[467,25]]}}}],["iwaitingcli",{"_index":3239,"t":{"857":{"position":[[213,14]]},"859":{"position":[[112,14]]}}}],["iwaitsend",{"_index":3236,"t":{"854":{"position":[[93,11]]}}}],["iwebapicallcontext",{"_index":1551,"t":{"286":{"position":[[808,18]]},"880":{"position":[[280,18]]},"894":{"position":[[560,18]]}}}],["iwebhostenviron",{"_index":1478,"t":{"261":{"position":[[668,19]]}}}],["iwebsocketplugin",{"_index":1531,"t":{"279":{"position":[[25,16]]},"284":{"position":[[49,16]]},"290":{"position":[[1045,16]]},"315":{"position":[[13,16]]}}}],["iwstouchrpcservic",{"_index":1466,"t":{"261":{"position":[[328,18]]}}}],["j",{"_index":1886,"t":{"370":{"position":[[379,1]]}}}],["javascript",{"_index":896,"t":{"120":{"position":[[2006,10]]}}}],["jobject",{"_index":683,"t":{"80":{"position":[[738,7],[756,7],[825,7],[863,7],[1402,7],[1420,7],[1489,7],[1527,7],[2237,7],[2255,7],[2324,7]]},"512":{"position":[[1237,7],[1257,7]]}}}],["john",{"_index":2431,"t":{"523":{"position":[[196,4]]}}}],["joinmulticastgroup",{"_index":3226,"t":{"841":{"position":[[49,18]]},"843":{"position":[[350,18]]}}}],["joker",{"_index":1831,"t":{"370":{"position":[[5,5]]}}}],["jrpt",{"_index":678,"t":{"80":{"position":[[211,4],[1188,4],[1886,4]]},"86":{"position":[[194,4]]}}}],["js",{"_index":2344,"t":{"500":{"position":[[32,2]]},"864":{"position":[[48,2]]}}}],["json",{"_index":656,"t":{"78":{"position":[[25,4]]},"157":{"position":[[222,4],[556,4]]},"180":{"position":[[54,4]]},"212":{"position":[[124,4]]},"261":{"position":[[849,4]]},"427":{"position":[[41,4]]},"431":{"position":[[545,4]]},"436":{"position":[[2037,4]]},"509":{"position":[[43,4],[60,4]]},"516":{"position":[[92,4]]},"519":{"position":[[17,4]]},"521":{"position":[[59,4],[68,4],[102,4],[158,4],[185,4],[220,4],[297,4],[321,4],[449,4]]},"679":{"position":[[36,4],[89,4]]},"681":{"position":[[361,4]]},"738":{"position":[[133,4]]},"743":{"position":[[9,4]]},"792":{"position":[[158,4]]},"872":{"position":[[560,4],[574,4],[591,4],[988,4],[1002,4],[1019,4]]},"925":{"position":[[182,4],[731,4]]},"957":{"position":[[77,4]]}}}],["jsonconvert",{"_index":2424,"t":{"521":{"position":[[406,11]]}}}],["jsonfast",{"_index":2413,"t":{"521":{"position":[[39,8]]},"523":{"position":[[125,8],[355,8],[2503,8],[2709,8]]}}}],["jsonfast_complexobject",{"_index":2442,"t":{"523":{"position":[[2503,22]]}}}],["jsonfast_simpleobject",{"_index":2428,"t":{"523":{"position":[[125,21]]}}}],["jsonfastconvert",{"_index":2432,"t":{"523":{"position":[[249,17],[288,17],[2602,17],[2641,17]]}}}],["jsonfrom",{"_index":2435,"t":{"523":{"position":[[306,8],[2659,8]]}}}],["jsonrpc",{"_index":654,"t":{"78":{"position":[[2,7],[111,7],[219,7],[341,7]]},"80":{"position":[[14,7],[1169,7]]},"86":{"position":[[249,7]]},"498":{"position":[[0,7],[39,7]]},"512":{"position":[[55,7],[140,7],[326,7],[595,7],[1221,7]]},"516":{"position":[[117,7],[178,7],[570,7]]},"806":{"position":[[315,7]]},"872":{"position":[[245,7]]},"874":{"position":[[402,7]]},"880":{"position":[[244,7]]}}}],["jsonrpcclient",{"_index":602,"t":{"60":{"position":[[298,13],[334,13],[387,13],[446,13]]},"66":{"position":[[354,13],[390,13],[443,13],[502,13]]},"80":{"position":[[72,13],[86,13],[106,13],[123,13],[223,13],[291,13],[450,13],[585,13],[842,13],[1034,13],[1048,13],[1068,13],[1085,13],[1201,13],[1269,13],[1506,13],[1646,13],[1660,13],[1680,13],[1697,13],[1904,13],[1972,13],[2062,13],[2153,13],[2341,13]]},"86":{"position":[[146,13],[160,13],[180,13],[206,13],[260,13],[311,13]]}}}],["jsonrpcclientinvokebyhttp",{"_index":689,"t":{"80":{"position":[[1004,25]]}}}],["jsonrpcconsoleapp",{"_index":680,"t":{"80":{"position":[[321,17],[615,17],[873,17]]}}}],["jsonrpcparserplugin",{"_index":2401,"t":{"514":{"position":[[42,19],[334,19]]},"516":{"position":[[1,19],[530,19]]}}}],["jsonrpcserv",{"_index":2394,"t":{"512":{"position":[[111,13]]},"514":{"position":[[263,13]]},"516":{"position":[[405,13]]}}}],["jsonstr",{"_index":2408,"t":{"519":{"position":[[38,7],[135,7]]}}}],["jsonto",{"_index":2433,"t":{"523":{"position":[[267,6],[2620,6]]}}}],["jump",{"_index":897,"t":{"120":{"position":[[2017,4]]}}}],["key",{"_index":2372,"t":{"507":{"position":[[740,3]]}}}],["kuang",{"_index":867,"t":{"120":{"position":[[1525,5]]}}}],["l",{"_index":3026,"t":{"748":{"position":[[58,1],[104,1]]}}}],["left",{"_index":873,"t":{"120":{"position":[[1564,4]]}}}],["len",{"_index":1160,"t":{"159":{"position":[[545,3],[890,3]]},"188":{"position":[[354,3]]},"192":{"position":[[235,3]]},"207":{"position":[[217,3]]},"223":{"position":[[419,3]]},"225":{"position":[[323,3]]},"229":{"position":[[238,3]]},"340":{"position":[[634,3]]},"361":{"position":[[1042,3],[1449,3]]},"365":{"position":[[2070,3]]},"406":{"position":[[281,3],[546,3]]},"411":{"position":[[98,3],[279,3],[311,3]]},"422":{"position":[[112,3],[294,3],[530,3]]},"431":{"position":[[291,3]]},"470":{"position":[[486,3]]},"745":{"position":[[112,3],[294,3],[601,3]]},"780":{"position":[[455,3]]},"980":{"position":[[80,3],[262,3]]}}}],["lenbuff",{"_index":2919,"t":{"702":{"position":[[2158,9],[2188,9],[2269,9]]}}}],["length",{"_index":545,"t":{"57":{"position":[[682,6],[1738,6]]},"196":{"position":[[251,6],[427,6]]},"241":{"position":[[204,6],[432,6]]},"243":{"position":[[135,6],[331,6]]},"301":{"position":[[2665,6]]},"308":{"position":[[1009,6],[1180,6],[2144,6]]},"347":{"position":[[778,6],[2309,6]]},"361":{"position":[[323,6],[617,6],[641,6],[984,6],[2292,6],[2386,6],[2432,6],[2480,6],[2582,6],[2614,6],[2724,6]]},"406":{"position":[[570,6]]},"411":{"position":[[247,6]]},"413":{"position":[[329,6]]},"422":{"position":[[554,6]]},"465":{"position":[[637,6]]},"470":{"position":[[191,6],[266,6],[315,6],[328,6],[606,6]]},"489":{"position":[[619,6],[753,6],[1014,6]]},"600":{"position":[[124,6]]},"610":{"position":[[167,6]]},"632":{"position":[[273,6],[512,6]]},"672":{"position":[[922,6]]},"674":{"position":[[513,6]]},"697":{"position":[[24,6],[52,6]]},"702":{"position":[[2031,6],[2735,6]]},"727":{"position":[[1339,6]]},"745":{"position":[[625,6]]},"748":{"position":[[51,6],[338,6]]},"809":{"position":[[342,6]]}}}],["lengttyp",{"_index":3035,"t":{"748":{"position":[[360,9]]}}}],["lib",{"_index":2955,"t":{"718":{"position":[[126,3]]}}}],["licencekey",{"_index":3454,"t":{"969":{"position":[[162,10],[554,10]]}}}],["licens",{"_index":29,"t":{"5":{"position":[[59,7]]}}}],["list",{"_index":1824,"t":{"365":{"position":[[2136,4],[2175,4],[2424,4],[2463,4],[2714,4],[2753,4],[3006,4],[3045,4]]},"427":{"position":[[75,4]]},"436":{"position":[[262,4],[299,4],[339,4],[1155,4],[1254,4],[1362,4]]},"507":{"position":[[159,4],[1106,4],[1117,4],[1169,4],[1214,4],[1860,4]]},"523":{"position":[[615,4],[652,4],[692,4],[1451,4],[1574,4],[1706,4]]},"679":{"position":[[161,4]]}}}],["list1",{"_index":2061,"t":{"436":{"position":[[272,5],[1143,5],[1176,5],[1198,5],[1220,5]]},"523":{"position":[[625,5],[1439,5],[1478,5],[1506,5],[1534,5]]}}}],["list2",{"_index":2062,"t":{"436":{"position":[[312,5],[1242,5],[1278,5],[1302,5],[1326,5]]},"523":{"position":[[665,5],[1562,5],[1604,5],[1634,5],[1664,5]]}}}],["list3",{"_index":2063,"t":{"436":{"position":[[352,5],[1350,5],[1386,5],[1421,5],[1456,5]]},"523":{"position":[[705,5],[1694,5],[1736,5],[1777,5],[1818,5]]}}}],["littleendian",{"_index":2920,"t":{"702":{"position":[[2247,12]]},"765":{"position":[[37,12]]}}}],["loadconfig",{"_index":1415,"t":{"225":{"position":[[513,10],[581,10]]}}}],["loadingstreameventarg",{"_index":2740,"t":{"630":{"position":[[390,22]]}}}],["loadnewtonsoftjson",{"_index":2423,"t":{"521":{"position":[[380,18]]}}}],["loadremotestream",{"_index":2735,"t":{"630":{"position":[[68,16],[154,16]]},"632":{"position":[[122,16]]}}}],["localhost",{"_index":741,"t":{"102":{"position":[[124,9]]},"104":{"position":[[136,9]]}}}],["lock",{"_index":3253,"t":{"859":{"position":[[1156,4]]}}}],["log",{"_index":2279,"t":{"473":{"position":[[157,3]]},"477":{"position":[[23,4],[40,3]]}}}],["log1",{"_index":2592,"t":{"554":{"position":[[418,4],[505,4],[525,4],[614,4],[709,4],[728,4]]}}}],["log10",{"_index":2581,"t":{"552":{"position":[[1599,5],[1664,5],[1687,5],[1714,5]]}}}],["log2",{"_index":2593,"t":{"554":{"position":[[456,4],[533,4],[654,4],[736,4]]}}}],["log3",{"_index":2565,"t":{"548":{"position":[[168,4],[227,4],[256,4]]}}}],["log5",{"_index":2571,"t":{"550":{"position":[[391,4],[450,4],[479,4],[505,4],[559,4]]}}}],["log6",{"_index":2575,"t":{"552":{"position":[[518,4],[577,4],[606,4],[632,4],[686,4],[749,4],[793,4]]}}}],["logger",{"_index":978,"t":{"129":{"position":[[327,6]]},"142":{"position":[[73,6]]},"223":{"position":[[432,6]]},"229":{"position":[[251,6]]},"235":{"position":[[396,6],[444,6],[461,6],[470,6],[565,6]]},"255":{"position":[[354,6]]},"257":{"position":[[328,6]]},"259":{"position":[[303,6]]},"286":{"position":[[618,6],[647,6],[664,6],[673,6],[970,6]]},"317":{"position":[[388,6]]},"465":{"position":[[655,6],[787,6]]},"479":{"position":[[56,6]]},"481":{"position":[[28,6],[92,6],[116,6],[143,6]]},"491":{"position":[[507,6],[765,6]]},"493":{"position":[[165,6],[254,6],[297,6],[306,6],[1160,6]]},"495":{"position":[[648,6],[1036,6]]},"537":{"position":[[750,6],[925,6]]},"539":{"position":[[324,6]]},"648":{"position":[[369,6],[668,6],[1019,6]]},"734":{"position":[[129,6],[169,6],[184,6],[248,6],[257,6],[428,6],[710,6]]},"736":{"position":[[531,6],[564,6],[605,6],[646,6]]},"832":{"position":[[356,6],[603,6],[838,6],[1044,6],[1198,6],[1584,6],[2249,6],[2436,6]]},"857":{"position":[[560,6]]},"859":{"position":[[449,6]]},"878":{"position":[[519,6],[687,6]]},"891":{"position":[[15,6]]},"925":{"position":[[595,6],[633,6]]}}}],["loggergroup",{"_index":389,"t":{"46":{"position":[[257,11]]},"317":{"position":[[288,11]]},"479":{"position":[[44,11],[69,11]]},"481":{"position":[[16,11],[41,11]]}}}],["login",{"_index":954,"t":{"127":{"position":[[233,5],[298,5],[509,5],[574,5]]},"132":{"position":[[395,5]]},"134":{"position":[[486,5],[1331,5],[1707,5],[2189,5],[2530,5],[2903,5],[3389,5],[3635,5],[3655,5]]},"455":{"position":[[139,5],[302,5],[811,5]]},"641":{"position":[[239,5]]},"643":{"position":[[142,5]]},"686":{"position":[[351,5]]}}}],["loginasync",{"_index":1009,"t":{"134":{"position":[[828,10],[1824,10],[3027,10]]}}}],["loginform",{"_index":1433,"t":{"235":{"position":[[572,14]]}}}],["loginmodel",{"_index":2838,"t":{"686":{"position":[[361,10]]}}}],["logtyp",{"_index":2277,"t":{"473":{"position":[[82,7],[90,7],[114,7],[130,7],[161,7],[169,7],[256,7]]},"548":{"position":[[471,7],[479,7],[562,7],[570,7]]},"550":{"position":[[790,7],[798,7],[881,7],[889,7]]},"552":{"position":[[1258,7],[1266,7],[1349,7],[1357,7],[1883,7],[1891,7],[1974,7],[1982,7]]},"556":{"position":[[137,7],[145,7],[228,7],[236,7],[329,7],[337,7],[420,7],[428,7],[673,7],[681,7],[764,7],[772,7],[1143,7],[1151,7],[1234,7],[1242,7],[1475,7],[1483,7],[1566,7],[1574,7],[2057,7],[2065,7],[2148,7],[2156,7],[2370,7],[2378,7],[2461,7],[2469,7],[2990,7],[2998,7],[3081,7],[3089,7],[3634,7],[3642,7],[3725,7],[3733,7]]}}}],["long",{"_index":535,"t":{"57":{"position":[[558,4]]},"157":{"position":[[127,4],[403,4]]},"436":{"position":[[109,4]]},"523":{"position":[[791,4]]},"608":{"position":[[8,4],[84,4]]},"820":{"position":[[93,4]]},"868":{"position":[[162,4]]},"872":{"position":[[673,4]]}}}],["longvalu",{"_index":1130,"t":{"157":{"position":[[408,9]]}}}],["loop",{"_index":2490,"t":{"528":{"position":[[907,4],[944,4],[1605,4],[1642,4]]},"832":{"position":[[2153,4],[2224,4]]}}}],["loopact",{"_index":2488,"t":{"528":{"position":[[848,10],[859,10],[872,10],[1048,10],[1546,10],[1557,10],[1570,10],[1746,10]]},"727":{"position":[[1539,10],[1550,10],[1563,10],[1771,10]]},"832":{"position":[[2090,10],[2101,10],[2114,10],[2323,10]]}}}],["m",{"_index":378,"t":{"46":{"position":[[35,1]]},"235":{"position":[[394,1],[459,1],[563,1]]},"286":{"position":[[616,1],[662,1],[968,1]]},"493":{"position":[[131,1],[269,1],[674,1]]},"617":{"position":[[176,1]]},"702":{"position":[[584,1],[604,1],[633,1],[657,1],[682,1],[722,1],[808,1],[823,1],[929,1],[1028,1],[1044,1],[1789,1],[1806,1],[1892,1],[2139,1],[2208,1],[2328,1],[2859,1],[2874,1],[2917,1]]},"752":{"position":[[128,1]]},"857":{"position":[[10,1],[140,1],[167,1],[249,1],[548,1]]}}}],["m_bodylength",{"_index":2877,"t":{"702":{"position":[[604,12],[722,12],[929,12],[2208,12],[2874,12]]}}}],["m_client",{"_index":3043,"t":{"752":{"position":[[128,8]]}}}],["m_cmdid",{"_index":2878,"t":{"702":{"position":[[633,7],[1028,7],[1044,7],[2328,7]]}}}],["m_crc16",{"_index":2882,"t":{"702":{"position":[[682,7],[1892,7],[2917,7]]}}}],["m_logger",{"_index":1431,"t":{"235":{"position":[[394,8],[459,8],[563,8]]},"286":{"position":[[616,8],[662,8],[968,8]]}}}],["m_sampl",{"_index":2880,"t":{"702":{"position":[[657,8],[1789,8],[1806,8],[2859,8]]}}}],["m_servic",{"_index":2724,"t":{"617":{"position":[[176,9]]}}}],["m_sync",{"_index":2875,"t":{"702":{"position":[[584,6],[808,6],[823,6],[2139,6]]}}}],["m_tcpclient",{"_index":3237,"t":{"857":{"position":[[10,11],[140,11],[167,11],[249,11],[548,11]]}}}],["m_timetick",{"_index":2323,"t":{"493":{"position":[[131,10],[269,10],[674,10]]}}}],["m_udpsess",{"_index":377,"t":{"46":{"position":[[35,12]]}}}],["main",{"_index":588,"t":{"60":{"position":[[46,4]]},"66":{"position":[[113,4]]},"495":{"position":[[173,4]]},"537":{"position":[[12,4]]},"932":{"position":[[50,4]]},"969":{"position":[[124,4]]}}}],["mapcontrol",{"_index":1491,"t":{"261":{"position":[[1063,14]]}}}],["mapper",{"_index":3337,"t":{"884":{"position":[[98,6]]}}}],["math",{"_index":1997,"t":{"413":{"position":[[305,4]]}}}],["maui",{"_index":1407,"t":{"223":{"position":[[928,4]]},"225":{"position":[[1264,4],[1818,4]]},"229":{"position":[[520,4]]},"806":{"position":[[111,4]]},"859":{"position":[[974,4]]}}}],["maxcount",{"_index":2474,"t":{"528":{"position":[[270,8]]},"530":{"position":[[637,8]]}}}],["maxpackages",{"_index":1246,"t":{"184":{"position":[[229,14]]},"218":{"position":[[229,14]]}}}],["maxvalu",{"_index":1113,"t":{"157":{"position":[[69,8],[100,8],[132,8]]},"361":{"position":[[693,8]]},"365":{"position":[[1668,8]]}}}],["md5",{"_index":2694,"t":{"604":{"position":[[13,3],[53,3]]},"822":{"position":[[88,3]]},"832":{"position":[[1839,3],[2034,3]]}}}],["mdx",{"_index":1512,"t":{"268":{"position":[[149,3]]}}}],["me",{"_index":1159,"t":{"159":{"position":[[484,3],[579,3],[829,3],[978,3]]},"188":{"position":[[293,3],[387,3]]},"192":{"position":[[174,3],[268,3]]},"223":{"position":[[358,3],[466,3],[486,3],[527,3],[691,3]]},"225":{"position":[[262,3],[357,3]]},"229":{"position":[[177,3],[285,3]]},"406":{"position":[[220,3]]},"422":{"position":[[233,3]]},"745":{"position":[[233,3]]},"980":{"position":[[201,3]]}}}],["memorycach",{"_index":3277,"t":{"872":{"position":[[148,11]]}}}],["memorypack",{"_index":2392,"t":{"509":{"position":[[27,10]]},"684":{"position":[[75,10]]},"686":{"position":[[446,10]]}}}],["memorypackseri",{"_index":2831,"t":{"684":{"position":[[323,20],[667,20]]}}}],["memorypackserializationselector",{"_index":2829,"t":{"684":{"position":[[118,31]]},"686":{"position":[[98,31]]}}}],["memorystream",{"_index":1090,"t":{"151":{"position":[[53,12],[97,12]]},"155":{"position":[[5,12]]},"630":{"position":[[264,12],[461,12]]},"727":{"position":[[158,12],[178,12],[1232,12],[1258,12]]}}}],["messag",{"_index":1553,"t":{"286":{"position":[[977,7]]},"317":{"position":[[395,7]]},"473":{"position":[[200,7]]},"481":{"position":[[105,7]]},"537":{"position":[[932,7]]},"548":{"position":[[510,7],[601,7]]},"550":{"position":[[829,7],[920,7]]},"552":{"position":[[1297,7],[1388,7],[1922,7],[2013,7]]},"556":{"position":[[176,7],[267,7],[368,7],[459,7],[712,7],[803,7],[1182,7],[1273,7],[1514,7],[1605,7],[2096,7],[2187,7],[2409,7],[2500,7],[3029,7],[3120,7],[3673,7],[3764,7]]},"648":{"position":[[258,7],[1092,7]]},"774":{"position":[[256,7]]},"925":{"position":[[602,7],[640,7]]},"971":{"position":[[183,7]]}}}],["messagebox",{"_index":2498,"t":{"528":{"position":[[1161,10],[1208,10],[1858,10],[1905,10]]}}}],["messageinst",{"_index":3301,"t":{"872":{"position":[[865,15]]}}}],["messageobject",{"_index":186,"t":{"25":{"position":[[56,13],[343,13]]}}}],["meta",{"_index":862,"t":{"120":{"position":[[1332,4]]}}}],["metadata",{"_index":1191,"t":{"166":{"position":[[161,8]]},"252":{"position":[[161,8]]},"581":{"position":[[94,8],[253,8]]},"630":{"position":[[175,8],[424,8]]},"632":{"position":[[143,8]]},"727":{"position":[[256,8],[265,8],[278,8],[1794,8],[1803,8],[1818,8],[1845,8],[1869,8],[1965,8]]},"774":{"position":[[194,8]]},"830":{"position":[[733,8]]},"832":{"position":[[1605,8],[1614,8],[1629,8],[1653,8],[1677,8],[1925,8],[1935,8]]},"884":{"position":[[47,8],[219,8]]}}}],["method",{"_index":660,"t":{"78":{"position":[[49,6],[129,6],[237,6],[359,6]]},"556":{"position":[[3195,6]]},"882":{"position":[[53,6]]}}}],["methodcal",{"_index":612,"t":{"60":{"position":[[517,10],[671,10]]}}}],["methodflag",{"_index":1549,"t":{"286":{"position":[[739,11],[753,11]]},"512":{"position":[[603,11],[617,11]]},"641":{"position":[[13,11],[171,11],[185,11]]},"663":{"position":[[184,11]]},"672":{"position":[[215,11],[229,11]]},"674":{"position":[[187,11],[201,11]]},"894":{"position":[[480,11],[494,11]]}}}],["methodinst",{"_index":2756,"t":{"648":{"position":[[404,14],[701,14],[1052,14]]}}}],["methodnam",{"_index":613,"t":{"60":{"position":[[530,10],[546,10]]}}}],["methodshouldbeok",{"_index":2574,"t":{"552":{"position":[[144,16]]}}}],["microsoft",{"_index":3455,"t":{"969":{"position":[[224,9]]}}}],["min",{"_index":1519,"t":{"272":{"position":[[362,3]]},"413":{"position":[[310,3]]}}}],["mincount",{"_index":2473,"t":{"528":{"position":[[256,8]]},"530":{"position":[[623,8]]}}}],["minsiz",{"_index":1526,"t":{"272":{"position":[[937,7]]}}}],["mm",{"_index":879,"t":{"120":{"position":[[1642,2]]}}}],["modbu",{"_index":1636,"t":{"306":{"position":[[18,6]]}}}],["model",{"_index":2186,"t":{"449":{"position":[[211,6]]}}}],["movenext",{"_index":2812,"t":{"672":{"position":[[859,8]]},"674":{"position":[[470,8]]}}}],["mqtt",{"_index":1933,"t":{"389":{"position":[[24,4]]}}}],["msg",{"_index":2837,"t":{"686":{"position":[[338,3]]},"780":{"position":[[390,3]]}}}],["msgeventarg",{"_index":3345,"t":{"889":{"position":[[155,12],[168,12]]}}}],["mtu",{"_index":3143,"t":{"816":{"position":[[93,3]]},"818":{"position":[[16,3]]}}}],["mul",{"_index":3010,"t":{"736":{"position":[[622,3]]}}}],["mulcommand",{"_index":3007,"t":{"734":{"position":[[651,10],[771,10]]}}}],["multicast",{"_index":3223,"t":{"839":{"position":[[75,9]]}}}],["multifilecollect",{"_index":2257,"t":{"465":{"position":[[394,19],[481,19]]}}}],["multithreadingfileoper",{"_index":2483,"t":{"528":{"position":[[730,26],[1444,26]]}}}],["myarg",{"_index":2204,"t":{"453":{"position":[[48,6]]}}}],["mybetweenandrequestinfo",{"_index":1517,"t":{"272":{"position":[[247,23],[277,23],[392,23],[856,23],[1179,23],[1230,23],[1461,23]]}}}],["mybigfixedheadercustomdatahandlingadapt",{"_index":562,"t":{"57":{"position":[[931,41],[1108,41],[1892,41]]}}}],["mybigfixedheaderrequestinfo",{"_index":521,"t":{"57":{"position":[[255,27],[289,27],[492,27],[1192,27],[1280,27],[1335,27],[1570,27],[1623,27]]},"272":{"position":[[1510,27]]}}}],["myclass",{"_index":652,"t":{"69":{"position":[[634,7]]},"75":{"position":[[132,7]]},"376":{"position":[[39,7],[203,7],[543,7],[871,7]]},"507":{"position":[[12,7],[1750,7],[1764,7],[1775,7],[1791,7],[1812,7],[1830,7],[1845,7],[1883,7],[2069,7],[2158,7]]},"546":{"position":[[93,7],[205,7]]},"894":{"position":[[313,7],[321,7],[339,7],[351,7],[810,7]]},"928":{"position":[[232,7],[240,7],[258,7],[270,7],[298,7]]}}}],["myclassmodel",{"_index":2367,"t":{"507":{"position":[[209,12],[786,12],[1351,12],[1460,12],[1507,12],[1915,12],[1941,12],[1985,12]]}}}],["mycommandlineplugin",{"_index":3001,"t":{"734":{"position":[[62,19],[144,19]]},"736":{"position":[[443,19]]}}}],["mycustombetweenanddatahandlingadapt",{"_index":338,"t":{"38":{"position":[[76,37]]},"272":{"position":[[657,37],[780,37],[890,37],[1690,37]]}}}],["mycustomdatahandlingadapt",{"_index":1604,"t":{"301":{"position":[[239,27],[2819,27]]}}}],["mycustomunfixedheaderdatahandlingadapt",{"_index":1732,"t":{"347":{"position":[[1629,40],[1724,40],[2463,40]]}}}],["mydatacompressor",{"_index":2716,"t":{"610":{"position":[[368,16]]}}}],["mydatahandleadapt",{"_index":1755,"t":{"361":{"position":[[50,19]]}}}],["myfixedheadercustomdatahandlingadapt",{"_index":1643,"t":{"308":{"position":[[1298,38],[1424,38],[2298,38]]}}}],["myfixedheaderdatahandlingadapt",{"_index":2310,"t":{"489":{"position":[[34,32]]},"495":{"position":[[473,32],[851,32]]}}}],["myfixedheaderrequestinfo",{"_index":1641,"t":{"308":{"position":[[249,24],[280,24],[432,24],[1502,24],[1698,24],[1750,24],[1982,24],[2032,24]]},"347":{"position":[[284,24]]}}}],["myhttpplug",{"_index":822,"t":{"120":{"position":[[305,10],[635,10]]},"463":{"position":[[42,10]]},"465":{"position":[[41,10]]}}}],["mylog1",{"_index":2559,"t":{"548":{"position":[[2,6],[232,6],[315,6],[322,6],[352,6],[361,6],[400,6],[407,6]]},"550":{"position":[[217,6],[226,6],[455,6],[510,6],[537,6],[659,6],[681,6]]},"552":{"position":[[89,6],[238,6],[247,6],[582,6],[637,6],[664,6],[961,6],[976,6],[1076,6],[1085,6],[1186,6],[1534,6],[1693,6],[1720,6],[1747,6],[1844,6]]},"554":{"position":[[403,6]]},"556":{"position":[[103,6],[517,6],[524,6],[554,6],[563,6],[602,6],[609,6],[916,6],[923,6],[977,6],[986,6],[1072,6],[1079,6],[1344,6],[1366,6],[1760,6],[1775,6],[1875,6],[1884,6],[1985,6],[2693,6],[2708,6],[2808,6],[2817,6],[2918,6],[3337,6],[3352,6],[3452,6],[3461,6],[3562,6]]}}}],["mylog10",{"_index":2580,"t":{"552":{"position":[[1579,7],[1640,7],[1772,7]]}}}],["mylog2",{"_index":2560,"t":{"548":{"position":[[9,6],[261,6],[330,6],[337,6],[374,6],[383,6],[430,6],[437,6]]},"550":{"position":[[270,6],[279,6],[484,6],[564,6],[591,6],[729,6],[751,6]]},"552":{"position":[[291,6],[300,6]]},"556":{"position":[[295,6],[532,6],[539,6],[576,6],[585,6],[632,6],[639,6],[931,6],[938,6],[999,6],[1008,6],[1102,6],[1109,6],[1414,6],[1436,6],[2260,6],[2327,6]]}}}],["mylog3",{"_index":2564,"t":{"548":{"position":[[153,6],[204,6],[285,6],[308,6]]},"550":{"position":[[323,6],[332,6]]},"552":{"position":[[344,6],[353,6]]},"556":{"position":[[487,6],[510,6]]}}}],["mylog4",{"_index":2573,"t":{"552":{"position":[[96,6],[397,6],[406,6],[611,6],[691,6],[718,6],[742,6],[754,6],[786,6],[798,6],[1011,6],[1037,6],[1098,6],[1107,6],[1219,6]]},"556":{"position":[[831,6],[892,6],[1810,6],[1836,6],[1897,6],[1906,6],[2018,6],[2743,6],[2769,6],[2830,6],[2839,6],[2951,6],[3387,6],[3413,6],[3474,6],[3483,6],[3595,6]]}}}],["mylog5",{"_index":2570,"t":{"550":{"position":[[376,6],[427,6],[616,6]]},"552":{"position":[[459,6]]},"556":{"position":[[1301,6]]}}}],["mylog6",{"_index":2572,"t":{"552":{"position":[[52,6],[450,6],[503,6],[554,6],[834,6]]},"556":{"position":[[1633,6]]}}}],["mylog7",{"_index":2599,"t":{"556":{"position":[[2215,6],[2238,6]]}}}],["mylog8",{"_index":2600,"t":{"556":{"position":[[2573,6]]}}}],["mylog9",{"_index":2601,"t":{"556":{"position":[[3217,6]]}}}],["mylogg",{"_index":2276,"t":{"473":{"position":[[57,8]]}}}],["mynamespac",{"_index":2152,"t":{"447":{"position":[[143,11]]}}}],["mynatservic",{"_index":2517,"t":{"537":{"position":[[34,12],[61,12],[337,12]]}}}],["mynewclass",{"_index":2389,"t":{"507":{"position":[[2141,10],[2169,10]]}}}],["mypackperson",{"_index":2051,"t":{"434":{"position":[[34,12]]}}}],["myplugin",{"_index":365,"t":{"42":{"position":[[45,8]]},"194":{"position":[[110,8],[155,8],[763,8]]},"233":{"position":[[110,8],[158,8],[809,8]]},"832":{"position":[[216,8],[386,8]]}}}],["myproperti",{"_index":1900,"t":{"376":{"position":[[60,10],[279,10],[523,10],[638,10],[851,10],[906,10],[1250,10],[1586,10]]},"436":{"position":[[620,10],[639,10],[652,10],[761,10]]},"523":{"position":[[990,10],[1004,10],[1017,10],[1042,10]]}}}],["mypropertyproperti",{"_index":1905,"t":{"376":{"position":[[314,18],[352,18],[468,18],[796,18],[1185,18],[1488,18]]}}}],["myrequest",{"_index":2328,"t":{"493":{"position":[[1142,9],[1172,9],[1199,9]]}}}],["myrequestinfo",{"_index":571,"t":{"57":{"position":[[1598,13],[1696,13],[1719,13]]},"272":{"position":[[1485,13]]},"301":{"position":[[295,13],[1014,13],[1216,13],[1230,13],[1250,13],[1711,13],[1742,13],[1778,13],[1815,13],[1852,13],[1930,13],[2525,13],[2539,13],[2564,13],[2623,13],[2646,13]]},"308":{"position":[[2007,13],[2102,13],[2125,13]]},"347":{"position":[[2170,13],[2267,13],[2290,13]]},"489":{"position":[[106,13],[231,13],[272,13],[411,13]]},"491":{"position":[[398,13],[656,13]]},"493":{"position":[[1128,13]]},"495":{"position":[[1235,13]]}}}],["myrpcactionfilt",{"_index":2761,"t":{"650":{"position":[[34,17]]}}}],["myrpcactionfilterattribut",{"_index":2749,"t":{"648":{"position":[[13,26]]}}}],["myrpcserv",{"_index":939,"t":{"127":{"position":[[13,11],[156,11],[423,11]]},"129":{"position":[[233,11]]},"134":{"position":[[940,11],[976,11]]},"447":{"position":[[499,11]]},"455":{"position":[[90,11],[407,11],[585,11],[676,11]]},"641":{"position":[[115,11]]},"643":{"position":[[64,11]]}}}],["myrpcserverextens",{"_index":1019,"t":{"134":{"position":[[2248,21]]}}}],["myserv",{"_index":1541,"t":{"286":{"position":[[88,8],[374,8],[536,8],[571,8],[633,8]]}}}],["myservic",{"_index":1414,"t":{"225":{"position":[[448,9],[837,9],[849,9],[873,9],[1357,9]]}}}],["mysocketcli",{"_index":347,"t":{"40":{"position":[[117,14],[172,14]]},"48":{"position":[[73,14]]},"225":{"position":[[92,14],[471,14],[640,14],[1380,14],[1421,14]]},"231":{"position":[[13,14]]},"365":{"position":[[200,14]]}}}],["mytclient",{"_index":1158,"t":{"159":{"position":[[345,9],[655,9]]},"574":{"position":[[417,9]]}}}],["mytcpplugin",{"_index":1429,"t":{"235":{"position":[[321,11],[381,11],[411,11],[431,11],[1122,11]]}}}],["mytcpservic",{"_index":345,"t":{"40":{"position":[[91,12]]}}}],["mytcptouchrpcplugin",{"_index":2739,"t":{"630":{"position":[[289,19]]}}}],["mytouchrpcplugin",{"_index":1074,"t":{"146":{"position":[[136,16]]},"530":{"position":[[168,16]]},"693":{"position":[[68,16]]},"774":{"position":[[65,16]]},"780":{"position":[[167,16]]},"836":{"position":[[118,16]]}}}],["myudpadatp",{"_index":3135,"t":{"809":{"position":[[79,12]]}}}],["myunfixedheaderrequestinfo",{"_index":1719,"t":{"347":{"position":[[251,26],[438,26],[1806,26],[1855,26],[1909,26],[2143,26],[2195,26]]}}}],["mywebsocketplugin",{"_index":1539,"t":{"284":{"position":[[457,17],[480,17]]}}}],["mywebsocketserverplugin",{"_index":1578,"t":{"290":{"position":[[814,23],[1109,23]]}}}],["mywsclient",{"_index":1656,"t":{"317":{"position":[[16,10],[54,10],[82,10],[105,10],[135,10],[158,10],[355,10],[377,10]]},"319":{"position":[[126,10],[162,10],[632,10]]}}}],["mywsclient_handshak",{"_index":1659,"t":{"317":{"position":[[135,21]]}}}],["mywsclient_receiv",{"_index":1657,"t":{"317":{"position":[[82,19]]}}}],["mywscommandlineplugin",{"_index":3387,"t":{"925":{"position":[[513,21],[770,21]]}}}],["n",{"_index":667,"t":{"78":{"position":[[104,1]]},"80":{"position":[[1872,1]]},"343":{"position":[[46,1]]},"347":{"position":[[1020,1],[1024,1],[1157,1],[1161,1],[1194,1],[1198,1],[1548,1],[1552,1]]},"370":{"position":[[381,1]]},"470":{"position":[[240,1],[464,1],[469,1]]},"487":{"position":[[159,1]]},"514":{"position":[[125,1],[487,1]]},"697":{"position":[[59,1]]},"736":{"position":[[257,1],[272,1],[325,1]]},"738":{"position":[[60,1],[65,1]]},"745":{"position":[[471,1],[495,1]]},"783":{"position":[[60,1]]}}}],["name",{"_index":981,"t":{"129":{"position":[[360,4]]},"138":{"position":[[337,4],[355,4]]},"255":{"position":[[387,4]]},"257":{"position":[[361,4]]},"259":{"position":[[336,4]]},"301":{"position":[[702,4],[742,4],[818,4],[856,4]]},"361":{"position":[[2113,4],[2151,4],[2184,4],[2789,4]]},"376":{"position":[[947,4],[986,4],[1020,4],[1291,4],[1330,4]]},"434":{"position":[[92,4]]},"436":{"position":[[718,4],[839,4]]},"495":{"position":[[132,4]]},"512":{"position":[[281,4],[511,4],[550,4]]},"523":{"position":[[80,4],[188,4]]},"648":{"position":[[419,4],[716,4],[1067,4]]},"672":{"position":[[90,4],[129,4]]},"674":{"position":[[62,4],[101,4]]},"734":{"position":[[314,4],[343,4],[541,4],[569,4],[598,4]]},"894":{"position":[[424,4]]}}}],["nameof",{"_index":3005,"t":{"734":{"position":[[445,6],[764,6]]}}}],["namespac",{"_index":998,"t":{"134":{"position":[[173,9]]},"447":{"position":[[1383,9]]},"702":{"position":[[51,9]]}}}],["nat",{"_index":2515,"t":{"535":{"position":[[39,3]]},"537":{"position":[[504,3]]},"539":{"position":[[19,3]]}}}],["natservic",{"_index":2510,"t":{"533":{"position":[[0,10]]},"537":{"position":[[294,10],[352,10]]},"884":{"position":[[159,10]]}}}],["natsocketcli",{"_index":2519,"t":{"537":{"position":[[401,15],[827,15],[1130,15],[1336,15]]}}}],["net",{"_index":2333,"t":{"495":{"position":[[61,3]]},"554":{"position":[[242,3]]},"661":{"position":[[75,3]]},"705":{"position":[[20,3],[41,3],[56,3]]},"718":{"position":[[156,3]]},"792":{"position":[[148,3]]},"806":{"position":[[410,3],[431,3]]}}}],["net45",{"_index":2411,"t":{"521":{"position":[[8,5]]},"707":{"position":[[21,5]]},"718":{"position":[[178,5]]}}}],["net6",{"_index":2353,"t":{"503":{"position":[[77,4],[128,4]]}}}],["net7",{"_index":2933,"t":{"707":{"position":[[68,4]]},"872":{"position":[[49,4]]}}}],["netcoreapp3",{"_index":2419,"t":{"521":{"position":[[119,11]]},"707":{"position":[[42,11]]},"718":{"position":[[215,11]]}}}],["netstandard2",{"_index":2412,"t":{"521":{"position":[[14,12]]},"707":{"position":[[27,12]]}}}],["networkstream",{"_index":2606,"t":{"559":{"position":[[35,13]]}}}],["new",{"_index":202,"t":{"25":{"position":[[301,3]]},"38":{"position":[[72,3]]},"40":{"position":[[267,3]]},"42":{"position":[[192,3]]},"46":{"position":[[54,3],[93,3],[166,3],[253,3],[269,3],[299,3]]},"57":{"position":[[583,3],[1331,3],[1396,3],[1766,3],[1814,3],[1829,3],[1888,3]]},"60":{"position":[[314,3]]},"66":{"position":[[183,3],[370,3]]},"69":{"position":[[297,3],[630,3]]},"75":{"position":[[128,3]]},"80":{"position":[[102,3],[143,3],[752,3],[1064,3],[1105,3],[1416,3],[1676,3],[1717,3],[1839,3],[2251,3]]},"86":{"position":[[176,3],[300,3]]},"91":{"position":[[30,3]]},"102":{"position":[[20,3],[51,3],[105,3],[183,3]]},"104":{"position":[[98,3],[238,3],[283,3],[317,3]]},"120":{"position":[[93,3],[126,3],[187,3],[202,3],[1167,3]]},"122":{"position":[[59,3],[98,3]]},"129":{"position":[[58,3],[110,3],[156,3],[171,3]]},"132":{"position":[[103,3],[141,3],[315,3]]},"134":{"position":[[1452,3],[1558,3],[1612,3],[1950,3],[2056,3],[2110,3],[2754,3],[2808,3],[3256,3],[3310,3],[3469,3],[3507,3]]},"138":{"position":[[447,3],[485,3]]},"153":{"position":[[53,3],[140,3],[345,3]]},"157":{"position":[[29,3],[190,3],[257,3]]},"169":{"position":[[54,3],[92,3]]},"171":{"position":[[55,3],[94,3]]},"173":{"position":[[38,3],[70,3]]},"175":{"position":[[26,3],[63,3]]},"188":{"position":[[76,3],[432,3],[480,3]]},"192":{"position":[[79,3],[313,3],[361,3]]},"194":{"position":[[567,3],[597,3],[638,3]]},"207":{"position":[[24,3],[246,3],[285,3]]},"223":{"position":[[111,3],[718,3],[766,3],[781,3],[817,3]]},"225":{"position":[[869,3],[1054,3],[1102,3],[1117,3],[1153,3],[1406,3],[1608,3],[1656,3],[1671,3],[1707,3]]},"229":{"position":[[84,3],[310,3],[358,3],[373,3],[409,3]]},"233":{"position":[[575,3],[607,3],[649,3],[664,3],[694,3]]},"235":{"position":[[1009,3],[1024,3]]},"255":{"position":[[77,3],[116,3],[162,3],[177,3]]},"257":{"position":[[53,3],[107,3],[153,3],[168,3]]},"259":{"position":[[84,3],[130,3],[173,3]]},"261":{"position":[[370,3],[515,3]]},"272":{"position":[[1226,3],[1287,3],[1564,3],[1612,3],[1627,3],[1686,3]]},"284":{"position":[[108,3],[141,3],[202,3],[217,3]]},"286":{"position":[[134,3],[167,3],[228,3],[243,3]]},"288":{"position":[[111,3],[207,3],[222,3],[263,3],[350,3]]},"301":{"position":[[1246,3],[2351,3],[2693,3],[2741,3],[2756,3],[2815,3]]},"308":{"position":[[1746,3],[1808,3],[2172,3],[2220,3],[2235,3],[2294,3]]},"317":{"position":[[29,3],[175,3],[284,3],[300,3],[330,3]]},"319":{"position":[[139,3],[179,3],[220,3],[280,3],[325,3],[359,3]]},"340":{"position":[[400,3],[488,3]]},"347":{"position":[[1905,3],[1969,3],[2337,3],[2385,3],[2400,3],[2459,3]]},"361":{"position":[[717,3],[824,3],[886,3],[2418,3],[2568,3]]},"365":{"position":[[298,3],[343,3],[557,3],[602,3],[816,3],[861,3],[1077,3],[1122,3],[1692,3],[1799,3],[1861,3],[2171,3],[2215,3],[2232,3],[2269,3],[2286,3],[2323,3],[2459,3],[2503,3],[2520,3],[2558,3],[2575,3],[2613,3],[2749,3],[2793,3],[2810,3],[2848,3],[2865,3],[2903,3],[3041,3],[3085,3],[3102,3],[3140,3],[3157,3],[3195,3]]},"376":{"position":[[1535,3]]},"391":{"position":[[119,3],[158,3],[200,3],[215,3]]},"393":{"position":[[43,3]]},"406":{"position":[[126,3],[304,3],[352,3],[367,3],[426,3]]},"411":{"position":[[123,3]]},"413":{"position":[[152,3]]},"422":{"position":[[139,3],[317,3],[365,3],[380,3],[438,3]]},"431":{"position":[[314,3],[376,3],[921,3]]},"436":{"position":[[697,3],[910,3],[1054,3],[1091,3],[1151,3],[1250,3],[1358,3],[1396,3],[1431,3],[1466,3],[1498,3],[1613,3],[1737,3],[1870,3],[1918,3],[1951,3],[1984,3]]},"447":{"position":[[265,3],[304,3],[350,3],[365,3],[612,3],[1394,3],[1425,3]]},"451":{"position":[[157,3]]},"458":{"position":[[57,3],[89,3],[185,3],[200,3]]},"465":{"position":[[534,3]]},"470":{"position":[[36,3],[257,3],[673,3]]},"479":{"position":[[65,3],[81,3],[101,3]]},"481":{"position":[[37,3],[53,3],[73,3]]},"489":{"position":[[268,3],[361,3],[1175,3]]},"491":{"position":[[394,3],[652,3]]},"493":{"position":[[628,3]]},"495":{"position":[[225,3],[273,3],[305,3],[353,3],[368,3],[398,3],[469,3],[700,3],[733,3],[774,3],[847,3],[1231,3]]},"507":{"position":[[1113,3],[1331,3],[1760,3],[1856,3],[1895,3],[1937,3],[1981,3],[2050,3],[2154,3]]},"514":{"position":[[151,3],[183,3],[412,3],[454,3],[540,3],[555,3]]},"516":{"position":[[223,3],[256,3],[311,3],[326,3]]},"519":{"position":[[70,3]]},"523":{"position":[[159,3],[1146,3],[1338,3],[1375,3],[1447,3],[1570,3],[1702,3],[1746,3],[1787,3],[1828,3],[1866,3],[2005,3],[2153,3],[2310,3],[2364,3],[2403,3],[2442,3]]},"528":{"position":[[223,3],[325,3],[440,3],[726,3],[1440,3]]},"530":{"position":[[590,3],[692,3],[838,3],[1084,3]]},"537":{"position":[[57,3],[90,3],[139,3],[154,3],[563,3],[652,3]]},"539":{"position":[[78,3]]},"548":{"position":[[102,3]]},"550":{"position":[[166,3]]},"552":{"position":[[187,3],[1483,3]]},"554":{"position":[[355,3]]},"561":{"position":[[45,3],[260,3],[520,3],[569,3],[584,3],[614,3],[674,3]]},"574":{"position":[[637,3]]},"581":{"position":[[249,3],[269,3]]},"600":{"position":[[70,3]]},"608":{"position":[[55,3]]},"610":{"position":[[39,3],[55,3],[112,3],[470,3],[570,3]]},"615":{"position":[[191,3]]},"630":{"position":[[171,3],[457,3]]},"632":{"position":[[139,3],[192,3],[365,3]]},"648":{"position":[[197,3]]},"655":{"position":[[56,3],[349,3]]},"659":{"position":[[66,3]]},"661":{"position":[[185,3],[243,3]]},"668":{"position":[[121,3]]},"672":{"position":[[574,3]]},"674":{"position":[[789,3]]},"681":{"position":[[113,3]]},"686":{"position":[[40,3],[94,3],[208,3],[357,3]]},"702":{"position":[[375,3],[470,3],[2076,3],[2812,3]]},"727":{"position":[[154,3],[1174,3],[1202,3],[1254,3],[1382,3],[1814,3]]},"734":{"position":[[919,3]]},"736":{"position":[[21,3],[52,3],[101,3],[116,3],[146,3],[218,3],[283,3]]},"745":{"position":[[139,3],[317,3],[365,3],[380,3],[438,3]]},"750":{"position":[[108,3],[272,3],[385,3]]},"756":{"position":[[139,3],[165,3],[233,3],[282,3],[334,3]]},"758":{"position":[[25,3]]},"772":{"position":[[56,3]]},"816":{"position":[[131,3],[232,3],[271,3],[334,3]]},"832":{"position":[[20,3],[66,3],[81,3],[308,3],[1306,3],[1625,3],[1729,3]]},"843":{"position":[[39,3],[178,3],[217,3],[284,3]]},"845":{"position":[[23,3],[57,3],[96,3],[147,3],[209,3]]},"849":{"position":[[57,3],[196,3],[235,3],[302,3]]},"851":{"position":[[23,3],[57,3],[127,3],[178,3],[240,3]]},"857":{"position":[[24,3],[54,3],[102,3],[278,3]]},"859":{"position":[[14,3],[172,3],[764,3],[812,3],[827,3],[863,3]]},"891":{"position":[[212,3],[259,3]]},"896":{"position":[[22,3],[55,3],[110,3],[125,3]]},"925":{"position":[[205,3],[237,3],[333,3],[348,3]]},"930":{"position":[[107,3],[140,3],[187,3],[202,3]]},"932":{"position":[[96,3],[313,3]]},"980":{"position":[[107,3],[285,3],[333,3],[348,3],[406,3]]}}}],["newdata",{"_index":1739,"t":{"350":{"position":[[112,7]]}}}],["newid",{"_index":2730,"t":{"621":{"position":[[25,5]]},"623":{"position":[[22,5]]}}}],["newobj",{"_index":687,"t":{"80":{"position":[[833,6],[972,6],[1497,6],[1619,6],[2332,6],[2408,6]]},"429":{"position":[[83,6]]}}}],["newtonsoft",{"_index":2416,"t":{"521":{"position":[[91,10],[174,10],[209,10],[286,10],[310,10],[438,10]]},"872":{"position":[[549,10],[977,10]]}}}],["newtonsoftjson",{"_index":2078,"t":{"436":{"position":[[2048,14]]}}}],["newtonsoftjsonfirst",{"_index":2425,"t":{"521":{"position":[[493,19]]}}}],["newtonsoftjsonissupport",{"_index":2420,"t":{"521":{"position":[[247,25]]}}}],["nextbyt",{"_index":2072,"t":{"436":{"position":[[1112,9]]},"523":{"position":[[1396,9]]},"610":{"position":[[68,9]]},"727":{"position":[[1215,9]]}}}],["nextid",{"_index":2706,"t":{"608":{"position":[[102,6]]}}}],["nineti",{"_index":1836,"t":{"370":{"position":[[44,6]]}}}],["nn",{"_index":890,"t":{"120":{"position":[[1768,2]]}}}],["nodelay",{"_index":1291,"t":{"184":{"position":[[798,7],[1977,7]]},"218":{"position":[[798,7],[1977,7]]}}}],["none",{"_index":1275,"t":{"184":{"position":[[624,4]]},"218":{"position":[[624,4]]}}}],["normaldatahandlingadapt",{"_index":354,"t":{"40":{"position":[[271,25]]},"42":{"position":[[196,25]]},"514":{"position":[[416,25]]},"736":{"position":[[287,25]]},"980":{"position":[[410,25]]}}}],["normaludpdatahandlingadapt",{"_index":386,"t":{"46":{"position":[[170,28]]},"816":{"position":[[40,28]]},"843":{"position":[[288,28]]},"845":{"position":[[151,28]]},"849":{"position":[[306,28]]},"851":{"position":[[182,28]]}}}],["notimplementedexcept",{"_index":537,"t":{"57":{"position":[[587,23]]},"489":{"position":[[365,23]]},"610":{"position":[[474,23],[574,23]]},"702":{"position":[[481,23]]}}}],["notnul",{"_index":2567,"t":{"548":{"position":[[219,7],[248,7]]},"550":{"position":[[442,7],[471,7]]},"552":{"position":[[569,7],[598,7],[1656,7],[1679,7]]},"554":{"position":[[497,7],[701,7]]}}}],["now",{"_index":2070,"t":{"436":{"position":[[1019,3]]},"507":{"position":[[1969,3],[2013,3]]},"523":{"position":[[1291,3]]}}}],["nuget",{"_index":705,"t":{"89":{"position":[[34,5]]},"149":{"position":[[82,5]]},"261":{"position":[[5,5]]},"350":{"position":[[0,5]]},"707":{"position":[[193,5]]},"714":{"position":[[11,5]]},"716":{"position":[[138,5]]},"718":{"position":[[1,5]]},"961":{"position":[[133,5],[141,5],[149,5]]}}}],["null",{"_index":265,"t":{"32":{"position":[[160,4],[226,4]]},"57":{"position":[[1524,4]]},"69":{"position":[[510,4],[624,4]]},"134":{"position":[[1438,4],[1936,4]]},"184":{"position":[[766,4],[1415,4]]},"218":{"position":[[766,4],[1415,4]]},"272":{"position":[[1415,4]]},"288":{"position":[[296,4]]},"301":{"position":[[2479,4]]},"308":{"position":[[1936,4]]},"347":{"position":[[2097,4]]},"357":{"position":[[179,4]]},"361":{"position":[[1480,4],[1704,4],[1902,4],[2898,4]]},"470":{"position":[[145,4]]},"489":{"position":[[993,4],[1079,4],[1331,4],[1339,4]]},"491":{"position":[[282,4]]},"493":{"position":[[665,4],[1007,4]]},"507":{"position":[[394,4],[436,4],[450,4],[575,4],[617,4],[631,4]]},"684":{"position":[[634,4]]},"750":{"position":[[168,4],[445,4]]}}}],["num",{"_index":1995,"t":{"413":{"position":[[239,3]]}}}],["nupkg",{"_index":2951,"t":{"718":{"position":[[49,5],[93,5]]}}}],["o",{"_index":2326,"t":{"493":{"position":[[639,1]]}}}],["obj",{"_index":684,"t":{"80":{"position":[[746,3],[767,3],[786,3],[804,3],[937,3],[1410,3],[1431,3],[1450,3],[1468,3],[1583,3],[2245,3],[2266,3],[2285,3],[2303,3],[2367,3]]},"429":{"position":[[4,3],[73,3]]},"431":{"position":[[370,3],[391,3],[423,3],[463,3],[528,3],[615,3],[640,3],[683,3]]},"495":{"position":[[1494,3],[1519,3]]},"512":{"position":[[1265,3],[1279,3]]},"519":{"position":[[97,3]]}}}],["object",{"_index":1015,"t":{"134":{"position":[[1590,6],[1616,6],[2088,6],[2114,6],[2786,6],[2812,6],[3288,6],[3314,6]]},"473":{"position":[[178,6]]},"519":{"position":[[74,6],[90,6],[127,6]]},"544":{"position":[[150,6]]},"548":{"position":[[488,6],[579,6]]},"550":{"position":[[807,6],[898,6]]},"552":{"position":[[1275,6],[1366,6],[1403,6],[1837,6],[1900,6],[1991,6]]},"556":{"position":[[154,6],[245,6],[346,6],[437,6],[690,6],[781,6],[1160,6],[1251,6],[1492,6],[1583,6],[2074,6],[2165,6],[2387,6],[2478,6],[3007,6],[3098,6],[3651,6],[3742,6]]},"648":{"position":[[126,6],[547,6],[877,6]]},"684":{"position":[[260,6],[468,6]]}}}],["objectsingletonshouldbeok",{"_index":2578,"t":{"552":{"position":[[1431,25]]}}}],["objectvalu",{"_index":1134,"t":{"157":{"position":[[495,11]]}}}],["offset",{"_index":544,"t":{"57":{"position":[[670,6]]},"196":{"position":[[239,6],[415,6]]},"241":{"position":[[192,6],[420,6]]},"243":{"position":[[123,6],[319,6]]},"361":{"position":[[311,6],[605,6],[650,6],[976,6]]},"365":{"position":[[1998,6]]},"431":{"position":[[279,6],[358,6]]},"470":{"position":[[183,6],[294,6]]},"809":{"position":[[330,6]]}}}],["ok",{"_index":2145,"t":{"444":{"position":[[665,2]]},"465":{"position":[[739,2]]},"894":{"position":[[751,2]]}}}],["oldid",{"_index":2729,"t":{"621":{"position":[[17,5]]}}}],["onappendbodi",{"_index":541,"t":{"57":{"position":[[638,12]]}}}],["onclick",{"_index":895,"t":{"120":{"position":[[1996,7]]}}}],["onconnect",{"_index":339,"t":{"40":{"position":[[4,12],[159,12],[323,12]]},"42":{"position":[[96,12],[231,12]]},"186":{"position":[[53,12],[90,11]]},"220":{"position":[[53,12],[100,11]]},"225":{"position":[[627,12],[791,12]]},"235":{"position":[[504,11],[602,11]]},"493":{"position":[[340,11],[693,11]]},"537":{"position":[[389,11],[455,11]]}}}],["ondelet",{"_index":813,"t":{"118":{"position":[[78,8]]},"120":{"position":[[532,8]]}}}],["ondisconnect",{"_index":1343,"t":{"186":{"position":[[121,15],[154,14]]},"220":{"position":[[128,15],[161,14]]},"493":{"position":[[743,14],[819,14]]},"832":{"position":[[1111,14],[1242,14]]}}}],["onedr",{"_index":1928,"t":{"383":{"position":[[45,8]]}}}],["onexcept",{"_index":711,"t":{"91":{"position":[[83,11],[112,11]]},"495":{"position":[[1074,11],[1103,11],[1472,11]]}}}],["onfiletransf",{"_index":1193,"t":{"166":{"position":[[200,17],[232,16]]},"252":{"position":[[200,17],[232,16]]},"832":{"position":[[467,17],[717,16]]}}}],["onfindtransferid",{"_index":2506,"t":{"530":{"position":[[473,17],[939,17]]}}}],["onfinish",{"_index":556,"t":{"57":{"position":[[769,10]]}}}],["onget",{"_index":815,"t":{"118":{"position":[[100,5],[109,5]]},"120":{"position":[[519,5],[707,5]]},"463":{"position":[[96,5],[307,5]]}}}],["ongetmainconfig",{"_index":2475,"t":{"528":{"position":[[285,15]]},"530":{"position":[[652,15]]}}}],["ongettransferconfig",{"_index":2476,"t":{"528":{"position":[[394,19]]},"530":{"position":[[792,19]]}}}],["onhandlewsdatafram",{"_index":1532,"t":{"281":{"position":[[48,19]]},"290":{"position":[[761,19],[887,19],[961,19],[1180,19],[1271,19]]}}}],["onhandshak",{"_index":1188,"t":{"166":{"position":[[87,13],[177,12]]},"252":{"position":[[87,13],[177,12]]},"281":{"position":[[0,13],[26,12]]},"284":{"position":[[74,13]]},"774":{"position":[[7,13],[129,13],[409,13]]},"832":{"position":[[965,12]]}}}],["onidchang",{"_index":1397,"t":{"220":{"position":[[348,11]]}}}],["onloadingstream",{"_index":1199,"t":{"166":{"position":[[289,15]]},"252":{"position":[[289,15]]},"630":{"position":[[228,15],[356,15],[484,15]]}}}],["onlysend",{"_index":2763,"t":{"653":{"position":[[25,8],[59,8]]},"655":{"position":[[172,8]]}}}],["onnatreceiv",{"_index":2524,"t":{"537":{"position":[[1116,13],[1232,13]]}}}],["onparsingbodi",{"_index":1520,"t":{"272":{"position":[[455,13]]},"308":{"position":[[971,13],[2519,13]]},"347":{"position":[[740,13]]},"489":{"position":[[581,13]]},"702":{"position":[[2697,13]]}}}],["onparsingendcod",{"_index":1521,"t":{"272":{"position":[[517,16]]}}}],["onparsinghead",{"_index":523,"t":{"57":{"position":[[364,15],[859,15]]},"308":{"position":[[349,15],[1099,15]]},"347":{"position":[[355,15],[868,15]]},"489":{"position":[[709,15]]},"702":{"position":[[1987,15]]}}}],["onparsingstartcod",{"_index":1523,"t":{"272":{"position":[[599,18]]}}}],["onpost",{"_index":816,"t":{"118":{"position":[[118,6],[128,6]]},"120":{"position":[[525,6],[2314,6]]},"465":{"position":[[95,6],[818,6]]}}}],["onput",{"_index":817,"t":{"118":{"position":[[138,5],[147,5]]},"120":{"position":[[541,5]]}}}],["onreceiveddata",{"_index":1348,"t":{"186":{"position":[[228,14]]},"194":{"position":[[244,14],[501,14]]},"205":{"position":[[90,14]]},"220":{"position":[[235,14]]},"233":{"position":[[247,14],[507,14]]},"235":{"position":[[652,14]]},"493":{"position":[[1042,14],[1262,14]]}}}],["onreceivedotherhttprequest",{"_index":818,"t":{"118":{"position":[[156,26],[186,26]]}}}],["onreceivedprotocoldata",{"_index":1201,"t":{"166":{"position":[[318,22]]},"252":{"position":[[318,22]]},"780":{"position":[[104,22],[231,22],[472,22]]}}}],["onreceivingdata",{"_index":1346,"t":{"186":{"position":[[181,15]]},"220":{"position":[[188,15]]}}}],["onremoteaccess",{"_index":1202,"t":{"166":{"position":[[348,17],[377,16]]},"252":{"position":[[348,17],[377,16]]}}}],["onreveiv",{"_index":2608,"t":{"559":{"position":[[83,10]]}}}],["onrout",{"_index":1076,"t":{"146":{"position":[[200,9],[327,9]]},"166":{"position":[[405,9]]},"252":{"position":[[405,9]]},"530":{"position":[[232,9],[399,9]]},"693":{"position":[[132,9],[299,9]]},"836":{"position":[[182,9],[389,9]]},"872":{"position":[[281,9],[310,9]]}}}],["onsendingdata",{"_index":1350,"t":{"186":{"position":[[295,13]]},"220":{"position":[[302,13]]}}}],["onstreamtransf",{"_index":1204,"t":{"166":{"position":[[454,19],[505,18]]},"252":{"position":[[454,19],[505,18]]}}}],["ontargetclientdisconnect",{"_index":2522,"t":{"537":{"position":[[800,26],[1032,26]]}}}],["ontargetclientreceiv",{"_index":2525,"t":{"537":{"position":[[1313,22],[1463,22]]}}}],["opcod",{"_index":1565,"t":{"290":{"position":[[188,6]]},"323":{"position":[[65,6]]}}}],["openapiinfo",{"_index":1471,"t":{"261":{"position":[[519,11]]}}}],["oper",{"_index":2975,"t":{"727":{"position":[[229,9]]}}}],["option",{"_index":828,"t":{"120":{"position":[[373,6]]}}}],["order",{"_index":1361,"t":{"194":{"position":[[173,5]]},"233":{"position":[[176,5]]},"570":{"position":[[104,5],[136,5]]}}}],["ordertyp",{"_index":1628,"t":{"301":{"position":[[1395,9],[1792,9],[2253,9],[2290,9]]},"308":{"position":[[739,9],[808,9],[833,9],[1256,9]]}}}],["osi",{"_index":919,"t":{"125":{"position":[[109,3]]}}}],["out",{"_index":1062,"t":{"142":{"position":[[346,3]]},"239":{"position":[[345,3]]},"301":{"position":[[1336,3],[1681,3]]},"442":{"position":[[8,3]]},"672":{"position":[[486,3]]},"674":{"position":[[431,3]]},"702":{"position":[[2135,3],[2184,3],[2324,3],[2850,3],[2908,3]]},"792":{"position":[[35,3]]}}}],["overlengthexcept",{"_index":1766,"t":{"361":{"position":[[721,19]]},"365":{"position":[[1696,19]]},"889":{"position":[[292,19]]}}}],["overrid",{"_index":349,"t":{"40":{"position":[[145,8]]},"42":{"position":[[82,8]]},"48":{"position":[[159,8]]},"57":{"position":[[1230,8],[1271,8]]},"120":{"position":[[693,8],[2300,8]]},"146":{"position":[[186,8]]},"159":{"position":[[379,8],[689,8]]},"194":{"position":[[230,8]]},"225":{"position":[[134,8],[499,8],[613,8]]},"233":{"position":[[233,8]]},"235":{"position":[[490,8],[638,8]]},"272":{"position":[[1007,8],[1094,8],[1170,8]]},"290":{"position":[[873,8],[1166,8]]},"301":{"position":[[945,8]]},"308":{"position":[[1584,8],[1689,8]]},"347":{"position":[[1846,8]]},"361":{"position":[[101,8],[148,8],[201,8],[266,8],[345,8],[411,8],[492,8],[560,8],[1344,8]]},"365":{"position":[[1500,8]]},"431":{"position":[[238,8],[480,8]]},"463":{"position":[[82,8]]},"465":{"position":[[81,8]]},"489":{"position":[[130,8],[169,8],[222,8],[301,8],[1254,8]]},"493":{"position":[[326,8],[729,8],[1028,8]]},"507":{"position":[[1576,8],[1651,8]]},"530":{"position":[[218,8]]},"537":{"position":[[375,8],[786,8],[1100,8],[1297,8]]},"574":{"position":[[451,8]]},"630":{"position":[[342,8]]},"648":{"position":[[76,8],[498,8],[821,8]]},"684":{"position":[[188,8],[459,8]]},"693":{"position":[[118,8]]},"702":{"position":[[234,8],[274,8],[327,8],[410,8]]},"774":{"position":[[115,8]]},"780":{"position":[[217,8]]},"809":{"position":[[126,8],[176,8],[266,8],[378,8],[486,8]]},"832":{"position":[[453,8],[703,8],[951,8],[1097,8]]},"836":{"position":[[168,8]]}}}],["owner",{"_index":1945,"t":{"391":{"position":[[365,5]]}}}],["p1",{"_index":2040,"t":{"431":{"position":[[395,2],[619,2],[783,2]]},"436":{"position":[[54,2],[933,2]]},"507":{"position":[[44,2],[311,2],[887,2],[1552,2],[1637,2],[1703,2],[1783,2],[1957,2],[2001,2]]},"523":{"position":[[736,2],[1181,2]]}}}],["p2",{"_index":2041,"t":{"431":{"position":[[427,2],[644,2],[814,2]]},"436":{"position":[[85,2],[950,2]]},"507":{"position":[[75,2],[332,2],[920,2],[1799,2]]},"523":{"position":[[767,2],[1204,2]]}}}],["p3",{"_index":2054,"t":{"436":{"position":[[114,2],[971,2]]},"507":{"position":[[104,2],[353,2],[954,2],[1820,2]]},"523":{"position":[[796,2],[1231,2]]}}}],["p4",{"_index":2055,"t":{"436":{"position":[[143,2],[989,2]]},"507":{"position":[[135,2],[374,2],[986,2],[1838,2]]},"523":{"position":[[825,2],[1255,2]]}}}],["p5",{"_index":2057,"t":{"436":{"position":[[176,2],[1005,2]]},"507":{"position":[[169,2],[421,2],[430,2],[495,2],[527,2],[1209,2],[1853,2]]},"523":{"position":[[858,2],[1277,2]]}}}],["p6",{"_index":2059,"t":{"436":{"position":[[207,2],[1032,2]]},"507":{"position":[[223,2],[602,2],[611,2],[681,2],[713,2],[1485,2],[1891,2]]},"523":{"position":[[889,2],[1310,2]]}}}],["p7",{"_index":2060,"t":{"436":{"position":[[238,2],[1049,2],[1130,2]]},"523":{"position":[[920,2],[1333,2],[1420,2]]}}}],["packag",{"_index":706,"t":{"89":{"position":[[40,7]]},"149":{"position":[[88,7]]},"350":{"position":[[6,7]]},"413":{"position":[[245,7],[267,7]]},"489":{"position":[[923,7],[1197,7]]},"507":{"position":[[252,7],[1590,7],[2077,7]]},"672":{"position":[[349,7],[551,7],[583,7]]},"674":{"position":[[616,7],[766,7],[798,7]]},"718":{"position":[[30,7]]},"806":{"position":[[232,7]]}}}],["packageasbyt",{"_index":2313,"t":{"489":{"position":[[1128,14]]},"491":{"position":[[443,14],[701,14]]},"495":{"position":[[1332,14]]}}}],["packagebas",{"_index":2384,"t":{"507":{"position":[[1522,11]]}}}],["packageid",{"_index":3151,"t":{"820":{"position":[[83,9]]}}}],["packagerefer",{"_index":2945,"t":{"716":{"position":[[37,16]]}}}],["packageroutereventarg",{"_index":1078,"t":{"146":{"position":[[228,22]]},"530":{"position":[[260,22]]},"693":{"position":[[160,22]]},"836":{"position":[[210,22]]}}}],["packages",{"_index":1587,"t":{"292":{"position":[[395,11]]},"321":{"position":[[90,11]]},"727":{"position":[[1419,11]]}}}],["packet",{"_index":2862,"t":{"697":{"position":[[17,6],[45,6]]}}}],["packet_length",{"_index":2861,"t":{"697":{"position":[[17,13],[45,13]]}}}],["packetlength",{"_index":2884,"t":{"702":{"position":[[893,12]]}}}],["packetno",{"_index":2912,"t":{"702":{"position":[[1603,8],[2574,8]]}}}],["packettyp",{"_index":2892,"t":{"702":{"position":[[1212,10],[2392,10]]}}}],["para",{"_index":1608,"t":{"301":{"position":[[374,4],[469,4],[480,4],[567,4],[578,4],[670,4]]}}}],["param",{"_index":614,"t":{"60":{"position":[[559,6],[568,5],[606,5],[614,5],[652,5],[661,6]]},"78":{"position":[[154,6],[262,6],[384,6]]},"301":{"position":[[696,5],[724,5],[736,5],[800,5],[812,5],[838,5],[850,5],[904,5]]},"361":{"position":[[2107,5],[2133,5],[2145,5],[2166,5],[2178,5],[2195,5],[2783,5],[2808,5]]},"376":{"position":[[980,5],[1002,5],[1014,5],[1035,5],[1324,5],[1346,5]]},"495":{"position":[[126,5],[146,5]]},"512":{"position":[[275,5],[294,5],[505,5],[532,5],[544,5],[563,5]]},"672":{"position":[[84,5],[111,5],[123,5],[148,5]]},"674":{"position":[[56,5],[83,5],[95,5],[120,5]]},"734":{"position":[[308,5],[325,5],[337,5],[354,5],[535,5],[551,5],[563,5],[580,5],[592,5],[609,5]]},"894":{"position":[[418,5],[445,5]]}}}],["paramet",{"_index":1016,"t":{"134":{"position":[[1599,10],[1729,10],[2097,10],[2211,10],[2795,10],[2925,10],[3297,10],[3411,10]]},"648":{"position":[[135,10],[458,10],[556,10],[781,10],[886,10],[1140,10]]},"684":{"position":[[267,9],[354,9],[374,9],[438,9]]}}}],["parameterbyt",{"_index":2832,"t":{"684":{"position":[[540,14],[618,14],[714,14],[785,14]]}}}],["parametertyp",{"_index":2833,"t":{"684":{"position":[[561,13],[700,13],[801,13]]}}}],["pars",{"_index":3230,"t":{"843":{"position":[[379,5]]},"845":{"position":[[234,5]]},"851":{"position":[[265,5]]}}}],["password",{"_index":966,"t":{"127":{"position":[[326,8],[358,8],[602,8],[634,8]]},"134":{"position":[[529,8],[876,8],[1374,8],[1636,8],[1872,8],[2134,8],[2603,8],[2832,8],[3105,8],[3334,8]]},"455":{"position":[[168,8],[204,8],[331,8],[840,8]]},"641":{"position":[[292,8],[415,8]]},"643":{"position":[[170,8],[299,8]]},"686":{"position":[[397,8],[409,8]]}}}],["path",{"_index":1992,"t":{"411":{"position":[[185,4]]},"413":{"position":[[207,4]]},"528":{"position":[[776,4],[1490,4]]},"691":{"position":[[137,4]]}}}],["payloadlength",{"_index":1570,"t":{"290":{"position":[[264,13],[451,13],[527,13]]}}}],["paypal",{"_index":1872,"t":{"370":{"position":[[281,6]]}}}],["perform",{"_index":2762,"t":{"650":{"position":[[64,11]]}}}],["permit",{"_index":2976,"t":{"727":{"position":[[239,6]]}}}],["person",{"_index":1115,"t":{"157":{"position":[[194,6],[488,6],[530,6]]},"436":{"position":[[681,6],[688,6],[701,6],[711,6],[731,6],[816,6]]}}}],["pfx",{"_index":777,"t":{"104":{"position":[[350,3]]},"122":{"position":[[131,3]]},"288":{"position":[[383,3]]},"319":{"position":[[392,3]]}}}],["ping",{"_index":1575,"t":{"290":{"position":[[653,4]]},"323":{"position":[[210,4]]},"489":{"position":[[1422,4]]},"491":{"position":[[20,4],[308,4],[436,4]]},"493":{"position":[[34,4],[654,4],[1230,4]]},"495":{"position":[[1165,4]]},"689":{"position":[[128,4]]},"748":{"position":[[292,4]]},"750":{"position":[[253,4],[544,4]]},"752":{"position":[[19,4],[66,4],[102,4],[137,4],[174,4]]},"754":{"position":[[28,4]]}}}],["pipelin",{"_index":2602,"t":{"559":{"position":[[0,8],[57,8]]},"561":{"position":[[140,8],[149,8],[163,8],[183,8],[277,8],[399,8],[430,8],[717,8]]},"880":{"position":[[73,8]]}}}],["pipelinedatahandlingadapt",{"_index":2622,"t":{"561":{"position":[[678,27]]}}}],["plc",{"_index":2302,"t":{"487":{"position":[[33,3]]}}}],["plugin",{"_index":3354,"t":{"896":{"position":[[386,7]]}}}],["pluginsmanag",{"_index":2638,"t":{"574":{"position":[[256,14],[593,14]]}}}],["po",{"_index":1118,"t":{"157":{"position":[[284,3]]},"297":{"position":[[51,3],[162,3],[213,3],[254,3],[326,3]]},"301":{"position":[[518,3],[655,3],[1169,3],[1185,3],[1310,3],[1552,3],[1558,3],[1646,3]]},"347":{"position":[[1103,3],[1226,3],[1286,3],[1360,3],[1400,3]]},"431":{"position":[[352,3],[578,3],[594,3],[666,3],[672,3]]},"470":{"position":[[721,3]]},"702":{"position":[[2111,3]]}}}],["pollingkeepal",{"_index":2682,"t":{"597":{"position":[[169,16]]}}}],["pollingkeepaliveplugin",{"_index":2526,"t":{"539":{"position":[[199,22]]},"597":{"position":[[103,22]]},"754":{"position":[[2,22]]}}}],["pong",{"_index":1576,"t":{"290":{"position":[[682,4]]},"323":{"position":[[239,4]]},"489":{"position":[[1428,4]]},"491":{"position":[[566,4],[694,4]]},"493":{"position":[[45,4],[1245,4]]},"748":{"position":[[313,4],[328,4]]},"752":{"position":[[31,4],[71,4]]}}}],["port",{"_index":1328,"t":{"184":{"position":[[1297,4]]},"218":{"position":[[1297,4]]},"447":{"position":[[376,4]]},"512":{"position":[[474,4],[871,4],[885,4],[923,4],[1077,4],[1091,4],[1179,4]]},"537":{"position":[[974,4],[1011,4]]},"617":{"position":[[245,4]]},"734":{"position":[[756,4]]}}}],["posit",{"_index":877,"t":{"120":{"position":[[1582,8],[1819,8],[1964,8]]},"411":{"position":[[67,8]]},"413":{"position":[[67,8],[228,8]]},"632":{"position":[[310,8],[337,8],[471,8]]},"725":{"position":[[22,8]]},"727":{"position":[[1285,8]]}}}],["post",{"_index":609,"t":{"60":{"position":[[484,4]]},"69":{"position":[[182,4],[209,4],[597,4],[685,4]]},"78":{"position":[[208,4]]},"120":{"position":[[584,4]]},"516":{"position":[[82,4]]},"862":{"position":[[105,4]]},"894":{"position":[[286,4]]},"917":{"position":[[55,4]]}}}],["presettingno",{"_index":2909,"t":{"702":{"position":[[1507,12],[2526,12]]}}}],["previewhandl",{"_index":1785,"t":{"361":{"position":[[1648,13],[1846,13],[2489,13],[2828,13]]}}}],["previewreceiv",{"_index":1758,"t":{"361":{"position":[[215,15],[1358,15]]},"809":{"position":[[190,15]]}}}],["previewsend",{"_index":1759,"t":{"361":{"position":[[280,11],[359,11],[425,11],[574,11]]},"365":{"position":[[1514,11]]},"489":{"position":[[315,11]]},"702":{"position":[[424,11]]},"809":{"position":[[280,11],[392,11]]}}}],["privat",{"_index":436,"t":{"48":{"position":[[225,7]]},"69":{"position":[[224,7]]},"134":{"position":[[1065,7]]},"235":{"position":[[365,7]]},"286":{"position":[[594,7]]},"308":{"position":[[485,7],[607,7],[726,7],[848,7]]},"347":{"position":[[495,7],[617,7]]},"361":{"position":[[1234,7],[1306,7],[2202,7],[2815,7]]},"393":{"position":[[237,7]]},"489":{"position":[[554,7]]},"493":{"position":[[110,7],[143,7]]},"495":{"position":[[153,7],[1438,7]]},"523":{"position":[[1073,7]]},"528":{"position":[[125,7]]},"702":{"position":[[569,7],[592,7],[618,7],[642,7],[667,7]]},"734":{"position":[[107,7]]}}}],["pro",{"_index":2923,"t":{"705":{"position":[[12,3]]},"707":{"position":[[14,3],[186,3]]}}}],["procedur",{"_index":906,"t":{"125":{"position":[[11,9]]}}}],["progress",{"_index":2494,"t":{"528":{"position":[[1029,8],[1727,8]]},"727":{"position":[[736,8],[1754,8]]},"830":{"position":[[603,8]]},"832":{"position":[[2280,8]]}}}],["propdp",{"_index":1903,"t":{"376":{"position":[[181,6]]}}}],["properti",{"_index":2558,"t":{"546":{"position":[[188,8]]}}}],["propertyshouldbeok",{"_index":2569,"t":{"550":{"position":[[121,18]]}}}],["protect",{"_index":348,"t":{"40":{"position":[[135,9]]},"42":{"position":[[72,9]]},"57":{"position":[[1261,9]]},"120":{"position":[[683,9],[2290,9]]},"146":{"position":[[176,9]]},"159":{"position":[[369,9],[679,9]]},"194":{"position":[[220,9]]},"225":{"position":[[124,9],[489,9],[603,9]]},"233":{"position":[[223,9]]},"235":{"position":[[480,9],[628,9]]},"272":{"position":[[1160,9]]},"290":{"position":[[863,9],[1156,9]]},"301":{"position":[[935,9]]},"308":{"position":[[1679,9]]},"347":{"position":[[1836,9]]},"361":{"position":[[191,9],[256,9],[335,9],[401,9],[482,9],[550,9],[1334,9]]},"365":{"position":[[1490,9]]},"431":{"position":[[228,9],[470,9]]},"463":{"position":[[72,9]]},"465":{"position":[[71,9]]},"489":{"position":[[212,9],[291,9]]},"493":{"position":[[316,9],[719,9],[1018,9]]},"530":{"position":[[208,9]]},"537":{"position":[[365,9],[776,9],[1090,9],[1287,9]]},"574":{"position":[[441,9]]},"630":{"position":[[332,9]]},"693":{"position":[[108,9]]},"702":{"position":[[317,9],[400,9]]},"774":{"position":[[105,9]]},"780":{"position":[[207,9]]},"809":{"position":[[166,9],[256,9],[368,9],[476,9]]},"832":{"position":[[443,9],[693,9],[941,9],[1087,9]]},"836":{"position":[[158,9]]}}}],["protocol",{"_index":420,"t":{"46":{"position":[[490,8]]},"780":{"position":[[305,8],[581,8]]}}}],["protocoldataeventarg",{"_index":3080,"t":{"780":{"position":[[272,21],[515,21]]}}}],["proxyattributemap",{"_index":2170,"t":{"447":{"position":[[1094,17]]}}}],["proxyclass1",{"_index":2199,"t":{"451":{"position":[[97,11],[218,11]]}}}],["proxyclass2",{"_index":2202,"t":{"451":{"position":[[277,11]]}}}],["proxygener",{"_index":2214,"t":{"455":{"position":[[419,14]]}}}],["proxyinfo",{"_index":3404,"t":{"932":{"position":[[363,9],[487,9]]}}}],["public",{"_index":184,"t":{"25":{"position":[[43,6],[96,6],[156,6]]},"40":{"position":[[78,6]]},"48":{"position":[[60,6],[152,6]]},"57":{"position":[[551,6],[626,6],[757,6],[847,6],[1223,6]]},"127":{"position":[[143,6],[286,6],[410,6],[562,6]]},"134":{"position":[[194,6],[927,6],[969,6],[1033,6],[1309,6],[1796,6],[2228,6],[2501,6],[2992,6]]},"138":{"position":[[247,6],[307,6]]},"159":{"position":[[332,6],[642,6]]},"194":{"position":[[97,6],[148,6]]},"196":{"position":[[107,6],[148,6],[195,6],[320,6],[366,6]]},"225":{"position":[[79,6],[435,6]]},"233":{"position":[[97,6],[151,6]]},"235":{"position":[[308,6],[404,6],[872,6]]},"241":{"position":[[60,6],[101,6],[148,6],[273,6],[319,6],[371,6]]},"243":{"position":[[10,6],[68,6],[144,6],[196,6],[259,6],[340,6]]},"261":{"position":[[256,6],[621,6]]},"272":{"position":[[443,6],[505,6],[587,6],[883,6],[1000,6],[1087,6]]},"286":{"position":[[558,6],[626,6],[786,6]]},"301":{"position":[[2005,6],[2093,6],[2185,6],[2278,6]]},"308":{"position":[[419,6],[554,6],[676,6],[796,6],[915,6],[959,6],[1087,6],[1411,6],[1577,6]]},"347":{"position":[[425,6],[564,6],[684,6],[728,6],[856,6],[1711,6]]},"361":{"position":[[94,6],[141,6]]},"365":{"position":[[187,6],[238,6],[495,6],[754,6],[1013,6],[2090,6],[2376,6],[2666,6],[2956,6]]},"376":{"position":[[49,6],[268,6],[421,6],[669,6],[749,6],[1066,6],[1377,6]]},"431":{"position":[[772,6],[800,6]]},"434":{"position":[[21,6],[49,6],[78,6]]},"436":{"position":[[20,6],[43,6],[71,6],[102,6],[131,6],[160,6],[193,6],[224,6],[255,6],[292,6],[332,6],[372,6],[419,6],[469,6],[522,6],[586,6],[605,6],[666,6],[750,6],[803,6],[825,6],[858,6]]},"453":{"position":[[58,6]]},"455":{"position":[[77,6],[127,6],[258,6],[290,6],[799,6]]},"473":{"position":[[75,6],[145,6]]},"489":{"position":[[123,6],[162,6],[453,6],[492,6],[525,6],[569,6],[697,6],[911,6],[1114,6],[1247,6]]},"491":{"position":[[125,6],[289,6],[547,6]]},"493":{"position":[[202,6]]},"507":{"position":[[33,6],[61,6],[92,6],[121,6],[152,6],[186,6],[240,6],[825,6],[1536,6],[1569,6],[1644,6]]},"512":{"position":[[98,6],[149,6],[341,6],[650,6],[1230,6]]},"523":{"position":[[9,6],[37,6],[66,6],[113,6],[382,6],[411,6],[458,6],[508,6],[561,6],[608,6],[645,6],[685,6],[725,6],[753,6],[784,6],[813,6],[842,6],[875,6],[906,6],[939,6],[958,6],[975,6],[1031,6],[2491,6]]},"548":{"position":[[49,6],[272,6],[301,6],[393,6],[423,6],[453,6],[544,6]]},"550":{"position":[[109,6],[603,6],[669,6],[739,6],[772,6],[863,6]]},"552":{"position":[[132,6],[821,6],[888,6],[1117,6],[1144,6],[1174,6],[1207,6],[1240,6],[1331,6],[1419,6],[1759,6],[1830,6],[1865,6],[1956,6]]},"554":{"position":[[300,6]]},"556":{"position":[[0,6],[38,6],[90,6],[119,6],[210,6],[282,6],[311,6],[402,6],[474,6],[503,6],[595,6],[625,6],[655,6],[746,6],[818,6],[885,6],[1018,6],[1040,6],[1065,6],[1095,6],[1125,6],[1216,6],[1288,6],[1354,6],[1424,6],[1457,6],[1548,6],[1620,6],[1687,6],[1916,6],[1943,6],[1973,6],[2006,6],[2039,6],[2130,6],[2202,6],[2231,6],[2305,6],[2352,6],[2443,6],[2560,6],[2620,6],[2849,6],[2876,6],[2906,6],[2939,6],[2972,6],[3063,6],[3204,6],[3264,6],[3493,6],[3520,6],[3550,6],[3583,6],[3616,6],[3707,6]]},"574":{"position":[[306,6],[404,6]]},"606":{"position":[[16,6],[123,6]]},"610":{"position":[[405,6],[503,6]]},"641":{"position":[[102,6],[227,6]]},"643":{"position":[[51,6],[130,6]]},"648":{"position":[[0,6],[69,6],[491,6],[814,6]]},"650":{"position":[[53,6]]},"663":{"position":[[96,6],[217,6]]},"672":{"position":[[262,6]]},"674":{"position":[[234,6]]},"684":{"position":[[105,6],[181,6],[452,6]]},"702":{"position":[[227,6],[267,6],[512,6],[691,6],[780,6],[879,6],[999,6],[1113,6],[1200,6],[1282,6],[1390,6],[1495,6],[1589,6],[1682,6],[1759,6],[1863,6],[1945,6],[1975,6],[2685,6]]},"734":{"position":[[137,6],[385,6],[640,6],[886,6]]},"809":{"position":[[119,6]]},"894":{"position":[[97,6],[216,6],[293,6],[527,6],[797,6],[820,6],[847,6]]},"925":{"position":[[816,6],[870,6],[996,6],[1023,6],[1050,6]]},"928":{"position":[[107,6],[155,6],[211,6],[285,6],[308,6],[335,6]]},"969":{"position":[[421,6],[470,6],[589,6]]}}}],["publishev",{"_index":1943,"t":{"391":{"position":[[332,12]]}}}],["pull",{"_index":3182,"t":{"826":{"position":[[95,4]]},"828":{"position":[[193,4]]},"830":{"position":[[39,4],[72,4]]},"834":{"position":[[5,4]]}}}],["pullfil",{"_index":2505,"t":{"530":{"position":[[352,8]]},"693":{"position":[[252,8]]},"832":{"position":[[2405,8]]},"836":{"position":[[302,8]]}}}],["pullfileasync",{"_index":2497,"t":{"528":{"position":[[1106,13]]},"832":{"position":[[2367,13]]}}}],["pullsmallfil",{"_index":2853,"t":{"691":{"position":[[11,13]]}}}],["pullsmallfileasync",{"_index":2854,"t":{"691":{"position":[[26,18],[118,18]]}}}],["push",{"_index":3183,"t":{"826":{"position":[[107,4]]},"828":{"position":[[202,4]]},"834":{"position":[[0,4]]}}}],["pushfil",{"_index":2504,"t":{"530":{"position":[[317,8]]},"693":{"position":[[217,8]]},"834":{"position":[[22,8]]},"836":{"position":[[267,8]]}}}],["pushfileasync",{"_index":2501,"t":{"528":{"position":[[1803,13]]}}}],["pushsmallfil",{"_index":2858,"t":{"691":{"position":[[214,13]]}}}],["pushsmallfileasync",{"_index":2859,"t":{"691":{"position":[[229,18],[296,18]]}}}],["put",{"_index":835,"t":{"120":{"position":[[589,3]]}}}],["qq",{"_index":7,"t":{"3":{"position":[[18,2]]},"12":{"position":[[150,2],[166,2]]},"94":{"position":[[33,2]]},"263":{"position":[[62,2]]},"495":{"position":[[65,2]]},"906":{"position":[[48,2]]},"935":{"position":[[153,2]]},"973":{"position":[[26,2]]}}}],["qq_40374647",{"_index":2334,"t":{"495":{"position":[[65,11]]}}}],["r",{"_index":666,"t":{"78":{"position":[[102,1]]},"80":{"position":[[1870,1]]},"343":{"position":[[44,1]]},"347":{"position":[[1018,1],[1022,1],[1155,1],[1159,1],[1192,1],[1196,1],[1546,1],[1550,1]]},"361":{"position":[[1435,1],[1528,1],[1562,1],[1756,1],[1944,1],[2029,1],[2056,1],[2190,1],[2262,1],[2282,1],[2345,1]]},"411":{"position":[[213,1],[260,1],[286,1]]},"413":{"position":[[301,1],[362,1],[376,1]]},"514":{"position":[[123,1],[485,1]]},"736":{"position":[[255,1],[270,1],[323,1]]},"738":{"position":[[58,1],[63,1]]},"745":{"position":[[469,1],[493,1]]}}}],["rabbitmq",{"_index":1934,"t":{"389":{"position":[[39,8]]}}}],["rais",{"_index":2639,"t":{"574":{"position":[[274,5],[608,5]]}}}],["raiseev",{"_index":1956,"t":{"395":{"position":[[54,10]]}}}],["raisesourcetyp",{"_index":1952,"t":{"393":{"position":[[333,15]]}}}],["random",{"_index":2071,"t":{"436":{"position":[[1075,6],[1082,6],[1095,6],[1105,6]]},"523":{"position":[[1359,6],[1366,6],[1379,6],[1389,6]]},"610":{"position":[[59,6]]},"727":{"position":[[1206,6]]}}}],["read",{"_index":1626,"t":{"301":{"position":[[1331,4],[1676,4]]},"411":{"position":[[224,4]]},"431":{"position":[[255,4]]},"559":{"position":[[108,4]]},"561":{"position":[[452,4]]},"632":{"position":[[25,4],[391,4]]},"702":{"position":[[2130,4],[2179,4],[2319,4],[2845,4],[2903,4]]},"725":{"position":[[35,4]]},"798":{"position":[[36,4]]}}}],["readbyt",{"_index":1127,"t":{"157":{"position":[[353,8]]},"702":{"position":[[2375,8],[2421,8],[2464,8],[2509,8],[2557,8],[2957,8]]}}}],["readbytespackag",{"_index":1137,"t":{"157":{"position":[[593,16]]}}}],["readchar",{"_index":2376,"t":{"507":{"position":[[969,8]]}}}],["readdatetim",{"_index":2385,"t":{"507":{"position":[[1718,12]]}}}],["readdoubl",{"_index":2377,"t":{"507":{"position":[[1001,10]]}}}],["reader",{"_index":1991,"t":{"411":{"position":[[157,6],[217,6]]}}}],["readint32",{"_index":1129,"t":{"157":{"position":[[390,9]]},"431":{"position":[[410,9]]},"507":{"position":[[902,9],[1089,9],[1188,9],[1308,9],[1425,9]]}}}],["readint64",{"_index":1131,"t":{"157":{"position":[[430,9]]}}}],["readisnul",{"_index":2379,"t":{"507":{"position":[[1038,10],[1241,10]]}}}],["readkey",{"_index":600,"t":{"60":{"position":[[232,7]]},"66":{"position":[[288,7]]},"896":{"position":[[526,7]]},"932":{"position":[[542,7]]}}}],["readlin",{"_index":725,"t":{"91":{"position":[[446,8]]},"319":{"position":[[662,8]]},"495":{"position":[[1317,8],[1421,8]]},"561":{"position":[[336,8]]}}}],["readobject",{"_index":1135,"t":{"157":{"position":[[519,10]]}}}],["readonli",{"_index":1544,"t":{"286":{"position":[[602,8]]},"376":{"position":[[435,8],[763,8]]},"491":{"position":[[139,8]]},"493":{"position":[[118,8],[151,8]]},"734":{"position":[[115,8]]}}}],["readpackag",{"_index":2383,"t":{"507":{"position":[[1448,11]]}}}],["readstr",{"_index":1133,"t":{"157":{"position":[[474,10]]},"431":{"position":[[442,10]]},"507":{"position":[[935,10]]}}}],["readtimeout",{"_index":2613,"t":{"561":{"position":[[192,11]]}}}],["readuint16",{"_index":2921,"t":{"702":{"position":[[2595,10],[2638,10]]}}}],["recedsurpluslength",{"_index":1789,"t":{"361":{"position":[[2324,18],[2364,18],[2623,18],[2692,18]]}}}],["receiv",{"_index":515,"t":{"57":{"position":[[193,8],[814,7],[1422,8]]},"188":{"position":[[31,8],[225,8]]},"192":{"position":[[33,8],[106,8]]},"207":{"position":[[53,8]]},"223":{"position":[[67,8],[291,8]]},"225":{"position":[[243,8]]},"229":{"position":[[39,8],[110,8]]},"235":{"position":[[217,8]]},"272":{"position":[[185,8],[577,7],[1313,8]]},"297":{"position":[[112,8]]},"301":{"position":[[155,8],[2377,8]]},"308":{"position":[[187,8],[1834,8]]},"317":{"position":[[65,8],[93,8]]},"323":{"position":[[2,8],[31,8]]},"347":{"position":[[189,8],[1995,8]]},"406":{"position":[[70,8],[152,8]]},"422":{"position":[[60,8],[165,8]]},"561":{"position":[[71,8]]},"745":{"position":[[60,8],[165,8]]},"816":{"position":[[160,8]]},"843":{"position":[[68,8]]},"849":{"position":[[86,8]]},"859":{"position":[[40,8]]},"980":{"position":[[28,8],[133,8]]}}}],["receivedcallback",{"_index":2270,"t":{"470":{"position":[[101,16],[381,16],[498,16],[768,16]]}}}],["receiveddataeventarg",{"_index":1364,"t":{"194":{"position":[[277,21]]},"233":{"position":[[283,21]]},"235":{"position":[[688,21]]},"493":{"position":[[1080,21]]}}}],["receivedinput",{"_index":2274,"t":{"470":{"position":[[738,13]]}}}],["receivedstream",{"_index":2989,"t":{"727":{"position":[[1061,14]]}}}],["receivetyp",{"_index":1560,"t":{"288":{"position":[[171,11]]},"458":{"position":[[149,11]]},"925":{"position":[[297,11]]}}}],["reconnectionplugin",{"_index":3332,"t":{"882":{"position":[[118,18]]}}}],["redi",{"_index":3285,"t":{"872":{"position":[[446,5]]},"950":{"position":[[72,5]]}}}],["ref",{"_index":1620,"t":{"301":{"position":[[1010,3],[1037,3],[1870,3]]},"442":{"position":[[12,3]]},"648":{"position":[[147,3],[470,3],[568,3],[793,3],[898,3],[1152,3]]},"792":{"position":[[39,3]]}}}],["regist",{"_index":203,"t":{"25":{"position":[[334,8]]},"376":{"position":[[513,8],[841,8]]},"491":{"position":[[225,8]]}}}],["registerallserv",{"_index":3400,"t":{"932":{"position":[[242,17]]}}}],["registerscop",{"_index":2591,"t":{"554":{"position":[[382,14]]}}}],["registerserv",{"_index":976,"t":{"129":{"position":[[218,14]]},"138":{"position":[[643,14]]},"286":{"position":[[359,14]]},"447":{"position":[[484,14]]},"514":{"position":[[248,14]]},"516":{"position":[[390,14]]},"896":{"position":[[250,14]]}}}],["registersingleton",{"_index":2579,"t":{"552":{"position":[[1510,17],[1555,17]]}}}],["registertransi",{"_index":2563,"t":{"548":{"position":[[129,17]]},"550":{"position":[[193,17],[246,17],[299,17],[352,17]]},"552":{"position":[[214,17],[267,17],[320,17],[373,17],[426,17],[479,17]]}}}],["rel",{"_index":891,"t":{"120":{"position":[[1829,8],[1974,8]]}}}],["remot",{"_index":905,"t":{"125":{"position":[[4,6]]},"207":{"position":[[66,6],[118,6]]},"843":{"position":[[80,6]]},"849":{"position":[[98,6]]}}}],["remotedirectoryinforesult",{"_index":2652,"t":{"581":{"position":[[165,25]]}}}],["remoteendpoint",{"_index":3137,"t":{"809":{"position":[[215,14]]}}}],["remoteiphost",{"_index":750,"t":{"102":{"position":[[269,12]]},"184":{"position":[[1430,12]]},"218":{"position":[[1430,12]]}}}],["remotestream",{"_index":2737,"t":{"630":{"position":[[119,12],[132,12]]},"632":{"position":[[1,12],[38,12],[87,12],[100,12],[222,12],[260,12],[297,12],[324,12],[378,12],[458,12],[499,12],[526,12]]},"876":{"position":[[100,12]]}}}],["request",{"_index":745,"t":{"102":{"position":[[173,7],[202,7],[319,7],[327,7]]},"106":{"position":[[9,7]]},"120":{"position":[[778,7],[941,7],[1067,7],[1098,7]]},"301":{"position":[[779,7],[824,7],[1028,7],[1842,7]]},"463":{"position":[[165,7],[281,7]]},"465":{"position":[[165,7],[221,7],[426,7]]},"894":{"position":[[717,7]]}}}],["requestinfo",{"_index":516,"t":{"57":{"position":[[213,11],[1454,11],[1529,11],[1555,11]]},"159":{"position":[[446,11],[756,11]]},"188":{"position":[[257,11]]},"192":{"position":[[138,11]]},"194":{"position":[[339,11],[420,11],[436,11]]},"207":{"position":[[84,11]]},"223":{"position":[[322,11]]},"225":{"position":[[201,11]]},"229":{"position":[[141,11]]},"233":{"position":[[345,11],[426,11],[442,11]]},"235":{"position":[[750,11],[831,11],[847,11]]},"272":{"position":[[205,11],[1345,11],[1420,11],[1446,11]]},"301":{"position":[[175,11],[2409,11],[2484,11],[2510,11]]},"308":{"position":[[207,11],[1866,11],[1941,11],[1967,11]]},"340":{"position":[[548,11],[588,11]]},"347":{"position":[[209,11],[2027,11],[2102,11],[2128,11]]},"361":{"position":[[384,11]]},"406":{"position":[[184,11]]},"422":{"position":[[197,11]]},"470":{"position":[[413,11]]},"489":{"position":[[340,11]]},"493":{"position":[[1113,11]]},"537":{"position":[[1194,11],[1271,11],[1422,11],[1522,11]]},"561":{"position":[[103,11],[125,11]]},"574":{"position":[[518,11]]},"702":{"position":[[449,11]]},"745":{"position":[[197,11]]},"756":{"position":[[125,11],[219,11],[258,11],[310,11]]},"816":{"position":[[194,11]]},"843":{"position":[[99,11]]},"849":{"position":[[117,11]]},"857":{"position":[[791,11],[819,11],[838,11]]},"859":{"position":[[71,11],[716,11],[735,11]]},"980":{"position":[[165,11]]}}}],["reserveterminatorcod",{"_index":3022,"t":{"745":{"position":[[540,21]]}}}],["reset",{"_index":1763,"t":{"361":{"position":[[506,5]]},"809":{"position":[[500,5]]}}}],["resetid",{"_index":2727,"t":{"619":{"position":[[63,7]]},"621":{"position":[[8,7]]},"623":{"position":[[13,7]]},"776":{"position":[[83,7]]}}}],["resolv",{"_index":2566,"t":{"548":{"position":[[185,7]]},"550":{"position":[[408,7]]},"552":{"position":[[535,7],[1617,7]]},"554":{"position":[[435,7],[473,7],[585,7],[637,7],[677,7]]}}}],["resourcepath",{"_index":2484,"t":{"528":{"position":[[761,12],[1475,12]]},"830":{"position":[[316,12],[331,12]]},"832":{"position":[[674,12],[906,12],[1878,12]]}}}],["respons",{"_index":843,"t":{"120":{"position":[[830,8],[991,8],[2152,8],[2267,8]]},"463":{"position":[[205,8]]},"465":{"position":[[289,8],[706,8]]},"894":{"position":[[649,8]]}}}],["responseddata",{"_index":3248,"t":{"857":{"position":[[687,13],[701,13],[805,13]]},"859":{"position":[[576,13],[590,13],[702,13]]}}}],["responserequestinfo",{"_index":3249,"t":{"859":{"position":[[680,19]]}}}],["respos",{"_index":753,"t":{"102":{"position":[[302,7],[373,7]]}}}],["result",{"_index":679,"t":{"80":{"position":[[282,6],[430,6],[441,6],[565,6],[576,6],[727,6],[1260,6],[1391,6],[1963,6],[2042,6],[2053,6],[2133,6],[2144,6],[2226,6]]},"132":{"position":[[365,6]]},"134":{"position":[[3619,6]]},"166":{"position":[[274,6],[580,6]]},"252":{"position":[[274,6],[580,6]]},"528":{"position":[[1071,6],[1078,6],[1139,6],[1177,6],[1769,6],[1776,6],[1836,6],[1874,6]]},"600":{"position":[[91,6]]},"648":{"position":[[280,6]]},"672":{"position":[[967,6]]},"674":{"position":[[874,6],[1008,6],[1016,6]]},"691":{"position":[[87,6],[167,6],[265,6],[340,6]]},"727":{"position":[[626,6],[822,6],[963,6],[1086,6],[1629,6],[1907,6],[1914,6],[1994,6]]},"752":{"position":[[116,6]]},"828":{"position":[[331,6]]},"830":{"position":[[632,6]]},"832":{"position":[[819,6],[928,6],[2181,6],[2389,6],[2448,6]]},"878":{"position":[[668,6],[782,6]]}}}],["result1",{"_index":592,"t":{"60":{"position":[[111,7],[212,7]]}}}],["result2",{"_index":635,"t":{"66":{"position":[[207,7],[268,7]]}}}],["resultcod",{"_index":2010,"t":{"415":{"position":[[237,10],[250,10]]},"727":{"position":[[633,10],[647,10],[970,10],[984,10],[1636,10],[1650,10]]},"830":{"position":[[655,10]]},"832":{"position":[[2188,10],[2202,10]]}}}],["resultcon",{"_index":2479,"t":{"528":{"position":[[610,9],[682,9],[1224,9],[1324,9],[1396,9],[1921,9]]}}}],["return",{"_index":190,"t":{"25":{"position":[[127,6],[187,6]]},"38":{"position":[[65,6]]},"46":{"position":[[159,6]]},"57":{"position":[[832,6],[912,6],[1324,6],[1881,6]]},"60":{"position":[[439,6]]},"66":{"position":[[495,6]]},"69":{"position":[[394,6]]},"104":{"position":[[517,6]]},"127":{"position":[[377,6],[392,6],[653,6],[668,6]]},"134":{"position":[[1742,6],[2146,6],[2938,6],[3346,6]]},"138":{"position":[[345,6]]},"272":{"position":[[552,6],[638,6],[1219,6],[1679,6]]},"301":{"position":[[916,7],[926,7],[1120,6],[1569,6],[1874,6],[2808,6]]},"308":{"position":[[584,6],[705,6],[826,6],[942,6],[1056,6],[1071,6],[1279,6],[1660,7],[1670,7],[1739,6],[2287,6]]},"319":{"position":[[559,6]]},"347":{"position":[[594,6],[711,6],[825,6],[840,6],[1516,6],[1607,6],[1898,6],[2452,6]]},"376":{"position":[[298,6],[1047,7],[1057,7],[1213,6],[1358,7],[1368,7],[1465,6]]},"406":{"position":[[419,6]]},"422":{"position":[[431,6]]},"431":{"position":[[456,6],[649,6]]},"455":{"position":[[225,6],[240,6]]},"465":{"position":[[335,6]]},"489":{"position":[[261,6],[666,6],[681,6],[880,6],[895,6],[1217,6],[1283,6]]},"491":{"position":[[462,6],[531,6],[720,6],[789,6]]},"493":{"position":[[432,6]]},"512":{"position":[[189,6],[306,7],[316,7],[382,6],[575,7],[585,7],[1190,6],[1272,6]]},"514":{"position":[[405,6],[447,6]]},"523":{"position":[[2455,6]]},"528":{"position":[[318,6],[433,6],[511,6]]},"530":{"position":[[685,6],[831,6],[1077,6]]},"537":{"position":[[1220,6],[1451,6]]},"615":{"position":[[184,6]]},"641":{"position":[[434,6],[449,6]]},"643":{"position":[[318,6],[333,6]]},"650":{"position":[[85,6]]},"663":{"position":[[437,6],[473,6]]},"672":{"position":[[655,6]]},"674":{"position":[[527,6]]},"684":{"position":[[316,6],[388,6],[642,6],[660,6],[733,6]]},"702":{"position":[[368,6],[2652,6],[2669,6],[2971,6],[2986,6]]},"734":{"position":[[366,7],[376,7],[468,6],[621,7],[631,7],[787,6]]},"736":{"position":[[211,6],[276,6]]},"745":{"position":[[431,6]]},"774":{"position":[[314,6],[394,6]]},"894":{"position":[[247,6],[332,6],[727,6],[759,6]]},"925":{"position":[[854,6],[958,6]]},"928":{"position":[[186,6],[251,6]]},"930":{"position":[[233,6]]},"980":{"position":[[399,6]]}}}],["returndata",{"_index":1017,"t":{"134":{"position":[[1663,10],[1749,10],[2859,10],[2945,10]]},"857":{"position":[[476,10],[606,10]]},"859":{"position":[[370,10],[495,10]]}}}],["returnexcept",{"_index":3002,"t":{"734":{"position":[[199,15]]}}}],["returnstr",{"_index":2770,"t":{"655":{"position":[[242,12]]},"659":{"position":[[162,12]]},"661":{"position":[[366,12]]},"681":{"position":[[446,12]]}}}],["reversecallbackserv",{"_index":1038,"t":{"138":{"position":[[260,21],[658,21]]},"142":{"position":[[127,21],[427,21]]}}}],["reverserpcconsoleapp",{"_index":1054,"t":{"142":{"position":[[106,20],[406,20]]}}}],["rfc",{"_index":3377,"t":{"909":{"position":[[60,3]]}}}],["rfc7936",{"_index":3379,"t":{"909":{"position":[[71,7]]}}}],["rootdirectoryinforesult",{"_index":2653,"t":{"581":{"position":[[191,23]]}}}],["rootpath",{"_index":3196,"t":{"830":{"position":[[376,8]]}}}],["router",{"_index":1546,"t":{"286":{"position":[[684,6]]},"882":{"position":[[317,6]]},"894":{"position":[[135,6]]}}}],["routertyp",{"_index":1079,"t":{"146":{"position":[[262,10]]},"530":{"position":[[294,10],[329,10]]},"693":{"position":[[194,10],[229,10]]},"836":{"position":[[244,10],[279,10],[314,10]]}}}],["routetyp",{"_index":1080,"t":{"146":{"position":[[275,9]]},"530":{"position":[[307,9],[342,9]]},"693":{"position":[[207,9],[242,9]]},"836":{"position":[[257,9],[292,9],[327,9]]}}}],["rpc",{"_index":585,"t":{"60":{"position":[[22,3]]},"69":{"position":[[22,3]]},"80":{"position":[[52,3]]},"125":{"position":[[0,3],[69,3],[120,3],[134,3]]},"132":{"position":[[30,3]]},"134":{"position":[[138,3],[371,3],[395,3],[707,3],[731,3],[1209,3],[1233,3],[1576,3],[2074,3],[2401,3],[2425,3],[2679,3],[2772,3],[3181,3],[3274,3]]},"136":{"position":[[3,3],[47,3]]},"138":{"position":[[7,3],[111,3],[118,3],[412,3]]},"140":{"position":[[146,3],[164,3],[213,3],[231,3]]},"144":{"position":[[4,3],[10,3],[36,3],[46,3]]},"146":{"position":[[52,3],[285,3]]},"440":{"position":[[2,3]]},"455":{"position":[[601,3],[910,3]]},"498":{"position":[[11,3]]},"516":{"position":[[371,3]]},"530":{"position":[[997,3]]},"639":{"position":[[0,3],[44,3],[68,3]]},"641":{"position":[[4,3]]},"646":{"position":[[0,3]]},"648":{"position":[[387,3],[684,3],[1035,3]]},"653":{"position":[[0,3],[91,3],[176,3],[196,3],[214,3],[243,3]]},"657":{"position":[[2,3]]},"661":{"position":[[1,3]]},"666":{"position":[[1,3],[23,3],[59,3],[123,3]]},"670":{"position":[[8,3],[53,3]]},"677":{"position":[[20,3],[53,3]]},"686":{"position":[[465,3]]},"778":{"position":[[76,3]]},"792":{"position":[[4,3]]},"806":{"position":[[28,3],[143,3],[264,3]]},"862":{"position":[[10,3]]},"868":{"position":[[102,3]]},"874":{"position":[[32,3],[375,3]]},"876":{"position":[[186,3]]},"880":{"position":[[132,3],[156,3],[172,3],[226,3]]},"891":{"position":[[60,3]]},"917":{"position":[[23,3],[33,3]]},"930":{"position":[[296,3]]},"932":{"position":[[143,3],[417,3]]}}}],["rpcactionfilterattribut",{"_index":2750,"t":{"648":{"position":[[42,24]]}}}],["rpcargsclasslib",{"_index":2198,"t":{"451":{"position":[[81,15],[202,15],[261,15]]}}}],["rpcexcept",{"_index":1012,"t":{"134":{"position":[[1456,12],[1562,12],[1954,12],[2060,12],[2758,12],[3260,12]]}}}],["rpcinvokeexcept",{"_index":1006,"t":{"134":{"position":[[375,18],[711,18],[1213,18],[2405,18]]}}}],["rpcproxi",{"_index":999,"t":{"134":{"position":[[183,8]]},"453":{"position":[[11,8],[38,8]]}}}],["rpcproxyinfo",{"_index":3403,"t":{"932":{"position":[[350,12]]}}}],["rpcpullchannel",{"_index":2807,"t":{"672":{"position":[[273,14],[983,14],[1012,14]]}}}],["rpcpushchannel",{"_index":2814,"t":{"674":{"position":[[245,14],[890,14],[919,14]]}}}],["rpcserver",{"_index":940,"t":{"127":{"position":[[29,9],[170,9]]},"138":{"position":[[284,9]]},"286":{"position":[[582,9]]},"447":{"position":[[1412,9]]},"455":{"position":[[104,9]]},"512":{"position":[[15,9],[127,9]]},"641":{"position":[[129,9]]},"889":{"position":[[258,9]]},"894":{"position":[[15,9],[122,9]]}}}],["rpcservic",{"_index":2201,"t":{"451":{"position":[[133,10],[144,10],[161,10]]},"932":{"position":[[72,10],[83,10],[100,10],[149,10],[231,10],[291,10],[375,10]]}}}],["rpcsocketcli",{"_index":1063,"t":{"142":{"position":[[354,15],[374,15]]}}}],["rpcstore",{"_index":2149,"t":{"447":{"position":[[77,8],[119,8],[870,8],[1063,8],[1085,8]]},"514":{"position":[[284,8]]},"891":{"position":[[40,8],[75,8],[116,8],[131,8],[170,8],[186,8],[216,8]]}}}],["rpctype",{"_index":3405,"t":{"932":{"position":[[399,7]]}}}],["rrqm",{"_index":2,"t":{"3":{"position":[[5,4]]},"78":{"position":[[164,4],[272,4],[394,4]]},"80":{"position":[[1999,4],[2090,4],[2183,4]]},"94":{"position":[[0,4]]},"151":{"position":[[71,4]]},"157":{"position":[[160,4]]},"188":{"position":[[593,4]]},"365":{"position":[[38,4]]},"470":{"position":[[566,4]]},"556":{"position":[[2612,4],[3256,4]]},"588":{"position":[[34,4]]},"666":{"position":[[150,4]]},"758":{"position":[[74,4]]},"826":{"position":[[73,4]]},"857":{"position":[[539,4],[769,4]]},"859":{"position":[[433,4],[658,4]]},"884":{"position":[[181,4]]},"894":{"position":[[616,4]]},"917":{"position":[[111,4]]}}}],["rrqmbitconvert",{"_index":3341,"t":{"889":{"position":[[12,16]]}}}],["rrqmbox",{"_index":1556,"t":{"288":{"position":[[46,7]]}}}],["rrqmconfig",{"_index":1941,"t":{"391":{"position":[[162,10]]},"889":{"position":[[53,10]]},"891":{"position":[[3,10]]},"930":{"position":[[144,10]]}}}],["rrqmconvert",{"_index":3342,"t":{"889":{"position":[[82,13]]}}}],["rrqmcore",{"_index":2982,"t":{"727":{"position":[[481,8]]}}}],["rrqmdependencyobject",{"_index":3344,"t":{"889":{"position":[[117,20]]}}}],["rrqmeventagr",{"_index":3346,"t":{"889":{"position":[[181,13]]}}}],["rrqmeventarg",{"_index":2520,"t":{"537":{"position":[[431,13]]}}}],["rrqmoverlengthexcept",{"_index":3348,"t":{"889":{"position":[[268,23]]}}}],["rrqmproxi",{"_index":628,"t":{"66":{"position":[[23,9]]},"75":{"position":[[23,9]]},"86":{"position":[[23,9]]},"447":{"position":[[1180,9]]},"932":{"position":[[475,9]]}}}],["rrqmrpc",{"_index":2181,"t":{"449":{"position":[[19,7]]},"663":{"position":[[176,7]]},"932":{"position":[[407,7]]}}}],["rrqmsocket",{"_index":776,"t":{"104":{"position":[[339,10],[357,10]]},"122":{"position":[[120,10],[138,10]]},"159":{"position":[[64,10],[139,10]]},"288":{"position":[[72,10],[372,10],[390,10]]},"319":{"position":[[381,10],[399,10]]},"391":{"position":[[219,10]]},"886":{"position":[[29,10]]},"906":{"position":[[74,10]]}}}],["rrqmtimeoutexcept",{"_index":2774,"t":{"659":{"position":[[132,20]]}}}],["rrqmtool",{"_index":3401,"t":{"932":{"position":[[277,8]]}}}],["run",{"_index":724,"t":{"91":{"position":[[434,3]]},"159":{"position":[[466,3],[811,3]]},"338":{"position":[[53,3]]},"340":{"position":[[925,3]]},"495":{"position":[[1409,3]]},"602":{"position":[[64,3]]},"672":{"position":[[805,3]]},"674":{"position":[[704,3]]},"727":{"position":[[490,3],[586,3]]}}}],["runasync",{"_index":2496,"t":{"528":{"position":[[1059,8],[1757,8]]},"727":{"position":[[1782,8]]},"832":{"position":[[2334,8]]}}}],["s",{"_index":1393,"t":{"212":{"position":[[69,1]]},"822":{"position":[[52,1]]},"824":{"position":[[4,1]]}}}],["safedispos",{"_index":2492,"t":{"528":{"position":[[949,11],[1647,11]]},"632":{"position":[[539,11]]}}}],["sampl",{"_index":2881,"t":{"702":{"position":[[659,6],[1773,6],[1791,6],[1808,6],[2861,6]]}}}],["save",{"_index":2855,"t":{"691":{"position":[[59,4],[174,4]]}}}],["savepath",{"_index":2485,"t":{"528":{"position":[[790,8],[801,8],[1496,8],[1507,8]]},"691":{"position":[[179,8],[315,8]]},"830":{"position":[[449,8],[460,8]]},"832":{"position":[[1844,8]]}}}],["saveresult",{"_index":2857,"t":{"691":{"position":[[154,10]]}}}],["sayhello",{"_index":1039,"t":{"138":{"position":[[321,8]]},"142":{"position":[[149,8],[449,8]]}}}],["scope",{"_index":2553,"t":{"544":{"position":[[44,6]]},"554":{"position":[[106,6],[179,6],[192,6]]}}}],["scopedcontain",{"_index":2594,"t":{"554":{"position":[[557,15],[621,15],[661,15]]}}}],["scopedshouldbeok",{"_index":2590,"t":{"554":{"position":[[312,16]]}}}],["seal",{"_index":432,"t":{"48":{"position":[[168,6]]}}}],["see",{"_index":1611,"t":{"301":{"position":[[393,3],[431,3],[498,3],[535,3],[598,3],[635,3]]},"431":{"position":[[73,3],[113,3]]},"495":{"position":[[33,3]]}}}],["seek",{"_index":2387,"t":{"507":{"position":[[2118,4]]}}}],["select",{"_index":3386,"t":{"911":{"position":[[37,6]]}}}],["send",{"_index":209,"t":{"25":{"position":[[407,4],[478,4]]},"184":{"position":[[915,4],[939,4],[1694,4],[1718,4]]},"188":{"position":[[587,4]]},"196":{"position":[[127,4],[168,4],[215,4]]},"207":{"position":[[113,4]]},"218":{"position":[[915,4],[939,4],[1694,4],[1718,4]]},"223":{"position":[[481,4],[517,4],[676,4]]},"241":{"position":[[80,4],[121,4],[168,4]]},"243":{"position":[[30,4],[88,4],[164,4]]},"292":{"position":[[78,4],[90,4],[104,4]]},"365":{"position":[[50,4],[256,4],[441,4],[515,4],[700,4],[774,4],[959,4],[1035,4],[1220,4],[2353,4],[2643,4],[2933,4],[3225,4]]},"491":{"position":[[389,4],[647,4]]},"495":{"position":[[1226,4]]},"512":{"position":[[1104,4]]},"758":{"position":[[20,4]]},"780":{"position":[[42,4]]},"845":{"position":[[204,4]]},"851":{"position":[[235,4]]}}}],["sendasync",{"_index":1373,"t":{"196":{"position":[[340,9],[386,9]]},"241":{"position":[[293,9],[339,9],[391,9]]},"243":{"position":[[216,9],[279,9],[360,9]]}}}],["sendcallback",{"_index":2269,"t":{"470":{"position":[[74,12],[159,12],[347,12],[623,12]]}}}],["sender",{"_index":779,"t":{"104":{"position":[[467,6]]},"319":{"position":[[509,6]]}}}],["sendinput",{"_index":2272,"t":{"470":{"position":[[582,9]]}}}],["sendstream",{"_index":2993,"t":{"727":{"position":[[1930,10]]}}}],["sendthenrespons",{"_index":3247,"t":{"857":{"position":[[669,16],[728,16]]},"859":{"position":[[558,16],[617,16]]}}}],["sendthenreturn",{"_index":3246,"t":{"857":{"position":[[453,14],[500,14]]},"859":{"position":[[347,14],[394,14]]}}}],["sendwithw",{"_index":1585,"t":{"292":{"position":[[313,10]]},"319":{"position":[[643,10]]}}}],["sentdata",{"_index":2271,"t":{"470":{"position":[[134,8],[246,8],[302,8],[704,8]]}}}],["sequenceequ",{"_index":1704,"t":{"340":{"position":[[664,13]]},"632":{"position":[[424,13]]}}}],["serial",{"_index":2825,"t":{"681":{"position":[[329,13],[402,13]]},"684":{"position":[[344,9]]}}}],["serializ",{"_index":2050,"t":{"434":{"position":[[7,12]]},"436":{"position":[[6,12],[572,12],[789,12]]}}}],["serializationtyp",{"_index":1116,"t":{"157":{"position":[[204,17],[538,17]]},"681":{"position":[[244,17],[264,17],[309,17],[343,17],[382,17],[416,17]]},"684":{"position":[[223,17],[241,17],[290,17],[419,17],[496,17],[514,17],[588,17],[766,17]]},"686":{"position":[[143,17],[269,17],[290,17]]}}}],["serializeconvert",{"_index":2027,"t":{"429":{"position":[[36,16],[92,16]]},"519":{"position":[[46,16],[101,16]]},"521":{"position":[[230,16],[363,16],[476,16]]}}}],["serializeparamet",{"_index":2826,"t":{"684":{"position":[[26,18],[204,18],[400,18]]}}}],["server",{"_index":634,"t":{"66":{"position":[[167,6],[174,6],[187,6],[217,6]]},"80":{"position":[[339,6],[633,6],[891,6],[1299,6],[1537,6]]},"86":{"position":[[285,6],[292,6],[304,6],[328,6],[343,6]]},"894":{"position":[[171,6]]},"928":{"position":[[120,6]]}}}],["servercallcontext",{"_index":2787,"t":{"663":{"position":[[254,17],[346,17]]}}}],["servercellcod",{"_index":2169,"t":{"447":{"position":[[1038,14]]}}}],["serverprovid",{"_index":2785,"t":{"663":{"position":[[132,14]]},"889":{"position":[[243,14]]},"928":{"position":[[15,14],[129,14]]}}}],["servic",{"_index":569,"t":{"57":{"position":[[1386,7],[1414,7],[1752,7]]},"120":{"position":[[83,7],[112,7]]},"129":{"position":[[49,7],[287,7],[319,7],[342,7]]},"216":{"position":[[85,7]]},"223":{"position":[[101,7],[129,7],[180,7],[230,7],[283,7],[562,7],[668,7],[704,7]]},"225":{"position":[[859,7],[886,7],[937,7],[987,7],[1040,7],[1396,7],[1440,7],[1491,7],[1541,7],[1594,7]]},"229":{"position":[[74,7],[102,7],[296,7]]},"233":{"position":[[565,7],[593,7]]},"235":{"position":[[921,8],[950,8],[1081,8]]},"239":{"position":[[17,7],[83,7],[196,7],[288,7],[310,7]]},"255":{"position":[[67,7],[314,7],[346,7],[369,7]]},"257":{"position":[[43,7],[288,7],[320,7],[343,7]]},"259":{"position":[[74,7],[263,7],[295,7],[318,7]]},"261":{"position":[[305,8],[347,8],[418,8],[439,8],[466,8]]},"272":{"position":[[1277,7],[1305,7],[1550,7]]},"284":{"position":[[98,7],[127,7]]},"286":{"position":[[124,7],[153,7]]},"292":{"position":[[206,7],[229,7],[254,7]]},"301":{"position":[[2341,7],[2369,7],[2679,7]]},"308":{"position":[[1798,7],[1826,7],[2158,7]]},"347":{"position":[[1959,7],[1987,7],[2323,7]]},"391":{"position":[[384,7]]},"406":{"position":[[116,7],[144,7],[290,7]]},"422":{"position":[[129,7],[157,7],[303,7]]},"447":{"position":[[255,7],[695,7]]},"458":{"position":[[47,7],[323,7]]},"495":{"position":[[263,7],[291,7],[640,7]]},"514":{"position":[[141,7],[169,7]]},"516":{"position":[[213,7],[242,7]]},"537":{"position":[[47,7],[175,7],[198,7]]},"561":{"position":[[35,7],[63,7],[733,7],[761,7]]},"617":{"position":[[178,7]]},"621":{"position":[[0,7]]},"672":{"position":[[1,7]]},"674":{"position":[[1,7]]},"727":{"position":[[53,7],[91,7],[870,7]]},"736":{"position":[[11,7],[478,7],[506,7],[523,7],[556,7],[597,7],[638,7]]},"745":{"position":[[129,7],[157,7],[303,7]]},"832":{"position":[[10,7],[348,7]]},"859":{"position":[[4,7],[32,7],[750,7]]},"896":{"position":[[12,7],[41,7]]},"925":{"position":[[195,7],[555,7],[587,7],[625,7]]},"930":{"position":[[97,7],[126,7],[240,7]]},"969":{"position":[[524,7],[638,8],[650,8]]},"980":{"position":[[97,7],[125,7],[271,7]]}}}],["servicecollectionextens",{"_index":3457,"t":{"969":{"position":[[297,26],[441,26]]}}}],["servicesslopt",{"_index":904,"t":{"122":{"position":[[63,16]]},"288":{"position":[[267,16]]}}}],["servicetocli",{"_index":2804,"t":{"672":{"position":[[32,15],[171,15]]},"674":{"position":[[143,15]]}}}],["set",{"_index":1011,"t":{"134":{"position":[[1073,3]]},"301":{"position":[[2040,3],[2130,3],[2222,3],[2316,3]]},"376":{"position":[[17,3],[78,3],[337,3]]},"431":{"position":[[793,3],[824,3]]},"434":{"position":[[71,3],[104,3]]},"436":{"position":[[64,3],[95,3],[124,3],[153,3],[186,3],[217,3],[248,3],[285,3],[325,3],[365,3],[412,3],[462,3],[515,3],[562,3],[779,3],[851,3],[880,3]]},"473":{"position":[[105,3]]},"489":{"position":[[485,3],[518,3],[562,3]]},"507":{"position":[[54,3],[85,3],[114,3],[145,3],[179,3],[233,3],[1562,3]]},"523":{"position":[[59,3],[92,3],[451,3],[501,3],[554,3],[601,3],[638,3],[678,3],[718,3],[746,3],[777,3],[806,3],[835,3],[868,3],[899,3],[930,3],[1060,3]]},"550":{"position":[[695,3],[765,3]]},"552":{"position":[[1137,3],[1167,3],[1200,3],[1233,3],[1858,3]]},"556":{"position":[[1380,3],[1450,3],[1936,3],[1966,3],[1999,3],[2032,3],[2869,3],[2899,3],[2932,3],[2965,3],[3513,3],[3543,3],[3576,3],[3609,3]]},"702":{"position":[[816,3],[1037,3],[1142,3],[1230,3],[1309,3],[1419,3],[1527,3],[1619,3],[1715,3],[1799,3],[1968,3]]},"894":{"position":[[840,3],[867,3]]},"925":{"position":[[1016,3],[1043,3],[1072,3]]},"928":{"position":[[328,3],[355,3]]}}}],["setadapt",{"_index":440,"t":{"48":{"position":[[293,10]]}}}],["setbacklogproperti",{"_index":1267,"t":{"184":{"position":[[516,18]]},"218":{"position":[[516,18]]}}}],["setbindiphost",{"_index":381,"t":{"46":{"position":[[79,13]]},"173":{"position":[[95,13]]},"184":{"position":[[1527,13]]},"207":{"position":[[271,13],[393,13]]},"218":{"position":[[1527,13]]},"259":{"position":[[159,13]]},"816":{"position":[[257,13]]},"843":{"position":[[203,13]]},"845":{"position":[[82,13]]},"849":{"position":[[221,13]]},"851":{"position":[[113,13]]}}}],["setbufferlength",{"_index":1225,"t":{"184":{"position":[[5,15]]},"218":{"position":[[5,15]]}}}],["setcallback",{"_index":1537,"t":{"284":{"position":[[395,11]]},"290":{"position":[[39,11]]}}}],["setclientsslopt",{"_index":766,"t":{"104":{"position":[[79,18],[219,18]]},"184":{"position":[[1385,18]]},"218":{"position":[[1385,18]]},"319":{"position":[[260,18]]}}}],["setcont",{"_index":899,"t":{"120":{"position":[[2219,10]]}}}],["setcontenttypebyextens",{"_index":898,"t":{"120":{"position":[[2183,25]]}}}],["setdatahandlingadapt",{"_index":337,"t":{"38":{"position":[[35,22]]},"40":{"position":[[48,22],[244,22]]},"42":{"position":[[169,22]]},"57":{"position":[[1850,22]]},"80":{"position":[[1810,22]]},"272":{"position":[[1648,22]]},"301":{"position":[[2777,22]]},"308":{"position":[[2256,22]]},"347":{"position":[[2421,22]]},"406":{"position":[[388,22]]},"422":{"position":[[401,22]]},"495":{"position":[[442,22],[818,22]]},"514":{"position":[[374,22]]},"561":{"position":[[645,22]]},"736":{"position":[[178,22]]},"745":{"position":[[401,22]]},"750":{"position":[[79,22],[356,22]]},"980":{"position":[[369,22]]}}}],["setfiletransf",{"_index":3321,"t":{"878":{"position":[[459,18],[613,17]]}}}],["setgetdefaultnewid",{"_index":1258,"t":{"184":{"position":[[411,18]]},"218":{"position":[[411,18]]},"615":{"position":[[89,18],[158,18]]}}}],["setheartbeatfrequ",{"_index":1173,"t":{"164":{"position":[[84,21]]},"250":{"position":[[84,21]]}}}],["sethold",{"_index":1164,"t":{"159":{"position":[[781,10],[906,10]]}}}],["sethost",{"_index":749,"t":{"102":{"position":[[254,7]]}}}],["setjrpt",{"_index":677,"t":{"80":{"position":[[203,7],[1180,7],[1878,7]]}}}],["setjsonrpcurl",{"_index":2407,"t":{"516":{"position":[[554,13]]}}}],["setkeepalivevalu",{"_index":1335,"t":{"184":{"position":[[1474,17]]},"218":{"position":[[1474,17]]},"485":{"position":[[186,17]]}}}],["setlengthtyp",{"_index":3041,"t":{"750":{"position":[[551,13]]}}}],["setlisteniphost",{"_index":577,"t":{"57":{"position":[[1797,16]]},"120":{"position":[[170,16]]},"129":{"position":[[139,16]]},"184":{"position":[[443,16]]},"218":{"position":[[443,16]]},"223":{"position":[[749,16]]},"225":{"position":[[1085,16],[1639,16]]},"229":{"position":[[341,16]]},"233":{"position":[[632,16]]},"235":{"position":[[992,16]]},"255":{"position":[[145,16]]},"257":{"position":[[136,16]]},"272":{"position":[[1595,16]]},"284":{"position":[[185,16]]},"286":{"position":[[211,16]]},"288":{"position":[[190,16]]},"301":{"position":[[2724,16]]},"308":{"position":[[2203,16]]},"347":{"position":[[2368,16]]},"391":{"position":[[183,16]]},"406":{"position":[[335,16]]},"422":{"position":[[348,16]]},"447":{"position":[[333,16]]},"458":{"position":[[168,16]]},"495":{"position":[[336,16]]},"514":{"position":[[523,16]]},"516":{"position":[[294,16]]},"537":{"position":[[122,16]]},"561":{"position":[[552,16]]},"736":{"position":[[84,16]]},"745":{"position":[[348,16]]},"832":{"position":[[49,16]]},"859":{"position":[[795,16]]},"896":{"position":[[93,16]]},"925":{"position":[[316,16]]},"930":{"position":[[170,16]]},"980":{"position":[[316,16]]}}}],["setmaxcount",{"_index":1270,"t":{"184":{"position":[[560,11]]},"218":{"position":[[560,11]]}}}],["setmaxpackages",{"_index":1243,"t":{"184":{"position":[[146,17]]},"218":{"position":[[146,17]]},"668":{"position":[[150,17]]},"750":{"position":[[41,17],[317,17],[604,17]]}}}],["setmaxspe",{"_index":2980,"t":{"727":{"position":[[426,11],[545,11],[1467,11]]}}}],["setmyproperti",{"_index":1913,"t":{"376":{"position":[[1088,13],[1562,13]]}}}],["setproxytoken",{"_index":3395,"t":{"930":{"position":[[281,13]]}}}],["setreceivetyp",{"_index":1273,"t":{"184":{"position":[[589,14]]},"218":{"position":[[589,14]]},"288":{"position":[[156,14]]},"458":{"position":[[134,14]]},"925":{"position":[[282,14]]}}}],["setremoteiphost",{"_index":675,"t":{"80":{"position":[[168,15],[1130,15],[1742,15]]},"102":{"position":[[89,15]]},"132":{"position":[[166,15]]},"134":{"position":[[3532,15]]},"138":{"position":[[510,15]]},"169":{"position":[[117,15]]},"171":{"position":[[119,15]]},"173":{"position":[[116,15]]},"175":{"position":[[88,15]]},"184":{"position":[[1251,15]]},"188":{"position":[[464,15]]},"192":{"position":[[345,15]]},"194":{"position":[[622,15]]},"218":{"position":[[1251,15]]},"317":{"position":[[200,15]]},"319":{"position":[[204,15]]},"495":{"position":[[758,15]]},"528":{"position":[[350,15],[465,15]]},"530":{"position":[[717,15],[863,15]]},"537":{"position":[[587,15],[676,15]]},"539":{"position":[[103,15]]},"832":{"position":[[1331,15]]},"857":{"position":[[86,15]]}}}],["setresponsetyp",{"_index":1184,"t":{"164":{"position":[[174,15]]},"250":{"position":[[174,15]]}}}],["setrootpath",{"_index":1185,"t":{"164":{"position":[[201,11]]},"250":{"position":[[201,11]]}}}],["setserializationselector",{"_index":1181,"t":{"164":{"position":[[138,24]]},"250":{"position":[[138,24]]},"686":{"position":[[69,24]]}}}],["setservernam",{"_index":1263,"t":{"184":{"position":[[484,13]]},"218":{"position":[[484,13]]}}}],["setservicesslopt",{"_index":903,"t":{"122":{"position":[[39,19]]},"184":{"position":[[738,19]]},"218":{"position":[[738,19]]},"288":{"position":[[243,19]]}}}],["setsingletonlogg",{"_index":388,"t":{"46":{"position":[[234,18]]},"284":{"position":[[266,18]]},"286":{"position":[[292,18]]},"317":{"position":[[265,18]]},"896":{"position":[[174,18]]},"925":{"position":[[396,18]]}}}],["setstatu",{"_index":850,"t":{"120":{"position":[[1001,9],[2162,9]]},"463":{"position":[[215,9]]},"465":{"position":[[299,9],[716,9]]}}}],["setthreadcount",{"_index":1247,"t":{"184":{"position":[[245,14]]},"218":{"position":[[245,14]]}}}],["settick",{"_index":2527,"t":{"539":{"position":[[237,7]]},"597":{"position":[[141,7]]}}}],["setudpdatahandlingadapt",{"_index":385,"t":{"46":{"position":[[126,25]]},"816":{"position":[[303,25]]},"843":{"position":[[252,25]]},"845":{"position":[[115,25]]},"849":{"position":[[270,25]]},"851":{"position":[[146,25]]}}}],["setup",{"_index":379,"t":{"46":{"position":[[48,5]]},"57":{"position":[[1760,5]]},"60":{"position":[[348,5]]},"66":{"position":[[404,5]]},"69":{"position":[[324,5]]},"80":{"position":[[137,5],[1099,5],[1711,5]]},"86":{"position":[[220,5]]},"102":{"position":[[45,5]]},"120":{"position":[[120,5]]},"129":{"position":[[295,5]]},"132":{"position":[[135,5]]},"134":{"position":[[3501,5]]},"138":{"position":[[479,5]]},"169":{"position":[[86,5]]},"171":{"position":[[88,5]]},"173":{"position":[[64,5]]},"175":{"position":[[57,5]]},"188":{"position":[[541,5]]},"192":{"position":[[422,5]]},"194":{"position":[[591,5]]},"207":{"position":[[240,5],[352,5]]},"223":{"position":[[712,5]]},"225":{"position":[[1048,5],[1602,5]]},"229":{"position":[[304,5]]},"233":{"position":[[601,5]]},"255":{"position":[[322,5]]},"257":{"position":[[296,5]]},"259":{"position":[[271,5]]},"272":{"position":[[1558,5]]},"284":{"position":[[135,5]]},"286":{"position":[[161,5]]},"301":{"position":[[2687,5]]},"308":{"position":[[2166,5]]},"317":{"position":[[169,5]]},"319":{"position":[[173,5]]},"347":{"position":[[2331,5]]},"391":{"position":[[262,5]]},"393":{"position":[[82,5]]},"406":{"position":[[298,5]]},"422":{"position":[[311,5]]},"447":{"position":[[703,5]]},"458":{"position":[[331,5]]},"495":{"position":[[299,5],[727,5]]},"514":{"position":[[177,5]]},"516":{"position":[[250,5]]},"537":{"position":[[183,5]]},"561":{"position":[[741,5]]},"736":{"position":[[486,5]]},"745":{"position":[[311,5]]},"816":{"position":[[226,5]]},"832":{"position":[[333,5]]},"843":{"position":[[172,5]]},"845":{"position":[[51,5]]},"849":{"position":[[190,5]]},"851":{"position":[[51,5]]},"857":{"position":[[152,5]]},"859":{"position":[[758,5]]},"896":{"position":[[49,5]]},"925":{"position":[[563,5]]},"930":{"position":[[134,5]]},"980":{"position":[[279,5]]}}}],["seturl",{"_index":747,"t":{"102":{"position":[[226,6]]}}}],["setvalu",{"_index":1906,"t":{"376":{"position":[[343,8],[1176,8]]},"493":{"position":[[574,8],[953,8]]}}}],["setverifytimeout",{"_index":1168,"t":{"164":{"position":[[5,16]]},"250":{"position":[[5,16]]}}}],["setverifytoken",{"_index":977,"t":{"129":{"position":[[259,14]]},"132":{"position":[[201,14]]},"134":{"position":[[3567,14]]},"138":{"position":[[688,14]]},"164":{"position":[[60,14]]},"169":{"position":[[152,14]]},"171":{"position":[[154,14]]},"250":{"position":[[60,14]]},"255":{"position":[[269,14]]},"257":{"position":[[260,14]]},"259":{"position":[[54,14]]},"447":{"position":[[667,14]]},"530":{"position":[[758,14],[904,14]]},"772":{"position":[[85,14]]},"832":{"position":[[233,14],[1366,14]]}}}],["setwsurl",{"_index":1536,"t":{"284":{"position":[[378,8]]},"516":{"position":[[483,8]]}}}],["setxmlrpcurl",{"_index":3396,"t":{"930":{"position":[[303,12]]}}}],["sgcccustomdatahandlingadapt",{"_index":2873,"t":{"702":{"position":[[139,29]]}}}],["sgccrequestinfo",{"_index":2874,"t":{"702":{"position":[[208,15],[336,15],[379,15],[525,15]]}}}],["shareproxi",{"_index":715,"t":{"91":{"position":[[140,10],[203,10],[224,10]]},"932":{"position":[[302,10]]}}}],["short",{"_index":3078,"t":{"780":{"position":[[58,5]]}}}],["show",{"_index":2499,"t":{"528":{"position":[[1172,4],[1219,4],[1869,4],[1916,4]]}}}],["showal",{"_index":723,"t":{"91":{"position":[[389,7]]},"495":{"position":[[1369,7]]}}}],["showmsg",{"_index":391,"t":{"46":{"position":[[289,7]]},"317":{"position":[[320,7]]},"393":{"position":[[309,7]]}}}],["silent",{"_index":1867,"t":{"370":{"position":[[256,6]]}}}],["simpleobject",{"_index":2426,"t":{"523":{"position":[[22,12],[134,12],[163,12],[315,12]]}}}],["simplesocketcli",{"_index":1803,"t":{"365":{"position":[[217,18]]}}}],["singletim",{"_index":3280,"t":{"872":{"position":[[217,11]]}}}],["singleton",{"_index":2552,"t":{"544":{"position":[[34,9]]},"554":{"position":[[42,9]]}}}],["size",{"_index":881,"t":{"120":{"position":[[1660,4],[1797,4],[1941,4]]},"672":{"position":[[335,4],[543,4],[662,4],[730,4],[909,4],[1103,4],[1109,4]]},"674":{"position":[[307,4],[484,4],[534,4],[602,4],[758,4]]}}}],["sleep",{"_index":1712,"t":{"340":{"position":[[962,5]]},"602":{"position":[[83,5]]},"663":{"position":[[330,5]]}}}],["sn",{"_index":3160,"t":{"820":{"position":[[158,2]]}}}],["snowflakeidgener",{"_index":2705,"t":{"608":{"position":[[22,20],[59,20]]}}}],["socket",{"_index":1290,"t":{"184":{"position":[[791,6],[1494,6],[1970,6]]},"186":{"position":[[67,6],[103,6]]},"218":{"position":[[791,6],[1494,6],[1970,6]]},"220":{"position":[[68,6]]},"468":{"position":[[84,6]]},"485":{"position":[[75,6]]},"702":{"position":[[42,7]]},"978":{"position":[[29,6]]}}}],["socketcli",{"_index":351,"t":{"40":{"position":[[187,12],[231,12],[336,12]]},"48":{"position":[[90,12]]},"178":{"position":[[54,12]]},"210":{"position":[[49,12],[66,12]]},"216":{"position":[[19,12],[72,12],[105,12]]},"220":{"position":[[361,12]]},"223":{"position":[[22,12]]},"225":{"position":[[62,12],[109,12],[655,12],[804,12]]},"233":{"position":[[135,12],[262,12]]},"235":{"position":[[349,12],[516,12],[667,12]]},"237":{"position":[[29,12]]},"239":{"position":[[52,12],[67,13],[110,12],[155,12],[349,12],[362,12]]},"241":{"position":[[7,12]]},"286":{"position":[[885,12],[905,12]]},"292":{"position":[[177,12],[193,12]]},"512":{"position":[[454,12],[960,12],[1039,12]]},"537":{"position":[[417,12],[467,12],[534,12],[623,12],[737,12],[843,12],[912,12],[943,12],[961,12],[1059,12],[1146,12],[1246,12],[1352,12],[1486,12]]},"539":{"position":[[49,12],[311,12]]},"581":{"position":[[53,12]]},"613":{"position":[[46,12]]},"617":{"position":[[39,12],[67,12],[149,12]]},"623":{"position":[[0,12],[67,12]]},"672":{"position":[[422,12],[442,12]]},"674":{"position":[[367,12],[387,12]]},"727":{"position":[[121,12],[899,12]]},"734":{"position":[[676,12],[725,12],[743,12]]},"776":{"position":[[24,12]]}}}],["socketclient1",{"_index":3185,"t":{"826":{"position":[[135,13]]}}}],["socketclient2",{"_index":3187,"t":{"826":{"position":[[157,13]]}}}],["sourc",{"_index":2280,"t":{"473":{"position":[[185,6]]},"548":{"position":[[495,6],[586,6]]},"550":{"position":[[814,6],[905,6]]},"552":{"position":[[1282,6],[1373,6],[1907,6],[1998,6]]},"556":{"position":[[161,6],[252,6],[353,6],[444,6],[697,6],[788,6],[1167,6],[1258,6],[1499,6],[1590,6],[2081,6],[2172,6],[2394,6],[2485,6],[3014,6],[3105,6],[3658,6],[3749,6]]}}}],["sp",{"_index":718,"t":{"91":{"position":[[200,2]]}}}],["speed",{"_index":2493,"t":{"528":{"position":[[1003,5],[1701,5]]},"727":{"position":[[708,5],[1726,5]]},"830":{"position":[[555,5]]},"832":{"position":[[2307,5]]}}}],["splicingsend",{"_index":1823,"t":{"365":{"position":[[2108,12],[2396,12],[2686,12],[2978,12]]}}}],["splite",{"_index":2701,"t":{"606":{"position":[[86,6]]}}}],["splitpackag",{"_index":1782,"t":{"361":{"position":[[1504,12],[1908,12],[2215,12]]}}}],["ss",{"_index":2617,"t":{"561":{"position":[[318,2],[389,2]]}}}],["ssl",{"_index":758,"t":{"104":{"position":[[23,3]]},"122":{"position":[[30,3]]},"184":{"position":[[759,3],[1408,3]]},"218":{"position":[[759,3],[1408,3]]},"288":{"position":[[62,3],[288,3]]},"311":{"position":[[2,3]]},"319":{"position":[[82,3]]},"537":{"position":[[313,3],[326,3]]},"790":{"position":[[61,3]]}}}],["ssloption",{"_index":1555,"t":{"288":{"position":[[30,9]]}}}],["sslpolicyerror",{"_index":782,"t":{"104":{"position":[[495,15]]},"319":{"position":[[537,15]]}}}],["sslprotocol",{"_index":765,"t":{"104":{"position":[[65,12],[148,12],[163,12],[373,12],[388,12]]},"122":{"position":[[152,12],[167,12]]},"288":{"position":[[404,12],[419,12]]},"319":{"position":[[415,12],[430,12]]}}}],["ssp",{"_index":720,"t":{"91":{"position":[[262,3]]}}}],["start",{"_index":393,"t":{"46":{"position":[[324,5]]},"57":{"position":[[1949,5]]},"120":{"position":[[426,5]]},"129":{"position":[[310,5]]},"173":{"position":[[168,5]]},"207":{"position":[[305,5],[358,5]]},"223":{"position":[[997,5]]},"225":{"position":[[1333,5],[1887,5]]},"229":{"position":[[540,5]]},"233":{"position":[[827,5]]},"255":{"position":[[337,5]]},"257":{"position":[[311,5]]},"259":{"position":[[286,5]]},"272":{"position":[[1743,5]]},"284":{"position":[[530,5]]},"286":{"position":[[449,5]]},"301":{"position":[[2862,5]]},"308":{"position":[[2352,5]]},"347":{"position":[[2519,5]]},"391":{"position":[[277,5]]},"406":{"position":[[512,5]]},"422":{"position":[[496,5]]},"447":{"position":[[718,5]]},"458":{"position":[[345,5]]},"495":{"position":[[627,5]]},"514":{"position":[[577,5]]},"516":{"position":[[586,5]]},"537":{"position":[[206,5]]},"561":{"position":[[769,5]]},"736":{"position":[[514,5]]},"745":{"position":[[501,5]]},"816":{"position":[[378,5]]},"832":{"position":[[341,5]]},"843":{"position":[[322,5]]},"845":{"position":[[185,5]]},"849":{"position":[[340,5]]},"851":{"position":[[216,5]]},"859":{"position":[[1043,5]]},"896":{"position":[[400,5]]},"925":{"position":[[578,5]]},"930":{"position":[[224,5]]},"980":{"position":[[451,5]]}}}],["startcod",{"_index":1524,"t":{"272":{"position":[[625,9],[735,9],[1023,9]]}}}],["static",{"_index":587,"t":{"60":{"position":[[34,6],[245,6]]},"66":{"position":[[101,6],[301,6]]},"69":{"position":[[232,6]]},"80":{"position":[[992,6]]},"134":{"position":[[2235,6],[2508,6],[2999,6]]},"290":{"position":[[96,6]]},"376":{"position":[[428,6],[676,6],[756,6],[1073,6],[1384,6]]},"491":{"position":[[89,6],[132,6],[296,6],[554,6]]},"495":{"position":[[161,6],[1446,6]]},"537":{"position":[[0,6]]},"606":{"position":[[23,6],[130,6]]},"930":{"position":[[41,6]]},"932":{"position":[[38,6]]},"969":{"position":[[428,6],[477,6]]}}}],["statu",{"_index":2753,"t":{"648":{"position":[[223,6],[741,6]]},"672":{"position":[[694,6],[932,6],[949,6],[1095,6]]},"674":{"position":[[566,6],[1000,6]]},"727":{"position":[[947,6]]}}}],["stopshareproxi",{"_index":716,"t":{"91":{"position":[[151,14],[266,14],[293,14]]}}}],["stopwatch",{"_index":2690,"t":{"602":{"position":[[6,9]]}}}],["str",{"_index":2395,"t":{"512":{"position":[[182,3],[212,3],[287,3],[375,3],[405,3],[556,3],[712,3],[1213,3]]},"523":{"position":[[243,3],[329,3],[2596,3],[2683,3]]},"604":{"position":[[7,3],[85,3]]}}}],["stream",{"_index":1089,"t":{"151":{"position":[[41,6]]},"561":{"position":[[174,6]]},"626":{"position":[[12,6]]},"630":{"position":[[448,6]]},"632":{"position":[[53,6]]},"634":{"position":[[28,6]]},"723":{"position":[[0,6]]},"725":{"position":[[15,6]]},"727":{"position":[[8,6],[1245,6],[1278,6],[1332,6],[1941,6]]},"798":{"position":[[9,6]]}}}],["streamoper",{"_index":2977,"t":{"727":{"position":[[295,14],[310,14],[329,14],[411,14],[530,14],[611,14],[693,14],[721,14],[807,14],[1350,14],[1365,14],[1386,14],[1404,14],[1452,14],[1506,14],[1614,14],[1711,14],[1739,14],[1949,14]]}}}],["streamread",{"_index":2616,"t":{"561":{"position":[[232,12],[245,12],[264,12],[296,12],[323,12]]}}}],["streamtransf",{"_index":2972,"t":{"727":{"position":[[99,17],[878,16]]}}}],["string",{"_index":572,"t":{"57":{"position":[[1658,6]]},"60":{"position":[[51,6]]},"66":{"position":[[118,6]]},"80":{"position":[[275,6],[312,6],[471,6],[606,6],[1253,6],[1290,6],[1956,6]]},"127":{"position":[[304,6],[319,6],[580,6],[595,6]]},"134":{"position":[[499,6],[522,6],[846,6],[869,6],[1344,6],[1367,6],[1842,6],[1865,6],[2573,6],[2596,6],[3075,6],[3098,6]]},"138":{"position":[[314,6],[330,6]]},"142":{"position":[[97,6],[221,6],[397,6]]},"157":{"position":[[443,6]]},"159":{"position":[[477,6],[822,6]]},"188":{"position":[[286,6]]},"192":{"position":[[167,6]]},"223":{"position":[[351,6]]},"225":{"position":[[255,6]]},"229":{"position":[[170,6]]},"239":{"position":[[273,6]]},"243":{"position":[[35,6],[93,6],[169,6],[226,6],[289,6],[370,6]]},"301":{"position":[[2585,6]]},"308":{"position":[[2064,6]]},"347":{"position":[[1291,6],[2229,6]]},"393":{"position":[[146,6],[290,6]]},"406":{"position":[[213,6]]},"422":{"position":[[226,6]]},"429":{"position":[[131,6]]},"431":{"position":[[807,6]]},"434":{"position":[[85,6]]},"436":{"position":[[78,6],[304,6],[442,6],[487,6],[495,6],[832,6],[1259,6],[1633,6],[1752,6],[1760,6]]},"447":{"position":[[107,6],[1131,6],[1341,6]]},"455":{"position":[[145,6],[161,6],[308,6],[324,6],[817,6],[833,6]]},"473":{"position":[[193,6]]},"489":{"position":[[1263,6]]},"495":{"position":[[178,6]]},"507":{"position":[[68,6]]},"512":{"position":[[156,6],[175,6],[348,6],[368,6],[657,6],[705,6]]},"519":{"position":[[31,6]]},"523":{"position":[[73,6],[481,6],[526,6],[534,6],[657,6],[760,6],[1579,6],[2025,6],[2168,6],[2176,6]]},"530":{"position":[[1088,6]]},"537":{"position":[[17,6]]},"548":{"position":[[503,6],[594,6]]},"550":{"position":[[822,6],[913,6]]},"552":{"position":[[924,6],[1151,6],[1290,6],[1381,6],[1915,6],[2006,6]]},"556":{"position":[[169,6],[260,6],[361,6],[452,6],[705,6],[796,6],[906,6],[1047,6],[1175,6],[1266,6],[1507,6],[1598,6],[1723,6],[1950,6],[2089,6],[2180,6],[2402,6],[2493,6],[2656,6],[2883,6],[3022,6],[3113,6],[3300,6],[3527,6],[3666,6],[3757,6]]},"561":{"position":[[311,6]]},"604":{"position":[[0,6]]},"606":{"position":[[61,6],[79,6],[165,6]]},"641":{"position":[[270,6],[285,6]]},"643":{"position":[[148,6],[163,6]]},"655":{"position":[[235,6],[271,6]]},"659":{"position":[[155,6],[191,6]]},"661":{"position":[[359,6],[395,6]]},"681":{"position":[[439,6],[475,6]]},"745":{"position":[[226,6]]},"770":{"position":[[30,6]]},"780":{"position":[[383,6]]},"804":{"position":[[2,6]]},"830":{"position":[[744,6]]},"894":{"position":[[539,6],[592,6]]},"932":{"position":[[55,6],[426,6]]},"980":{"position":[[194,6]]}}}],["stringbuild",{"_index":858,"t":{"120":{"position":[[1137,13],[1151,13],[1171,13],[1188,13],[1233,13],[1269,13],[1305,13],[1360,13],[1416,13],[1453,13],[1489,13],[1608,13],[1716,13],[1856,13],[2032,13],[2068,13],[2105,13],[2230,13]]},"465":{"position":[[504,13],[518,13],[538,13],[555,13],[603,13],[667,13]]}}}],["stringvalu",{"_index":1132,"t":{"157":{"position":[[450,11]]}}}],["student",{"_index":2038,"t":{"431":{"position":[[217,7],[247,7],[380,7],[520,7],[762,7],[912,7]]},"436":{"position":[[33,7],[892,7],[900,7],[914,7],[925,7],[942,7],[963,7],[981,7],[997,7],[1024,7],[1041,7],[1122,7],[1135,7],[1168,7],[1190,7],[1212,7],[1234,7],[1270,7],[1294,7],[1318,7],[1342,7],[1378,7],[1413,7],[1448,7],[1483,7],[1526,7],[1550,7],[1574,7],[1598,7],[1644,7],[1670,7],[1696,7],[1722,7],[1771,7],[1799,7],[1827,7],[1855,7],[1898,7],[1931,7],[1964,7]]}}}],["studentfastbinaryconvert",{"_index":2037,"t":{"431":{"position":[[168,26],[726,26],[925,26]]}}}],["style",{"_index":868,"t":{"120":{"position":[[1533,5],[1647,5],[1784,5],[1928,5]]}}}],["sub",{"_index":191,"t":{"25":{"position":[[167,3],[459,3],[489,3],[521,3]]},"389":{"position":[[48,3]]}}}],["subpacketno",{"_index":2914,"t":{"702":{"position":[[1696,11],[2614,11]]}}}],["subscribeev",{"_index":1948,"t":{"393":{"position":[[131,14],[163,14],[182,14],[250,14]]}}}],["success",{"_index":840,"t":{"120":{"position":[[798,7],[849,7]]},"297":{"position":[[94,7],[290,7]]},"301":{"position":[[621,7],[1894,7]]},"415":{"position":[[261,7]]},"727":{"position":[[995,7]]}}}],["sum",{"_index":594,"t":{"60":{"position":[[141,3],[541,3]]},"66":{"position":[[224,3]]},"69":{"position":[[86,3],[492,3]]},"894":{"position":[[227,3]]},"896":{"position":[[501,3]]},"925":{"position":[[927,3],[1061,3]]},"928":{"position":[[166,3]]}}}],["sum1",{"_index":649,"t":{"69":{"position":[[450,4],[557,4]]}}}],["sum2",{"_index":650,"t":{"69":{"position":[[570,4],[698,4]]}}}],["sum3",{"_index":653,"t":{"75":{"position":[[105,4],[194,4]]}}}],["sumab",{"_index":3350,"t":{"894":{"position":[[178,5]]}}}],["sumclass",{"_index":3389,"t":{"925":{"position":[[877,8],[897,8],[906,8],[918,8],[933,8],[946,8],[965,8],[985,8]]}}}],["sumcommand",{"_index":3390,"t":{"925":{"position":[[886,10]]}}}],["summari",{"_index":430,"t":{"48":{"position":[[110,7],[143,7]]},"57":{"position":[[439,7],[477,7],[1055,7],[1093,7]]},"120":{"position":[[565,7],[611,7]]},"134":{"position":[[246,7],[266,7],[582,7],[602,7],[1084,7],[1104,7],[1767,7],[1787,7],[2276,7],[2296,7],[2963,7],[2983,7]]},"272":{"position":[[337,7],[377,7]]},"301":{"position":[[317,7],[682,7],[1966,7],[1996,7],[2052,7],[2084,7],[2142,7],[2176,7],[2234,7],[2269,7]]},"308":{"position":[[514,7],[545,7],[635,7],[667,7],[755,7],[787,7],[874,7],[906,7],[1535,7],[1568,7],[1621,7],[1646,7]]},"347":{"position":[[524,7],[555,7],[643,7],[675,7]]},"361":{"position":[[1192,7],[1225,7],[1272,7],[1297,7],[2070,7],[2093,7],[2745,7],[2769,7]]},"376":{"position":[[236,7],[259,7],[389,7],[412,7],[717,7],[740,7],[891,7],[923,7],[1235,7],[1267,7]]},"431":{"position":[[57,7],[153,7]]},"455":{"position":[[517,7],[635,7]]},"491":{"position":[[41,7],[71,7]]},"495":{"position":[[5,7],[112,7]]},"512":{"position":[[224,7],[261,7],[417,7],[491,7]]},"546":{"position":[[79,7],[119,7]]},"672":{"position":[[16,7],[70,7]]},"674":{"position":[[16,7],[42,7]]},"702":{"position":[[86,7],[115,7],[743,7],[771,7],[846,7],[870,7],[955,7],[990,7],[1068,7],[1104,7],[1154,7],[1191,7],[1242,7],[1273,7],[1321,7],[1381,7],[1431,7],[1486,7],[1539,7],[1580,7],[1631,7],[1673,7],[1727,7],[1750,7],[1831,7],[1854,7],[1908,7],[1936,7]]},"734":{"position":[[5,7],[47,7],[272,7],[294,7],[489,7],[521,7],[808,7],[832,7]]},"894":{"position":[[369,7],[404,7]]},"925":{"position":[[685,7],[755,7]]}}}],["surlen",{"_index":1996,"t":{"413":{"position":[[258,6],[283,6],[314,6],[366,6]]}}}],["surpluslength",{"_index":1781,"t":{"361":{"position":[[1319,13],[1545,13],[1632,13],[1710,13],[1740,13],[1830,13],[1929,13],[2033,13],[2515,13],[2591,13]]}}}],["swagger",{"_index":1482,"t":{"261":{"position":[[760,7],[830,7],[841,7]]}}}],["swaggerdoc",{"_index":1469,"t":{"261":{"position":[[498,10]]}}}],["swaggerendpoint",{"_index":1485,"t":{"261":{"position":[[812,15]]}}}],["switch",{"_index":1563,"t":{"290":{"position":[[168,6]]},"323":{"position":[[55,6]]}}}],["switchprotocoltowebsocket",{"_index":1552,"t":{"286":{"position":[[918,25]]}}}],["sync",{"_index":2876,"t":{"702":{"position":[[586,4],[794,4],[810,4],[825,4],[2141,4]]}}}],["system",{"_index":854,"t":{"120":{"position":[[1036,6]]},"134":{"position":[[149,6],[296,6],[436,6],[471,6],[492,6],[515,6],[632,6],[772,6],[812,6],[839,6],[862,6],[1134,6],[1274,6],[1316,6],[1337,6],[1360,6],[1648,6],[1690,6],[1808,6],[1835,6],[1858,6],[2172,6],[2326,6],[2466,6],[2515,6],[2566,6],[2589,6],[2844,6],[2886,6],[3011,6],[3068,6],[3091,6],[3372,6]]},"436":{"position":[[2008,6],[2025,6]]},"463":{"position":[[250,6]]},"521":{"position":[[146,6]]},"702":{"position":[[474,6]]},"832":{"position":[[1898,6]]},"894":{"position":[[672,6]]}}}],["systembinari",{"_index":2819,"t":{"679":{"position":[[45,12],[98,12]]}}}],["t",{"_index":2035,"t":{"431":{"position":[[103,1]]},"465":{"position":[[598,1]]},"748":{"position":[[43,1],[101,1]]}}}],["t1",{"_index":2596,"t":{"556":{"position":[[26,2],[59,2],[78,2]]}}}],["t2",{"_index":2597,"t":{"556":{"position":[[30,2],[63,2],[82,2]]}}}],["tag",{"_index":3025,"t":{"748":{"position":[[39,3],[197,3],[256,3],[285,3],[321,3]]},"752":{"position":[[12,3],[24,3]]}}}],["targethost",{"_index":764,"t":{"104":{"position":[[54,10],[122,10],[408,10]]},"319":{"position":[[450,10],[689,10],[734,10]]}}}],["targetid",{"_index":2508,"t":{"530":{"position":[[967,8],[1019,8],[1099,8]]}}}],["task",{"_index":997,"t":{"134":{"position":[[166,5],[807,4],[1803,4],[3006,4]]},"159":{"position":[[175,4],[252,4],[285,4],[461,4],[806,4]]},"196":{"position":[[335,4],[381,4]]},"241":{"position":[[288,4],[334,4],[386,4]]},"243":{"position":[[211,4],[274,4],[355,4]]},"672":{"position":[[788,4],[793,4],[800,4],[1055,4]]},"674":{"position":[[687,4],[692,4],[699,4],[960,4]]},"727":{"position":[[581,4],[755,4]]},"894":{"position":[[534,4],[734,4],[766,4]]}}}],["tclient",{"_index":1020,"t":{"134":{"position":[[2536,7],[2550,7],[2657,7],[3038,7],[3052,7],[3159,7]]},"376":{"position":[[953,7],[1080,7],[1102,7],[1116,7],[1149,7],[1297,7],[1409,7],[1423,7],[1445,7]]},"491":{"position":[[313,7],[327,7],[349,7],[571,7],[585,7],[607,7]]}}}],["tcp",{"_index":251,"t":{"32":{"position":[[24,3]]},"36":{"position":[[1,3]]},"78":{"position":[[69,3],[81,3]]},"80":{"position":[[65,3],[216,3],[421,3],[556,3],[718,3],[963,3]]},"129":{"position":[[7,3]]},"178":{"position":[[10,3],[25,3]]},"182":{"position":[[2,3],[44,3]]},"184":{"position":[[536,3],[845,3],[1624,3]]},"210":{"position":[[11,3]]},"214":{"position":[[2,3],[44,3]]},"218":{"position":[[536,3],[845,3],[1624,3]]},"223":{"position":[[793,3]]},"225":{"position":[[1129,3],[1683,3]]},"229":{"position":[[385,3]]},"248":{"position":[[34,3],[46,3]]},"255":{"position":[[4,3]]},"268":{"position":[[126,3]]},"292":{"position":[[111,3]]},"340":{"position":[[0,3],[61,3],[90,3]]},"357":{"position":[[54,3]]},"391":{"position":[[28,3]]},"485":{"position":[[165,3]]},"498":{"position":[[93,3]]},"512":{"position":[[995,3],[1168,3]]},"514":{"position":[[84,3],[359,3]]},"528":{"position":[[367,3],[482,3]]},"530":{"position":[[734,3],[880,3]]},"533":{"position":[[18,3],[34,3]]},"535":{"position":[[72,3]]},"568":{"position":[[0,3]]},"574":{"position":[[71,3]]},"593":{"position":[[8,3]]},"595":{"position":[[235,3]]},"597":{"position":[[258,3]]},"653":{"position":[[98,3]]},"723":{"position":[[14,3]]},"729":{"position":[[3,3],[24,3],[52,3],[73,3]]},"732":{"position":[[31,3]]},"738":{"position":[[14,3]]},"778":{"position":[[208,3]]},"783":{"position":[[292,3],[360,3],[379,3]]},"785":{"position":[[46,3]]},"787":{"position":[[10,3]]},"806":{"position":[[178,3],[185,3],[296,3],[363,3],[470,3]]},"809":{"position":[[26,3]]},"859":{"position":[[839,3]]},"870":{"position":[[149,3]]},"872":{"position":[[58,3],[654,3],[690,3],[749,3]]},"874":{"position":[[251,3]]},"884":{"position":[[115,3]]},"909":{"position":[[15,3]]},"976":{"position":[[16,3]]},"978":{"position":[[6,3]]}}}],["tcpclient",{"_index":418,"t":{"46":{"position":[[472,9]]},"99":{"position":[[2,9]]},"159":{"position":[[150,9],[357,9],[667,9]]},"169":{"position":[[11,9]]},"171":{"position":[[11,9]]},"178":{"position":[[0,9]]},"184":{"position":[[1574,9]]},"188":{"position":[[54,9],[64,9],[80,9],[93,9],[146,9],[215,9],[531,9],[556,9],[577,9]]},"190":{"position":[[1,9]]},"192":{"position":[[3,9],[57,9],[67,9],[83,9],[96,9],[412,9],[437,9]]},"194":{"position":[[135,9],[259,9],[548,9],[571,9]]},"196":{"position":[[7,9],[267,9]]},"210":{"position":[[80,9]]},"216":{"position":[[42,9]]},"218":{"position":[[1574,9]]},"241":{"position":[[220,9]]},"376":{"position":[[1513,9],[1523,9],[1539,9],[1552,9],[1599,9]]},"495":{"position":[[678,9],[688,9],[704,9],[717,9],[1005,9],[1026,9],[1155,9],[1216,9]]},"537":{"position":[[868,9],[986,9],[1001,9],[1073,9],[1377,9],[1500,9]]},"539":{"position":[[222,9]]},"574":{"position":[[429,9]]},"597":{"position":[[126,9]]},"610":{"position":[[299,9]]},"623":{"position":[[91,9]]},"857":{"position":[[0,9],[12,9],[28,9],[142,9],[169,9],[251,9],[550,9]]}}}],["tcpcommandlineplugin",{"_index":2996,"t":{"732":{"position":[[0,20]]},"734":{"position":[[84,20]]},"874":{"position":[[143,20]]}}}],["tcppluginbas",{"_index":366,"t":{"42":{"position":[[56,13]]},"186":{"position":[[20,13]]},"194":{"position":[[121,13]]},"220":{"position":[[20,13]]},"233":{"position":[[121,13]]},"235":{"position":[[335,13]]},"493":{"position":[[94,13]]}}}],["tcprpcclient",{"_index":1947,"t":{"393":{"position":[[28,12],[68,12],[118,12]]}}}],["tcprpcservic",{"_index":1940,"t":{"391":{"position":[[103,13],[247,13],[318,13]]},"395":{"position":[[40,13]]}}}],["tcpservic",{"_index":346,"t":{"40":{"position":[[106,10]]},"57":{"position":[[1375,10],[1400,10]]},"120":{"position":[[18,10]]},"210":{"position":[[0,10]]},"223":{"position":[[5,10],[90,10],[115,10]]},"225":{"position":[[374,10],[416,10],[460,10],[1369,10],[1410,10]]},"227":{"position":[[1,10]]},"229":{"position":[[3,10],[63,10],[88,10]]},"233":{"position":[[554,10],[579,10]]},"235":{"position":[[194,10],[250,10],[937,10],[1184,10],[1219,10]]},"255":{"position":[[42,10]]},"272":{"position":[[1266,10],[1291,10]]},"301":{"position":[[2330,10],[2355,10]]},"308":{"position":[[1787,10],[1812,10]]},"347":{"position":[[1948,10],[1973,10]]},"406":{"position":[[105,10],[130,10]]},"422":{"position":[[118,10],[143,10]]},"495":{"position":[[252,10],[277,10]]},"514":{"position":[[66,10],[130,10],[155,10]]},"561":{"position":[[24,10],[49,10]]},"623":{"position":[[49,10]]},"736":{"position":[[0,10],[25,10]]},"745":{"position":[[118,10],[143,10]]},"859":{"position":[[18,10]]},"882":{"position":[[158,10]]},"980":{"position":[[86,10],[111,10]]}}}],["tcptoucerpcservic",{"_index":2970,"t":{"727":{"position":[[34,18]]}}}],["tcptouchrpc",{"_index":1170,"t":{"164":{"position":[[43,11]]},"250":{"position":[[43,11]]},"641":{"position":[[376,11]]},"643":{"position":[[260,11]]}}}],["tcptouchrpcclient",{"_index":982,"t":{"132":{"position":[[45,17],[76,17],[107,17]]},"134":{"position":[[3442,17],[3473,17]]},"138":{"position":[[14,17],[390,17],[420,17],[451,17]]},"169":{"position":[[27,17],[58,17]]},"248":{"position":[[103,17]]},"393":{"position":[[10,17],[47,17]]},"727":{"position":[[1106,17]]},"828":{"position":[[115,17]]},"830":{"position":[[1,17]]},"832":{"position":[[1279,17],[1521,17]]},"878":{"position":[[420,17]]}}}],["tcptouchrpcclientfactori",{"_index":2471,"t":{"528":{"position":[[133,24],[182,24],[227,24],[542,24],[1256,24]]},"530":{"position":[[443,24],[549,24],[594,24]]}}}],["tcptouchrpcservic",{"_index":974,"t":{"129":{"position":[[62,18]]},"140":{"position":[[45,18]]},"142":{"position":[[31,18],[233,18],[304,18]]},"255":{"position":[[81,18]]},"391":{"position":[[62,18],[84,18],[123,18]]},"447":{"position":[[269,18]]},"828":{"position":[[133,18]]},"830":{"position":[[19,18]]},"832":{"position":[[312,18]]}}}],["tcptouchrpcsocketcli",{"_index":1047,"t":{"140":{"position":[[73,23],[101,23],[176,23]]},"248":{"position":[[71,23]]},"641":{"position":[[330,23]]},"643":{"position":[[214,23]]},"648":{"position":[[328,23],[627,23],[978,23]]},"672":{"position":[[398,23]]},"674":{"position":[[343,23]]},"828":{"position":[[156,23]]},"832":{"position":[[416,23],[485,23],[734,23],[978,23],[1126,23]]}}}],["telnet",{"_index":3013,"t":{"738":{"position":[[26,6]]}}}],["tempbyteblock",{"_index":1779,"t":{"361":{"position":[[1252,13],[1463,13],[1601,13],[1667,13],[1688,13],[1799,13],[1865,13],[1886,13],[1998,13],[2552,13],[2649,13]]}}}],["tempcapac",{"_index":1617,"t":{"301":{"position":[[862,12],[1045,12]]}}}],["terminatorpackageadapt",{"_index":691,"t":{"80":{"position":[[1843,24]]},"514":{"position":[[458,24]]},"736":{"position":[[222,24]]},"745":{"position":[[442,24]]}}}],["testclass",{"_index":3391,"t":{"928":{"position":[[222,9]]}}}],["tester",{"_index":1698,"t":{"340":{"position":[[448,6],[918,6]]}}}],["testgetcontext",{"_index":682,"t":{"80":{"position":[[640,14],[2167,14]]},"512":{"position":[[664,14]]}}}],["testjobject",{"_index":688,"t":{"80":{"position":[[898,11],[1544,11],[2355,11]]},"512":{"position":[[1245,11]]}}}],["testjsonrpc",{"_index":669,"t":{"78":{"position":[[139,11],[247,11],[369,11]]},"80":{"position":[[346,11],[1306,11],[1986,11]]},"86":{"position":[[350,11]]},"512":{"position":[[163,11]]}}}],["testjsonrpc1",{"_index":681,"t":{"80":{"position":[[480,12],[2076,12]]},"512":{"position":[[355,12]]}}}],["teston",{"_index":2771,"t":{"655":{"position":[[280,7]]},"659":{"position":[[200,7]]},"661":{"position":[[404,7]]},"681":{"position":[[484,7]]}}}],["testpost",{"_index":651,"t":{"69":{"position":[[613,8]]},"75":{"position":[[119,8]]},"894":{"position":[[304,8]]}}}],["text",{"_index":384,"t":{"46":{"position":[[118,4]]},"120":{"position":[[1756,4]]},"290":{"position":[[305,4]]},"317":{"position":[[230,4]]},"323":{"position":[[120,4]]},"436":{"position":[[2032,4]]},"521":{"position":[[153,4]]},"925":{"position":[[51,4]]}}}],["textbox2",{"_index":383,"t":{"46":{"position":[[109,8]]}}}],["textbox3",{"_index":1660,"t":{"317":{"position":[[221,8]]}}}],["thread",{"_index":996,"t":{"134":{"position":[[156,9]]},"159":{"position":[[18,6]]},"340":{"position":[[955,6]]},"602":{"position":[[76,6]]},"663":{"position":[[323,6]]}}}],["throw",{"_index":536,"t":{"57":{"position":[[577,5]]},"134":{"position":[[1446,5],[1552,5],[1944,5],[2050,5],[2748,5],[3250,5]]},"361":{"position":[[711,5]]},"365":{"position":[[1686,5]]},"489":{"position":[[355,5]]},"610":{"position":[[464,5],[564,5]]},"702":{"position":[[464,5]]},"734":{"position":[[913,5]]}}}],["throwbreakexcept",{"_index":3245,"t":{"857":{"position":[[399,19]]},"859":{"position":[[293,19]]}}}],["tick",{"_index":2788,"t":{"663":{"position":[[276,4],[310,4]]}}}],["time",{"_index":1711,"t":{"340":{"position":[[911,4],[1019,4]]}}}],["timemeasur",{"_index":2693,"t":{"602":{"position":[[51,12]]}}}],["timeout",{"_index":754,"t":{"102":{"position":[[336,7]]},"659":{"position":[[16,7],[99,7]]},"681":{"position":[[206,7]]},"686":{"position":[[311,7]]},"816":{"position":[[97,7]]},"832":{"position":[[1972,7]]}}}],["timeoutexcept",{"_index":1005,"t":{"134":{"position":[[303,16],[639,16],[1141,16],[2333,16]]}}}],["timer",{"_index":2317,"t":{"491":{"position":[[167,5],[218,5]]},"493":{"position":[[533,5],[539,5],[548,5],[632,5],[914,5],[920,5],[929,5]]},"528":{"position":[[829,5],[1527,5]]},"832":{"position":[[2066,5]]},"872":{"position":[[235,5]]}}}],["timespan",{"_index":2692,"t":{"602":{"position":[[31,8],[40,8]]},"832":{"position":[[1982,8]]}}}],["timetick",{"_index":2324,"t":{"493":{"position":[[133,8],[239,8],[271,8],[282,8],[676,8]]}}}],["tip",{"_index":2045,"t":{"431":{"position":[[833,3]]}}}],["titl",{"_index":865,"t":{"120":{"position":[[1387,5],[1406,5]]},"261":{"position":[[533,5]]}}}],["tls12",{"_index":768,"t":{"104":{"position":[[176,5],[401,5]]},"122":{"position":[[180,5]]},"288":{"position":[[432,5]]},"319":{"position":[[443,5]]}}}],["tlv",{"_index":3023,"t":{"748":{"position":[[0,3],[25,3],[83,3],[121,3]]},"752":{"position":[[0,3]]},"880":{"position":[[85,3]]},"938":{"position":[[12,3]]}}}],["tlvdatafram",{"_index":3045,"t":{"756":{"position":[[54,12]]}}}],["tlvdatahandlingadapt",{"_index":3038,"t":{"750":{"position":[[112,22],[389,22]]}}}],["tlvplugin",{"_index":3040,"t":{"750":{"position":[[180,9],[210,9],[457,9],[508,9]]}}}],["toarray",{"_index":1703,"t":{"340":{"position":[[654,7]]},"447":{"position":[[1119,7]]},"489":{"position":[[1234,7]]},"610":{"position":[[228,7]]}}}],["todo",{"_index":692,"t":{"86":{"position":[[35,4]]}}}],["tojson",{"_index":2409,"t":{"519":{"position":[[63,6]]}}}],["token",{"_index":1189,"t":{"166":{"position":[[125,5]]},"252":{"position":[[125,5]]},"661":{"position":[[319,5]]},"770":{"position":[[39,5]]},"772":{"position":[[34,5]]},"774":{"position":[[330,5]]},"830":{"position":[[692,5]]}}}],["tokeninst",{"_index":3300,"t":{"872":{"position":[[850,13]]}}}],["tokensourc",{"_index":2779,"t":{"661":{"position":[[229,11],[307,11],[328,11]]},"663":{"position":[[364,11]]}}}],["tolow",{"_index":1055,"t":{"142":{"position":[[159,7],[459,7]]}}}],["tom",{"_index":1848,"t":{"370":{"position":[[142,3]]}}}],["tonychen899",{"_index":1840,"t":{"370":{"position":[[87,11]]}}}],["top",{"_index":875,"t":{"120":{"position":[[1574,3],[1838,3],[1983,3]]}}}],["tostr",{"_index":900,"t":{"120":{"position":[[2244,8]]},"465":{"position":[[681,8]]},"489":{"position":[[1270,8]]},"493":{"position":[[1182,8]]},"528":{"position":[[1184,8],[1234,8],[1881,8],[1931,8]]},"574":{"position":[[569,8]]},"615":{"position":[[202,8]]},"832":{"position":[[2455,8]]},"843":{"position":[[145,8]]},"849":{"position":[[163,8]]}}}],["totext",{"_index":1572,"t":{"290":{"position":[[341,6]]},"292":{"position":[[336,6]]}}}],["touch",{"_index":2745,"t":{"639":{"position":[[62,5]]}}}],["touchclient",{"_index":1959,"t":{"397":{"position":[[47,11]]}}}],["touchrpc",{"_index":934,"t":{"125":{"position":[[217,8]]},"127":{"position":[[127,8],[223,8],[499,8]]},"129":{"position":[[12,8],[33,8],[275,8]]},"132":{"position":[[217,8]]},"134":{"position":[[3583,8]]},"138":{"position":[[236,8],[297,8],[704,8]]},"144":{"position":[[14,8]]},"162":{"position":[[0,8]]},"169":{"position":[[168,8]]},"171":{"position":[[170,8]]},"246":{"position":[[0,8]]},"248":{"position":[[0,8]]},"255":{"position":[[9,8],[22,8],[285,8]]},"257":{"position":[[276,8]]},"353":{"position":[[10,8]]},"391":{"position":[[8,8]]},"397":{"position":[[4,8]]},"447":{"position":[[683,8]]},"455":{"position":[[117,8]]},"528":{"position":[[113,8]]},"579":{"position":[[7,8]]},"581":{"position":[[19,8]]},"630":{"position":[[45,8]]},"641":{"position":[[162,8]]},"643":{"position":[[120,8]]},"650":{"position":[[23,8]]},"672":{"position":[[206,8]]},"674":{"position":[[178,8]]},"679":{"position":[[1,8]]},"681":{"position":[[1,8]]},"689":{"position":[[206,8]]},"772":{"position":[[101,8]]},"776":{"position":[[1,8]]},"778":{"position":[[13,8]]},"780":{"position":[[13,8],[26,8]]},"783":{"position":[[0,8],[190,8],[239,8],[256,8],[351,8],[396,8]]},"785":{"position":[[0,8],[84,8]]},"787":{"position":[[141,8],[162,8]]},"806":{"position":[[7,8],[39,8],[64,8],[153,8],[207,8],[255,8],[373,8],[481,8]]},"828":{"position":[[36,8]]},"868":{"position":[[29,8],[48,8],[79,8]]},"870":{"position":[[47,8]]},"872":{"position":[[73,8],[272,8],[327,8],[373,8],[437,8],[885,8],[912,8]]},"874":{"position":[[82,8],[388,8]]},"878":{"position":[[136,8],[155,8],[214,8],[277,8]]},"882":{"position":[[337,8]]}}}],["touchrpcactionplugin",{"_index":3320,"t":{"878":{"position":[[244,20],[326,20],[399,20]]}}}],["touchrpcattribut",{"_index":2158,"t":{"447":{"position":[[632,17],[1445,17]]}}}],["touchrpcclient",{"_index":3338,"t":{"884":{"position":[[201,14]]}}}],["touchrpcpluginbas",{"_index":1075,"t":{"146":{"position":[[155,18]]},"166":{"position":[[49,18]]},"252":{"position":[[49,18]]},"530":{"position":[[187,18]]},"630":{"position":[[311,18]]},"693":{"position":[[87,18]]},"774":{"position":[[84,18]]},"780":{"position":[[186,18]]},"832":{"position":[[397,18]]},"836":{"position":[[137,18]]}}}],["touchservic",{"_index":1957,"t":{"397":{"position":[[16,12]]}}}],["touchsocket",{"_index":13,"t":{"5":{"position":[[0,11]]},"12":{"position":[[115,11]]},"16":{"position":[[17,11],[43,11]]},"20":{"position":[[4,11]]},"28":{"position":[[1,11]]},"32":{"position":[[0,11]]},"34":{"position":[[14,11]]},"36":{"position":[[35,11]]},"69":{"position":[[138,11]]},"80":{"position":[[0,11],[386,11],[521,11],[683,11],[1346,11]]},"86":{"position":[[363,11]]},"89":{"position":[[48,11]]},"110":{"position":[[62,11]]},"120":{"position":[[1393,11]]},"134":{"position":[[126,11],[359,11],[695,11],[1197,11],[2389,11],[2667,11],[3169,11]]},"149":{"position":[[30,11],[96,11]]},"194":{"position":[[2,11]]},"233":{"position":[[2,11]]},"235":{"position":[[6,11],[83,11],[141,11]]},"261":{"position":[[13,11]]},"263":{"position":[[9,11]]},"350":{"position":[[14,11]]},"374":{"position":[[22,11]]},"376":{"position":[[576,11]]},"402":{"position":[[75,11],[98,11]]},"429":{"position":[[11,11]]},"498":{"position":[[57,11]]},"512":{"position":[[197,11],[390,11],[1198,11]]},"519":{"position":[[1,11]]},"542":{"position":[[186,11],[217,11]]},"552":{"position":[[68,11],[873,11]]},"554":{"position":[[21,11]]},"556":{"position":[[870,11],[1672,11]]},"564":{"position":[[4,11]]},"574":{"position":[[7,11],[45,11]]},"600":{"position":[[0,11]]},"604":{"position":[[29,11],[72,11]]},"702":{"position":[[6,11],[30,11]]},"705":{"position":[[0,11]]},"707":{"position":[[2,11],[174,11]]},"714":{"position":[[37,11]]},"716":{"position":[[63,11]]},"720":{"position":[[46,11]]},"767":{"position":[[0,11]]},"814":{"position":[[57,11]]},"816":{"position":[[410,11]]},"862":{"position":[[80,11]]},"866":{"position":[[0,11]]},"872":{"position":[[493,11],[524,11]]},"896":{"position":[[369,11]]},"935":{"position":[[15,11],[42,11]]},"954":{"position":[[54,11]]},"969":{"position":[[16,11]]}}}],["touchsocketbitconvert",{"_index":2311,"t":{"489":{"position":[[786,23]]},"702":{"position":[[2223,23]]},"763":{"position":[[13,23]]},"765":{"position":[[13,23]]},"767":{"position":[[54,23],[127,23]]},"889":{"position":[[29,23]]}}}],["touchsocketcli",{"_index":1958,"t":{"397":{"position":[[29,17]]}}}],["touchsocketconfig",{"_index":380,"t":{"46":{"position":[[58,17]]},"57":{"position":[[167,17],[1770,17]]},"80":{"position":[[147,17],[1109,17],[1721,17]]},"102":{"position":[[55,17]]},"120":{"position":[[130,17]]},"129":{"position":[[84,17],[114,17]]},"132":{"position":[[145,17]]},"134":{"position":[[3511,17]]},"138":{"position":[[489,17]]},"169":{"position":[[96,17]]},"171":{"position":[[98,17]]},"173":{"position":[[74,17]]},"175":{"position":[[67,17]]},"188":{"position":[[405,17],[436,17]]},"192":{"position":[[286,17],[317,17]]},"194":{"position":[[601,17]]},"207":{"position":[[250,17]]},"223":{"position":[[722,17]]},"225":{"position":[[524,17],[1058,17],[1612,17]]},"229":{"position":[[314,17]]},"233":{"position":[[611,17]]},"255":{"position":[[120,17]]},"257":{"position":[[80,17],[111,17]]},"259":{"position":[[103,17],[134,17]]},"261":{"position":[[374,17]]},"272":{"position":[[159,17],[1568,17]]},"284":{"position":[[145,17]]},"286":{"position":[[171,17]]},"288":{"position":[[115,17]]},"301":{"position":[[129,17],[2697,17]]},"308":{"position":[[161,17],[2176,17]]},"317":{"position":[[179,17]]},"319":{"position":[[183,17]]},"347":{"position":[[163,17],[2341,17]]},"406":{"position":[[24,17],[308,17]]},"422":{"position":[[24,17],[321,17]]},"447":{"position":[[308,17]]},"458":{"position":[[93,17]]},"495":{"position":[[309,17],[737,17]]},"514":{"position":[[187,17]]},"516":{"position":[[260,17]]},"528":{"position":[[329,17],[444,17]]},"530":{"position":[[696,17],[842,17]]},"537":{"position":[[94,17],[567,17],[656,17]]},"539":{"position":[[82,17]]},"561":{"position":[[524,17]]},"668":{"position":[[94,17],[125,17]]},"686":{"position":[[44,17]]},"736":{"position":[[56,17]]},"745":{"position":[[24,17],[321,17]]},"750":{"position":[[276,17]]},"772":{"position":[[60,17]]},"816":{"position":[[236,17]]},"832":{"position":[[24,17],[1310,17]]},"843":{"position":[[182,17]]},"845":{"position":[[61,17]]},"849":{"position":[[200,17]]},"851":{"position":[[61,17]]},"857":{"position":[[58,17]]},"859":{"position":[[768,17]]},"889":{"position":[[64,17]]},"896":{"position":[[59,17]]},"925":{"position":[[241,17]]},"980":{"position":[[3,17],[289,17]]}}}],["touchsocketconvert",{"_index":3343,"t":{"889":{"position":[[96,20]]}}}],["touchsocketcor",{"_index":1082,"t":{"149":{"position":[[4,15]]}}}],["touchsocketeventarg",{"_index":1432,"t":{"235":{"position":[[537,20]]},"493":{"position":[[375,20]]},"574":{"position":[[202,20],[377,20],[641,20]]},"889":{"position":[[195,20]]}}}],["touchsocketpro",{"_index":131,"t":{"16":{"position":[[0,14]]},"18":{"position":[[53,14]]},"20":{"position":[[16,14]]},"235":{"position":[[30,14],[107,14],[154,14]]},"261":{"position":[[37,14]]},"935":{"position":[[0,14],[101,14]]},"954":{"position":[[30,14]]},"957":{"position":[[1,14],[40,14]]},"969":{"position":[[40,14],[265,14]]},"971":{"position":[[8,14]]}}}],["toucsocket",{"_index":2929,"t":{"705":{"position":[[143,10]]}}}],["touint16",{"_index":2312,"t":{"489":{"position":[[818,8]]},"702":{"position":[[2260,8]]}}}],["tpc",{"_index":915,"t":{"125":{"position":[[85,3]]}}}],["transferbyt",{"_index":1762,"t":{"361":{"position":[[463,13]]},"365":{"position":[[1552,13],[1607,13],[1948,13],[2141,12],[2155,13],[2180,12],[2197,13],[2219,12],[2251,13],[2273,12],[2305,13],[2327,12],[2358,13],[2429,12],[2443,13],[2468,12],[2485,13],[2507,12],[2540,13],[2562,12],[2595,13],[2617,12],[2648,13],[2719,12],[2733,13],[2758,12],[2775,13],[2797,12],[2830,13],[2852,12],[2885,13],[2907,12],[2938,13],[3011,12],[3025,13],[3050,12],[3067,13],[3089,12],[3122,13],[3144,12],[3177,13],[3199,12],[3230,13]]},"809":{"position":[[429,12],[443,13]]}}}],["transferflag",{"_index":3209,"t":{"832":{"position":[[1788,13]]}}}],["transfertyp",{"_index":3205,"t":{"832":{"position":[[651,12],[885,12]]},"878":{"position":[[566,12],[734,12]]}}}],["transient",{"_index":2554,"t":{"544":{"position":[[51,9]]},"554":{"position":[[77,9]]}}}],["transientrpcserv",{"_index":944,"t":{"127":{"position":[[74,18],[437,18]]},"643":{"position":[[6,18],[78,18]]}}}],["trequest",{"_index":1605,"t":{"301":{"position":[[341,8]]}}}],["tri",{"_index":1791,"t":{"361":{"position":[[2865,3]]},"365":{"position":[[430,3],[689,3],[948,3],[1209,3]]},"465":{"position":[[201,3]]},"491":{"position":[[376,3],[634,3]]},"537":{"position":[[485,3]]},"539":{"position":[[0,3]]},"971":{"position":[[100,3],[109,3]]}}}],["true",{"_index":474,"t":{"50":{"position":[[262,4]]},"57":{"position":[[805,4],[839,4],[919,4]]},"91":{"position":[[407,4]]},"104":{"position":[[524,4]]},"120":{"position":[[914,4]]},"127":{"position":[[384,4],[660,4]]},"146":{"position":[[314,4]]},"159":{"position":[[792,4]]},"194":{"position":[[463,4]]},"233":{"position":[[469,4]]},"272":{"position":[[559,4],[645,4]]},"301":{"position":[[773,4]]},"308":{"position":[[1063,4],[1286,4]]},"319":{"position":[[566,4],[624,4]]},"340":{"position":[[383,4]]},"347":{"position":[[832,4],[1523,4]]},"411":{"position":[[201,4]]},"413":{"position":[[212,4]]},"451":{"position":[[120,4],[301,4]]},"455":{"position":[[232,4]]},"470":{"position":[[362,4],[517,4]]},"489":{"position":[[673,4],[887,4]]},"491":{"position":[[469,4],[727,4]]},"495":{"position":[[1387,4]]},"512":{"position":[[241,4],[334,4]]},"530":{"position":[[386,4]]},"550":{"position":[[500,4],[554,4]]},"552":{"position":[[627,4],[681,4],[735,4],[779,4],[1709,4]]},"554":{"position":[[723,4]]},"570":{"position":[[190,4]]},"595":{"position":[[78,4]]},"632":{"position":[[255,4],[292,4],[412,4],[453,4],[494,4]]},"641":{"position":[[441,4]]},"643":{"position":[[325,4]]},"663":{"position":[[480,4]]},"693":{"position":[[286,4]]},"702":{"position":[[2659,4],[2978,4]]},"734":{"position":[[217,4]]},"745":{"position":[[566,4]]},"752":{"position":[[150,4]]},"774":{"position":[[294,4],[370,4],[388,4]]},"832":{"position":[[567,4]]},"836":{"position":[[376,4]]},"857":{"position":[[377,4],[421,4]]},"859":{"position":[[271,4],[315,4]]},"872":{"position":[[968,4],[1069,4]]}}}],["trycaninvok",{"_index":1013,"t":{"134":{"position":[[1511,12],[2009,12],[2707,12],[3209,12]]}}}],["trycount",{"_index":2669,"t":{"595":{"position":[[101,8]]}}}],["trygetsocketcli",{"_index":1061,"t":{"142":{"position":[[323,18]]},"239":{"position":[[241,18],[318,18]]}}}],["tryreleasefil",{"_index":2001,"t":{"415":{"position":[[41,14],[132,14],[209,14]]}}}],["trysubscribechannel",{"_index":2808,"t":{"672":{"position":[[455,19]]},"674":{"position":[[400,19]]}}}],["type",{"_index":889,"t":{"120":{"position":[[1749,4],[1889,4]]},"447":{"position":[[616,4],[1398,4],[1429,4]]},"684":{"position":[[556,4]]}}}],["typeof",{"_index":1908,"t":{"376":{"position":[[536,6],[864,6]]},"431":{"position":[[719,6],[905,6]]},"447":{"position":[[625,6],[1405,6],[1438,6]]},"491":{"position":[[252,6]]},"521":{"position":[[399,6]]},"550":{"position":[[530,6],[584,6]]},"552":{"position":[[657,6],[711,6],[1740,6],[1815,6]]}}}],["typeparam",{"_index":1912,"t":{"376":{"position":[[937,9],[964,9],[1281,9],[1308,9]]}}}],["udp",{"_index":374,"t":{"46":{"position":[[0,3]]},"125":{"position":[[89,3]]},"199":{"position":[[0,3],[8,3]]},"203":{"position":[[0,3]]},"207":{"position":[[372,3]]},"259":{"position":[[4,3],[40,3]]},"391":{"position":[[21,3]]},"579":{"position":[[23,3]]},"581":{"position":[[82,3]]},"630":{"position":[[57,3]]},"653":{"position":[[144,3]]},"778":{"position":[[212,3]]},"783":{"position":[[364,3]]},"785":{"position":[[50,3]]},"806":{"position":[[221,3],[228,3]]},"809":{"position":[[0,3],[41,3]]},"814":{"position":[[0,3]]},"878":{"position":[[165,3]]},"884":{"position":[[126,3]]}}}],["udpclient",{"_index":3232,"t":{"845":{"position":[[11,9],[41,9],[194,9]]},"851":{"position":[[11,9],[41,9],[225,9]]}}}],["udpdataadaptertest",{"_index":3139,"t":{"811":{"position":[[2,20]]}}}],["udpdatahandlingadapt",{"_index":3136,"t":{"809":{"position":[[94,22]]}}}],["udppackageadapt",{"_index":3141,"t":{"816":{"position":[[15,17],[338,17]]}}}],["udpservic",{"_index":3228,"t":{"843":{"position":[[4,10],[26,10],[57,10],[161,10],[339,10]]},"849":{"position":[[22,10],[44,10],[75,10],[179,10]]}}}],["udpsess",{"_index":376,"t":{"46":{"position":[[23,10],[37,10]]},"207":{"position":[[0,10],[11,10],[28,10],[42,10],[102,10],[229,10]]},"259":{"position":[[25,10]]},"816":{"position":[[107,10],[118,10],[135,10],[149,10],[215,10],[367,10]]},"841":{"position":[[33,10]]},"843":{"position":[[15,10],[43,10]]},"845":{"position":[[0,10],[27,10]]},"849":{"position":[[33,10],[61,10]]},"851":{"position":[[0,10],[27,10]]},"880":{"position":[[326,10]]}}}],["udpsessionbas",{"_index":1338,"t":{"184":{"position":[[1549,14]]},"218":{"position":[[1549,14]]}}}],["udpsessionpluginbas",{"_index":1376,"t":{"205":{"position":[[50,20]]}}}],["udptouchrpc",{"_index":1027,"t":{"138":{"position":[[32,11]]},"173":{"position":[[17,11],[42,11]]},"259":{"position":[[88,11]]}}}],["ui",{"_index":3359,"t":{"906":{"position":[[57,2]]}}}],["unen",{"_index":2755,"t":{"648":{"position":[[245,8]]}}}],["uniti",{"_index":3126,"t":{"806":{"position":[[91,5]]},"824":{"position":[[47,5]]},"868":{"position":[[122,5]]},"876":{"position":[[34,5]]}}}],["unity3d",{"_index":2421,"t":{"521":{"position":[[329,7]]}}}],["unitysir",{"_index":1833,"t":{"370":{"position":[[17,8]]}}}],["unpackag",{"_index":2374,"t":{"507":{"position":[[837,9],[1665,9],[2180,9]]}}}],["up",{"_index":1798,"t":{"365":{"position":[[100,2],[250,2],[766,2],[2102,2],[2678,2]]}}}],["up_go_send",{"_index":1804,"t":{"365":{"position":[[250,10]]}}}],["up_go_splicingsend",{"_index":1822,"t":{"365":{"position":[[2102,18]]}}}],["up_hold_send",{"_index":1806,"t":{"365":{"position":[[766,12]]}}}],["up_hold_splicingsend",{"_index":1826,"t":{"365":{"position":[[2678,20]]}}}],["updatecachetimewhenrev",{"_index":471,"t":{"50":{"position":[[223,22]]}}}],["uploadfil",{"_index":2252,"t":{"465":{"position":[[185,10]]}}}],["url",{"_index":637,"t":{"69":{"position":[[47,3],[202,3],[217,3]]},"78":{"position":[[204,3]]},"80":{"position":[[1786,3]]},"261":{"position":[[204,3],[970,3]]},"284":{"position":[[17,3]]},"286":{"position":[[40,3]]},"319":{"position":[[41,3]]}}}],["urlequ",{"_index":839,"t":{"120":{"position":[[786,9],[949,9],[1106,9]]},"463":{"position":[[173,9]]},"465":{"position":[[173,9]]}}}],["us",{"_index":995,"t":{"134":{"position":[[120,5],[143,5]]},"153":{"position":[[317,5]]},"157":{"position":[[0,5]]},"361":{"position":[[857,5]]},"365":{"position":[[1832,5]]},"411":{"position":[[146,5]]},"413":{"position":[[168,5]]},"470":{"position":[[648,5]]},"489":{"position":[[1147,5]]},"507":{"position":[[2023,5]]},"610":{"position":[[85,5]]},"672":{"position":[[826,5]]},"702":{"position":[[0,5],[24,5],[2047,5],[2783,5]]},"896":{"position":[[363,5]]}}}],["useaspnetcorecontain",{"_index":1437,"t":{"235":{"position":[[1058,22]]},"261":{"position":[[395,22]]}}}],["useauthor",{"_index":1488,"t":{"261":{"position":[[1001,16]]}}}],["usebroadcast",{"_index":1340,"t":{"184":{"position":[[1996,12]]},"218":{"position":[[1996,12]]},"841":{"position":[[17,12]]},"843":{"position":[[236,12]]},"847":{"position":[[17,12]]},"849":{"position":[[254,12]]},"851":{"position":[[82,12],[348,12]]}}}],["usecheckclear",{"_index":3296,"t":{"872":{"position":[[713,13],[1132,13]]}}}],["useconsolelogg",{"_index":1416,"t":{"225":{"position":[[1227,16],[1781,16]]},"229":{"position":[[483,16]]},"233":{"position":[[755,16]]}}}],["usedefaulthttpserviceplugin",{"_index":831,"t":{"120":{"position":[[390,27]]}}}],["usedelaysend",{"_index":1292,"t":{"184":{"position":[[817,14],[1596,14]]},"218":{"position":[[817,14],[1596,14]]}}}],["usedeveloperexceptionpag",{"_index":1481,"t":{"261":{"position":[[726,25]]}}}],["useendpoint",{"_index":1489,"t":{"261":{"position":[[1025,12]]}}}],["usenodelay",{"_index":1289,"t":{"184":{"position":[[777,10],[1956,10]]},"218":{"position":[[777,10],[1956,10]]}}}],["useplugin",{"_index":740,"t":{"102":{"position":[[76,9]]},"120":{"position":[[157,9]]},"184":{"position":[[684,9]]},"188":{"position":[[511,9]]},"192":{"position":[[392,9]]},"194":{"position":[[61,9],[669,9]]},"218":{"position":[[684,9]]},"233":{"position":[[61,9],[715,9]]},"235":{"position":[[1045,9]]},"284":{"position":[[172,9]]},"286":{"position":[[198,9]]},"288":{"position":[[143,9]]},"458":{"position":[[121,9]]},"495":{"position":[[429,9],[805,9]]},"514":{"position":[[208,9]]},"516":{"position":[[281,9]]},"574":{"position":[[542,9]]},"595":{"position":[[21,9]]},"597":{"position":[[61,9]]},"736":{"position":[[348,9]]},"750":{"position":[[304,9]]},"832":{"position":[[102,9],[1390,9]]},"878":{"position":[[357,9]]},"896":{"position":[[80,9]]},"925":{"position":[[269,9]]},"930":{"position":[[157,9]]}}}],["usereconnect",{"_index":2529,"t":{"539":{"position":[[262,15]]},"595":{"position":[[59,15]]},"597":{"position":[[205,15]]}}}],["usereuseaddress",{"_index":1324,"t":{"184":{"position":[[1177,15]]},"218":{"position":[[1177,15]]}}}],["userout",{"_index":1487,"t":{"261":{"position":[[983,10]]}}}],["useswagg",{"_index":1483,"t":{"261":{"position":[[772,10]]}}}],["useswaggerui",{"_index":1484,"t":{"261":{"position":[[790,12]]}}}],["usetouchrpcheartbeat",{"_index":3207,"t":{"832":{"position":[[1500,20]]}}}],["usewebsocket",{"_index":1464,"t":{"261":{"position":[[151,13],[880,13]]},"882":{"position":[[99,12]]}}}],["usewstouchrpc",{"_index":1465,"t":{"261":{"position":[[187,13],[604,13],[917,13]]}}}],["ushort",{"_index":1969,"t":{"402":{"position":[[42,6]]},"404":{"position":[[45,6]]},"487":{"position":[[141,6]]},"489":{"position":[[971,6]]},"702":{"position":[[886,6],[916,6],[1596,6],[1689,6]]},"748":{"position":[[475,6]]},"780":{"position":[[574,6]]},"820":{"position":[[161,6]]}}}],["utf",{"_index":864,"t":{"120":{"position":[[1347,3]]}}}],["utf8",{"_index":574,"t":{"57":{"position":[[1681,4]]},"159":{"position":[[499,4],[844,4]]},"188":{"position":[[308,4]]},"192":{"position":[[189,4]]},"207":{"position":[[171,4]]},"223":{"position":[[373,4]]},"225":{"position":[[277,4]]},"229":{"position":[[192,4]]},"272":{"position":[[1045,4],[1130,4]]},"301":{"position":[[2608,4]]},"308":{"position":[[2087,4]]},"347":{"position":[[1139,4],[1317,4],[2252,4]]},"406":{"position":[[235,4]]},"422":{"position":[[248,4]]},"470":{"position":[[551,4]]},"489":{"position":[[1356,4]]},"495":{"position":[[1295,4]]},"512":{"position":[[1118,4]]},"745":{"position":[[248,4]]},"758":{"position":[[59,4]]},"780":{"position":[[405,4]]},"845":{"position":[[270,4]]},"851":{"position":[[307,4]]},"857":{"position":[[524,4],[591,4],[754,4]]},"859":{"position":[[418,4],[480,4],[643,4]]},"980":{"position":[[216,4]]}}}],["v",{"_index":2429,"t":{"523":{"position":[[155,1],[274,1],[2534,1],[2627,1]]},"748":{"position":[[71,1],[107,1]]}}}],["v1",{"_index":1470,"t":{"261":{"position":[[510,2],[564,2],[838,2],[866,2]]},"444":{"position":[[268,2],[280,2]]}}}],["val",{"_index":2434,"t":{"523":{"position":[[282,3],[2635,3]]}}}],["valu",{"_index":615,"t":{"60":{"position":[[576,5],[597,5],[622,5],[643,5]]},"120":{"position":[[1773,5],[1915,5]]},"376":{"position":[[372,5],[1026,5],[1136,5],[1205,5]]},"447":{"position":[[1112,6]]},"507":{"position":[[774,5]]},"702":{"position":[[832,5],[1054,5],[1817,5]]},"748":{"position":[[65,5],[271,5],[349,5],[485,5]]}}}],["valuebyteblock",{"_index":2039,"t":{"431":{"position":[[318,14]]},"872":{"position":[[111,14]]}}}],["valuetlvdatafram",{"_index":3047,"t":{"756":{"position":[[82,17],[107,17],[143,17],[201,17],[237,17]]},"758":{"position":[[29,17]]}}}],["var",{"_index":590,"t":{"60":{"position":[[68,3]]},"66":{"position":[[135,3]]},"69":{"position":[[411,3]]},"102":{"position":[[298,3]]},"120":{"position":[[79,3]]},"129":{"position":[[45,3]]},"142":{"position":[[19,3],[350,3]]},"223":{"position":[[552,3],[589,3]]},"235":{"position":[[933,3]]},"255":{"position":[[63,3],[103,3]]},"257":{"position":[[39,3]]},"259":{"position":[[70,3]]},"284":{"position":[[94,3]]},"286":{"position":[[120,3]]},"288":{"position":[[98,3]]},"292":{"position":[[240,3],[285,3]]},"340":{"position":[[389,3],[907,3]]},"350":{"position":[[31,3],[108,3]]},"365":{"position":[[1595,3],[1936,3]]},"391":{"position":[[145,3]]},"411":{"position":[[153,3]]},"413":{"position":[[175,3]]},"429":{"position":[[0,3],[25,3],[79,3]]},"431":{"position":[[298,3],[366,3]]},"447":{"position":[[251,3],[291,3]]},"458":{"position":[[43,3],[76,3]]},"465":{"position":[[390,3],[469,3]]},"507":{"position":[[515,3],[701,3],[1015,3],[1102,3],[1321,3],[1746,3],[2137,3]]},"512":{"position":[[794,3],[847,3],[867,3],[1004,3],[1053,3],[1073,3]]},"523":{"position":[[151,3],[239,3],[278,3],[2530,3],[2592,3],[2631,3]]},"528":{"position":[[606,3],[707,3],[1320,3],[1421,3]]},"537":{"position":[[77,3]]},"548":{"position":[[164,3]]},"550":{"position":[[387,3]]},"552":{"position":[[514,3],[1595,3]]},"554":{"position":[[414,3],[452,3]]},"561":{"position":[[507,3]]},"610":{"position":[[180,3]]},"632":{"position":[[61,3]]},"686":{"position":[[27,3],[334,3]]},"691":{"position":[[83,3],[150,3],[261,3]]},"736":{"position":[[39,3]]},"750":{"position":[[259,3]]},"772":{"position":[[43,3]]},"832":{"position":[[6,3]]},"857":{"position":[[41,3],[232,3]]},"859":{"position":[[0,3],[131,3]]},"925":{"position":[[191,3],[224,3]]}}}],["vb",{"_index":2925,"t":{"705":{"position":[[53,2]]}}}],["verifyfunc",{"_index":3039,"t":{"750":{"position":[[156,10],[433,10]]}}}],["verifymd5hash",{"_index":2696,"t":{"604":{"position":[[57,13]]}}}],["verifyoptioneventarg",{"_index":3074,"t":{"774":{"position":[[161,21]]},"832":{"position":[[1010,21]]}}}],["verifytoken",{"_index":3073,"t":{"772":{"position":[[15,11]]}}}],["version",{"_index":611,"t":{"60":{"position":[[500,7]]},"261":{"position":[[553,7]]},"716":{"position":[[76,7],[110,7]]}}}],["virtual",{"_index":1371,"t":{"196":{"position":[[114,7],[155,7],[202,7],[327,7],[373,7]]},"241":{"position":[[67,7],[108,7],[155,7],[280,7],[326,7],[378,7]]},"243":{"position":[[17,7],[75,7],[151,7],[203,7],[266,7],[347,7]]}}}],["void",{"_index":350,"t":{"40":{"position":[[154,4]]},"42":{"position":[[91,4]]},"48":{"position":[[233,4]]},"57":{"position":[[633,4]]},"60":{"position":[[41,4]]},"66":{"position":[[108,4]]},"80":{"position":[[999,4]]},"120":{"position":[[702,4],[2309,4]]},"146":{"position":[[195,4]]},"159":{"position":[[388,4],[698,4]]},"194":{"position":[[239,4]]},"196":{"position":[[122,4],[163,4],[210,4]]},"225":{"position":[[143,4],[508,4],[622,4]]},"233":{"position":[[242,4]]},"235":{"position":[[499,4],[647,4],[879,4]]},"241":{"position":[[75,4],[116,4],[163,4]]},"243":{"position":[[25,4],[83,4],[159,4]]},"261":{"position":[[263,4],[628,4]]},"272":{"position":[[450,4]]},"286":{"position":[[793,4]]},"290":{"position":[[103,4],[882,4],[1175,4]]},"361":{"position":[[210,4],[275,4],[354,4],[420,4],[501,4],[569,4],[1353,4],[2210,4],[2823,4]]},"365":{"position":[[245,4],[502,4],[761,4],[1020,4],[1509,4],[2097,4],[2383,4],[2673,4],[2963,4]]},"393":{"position":[[245,4]]},"463":{"position":[[91,4]]},"465":{"position":[[90,4]]},"473":{"position":[[152,4]]},"489":{"position":[[310,4],[918,4]]},"493":{"position":[[335,4],[738,4],[1037,4]]},"495":{"position":[[168,4],[1453,4]]},"507":{"position":[[247,4],[832,4],[1585,4],[1660,4]]},"523":{"position":[[120,4],[2498,4]]},"530":{"position":[[227,4]]},"537":{"position":[[7,4],[384,4],[795,4]]},"548":{"position":[[56,4],[460,4],[551,4]]},"550":{"position":[[116,4],[779,4],[870,4]]},"552":{"position":[[139,4],[895,4],[1247,4],[1338,4],[1426,4],[1872,4],[1963,4]]},"554":{"position":[[307,4]]},"556":{"position":[[126,4],[217,4],[318,4],[409,4],[662,4],[753,4],[1132,4],[1223,4],[1464,4],[1555,4],[1694,4],[2046,4],[2137,4],[2359,4],[2450,4],[2627,4],[2979,4],[3070,4],[3271,4],[3623,4],[3714,4]]},"574":{"position":[[344,4],[460,4]]},"630":{"position":[[351,4]]},"648":{"position":[[85,4],[507,4],[830,4]]},"693":{"position":[[127,4]]},"702":{"position":[[419,4]]},"734":{"position":[[893,4]]},"774":{"position":[[124,4]]},"780":{"position":[[226,4]]},"809":{"position":[[185,4],[275,4],[387,4],[495,4]]},"832":{"position":[[462,4],[712,4],[960,4],[1106,4]]},"836":{"position":[[177,4]]},"932":{"position":[[45,4]]},"969":{"position":[[484,4],[596,4]]}}}],["vs",{"_index":2935,"t":{"707":{"position":[[138,2]]}}}],["vs2010",{"_index":2934,"t":{"707":{"position":[[92,6]]}}}],["vs2022",{"_index":2358,"t":{"503":{"position":[[133,6]]},"707":{"position":[[118,6]]}}}],["w3c",{"_index":3380,"t":{"909":{"position":[[98,3]]}}}],["waitclient",{"_index":3240,"t":{"857":{"position":[[236,10],[489,10],[717,10]]},"859":{"position":[[135,10],[383,10],[606,10]]}}}],["waitingcli",{"_index":3235,"t":{"854":{"position":[[73,13]]},"870":{"position":[[76,13]]},"880":{"position":[[92,13]]}}}],["waitingopt",{"_index":3241,"t":{"857":{"position":[[282,14]]},"859":{"position":[[176,14]]}}}],["waitinvok",{"_index":596,"t":{"60":{"position":[[160,10]]},"80":{"position":[[373,10],[508,10],[670,10],[925,10],[1333,10],[1571,10]]},"132":{"position":[[416,10]]},"142":{"position":[[183,10],[483,10]]},"653":{"position":[[43,10],[77,10]]},"655":{"position":[[117,10]]},"681":{"position":[[194,10]]},"686":{"position":[[257,10]]}}}],["waitresultpackagebas",{"_index":3316,"t":{"876":{"position":[[122,21]]}}}],["waitsend",{"_index":2764,"t":{"653":{"position":[[34,8],[68,8]]},"655":{"position":[[225,8]]},"868":{"position":[[59,8]]}}}],["warn",{"_index":2287,"t":{"481":{"position":[[123,7],[132,7]]}}}],["weatherforecast",{"_index":748,"t":{"102":{"position":[[235,15]]}}}],["web",{"_index":790,"t":{"110":{"position":[[52,3],[94,3]]},"901":{"position":[[11,3]]},"919":{"position":[[26,3]]}}}],["webapi",{"_index":641,"t":{"69":{"position":[[115,6],[150,6]]},"286":{"position":[[2,6],[712,6],[990,6]]},"806":{"position":[[323,6]]},"862":{"position":[[0,6],[92,6]]},"880":{"position":[[273,6]]},"894":{"position":[[55,6],[188,6],[264,6],[453,6]]},"896":{"position":[[347,6],[436,6]]}}}],["webapicli",{"_index":647,"t":{"69":{"position":[[239,12],[275,12],[301,12]]}}}],["webapiparserplugin",{"_index":1542,"t":{"286":{"position":[[101,18],[421,18]]},"896":{"position":[[319,18]]}}}],["websocket",{"_index":292,"t":{"34":{"position":[[110,9]]},"78":{"position":[[290,9],[308,9]]},"80":{"position":[[1633,9],[1795,9],[1891,9],[2027,9],[2118,9],[2211,9],[2393,9]]},"261":{"position":[[590,9],[903,9],[958,9]]},"275":{"position":[[0,9]]},"284":{"position":[[365,9]]},"311":{"position":[[6,9]]},"391":{"position":[[37,9]]},"498":{"position":[[102,9]]},"516":{"position":[[49,9],[133,9],[503,9]]},"778":{"position":[[216,9]]},"783":{"position":[[314,9]]},"785":{"position":[[14,9],[65,9]]},"806":{"position":[[337,9],[387,9],[454,9]]},"874":{"position":[[339,9],[411,9]]},"878":{"position":[[115,9]]},"884":{"position":[[267,9]]},"909":{"position":[[0,9],[32,9],[83,9],[106,9],[155,9]]},"913":{"position":[[0,9],[48,9]]},"925":{"position":[[30,9],[495,9]]}}}],["websocketcli",{"_index":1655,"t":{"317":{"position":[[0,15],[33,15]]},"319":{"position":[[110,15],[143,15]]}}}],["websocketpluginbas",{"_index":1540,"t":{"284":{"position":[[501,19]]},"290":{"position":[[1065,19],[1134,19]]}}}],["websocketserverplugin",{"_index":1535,"t":{"284":{"position":[[337,21]]},"290":{"position":[[10,21],[728,21],[839,21]]},"516":{"position":[[457,21]]},"925":{"position":[[466,21]]}}}],["whisperserv",{"_index":2155,"t":{"447":{"position":[[229,14],[559,14],[596,14]]}}}],["width",{"_index":869,"t":{"120":{"position":[[1541,5],[1689,5],[1808,5],[1952,5]]}}}],["window",{"_index":855,"t":{"120":{"position":[[1043,7]]},"184":{"position":[[1515,6]]},"218":{"position":[[1515,6]]},"463":{"position":[[257,7]]},"636":{"position":[[11,6]]},"822":{"position":[[17,6]]},"832":{"position":[[1858,7],[1905,7]]},"894":{"position":[[679,7]]}}}],["winform",{"_index":2667,"t":{"590":{"position":[[17,7]]},"705":{"position":[[78,7]]},"806":{"position":[[99,7]]},"901":{"position":[[18,7]]}}}],["word",{"_index":2398,"t":{"512":{"position":[[1139,4]]}}}],["wpf",{"_index":728,"t":{"94":{"position":[[6,3]]},"374":{"position":[[2,3]]},"705":{"position":[[86,3]]},"806":{"position":[[107,3]]},"906":{"position":[[25,3]]}}}],["write",{"_index":1112,"t":{"157":{"position":[[58,5],[90,5],[121,5],[153,5]]},"361":{"position":[[924,5],[962,5],[1615,5],[1813,5],[2012,5],[2451,5],[2663,5]]},"365":{"position":[[365,5],[391,5],[417,5],[624,5],[650,5],[676,5],[883,5],[909,5],[935,5],[1144,5],[1170,5],[1196,5],[1311,5],[1899,5],[1975,5]]},"413":{"position":[[345,5]]},"431":{"position":[[493,5],[609,5],[634,5]]},"470":{"position":[[698,5]]},"489":{"position":[[964,5],[1039,5],[1097,5]]},"507":{"position":[[305,5],[326,5],[347,5],[368,5],[489,5],[543,5],[675,5],[729,5],[1631,5]]},"559":{"position":[[113,5]]},"632":{"position":[[30,5],[235,5]]},"672":{"position":[[568,5]]},"674":{"position":[[783,5]]},"798":{"position":[[41,5]]}}}],["writealltext",{"_index":2157,"t":{"447":{"position":[[536,12]]}}}],["writebytespackag",{"_index":1117,"t":{"157":{"position":[[239,17]]}}}],["writeisnul",{"_index":2369,"t":{"507":{"position":[[409,11],[590,11]]}}}],["writelin",{"_index":598,"t":{"60":{"position":[[189,9],[420,9]]},"66":{"position":[[245,9],[476,9]]},"69":{"position":[[375,9],[533,9],[673,9]]},"75":{"position":[[171,9]]},"80":{"position":[[256,9],[409,9],[544,9],[706,9],[951,9],[1234,9],[1369,9],[1597,9],[1937,9],[2015,9],[2106,9],[2199,9],[2381,9]]},"91":{"position":[[469,9]]},"102":{"position":[[363,9]]},"120":{"position":[[883,9]]},"159":{"position":[[559,9],[958,9]]},"188":{"position":[[368,9]]},"192":{"position":[[249,9]]},"207":{"position":[[146,9],[322,9]]},"225":{"position":[[337,9]]},"284":{"position":[[547,9],[580,9]]},"286":{"position":[[466,9],[505,9]]},"290":{"position":[[228,9],[319,9],[414,9],[486,9],[587,9]]},"319":{"position":[[598,9]]},"340":{"position":[[983,9],[1038,9]]},"411":{"position":[[301,9]]},"413":{"position":[[391,9]]},"458":{"position":[[362,9]]},"495":{"position":[[1509,9]]},"512":{"position":[[773,9],[899,9],[984,9],[1156,9]]},"528":{"position":[[974,9],[1672,9]]},"537":{"position":[[223,9]]},"561":{"position":[[379,9]]},"641":{"position":[[365,9]]},"643":{"position":[[249,9]]},"663":{"position":[[411,9]]},"672":{"position":[[1079,9]]},"674":{"position":[[984,9]]},"727":{"position":[[377,9],[455,9],[677,9],[783,9],[845,9],[1048,9],[1307,9],[1695,9],[1984,9]]},"843":{"position":[[125,9]]},"849":{"position":[[143,9]]},"896":{"position":[[417,9],[454,9]]},"932":{"position":[[513,9]]},"971":{"position":[[170,9]]}}}],["writeobject",{"_index":1114,"t":{"157":{"position":[[178,11]]}}}],["writepackag",{"_index":2373,"t":{"507":{"position":[[756,12]]}}}],["writer",{"_index":1994,"t":{"413":{"position":[[179,6],[221,6],[338,6]]}}}],["ws",{"_index":299,"t":{"34":{"position":[[168,2],[188,2]]},"80":{"position":[[1759,2],[1779,2]]},"175":{"position":[[105,2]]},"281":{"position":[[71,2]]},"284":{"position":[[389,2],[437,2],[591,2],[611,2]]},"286":{"position":[[516,2],[986,2]]},"288":{"position":[[310,2]]},"290":{"position":[[1006,2],[1037,2]]},"319":{"position":[[70,2],[107,2],[253,2],[716,2]]},"516":{"position":[[494,2],[516,2]]},"925":{"position":[[48,2],[147,2],[542,2],[649,2],[654,2],[674,2]]}}}],["wscallback",{"_index":1538,"t":{"284":{"position":[[407,10],[421,10]]},"290":{"position":[[108,10]]}}}],["wscommandlineplugin",{"_index":3309,"t":{"874":{"position":[[164,19]]},"925":{"position":[[0,19],[794,19]]}}}],["wsdataframeeventarg",{"_index":1562,"t":{"290":{"position":[[142,20],[930,20],[1223,20]]}}}],["wsdatatyp",{"_index":1567,"t":{"290":{"position":[[203,10],[294,10],[364,10],[559,10],[642,10],[671,10]]},"323":{"position":[[80,10],[109,10],[138,10],[169,10],[199,10],[228,10]]}}}],["wss",{"_index":1333,"t":{"184":{"position":[[1450,3]]},"218":{"position":[[1450,3]]},"288":{"position":[[2,3],[326,3]]},"319":{"position":[[49,3],[86,3],[232,3]]}}}],["wstouchrpc",{"_index":1209,"t":{"175":{"position":[[125,10]]},"261":{"position":[[933,10]]}}}],["wstouchrpcclient",{"_index":1030,"t":{"138":{"position":[[71,16]]},"175":{"position":[[0,16],[30,16]]}}}],["x",{"_index":1582,"t":{"292":{"position":[[85,1]]}}}],["x509certificate2",{"_index":775,"t":{"104":{"position":[[321,16]]},"122":{"position":[[102,16]]},"288":{"position":[[354,16]]},"319":{"position":[[363,16]]}}}],["x509certificatecollect",{"_index":774,"t":{"104":{"position":[[287,25]]},"319":{"position":[[329,25]]}}}],["xml",{"_index":610,"t":{"60":{"position":[[496,3]]},"679":{"position":[[41,3],[94,3]]},"681":{"position":[[434,3]]},"743":{"position":[[14,3]]},"792":{"position":[[166,3]]},"917":{"position":[[29,3],[46,3],[82,3]]}}}],["xmlrpc",{"_index":605,"t":{"60":{"position":[[377,6]]},"66":{"position":[[433,6]]},"806":{"position":[[330,6]]},"880":{"position":[[202,6]]},"917":{"position":[[0,6]]},"921":{"position":[[0,6]]},"928":{"position":[[65,6],[147,6],[203,6]]},"930":{"position":[[318,6]]}}}],["xmlrpcclient",{"_index":601,"t":{"60":{"position":[[252,12],[285,12],[318,12]]},"66":{"position":[[308,12],[341,12],[374,12]]}}}],["xmlrpcparser",{"_index":3399,"t":{"932":{"position":[[174,12]]}}}],["xmlrpcparserplugin",{"_index":3394,"t":{"930":{"position":[[258,18]]}}}],["xx",{"_index":893,"t":{"120":{"position":[[1910,2]]}}}],["y",{"_index":1887,"t":{"370":{"position":[[391,1]]}}}],["一一对应",{"_index":1213,"t":{"178":{"position":[[67,4]]},"216":{"position":[[51,4]]},"248":{"position":[[120,4]]},"340":{"position":[[33,4]]},"613":{"position":[[62,4]]},"776":{"position":[[53,4]]}}}],["一下",{"_index":2120,"t":{"444":{"position":[[310,2]]},"447":{"position":[[850,2]]},"554":{"position":[[177,2]]}}}],["一个",{"_index":50,"t":{"7":{"position":[[26,2]]},"32":{"position":[[32,2]]},"36":{"position":[[21,2]]},"48":{"position":[[23,2]]},"50":{"position":[[11,2],[152,2]]},"66":{"position":[[21,2]]},"75":{"position":[[21,2]]},"86":{"position":[[21,2]]},"89":{"position":[[2,2]]},"116":{"position":[[17,2]]},"122":{"position":[[28,2]]},"127":{"position":[[8,2],[714,2]]},"184":{"position":[[1126,2],[1905,2]]},"192":{"position":[[27,2]]},"207":{"position":[[447,2]]},"210":{"position":[[111,2]]},"216":{"position":[[17,2]]},"218":{"position":[[1126,2],[1905,2]]},"223":{"position":[[914,2]]},"225":{"position":[[1250,2],[1804,2]]},"229":{"position":[[33,2],[506,2]]},"237":{"position":[[24,2]]},"248":{"position":[[69,2]]},"284":{"position":[[13,2],[45,2]]},"288":{"position":[[58,2]]},"290":{"position":[[57,2]]},"292":{"position":[[352,2]]},"321":{"position":[[47,2]]},"328":{"position":[[9,2]]},"336":{"position":[[49,2],[77,2],[88,2],[206,2]]},"340":{"position":[[146,2],[174,2],[277,2],[891,2]]},"353":{"position":[[21,2]]},"359":{"position":[[146,2]]},"361":{"position":[[1105,2],[1137,2],[1152,2]]},"376":{"position":[[627,2]]},"378":{"position":[[109,2]]},"383":{"position":[[11,2],[17,2]]},"391":{"position":[[292,2]]},"395":{"position":[[34,2]]},"409":{"position":[[90,2]]},"411":{"position":[[28,2]]},"413":{"position":[[28,2]]},"444":{"position":[[56,2],[88,2],[98,2],[262,2],[393,2],[529,2]]},"447":{"position":[[227,2]]},"449":{"position":[[209,2]]},"451":{"position":[[59,2]]},"455":{"position":[[372,2]]},"485":{"position":[[18,2],[177,2]]},"491":{"position":[[54,2]]},"503":{"position":[[65,2]]},"512":{"position":[[8,2]]},"526":{"position":[[26,2],[220,2],[263,2]]},"528":{"position":[[81,2]]},"542":{"position":[[24,2]]},"546":{"position":[[2,2]]},"554":{"position":[[122,2],[212,2]]},"559":{"position":[[78,2]]},"570":{"position":[[102,2]]},"581":{"position":[[157,2]]},"610":{"position":[[257,2],[316,2]]},"613":{"position":[[25,2]]},"626":{"position":[[10,2]]},"628":{"position":[[7,2]]},"630":{"position":[[86,2],[101,2],[221,2]]},"636":{"position":[[9,2]]},"661":{"position":[[12,2]]},"666":{"position":[[143,2]]},"677":{"position":[[29,2]]},"689":{"position":[[76,2],[145,2],[174,2]]},"702":{"position":[[1354,2]]},"718":{"position":[[43,2]]},"720":{"position":[[60,2],[69,2]]},"748":{"position":[[165,2]]},"770":{"position":[[28,2]]},"778":{"position":[[96,2]]},"783":{"position":[[9,2],[174,2]]},"787":{"position":[[126,2]]},"822":{"position":[[15,2]]},"828":{"position":[[20,2]]},"854":{"position":[[20,2],[45,2]]},"859":{"position":[[960,2],[1162,2],[1171,2]]},"866":{"position":[[161,2]]},"891":{"position":[[58,2],[164,2]]},"894":{"position":[[8,2]]},"896":{"position":[[214,2]]},"917":{"position":[[27,2],[40,2]]},"928":{"position":[[8,2]]},"961":{"position":[[257,2]]}}}],["一个包",{"_index":1314,"t":{"184":{"position":[[1082,3],[1170,3],[1861,3],[1949,3]]},"218":{"position":[[1082,3],[1170,3],[1861,3],[1949,3]]}}}],["一些",{"_index":507,"t":{"57":{"position":[[82,2]]},"69":{"position":[[133,2]]},"146":{"position":[[113,2]]},"225":{"position":[[24,2]]},"235":{"position":[[176,2]]},"272":{"position":[[78,2]]},"301":{"position":[[58,2]]},"308":{"position":[[79,2],[2413,2]]},"347":{"position":[[79,2]]},"431":{"position":[[32,2]]},"523":{"position":[[371,2]]},"574":{"position":[[32,2]]},"617":{"position":[[91,2]]},"774":{"position":[[31,2]]},"783":{"position":[[210,2]]},"854":{"position":[[9,2]]},"935":{"position":[[61,2]]}}}],["一份",{"_index":120,"t":{"12":{"position":[[143,2]]}}}],["一位",{"_index":1602,"t":{"297":{"position":[[266,2],[338,2]]}}}],["一切",{"_index":3115,"t":{"792":{"position":[[130,2]]}}}],["一切都是",{"_index":2147,"t":{"444":{"position":[[683,4]]}}}],["一句",{"_index":244,"t":{"28":{"position":[[135,2]]}}}],["一同",{"_index":2127,"t":{"444":{"position":[[413,2]]},"597":{"position":[[220,2]]}}}],["一天",{"_index":81,"t":{"7":{"position":[[159,2]]}}}],["一头",{"_index":1874,"t":{"370":{"position":[[297,2]]}}}],["一定",{"_index":553,"t":{"57":{"position":[[743,2],[745,2]]},"184":{"position":[[878,2],[1050,2],[1233,2],[1657,2],[1829,2]]},"218":{"position":[[878,2],[1050,2],[1233,2],[1657,2],[1829,2]]},"297":{"position":[[144,2],[236,2],[308,2]]},"328":{"position":[[24,2]]},"374":{"position":[[9,2]]},"378":{"position":[[83,2]]},"485":{"position":[[117,2]]},"617":{"position":[[84,2]]},"668":{"position":[[59,2]]},"752":{"position":[[158,2]]},"832":{"position":[[809,2]]},"878":{"position":[[658,2]]}}}],["一对",{"_index":3215,"t":{"839":{"position":[[17,2],[90,2]]}}}],["一帧",{"_index":3029,"t":{"748":{"position":[[140,2]]}}}],["一幕",{"_index":2228,"t":{"455":{"position":[[860,2]]}}}],["一方",{"_index":1970,"t":{"402":{"position":[[110,2]]},"776":{"position":[[74,2]]}}}],["一旦",{"_index":45,"t":{"7":{"position":[[5,2],[115,2]]},"440":{"position":[[295,2]]},"965":{"position":[[70,2]]}}}],["一条",{"_index":1583,"t":{"292":{"position":[[122,2]]},"321":{"position":[[39,2]]}}}],["一样",{"_index":361,"t":{"42":{"position":[[17,2]]},"122":{"position":[[19,2]]},"125":{"position":[[206,2]]},"144":{"position":[[49,2]]},"151":{"position":[[65,2]]},"235":{"position":[[212,2],[275,2]]},"363":{"position":[[16,2]]},"376":{"position":[[113,2]]},"440":{"position":[[17,2]]},"509":{"position":[[39,2]]},"778":{"position":[[117,2]]},"785":{"position":[[23,2]]},"806":{"position":[[367,2]]}}}],["一模一样",{"_index":983,"t":{"132":{"position":[[70,4]]},"138":{"position":[[129,4]]}}}],["一次",{"_index":396,"t":{"46":{"position":[[350,2]]},"184":{"position":[[937,2],[1716,2]]},"218":{"position":[[937,2],[1716,2]]},"361":{"position":[[1099,2],[1111,2],[1124,2],[1146,2]]},"365":{"position":[[1440,2]]},"493":{"position":[[25,2]]},"689":{"position":[[126,2]]},"778":{"position":[[108,2]]},"830":{"position":[[588,2]]},"909":{"position":[[182,2]]},"967":{"position":[[55,2]]}}}],["一次性",{"_index":400,"t":{"46":{"position":[[370,3]]},"112":{"position":[[26,3]]},"184":{"position":[[473,3]]},"212":{"position":[[81,3]]},"218":{"position":[[473,3]]},"301":{"position":[[1070,3]]},"666":{"position":[[67,3]]},"911":{"position":[[54,3]]}}}],["一次次",{"_index":2144,"t":{"444":{"position":[[640,3]]}}}],["一步",{"_index":1223,"t":{"180":{"position":[[95,2]]},"212":{"position":[[165,2]]}}}],["一段",{"_index":1653,"t":{"308":{"position":[[2477,2]]},"559":{"position":[[138,2]]}}}],["一点点",{"_index":1282,"t":{"184":{"position":[[711,3]]},"218":{"position":[[711,3]]}}}],["一直",{"_index":547,"t":{"57":{"position":[[698,2]]},"301":{"position":[[350,2]]},"340":{"position":[[881,2]]},"409":{"position":[[11,2]]},"561":{"position":[[350,2]]},"854":{"position":[[6,2]]}}}],["一种",{"_index":907,"t":{"125":{"position":[[35,2]]},"334":{"position":[[23,2]]},"400":{"position":[[38,2]]},"449":{"position":[[274,2]]},"455":{"position":[[1,2]]},"487":{"position":[[105,2]]},"597":{"position":[[24,2]]},"748":{"position":[[10,2]]},"909":{"position":[[10,2]]}}}],["一系列",{"_index":3132,"t":{"806":{"position":[[347,3]]},"824":{"position":[[36,3]]}}}],["一组",{"_index":3028,"t":{"748":{"position":[[76,2]]},"839":{"position":[[92,2]]}}}],["一致",{"_index":136,"t":{"16":{"position":[[55,2]]},"36":{"position":[[68,2]]},"120":{"position":[[28,2]]},"140":{"position":[[167,2],[204,2],[234,2]]},"153":{"position":[[66,2]]},"155":{"position":[[17,2]]},"248":{"position":[[25,2],[52,2]]},"257":{"position":[[35,2]]},"259":{"position":[[35,2]]},"323":{"position":[[287,2]]},"350":{"position":[[180,2]]},"455":{"position":[[919,2]]},"679":{"position":[[256,2]]},"761":{"position":[[214,2]]},"834":{"position":[[11,2]]},"915":{"position":[[37,2]]},"965":{"position":[[67,2]]}}}],["一般",{"_index":483,"t":{"53":{"position":[[21,2]]},"136":{"position":[[0,2]]},"166":{"position":[[425,2]]},"184":{"position":[[123,2]]},"218":{"position":[[123,2]]},"252":{"position":[[425,2]]},"268":{"position":[[6,2]]},"340":{"position":[[838,2]]},"357":{"position":[[77,2]]},"418":{"position":[[64,2]]},"420":{"position":[[46,2]]},"485":{"position":[[4,2]]},"487":{"position":[[28,2]]},"514":{"position":[[119,2]]},"521":{"position":[[326,2]]},"535":{"position":[[70,2]]},"574":{"position":[[185,2]]},"679":{"position":[[205,2]]},"783":{"position":[[109,2]]},"806":{"position":[[304,2]]},"830":{"position":[[580,2]]}}}],["一般来说",{"_index":1321,"t":{"184":{"position":[[1146,4],[1925,4]]},"218":{"position":[[1146,4],[1925,4]]},"526":{"position":[[108,4]]},"718":{"position":[[146,4]]}}}],["一行",{"_index":2668,"t":{"595":{"position":[[12,2]]},"597":{"position":[[52,2]]}}}],["一起",{"_index":992,"t":{"134":{"position":[[87,2]]},"308":{"position":[[2543,2]]}}}],["一键",{"_index":1217,"t":{"180":{"position":[[32,2]]},"212":{"position":[[102,2]]}}}],["一项",{"_index":1357,"t":{"194":{"position":[[29,2]]},"233":{"position":[[29,2]]}}}],["七层",{"_index":920,"t":{"125":{"position":[[114,2]]}}}],["三",{"_index":1057,"t":{"142":{"position":[[197,1],[497,1]]},"336":{"position":[[196,1]]},"340":{"position":[[267,1]]},"436":{"position":[[727,1]]},"442":{"position":[[66,1]]}}}],["三个",{"_index":1634,"t":{"304":{"position":[[41,2]]},"363":{"position":[[37,2]]},"365":{"position":[[30,2]]},"707":{"position":[[55,2]]},"859":{"position":[[1101,2]]}}}],["三元组",{"_index":3024,"t":{"748":{"position":[[17,3]]}}}],["三种",{"_index":1367,"t":{"196":{"position":[[21,2],[281,2]]},"241":{"position":[[24,2],[234,2]]},"402":{"position":[[52,2]]},"440":{"position":[[54,2],[74,2],[104,2]]},"498":{"position":[[111,2]]},"544":{"position":[[12,2],[60,2]]},"546":{"position":[[25,2]]},"554":{"position":[[34,2]]},"653":{"position":[[14,2]]}}}],["三级",{"_index":3288,"t":{"872":{"position":[[483,2]]}}}],["三者",{"_index":1960,"t":{"397":{"position":[[58,2]]}}}],["上下文",{"_index":973,"t":{"127":{"position":[[755,3]]},"142":{"position":[[514,3],[530,3],[534,3]]},"146":{"position":[[60,3]]},"442":{"position":[[46,3]]},"512":{"position":[[434,3],[446,3]]},"639":{"position":[[75,3],[82,3]]},"663":{"position":[[59,3]]},"792":{"position":[[80,3]]},"880":{"position":[[197,3],[212,3],[232,3]]},"894":{"position":[[386,3]]}}}],["上传",{"_index":2250,"t":{"465":{"position":[[11,2],[372,2]]},"822":{"position":[[13,2]]},"826":{"position":[[115,2]]},"832":{"position":[[585,2]]},"874":{"position":[[300,2]]},"878":{"position":[[501,2]]},"906":{"position":[[97,2]]}}}],["上次",{"_index":1615,"t":{"301":{"position":[[761,2],[789,2]]},"830":{"position":[[567,2]]}}}],["上述",{"_index":581,"t":{"57":{"position":[[1965,2]]},"225":{"position":[[1904,2]]},"241":{"position":[[446,2]]},"272":{"position":[[1759,2]]},"301":{"position":[[2878,2]]},"308":{"position":[[2368,2],[2563,2]]},"347":{"position":[[2535,2]]},"365":{"position":[[1,2]]},"444":{"position":[[119,2],[470,2]]},"447":{"position":[[1266,2]]},"470":{"position":[[803,2]]},"489":{"position":[[9,2]]},"561":{"position":[[781,2]]},"597":{"position":[[13,2]]},"617":{"position":[[0,2],[269,2]]},"619":{"position":[[0,2]]},"623":{"position":[[34,2]]},"738":{"position":[[0,2]]},"758":{"position":[[131,2]]},"787":{"position":[[175,2]]},"859":{"position":[[1062,2]]},"954":{"position":[[8,2]]}}}],["上述情况",{"_index":462,"t":{"50":{"position":[[144,4]]},"365":{"position":[[168,4]]}}}],["上限",{"_index":1237,"t":{"184":{"position":[[118,2]]},"218":{"position":[[118,2]]},"526":{"position":[[95,2],[105,2]]}}}],["上面",{"_index":694,"t":{"86":{"position":[[47,2]]},"453":{"position":[[7,2]]}}}],["下列",{"_index":192,"t":{"25":{"position":[[210,2]]},"57":{"position":[[11,2],[452,2]]},"91":{"position":[[137,2]]},"118":{"position":[[31,2]]},"120":{"position":[[41,2]]},"132":{"position":[[42,2]]},"134":{"position":[[104,2]]},"138":{"position":[[188,2]]},"140":{"position":[[171,2]]},"146":{"position":[[33,2]]},"166":{"position":[[35,2]]},"205":{"position":[[37,2]]},"252":{"position":[[35,2]]},"272":{"position":[[11,2]]},"286":{"position":[[487,2]]},"301":{"position":[[3,2]]},"308":{"position":[[11,2]]},"340":{"position":[[40,2]]},"347":{"position":[[11,2],[982,2]]},"376":{"position":[[662,2]]},"391":{"position":[[59,2]]},"406":{"position":[[11,2]]},"415":{"position":[[187,2]]},"422":{"position":[[11,2]]},"431":{"position":[[561,2]]},"447":{"position":[[51,2]]},"455":{"position":[[50,2]]},"479":{"position":[[24,2]]},"489":{"position":[[0,2]]},"491":{"position":[[0,2]]},"493":{"position":[[0,2]]},"530":{"position":[[522,2]]},"561":{"position":[[0,2]]},"615":{"position":[[136,2]]},"630":{"position":[[0,2]]},"684":{"position":[[69,2]]},"718":{"position":[[233,2]]},"727":{"position":[[0,2]]},"745":{"position":[[11,2]]},"828":{"position":[[107,2]]},"870":{"position":[[36,2]]},"872":{"position":[[30,2]]},"925":{"position":[[137,2]]},"973":{"position":[[42,2]]}}}],["下图",{"_index":2436,"t":{"523":{"position":[[339,2],[2693,2]]},"677":{"position":[[1,2]]},"822":{"position":[[9,2]]},"826":{"position":[[123,2]]}}}],["下拉框",{"_index":2163,"t":{"447":{"position":[[799,3]]}}}],["下文",{"_index":2404,"t":{"516":{"position":[[111,2]]}}}],["下次",{"_index":1592,"t":{"297":{"position":[[70,2]]},"361":{"position":[[1985,2]]},"561":{"position":[[423,2],[461,2]]}}}],["下载",{"_index":1985,"t":{"409":{"position":[[62,2]]},"718":{"position":[[41,2],[86,2]]},"826":{"position":[[103,2]]},"830":{"position":[[58,2]]},"832":{"position":[[593,2]]},"878":{"position":[[509,2]]},"894":{"position":[[394,2]]},"906":{"position":[[100,2]]}}}],["下载速度",{"_index":2952,"t":{"718":{"position":[[63,4]]}}}],["下面",{"_index":697,"t":{"86":{"position":[[68,2]]},"155":{"position":[[20,2]]},"225":{"position":[[32,2]]},"705":{"position":[[112,2]]},"707":{"position":[[112,2]]}}}],["不二",{"_index":1968,"t":{"402":{"position":[[22,2]]}}}],["不仅",{"_index":1239,"t":{"184":{"position":[[135,2]]},"218":{"position":[[135,2]]}}}],["不仅如此",{"_index":3017,"t":{"741":{"position":[[58,4]]},"828":{"position":[[85,4]]}}}],["不会",{"_index":478,"t":{"50":{"position":[[283,2]]},"57":{"position":[[828,2]]},"153":{"position":[[101,2]]},"166":{"position":[[146,2]]},"184":{"position":[[674,2],[1094,2],[1873,2]]},"188":{"position":[[209,2]]},"207":{"position":[[408,2]]},"218":{"position":[[674,2],[1094,2],[1873,2]]},"252":{"position":[[146,2]]},"261":{"position":[[951,2]]},"272":{"position":[[959,2]]},"290":{"position":[[802,2]]},"415":{"position":[[112,2]]},"449":{"position":[[151,2]]},"570":{"position":[[200,2]]},"595":{"position":[[196,2],[226,2]]},"597":{"position":[[249,2]]},"653":{"position":[[129,2],[227,2]]},"745":{"position":[[526,2]]}}}],["不值一提",{"_index":1288,"t":{"184":{"position":[[732,4]]},"218":{"position":[[732,4]]}}}],["不再",{"_index":1035,"t":{"138":{"position":[[152,2]]},"965":{"position":[[79,2],[134,2],[174,2]]}}}],["不到",{"_index":826,"t":{"120":{"position":[[349,2]]},"440":{"position":[[26,2]]}}}],["不变",{"_index":1554,"t":{"288":{"position":[[14,2]]},"965":{"position":[[192,2]]}}}],["不可",{"_index":70,"t":{"7":{"position":[[110,2]]},"223":{"position":[[938,2]]},"225":{"position":[[1274,2],[1828,2]]},"229":{"position":[[530,2]]},"440":{"position":[[271,2]]},"738":{"position":[[97,2]]},"859":{"position":[[984,2]]},"872":{"position":[[230,2]]}}}],["不合理",{"_index":2849,"t":{"689":{"position":[[199,3]]}}}],["不同",{"_index":321,"t":{"36":{"position":[[30,2]]},"162":{"position":[[19,2]]},"194":{"position":[[353,2]]},"233":{"position":[[359,2]]},"235":{"position":[[764,2]]},"261":{"position":[[973,2]]},"343":{"position":[[67,2]]},"347":{"position":[[949,2]]},"409":{"position":[[25,2]]},"440":{"position":[[31,2]]},"447":{"position":[[1299,2]]},"526":{"position":[[59,2]]},"552":{"position":[[108,2]]},"559":{"position":[[52,2]]},"783":{"position":[[265,2]]},"932":{"position":[[138,2]]}}}],["不堪",{"_index":2776,"t":{"661":{"position":[[54,2]]}}}],["不够",{"_index":285,"t":{"34":{"position":[[84,2]]},"661":{"position":[[22,2]]}}}],["不定",{"_index":1713,"t":{"343":{"position":[[17,2]]}}}],["不宜",{"_index":2255,"t":{"465":{"position":[[376,2]]}}}],["不得",{"_index":83,"t":{"10":{"position":[[0,2],[16,2],[36,2]]},"12":{"position":[[0,2],[16,2],[36,2]]},"14":{"position":[[0,2],[16,2],[36,2]]}}}],["不得不",{"_index":2126,"t":{"444":{"position":[[405,3]]}}}],["不想",{"_index":2173,"t":{"447":{"position":[[1215,2]]},"521":{"position":[[460,2]]}}}],["不懈努力",{"_index":1828,"t":{"368":{"position":[[7,4]]}}}],["不是",{"_index":1257,"t":{"184":{"position":[[392,2],[722,2]]},"218":{"position":[[392,2],[722,2]]},"378":{"position":[[90,2]]},"406":{"position":[[551,2]]},"422":{"position":[[535,2]]},"526":{"position":[[185,2]]},"707":{"position":[[161,2]]},"716":{"position":[[127,2]]},"720":{"position":[[58,2]]},"745":{"position":[[606,2]]},"857":{"position":[[642,2]]},"859":{"position":[[531,2]]},"957":{"position":[[110,2]]}}}],["不然",{"_index":397,"t":{"46":{"position":[[353,2]]},"184":{"position":[[133,2]]},"218":{"position":[[133,2]]},"290":{"position":[[795,2]]},"297":{"position":[[168,2],[269,2],[341,2]]},"340":{"position":[[876,2]]},"365":{"position":[[1481,2]]},"402":{"position":[[92,2]]},"465":{"position":[[381,2]]},"530":{"position":[[116,2]]},"679":{"position":[[259,2]]},"738":{"position":[[93,2]]}}}],["不用",{"_index":78,"t":{"7":{"position":[[152,2]]},"62":{"position":[[10,2]]},"71":{"position":[[10,2]]},"82":{"position":[[10,2]]},"134":{"position":[[13,2],[26,2]]},"159":{"position":[[628,2],[937,2]]},"261":{"position":[[106,2]]},"444":{"position":[[479,2]]},"493":{"position":[[455,2]]}}}],["不相上下",{"_index":2417,"t":{"521":{"position":[[106,4]]}}}],["不管",{"_index":2987,"t":{"727":{"position":[[925,2]]}}}],["不能",{"_index":288,"t":{"34":{"position":[[96,2]]},"53":{"position":[[34,2]]},"299":{"position":[[19,2]]},"487":{"position":[[19,2]]},"505":{"position":[[93,2]]},"653":{"position":[[210,2]]},"657":{"position":[[6,2]]},"736":{"position":[[333,2]]},"976":{"position":[[42,2]]}}}],["不要",{"_index":554,"t":{"57":{"position":[[747,2]]},"110":{"position":[[104,2]]},"184":{"position":[[125,2]]},"218":{"position":[[125,2]]},"239":{"position":[[141,2]]},"290":{"position":[[786,2]]},"292":{"position":[[74,2]]},"338":{"position":[[22,2]]},"597":{"position":[[202,2]]},"780":{"position":[[78,2]]},"783":{"position":[[111,2]]}}}],["不足",{"_index":1630,"t":{"301":{"position":[[1538,2]]}}}],["不足以",{"_index":2725,"t":{"619":{"position":[[13,3]]}}}],["不过",{"_index":1794,"t":{"363":{"position":[[19,2]]}}}],["不难看出",{"_index":1809,"t":{"365":{"position":[[1293,4]]}}}],["与其",{"_index":1451,"t":{"248":{"position":[[14,2]]}}}],["与否",{"_index":2988,"t":{"727":{"position":[[931,2]]}}}],["专",{"_index":3313,"t":{"876":{"position":[[32,1]]}}}],["专属",{"_index":674,"t":{"80":{"position":[[22,2]]},"389":{"position":[[14,2]]},"876":{"position":[[145,2]]}}}],["业务",{"_index":492,"t":{"53":{"position":[[74,2]]},"125":{"position":[[176,2]]},"178":{"position":[[47,2]]},"225":{"position":[[393,2],[1937,2]]},"420":{"position":[[51,2]]},"487":{"position":[[23,2]]}}}],["业界",{"_index":3051,"t":{"761":{"position":[[7,2]]}}}],["东西",{"_index":3292,"t":{"872":{"position":[[644,2]]}}}],["丢弃",{"_index":2620,"t":{"561":{"position":[[474,2]]}}}],["两个",{"_index":219,"t":{"28":{"position":[[29,2]]},"32":{"position":[[61,2]]},"34":{"position":[[28,2],[202,2]]},"184":{"position":[[349,2],[1164,2],[1943,2]]},"218":{"position":[[349,2],[1164,2],[1943,2]]},"223":{"position":[[842,2]]},"225":{"position":[[1178,2],[1732,2]]},"229":{"position":[[434,2]]},"301":{"position":[[1276,2],[1614,2]]},"340":{"position":[[816,2],[841,2]]},"357":{"position":[[8,2]]},"365":{"position":[[1398,2]]},"444":{"position":[[555,2]]},"495":{"position":[[423,2]]},"526":{"position":[[201,2],[281,2]]},"561":{"position":[[639,2]]},"574":{"position":[[172,2]]},"736":{"position":[[172,2]]},"780":{"position":[[569,2]]},"783":{"position":[[77,2]]},"787":{"position":[[178,2]]},"820":{"position":[[267,2]]},"826":{"position":[[87,2]]},"859":{"position":[[888,2]]}}}],["两种",{"_index":1797,"t":{"365":{"position":[[94,2],[119,2]]},"554":{"position":[[151,2]]}}}],["两端",{"_index":2842,"t":{"689":{"position":[[89,2]]}}}],["两者",{"_index":1098,"t":{"153":{"position":[[60,2]]},"828":{"position":[[68,2]]}}}],["两者之间",{"_index":3382,"t":{"909":{"position":[[187,4]]}}}],["严重",{"_index":3282,"t":{"872":{"position":[[270,2],[468,2],[545,2],[601,2],[652,2],[688,2],[910,2]]}}}],["个人",{"_index":101,"t":{"10":{"position":[[65,2]]},"961":{"position":[[3,2],[10,2],[59,2],[62,2]]},"963":{"position":[[31,2],[56,2]]},"965":{"position":[[158,2],[183,2]]},"967":{"position":[[73,2]]}}}],["个人所有",{"_index":3438,"t":{"963":{"position":[[8,4]]},"965":{"position":[[8,4]]},"967":{"position":[[41,4]]}}}],["个性化",{"_index":3422,"t":{"961":{"position":[[86,3],[197,3],[273,3]]}}}],["中",{"_index":129,"t":{"14":{"position":[[68,1]]},"28":{"position":[[12,1]]},"36":{"position":[[5,1]]},"40":{"position":[[33,1]]},"44":{"position":[[14,1]]},"46":{"position":[[376,1]]},"57":{"position":[[79,1],[186,1],[211,1],[1511,1]]},"66":{"position":[[17,1],[63,1],[70,1]]},"75":{"position":[[17,1],[63,1],[70,1]]},"86":{"position":[[17,1],[108,1],[115,1]]},"120":{"position":[[471,1],[502,1]]},"125":{"position":[[118,1]]},"127":{"position":[[5,1],[118,1]]},"132":{"position":[[301,1]]},"138":{"position":[[229,1]]},"149":{"position":[[43,1]]},"159":{"position":[[74,1],[122,1],[315,1]]},"166":{"position":[[490,1],[538,1]]},"184":{"position":[[921,1],[1563,1],[1583,1],[1700,1]]},"190":{"position":[[10,1]]},"218":{"position":[[921,1],[1563,1],[1583,1],[1700,1]]},"223":{"position":[[932,1]]},"225":{"position":[[568,1],[1268,1],[1822,1]]},"227":{"position":[[11,1]]},"229":{"position":[[524,1]]},"231":{"position":[[48,1]]},"235":{"position":[[191,1],[1229,1]]},"252":{"position":[[490,1],[538,1]]},"257":{"position":[[18,1]]},"259":{"position":[[18,1]]},"261":{"position":[[325,1]]},"272":{"position":[[75,1],[178,1],[203,1],[1402,1]]},"284":{"position":[[89,1]]},"288":{"position":[[27,1],[53,1]]},"297":{"position":[[37,1]]},"301":{"position":[[55,1],[148,1],[173,1],[2466,1]]},"308":{"position":[[76,1],[180,1],[205,1],[1138,1],[1923,1]]},"347":{"position":[[76,1],[182,1],[207,1],[1012,1],[1213,1],[1567,1],[2084,1]]},"361":{"position":[[1087,1]]},"363":{"position":[[25,1]]},"365":{"position":[[5,1],[42,1],[1292,1],[1344,1],[1426,1]]},"397":{"position":[[14,1]]},"400":{"position":[[72,1]]},"406":{"position":[[43,1],[88,1]]},"409":{"position":[[29,1]]},"411":{"position":[[24,1]]},"413":{"position":[[24,1]]},"422":{"position":[[43,1],[78,1]]},"442":{"position":[[118,1]]},"444":{"position":[[123,1],[158,1],[385,1]]},"447":{"position":[[5,1]]},"449":{"position":[[26,1],[84,1],[135,1],[185,1],[206,1]]},"451":{"position":[[108,1]]},"470":{"position":[[635,1],[784,1]]},"485":{"position":[[55,1],[72,1],[154,1],[168,1]]},"487":{"position":[[85,1]]},"498":{"position":[[68,1]]},"512":{"position":[[5,1],[46,1]]},"516":{"position":[[174,1]]},"519":{"position":[[12,1]]},"521":{"position":[[170,1],[336,1]]},"526":{"position":[[174,1]]},"530":{"position":[[469,1]]},"535":{"position":[[10,1]]},"539":{"position":[[167,1]]},"542":{"position":[[15,1],[37,1],[75,1]]},"550":{"position":[[58,1]]},"552":{"position":[[37,1]]},"559":{"position":[[102,1]]},"600":{"position":[[39,1]]},"613":{"position":[[42,1]]},"615":{"position":[[85,1]]},"630":{"position":[[261,1]]},"636":{"position":[[1,1]]},"639":{"position":[[85,1]]},"655":{"position":[[17,1]]},"666":{"position":[[4,1],[38,1],[62,1],[129,1]]},"668":{"position":[[13,1]]},"677":{"position":[[23,1]]},"679":{"position":[[9,1]]},"681":{"position":[[9,1],[45,1]]},"686":{"position":[[19,1]]},"689":{"position":[[108,1],[124,1]]},"697":{"position":[[14,1]]},"714":{"position":[[56,1]]},"718":{"position":[[8,1],[211,1]]},"720":{"position":[[89,1]]},"732":{"position":[[60,1]]},"736":{"position":[[266,1]]},"745":{"position":[[43,1],[78,1],[533,1]]},"752":{"position":[[7,1],[60,1]]},"761":{"position":[[24,1],[54,1],[72,1],[143,1],[161,1]]},"776":{"position":[[9,1]]},"780":{"position":[[128,1]]},"816":{"position":[[6,1]]},"820":{"position":[[20,1]]},"826":{"position":[[125,1]]},"830":{"position":[[309,1]]},"839":{"position":[[36,1]]},"841":{"position":[[12,1]]},"847":{"position":[[12,1]]},"859":{"position":[[978,1]]},"868":{"position":[[127,1]]},"872":{"position":[[416,1],[1129,1]]},"891":{"position":[[241,1]]},"894":{"position":[[5,1],[46,1]]},"909":{"position":[[168,1]]},"917":{"position":[[115,1]]},"925":{"position":[[57,1],[98,1]]},"928":{"position":[[5,1],[56,1]]},"954":{"position":[[13,1]]},"957":{"position":[[15,1]]},"969":{"position":[[36,1],[191,1],[375,1],[406,1]]},"980":{"position":[[22,1],[46,1]]}}}],["中断",{"_index":2514,"t":{"535":{"position":[[22,2]]},"570":{"position":[[160,2]]},"792":{"position":[[111,2]]}}}],["中路",{"_index":2402,"t":{"514":{"position":[[362,2]]}}}],["中间",{"_index":1569,"t":{"290":{"position":[[242,2]]},"822":{"position":[[71,2]]}}}],["中间件",{"_index":1474,"t":{"261":{"position":[[580,3]]}}}],["串口",{"_index":2266,"t":{"468":{"position":[[56,2]]},"957":{"position":[[121,2]]}}}],["临时",{"_index":1621,"t":{"301":{"position":[[1082,2]]},"361":{"position":[[1205,2],[1491,2]]}}}],["为了",{"_index":320,"t":{"36":{"position":[[28,2]]},"50":{"position":[[64,2]]},"184":{"position":[[852,2],[900,2],[1631,2],[1679,2]]},"218":{"position":[[852,2],[900,2],[1631,2],[1679,2]]},"503":{"position":[[7,2]]},"610":{"position":[[283,2]]},"778":{"position":[[37,2]]},"959":{"position":[[26,2]]}}}],["为什么",{"_index":272,"t":{"34":{"position":[[11,3]]},"365":{"position":[[1276,3]]},"689":{"position":[[40,3]]}}}],["为准",{"_index":3311,"t":{"874":{"position":[[323,2]]}}}],["为的是",{"_index":3416,"t":{"959":{"position":[[3,3]]}}}],["主",{"_index":2470,"t":{"528":{"position":[[83,1],[312,1],[654,1],[1368,1]]},"530":{"position":[[679,1],[1030,1]]},"866":{"position":[[66,1],[164,1]]},"891":{"position":[[185,1]]}}}],["主体",{"_index":174,"t":{"25":{"position":[[3,2]]},"574":{"position":[[190,2]]},"630":{"position":[[279,2]]}}}],["主动",{"_index":1025,"t":{"136":{"position":[[33,2]]},"184":{"position":[[678,2]]},"186":{"position":[[141,2]]},"218":{"position":[[678,2]]},"220":{"position":[[148,2]]},"593":{"position":[[22,2]]},"595":{"position":[[166,2],[189,2]]},"634":{"position":[[11,2]]},"661":{"position":[[62,2]]},"663":{"position":[[77,2]]},"750":{"position":[[249,2],[540,2]]},"752":{"position":[[172,2]]},"792":{"position":[[54,2]]},"794":{"position":[[34,2]]},"796":{"position":[[38,2]]},"870":{"position":[[174,2]]},"909":{"position":[[143,2]]}}}],["主机",{"_index":2731,"t":{"628":{"position":[[3,2]]},"839":{"position":[[12,2],[39,2],[85,2],[112,2]]}}}],["主要",{"_index":736,"t":{"97":{"position":[[20,2]]},"489":{"position":[[4,2]]},"491":{"position":[[7,2]]},"493":{"position":[[4,2]]},"503":{"position":[[29,2]]},"809":{"position":[[8,2]]},"830":{"position":[[254,2]]}}}],["举例来说",{"_index":3104,"t":{"787":{"position":[[58,4]]}}}],["义务",{"_index":3443,"t":{"965":{"position":[[126,2]]}}}],["之一",{"_index":3111,"t":{"787":{"position":[[154,2]]},"820":{"position":[[27,2]]}}}],["之上",{"_index":1453,"t":{"255":{"position":[[33,2]]}}}],["之前",{"_index":150,"t":{"20":{"position":[[31,2]]},"166":{"position":[[373,2]]},"252":{"position":[[373,2]]},"297":{"position":[[140,2],[232,2]]},"449":{"position":[[2,2]]},"451":{"position":[[5,2]]},"455":{"position":[[993,2]]},"487":{"position":[[4,2]]},"516":{"position":[[382,2]]},"570":{"position":[[145,2]]}}}],["之后",{"_index":1196,"t":{"166":{"position":[[256,2],[401,2],[562,2]]},"186":{"position":[[327,2]]},"220":{"position":[[334,2]]},"252":{"position":[[256,2],[401,2],[562,2]]},"619":{"position":[[45,2]]}}}],["之所以",{"_index":2233,"t":{"455":{"position":[[982,3]]}}}],["之间",{"_index":917,"t":{"125":{"position":[[99,2],[245,2]]},"144":{"position":[[28,2]]},"166":{"position":[[433,2]]},"252":{"position":[[433,2]]},"530":{"position":[[9,2],[58,2]]},"623":{"position":[[80,2]]},"628":{"position":[[91,2]]},"693":{"position":[[9,2]]},"792":{"position":[[67,2]]},"794":{"position":[[54,2]]},"796":{"position":[[49,2]]},"826":{"position":[[91,2]]},"828":{"position":[[96,2],[187,2]]},"836":{"position":[[8,2]]},"839":{"position":[[14,2],[87,2]]},"872":{"position":[[299,2]]},"925":{"position":[[741,2]]}}}],["乘法",{"_index":3006,"t":{"734":{"position":[[502,2]]}}}],["也就是说",{"_index":2672,"t":{"595":{"position":[[213,4]]},"597":{"position":[[236,4]]},"613":{"position":[[33,4]]},"615":{"position":[[32,4]]}}}],["习惯",{"_index":2185,"t":{"449":{"position":[[201,2]]},"455":{"position":[[1062,2]]}}}],["了解",{"_index":910,"t":{"125":{"position":[[57,2]]},"806":{"position":[[26,2],[32,2]]}}}],["事件",{"_index":169,"t":{"23":{"position":[[27,2]]},"40":{"position":[[30,2]]},"57":{"position":[[202,2],[823,2]]},"166":{"position":[[488,2],[536,2]]},"252":{"position":[[488,2],[536,2]]},"272":{"position":[[194,2]]},"301":{"position":[[164,2]]},"308":{"position":[[196,2]]},"323":{"position":[[10,2]]},"347":{"position":[[198,2]]},"370":{"position":[[188,2]]},"391":{"position":[[294,2],[304,2]]},"393":{"position":[[6,2],[353,2]]},"395":{"position":[[6,2],[14,2]]},"406":{"position":[[79,2]]},"422":{"position":[[69,2]]},"559":{"position":[[80,2],[100,2]]},"561":{"position":[[410,2]]},"570":{"position":[[85,2],[211,2]]},"745":{"position":[[69,2]]},"802":{"position":[[2,2],[29,2]]},"828":{"position":[[251,2],[308,2]]},"830":{"position":[[110,2],[168,2],[303,2]]},"870":{"position":[[170,2],[191,2]]},"874":{"position":[[230,2]]},"878":{"position":[[225,2],[288,2],[315,2]]},"980":{"position":[[37,2]]}}}],["事务",{"_index":809,"t":{"118":{"position":[[33,2]]},"120":{"position":[[67,2]]},"166":{"position":[[37,2]]},"205":{"position":[[39,2]]},"252":{"position":[[37,2]]},"732":{"position":[[37,2]]},"859":{"position":[[1164,2]]},"925":{"position":[[42,2],[74,2],[547,2]]}}}],["事半功倍",{"_index":2760,"t":{"648":{"position":[[1208,4]]}}}],["事情",{"_index":2218,"t":{"455":{"position":[[485,2]]}}}],["二",{"_index":2100,"t":{"442":{"position":[[34,1]]}}}],["二次开发",{"_index":40,"t":{"5":{"position":[[93,4]]},"12":{"position":[[54,4],[185,4]]}}}],["二进制",{"_index":1505,"t":{"268":{"position":[[56,3],[83,3]]},"290":{"position":[[428,3],[504,3]]},"427":{"position":[[5,3]]},"431":{"position":[[568,3]]},"748":{"position":[[89,3]]},"792":{"position":[[151,3]]},"872":{"position":[[206,3]]},"874":{"position":[[65,3]]},"884":{"position":[[185,3]]}}}],["云",{"_index":2455,"t":{"526":{"position":[[156,1],[224,1]]}}}],["云台",{"_index":2906,"t":{"702":{"position":[[1450,2],[1465,2]]}}}],["互",{"_index":1069,"t":{"144":{"position":[[30,1]]},"146":{"position":[[46,1],[74,1]]},"792":{"position":[[69,1]]}}}],["互不",{"_index":3180,"t":{"826":{"position":[[41,2]]}}}],["互相",{"_index":935,"t":{"125":{"position":[[234,2]]},"530":{"position":[[11,2]]},"693":{"position":[[11,2]]},"794":{"position":[[56,2]]},"826":{"position":[[172,2]]},"828":{"position":[[78,2]]}}}],["互联网",{"_index":2845,"t":{"689":{"position":[[119,3]]},"872":{"position":[[411,3]]}}}],["五",{"_index":1685,"t":{"336":{"position":[[187,1]]},"340":{"position":[[258,1]]}}}],["五种",{"_index":3413,"t":{"957":{"position":[[95,2]]}}}],["五秒",{"_index":2320,"t":{"493":{"position":[[19,2]]}}}],["交互",{"_index":1286,"t":{"184":{"position":[[728,2]]},"210":{"position":[[30,2]]},"218":{"position":[[728,2]]},"449":{"position":[[38,2]]},"743":{"position":[[22,2]]},"806":{"position":[[290,2]]},"830":{"position":[[763,2]]},"872":{"position":[[705,2]]}}}],["交给",{"_index":2128,"t":{"444":{"position":[[415,2]]}}}],["亦然",{"_index":1303,"t":{"184":{"position":[[966,2],[1745,2]]},"218":{"position":[[966,2],[1745,2]]},"750":{"position":[[227,2]]}}}],["产品",{"_index":75,"t":{"7":{"position":[[139,2],[148,2]]},"149":{"position":[[41,2]]},"564":{"position":[[15,2]]},"963":{"position":[[22,2],[39,2]]},"965":{"position":[[22,2],[45,2],[112,2]]}}}],["产物",{"_index":2605,"t":{"559":{"position":[[27,2]]}}}],["享有",{"_index":3446,"t":{"967":{"position":[[21,2]]}}}],["什么",{"_index":930,"t":{"125":{"position":[[168,2]]},"455":{"position":[[953,2],[962,2]]},"526":{"position":[[41,2]]},"720":{"position":[[34,2]]},"783":{"position":[[368,2],[411,2]]},"806":{"position":[[0,2]]}}}],["仅",{"_index":114,"t":{"12":{"position":[[113,1]]},"32":{"position":[[129,1],[199,1]]},"48":{"position":[[34,1],[315,1]]},"57":{"position":[[464,1]]},"120":{"position":[[43,1]]},"129":{"position":[[2,1]]},"155":{"position":[[22,1]]},"164":{"position":[[42,1]]},"184":{"position":[[1513,1]]},"218":{"position":[[1513,1]]},"250":{"position":[[42,1]]},"319":{"position":[[36,1]]},"361":{"position":[[1211,1]]},"365":{"position":[[48,1]]},"395":{"position":[[31,1]]},"449":{"position":[[58,1]]},"465":{"position":[[5,1]]},"546":{"position":[[43,1],[100,1]]},"595":{"position":[[11,1]]},"597":{"position":[[51,1]]},"653":{"position":[[88,1]]},"679":{"position":[[143,1]]},"689":{"position":[[235,1]]},"697":{"position":[[3,1]]},"806":{"position":[[252,1],[402,1]]},"828":{"position":[[111,1]]},"834":{"position":[[14,1]]},"862":{"position":[[98,1]]},"864":{"position":[[19,1]]},"874":{"position":[[305,1]]},"884":{"position":[[299,1]]},"891":{"position":[[56,1]]},"957":{"position":[[60,1]]},"967":{"position":[[18,1]]}}}],["仅仅",{"_index":789,"t":{"110":{"position":[[45,2]]},"449":{"position":[[112,2]]},"461":{"position":[[13,2]]},"470":{"position":[[805,2]]},"623":{"position":[[42,2]]},"653":{"position":[[161,2]]},"663":{"position":[[12,2]]}}}],["仅次于",{"_index":2626,"t":{"570":{"position":[[74,3]]},"741":{"position":[[102,3]]}}}],["仅此而已",{"_index":2237,"t":{"455":{"position":[[1040,4]]}}}],["介绍",{"_index":1111,"t":{"155":{"position":[[23,2]]}}}],["仍然",{"_index":2502,"t":{"530":{"position":[[127,2]]},"806":{"position":[[292,2]]},"820":{"position":[[250,2]]}}}],["从而",{"_index":2396,"t":{"512":{"position":[[467,2]]},"672":{"position":[[52,2],[191,2]]},"674":{"position":[[163,2]]},"891":{"position":[[87,2]]}}}],["仔细",{"_index":2758,"t":{"648":{"position":[[1201,2]]}}}],["他们",{"_index":2305,"t":{"487":{"position":[[43,2]]}}}],["付费",{"_index":142,"t":{"18":{"position":[[24,2],[82,2]]},"935":{"position":[[71,2]]}}}],["代替",{"_index":168,"t":{"23":{"position":[[25,2]]},"878":{"position":[[296,2]]}}}],["代理",{"_index":583,"t":{"60":{"position":[[12,2]]},"62":{"position":[[0,2],[32,2]]},"64":{"position":[[2,2]]},"66":{"position":[[1,2],[49,2],[79,2],[84,2],[92,2],[257,2]]},"69":{"position":[[12,2]]},"71":{"position":[[0,2],[32,2]]},"73":{"position":[[2,2]]},"75":{"position":[[1,2],[49,2],[79,2],[84,2],[92,2],[183,2]]},"80":{"position":[[42,2]]},"82":{"position":[[0,2],[32,2]]},"84":{"position":[[2,2]]},"86":{"position":[[1,2],[52,2],[94,2],[124,2],[129,2],[137,2],[338,2],[379,2]]},"91":{"position":[[219,2],[288,2]]},"127":{"position":[[211,2],[487,2]]},"132":{"position":[[12,2]]},"134":{"position":[[0,2],[48,2],[68,2],[106,2],[116,2],[3432,2]]},"140":{"position":[[154,2],[221,2]]},"440":{"position":[[42,2],[59,2],[125,2]]},"442":{"position":[[21,2]]},"444":{"position":[[3,2],[9,2],[27,2],[42,2],[570,2]]},"447":{"position":[[43,2],[69,2],[166,2],[750,2],[856,2],[910,2],[919,2],[987,2],[1032,2],[1218,2],[1301,2]]},"451":{"position":[[49,2],[129,2]]},"453":{"position":[[3,2],[31,2]]},"455":{"position":[[14,2],[384,2],[780,2],[940,2],[949,2],[1051,2],[1078,2]]},"512":{"position":[[90,2]]},"672":{"position":[[1027,2]]},"674":{"position":[[934,2]]},"792":{"position":[[13,2]]},"878":{"position":[[127,2],[132,2]]},"894":{"position":[[89,2]]},"928":{"position":[[99,2]]},"932":{"position":[[267,2],[270,2],[342,2]]}}}],["代理会",{"_index":2140,"t":{"444":{"position":[[600,3]]}}}],["代码",{"_index":76,"t":{"7":{"position":[[141,2],[167,2]]},"134":{"position":[[108,2]]},"188":{"position":[[48,2]]},"194":{"position":[[83,2]]},"223":{"position":[[84,2]]},"225":{"position":[[51,2],[1906,2]]},"233":{"position":[[83,2]]},"235":{"position":[[294,2]]},"288":{"position":[[39,2]]},"365":{"position":[[1290,2]]},"376":{"position":[[187,2],[664,2]]},"431":{"position":[[34,2]]},"440":{"position":[[279,2]]},"444":{"position":[[341,2]]},"447":{"position":[[53,2],[191,2],[206,2],[969,2],[989,2],[1012,2],[1212,2],[1220,2],[1235,2]]},"455":{"position":[[388,2],[1082,2]]},"489":{"position":[[2,2]]},"491":{"position":[[2,2]]},"493":{"position":[[2,2]]},"505":{"position":[[29,2]]},"530":{"position":[[524,2]]},"542":{"position":[[35,2]]},"561":{"position":[[4,2]]},"595":{"position":[[14,2]]},"597":{"position":[[54,2]]},"684":{"position":[[71,2]]},"686":{"position":[[512,2]]},"697":{"position":[[1,2]]},"699":{"position":[[1,2]]},"872":{"position":[[129,2]]},"874":{"position":[[382,2]]},"969":{"position":[[137,2],[413,2]]}}}],["代码生成",{"_index":2088,"t":{"440":{"position":[[160,4]]},"792":{"position":[[15,4]]}}}],["代表",{"_index":2723,"t":{"617":{"position":[[89,2]]}}}],["令箭",{"_index":2651,"t":{"581":{"position":[[162,2]]},"830":{"position":[[723,2]]}}}],["以上",{"_index":96,"t":{"10":{"position":[[54,2]]},"12":{"position":[[174,2]]},"14":{"position":[[73,2]]},"134":{"position":[[96,2]]},"292":{"position":[[1,2]]},"503":{"position":[[139,2]]},"521":{"position":[[133,2]]},"707":{"position":[[99,2]]},"872":{"position":[[366,2]]}}}],["以下",{"_index":657,"t":{"78":{"position":[[36,2]]},"129":{"position":[[0,2]]},"301":{"position":[[1063,2]]},"361":{"position":[[1093,2]]},"365":{"position":[[79,2],[179,2]]},"376":{"position":[[568,2]]},"434":{"position":[[116,2]]},"473":{"position":[[13,2]]},"475":{"position":[[16,2]]},"539":{"position":[[171,2]]},"595":{"position":[[134,2]]},"597":{"position":[[194,2]]},"697":{"position":[[6,2]]},"806":{"position":[[58,2]]},"896":{"position":[[428,2]]},"969":{"position":[[135,2]]},"973":{"position":[[5,2]]}}}],["以下内容",{"_index":2641,"t":{"579":{"position":[[0,4]]}}}],["以内",{"_index":2851,"t":{"689":{"position":[[232,2]]}}}],["以及",{"_index":34,"t":{"5":{"position":[[76,2]]},"530":{"position":[[36,2]]},"741":{"position":[[51,2]]},"792":{"position":[[181,2]]},"830":{"position":[[270,2],[647,2]]},"872":{"position":[[1059,2]]}}}],["以后",{"_index":255,"t":{"32":{"position":[[55,2]]},"34":{"position":[[161,2]]},"66":{"position":[[9,2]]},"75":{"position":[[9,2]]},"86":{"position":[[9,2]]},"138":{"position":[[148,2]]},"184":{"position":[[658,2]]},"210":{"position":[[101,2]]},"218":{"position":[[658,2]]},"292":{"position":[[101,2]]},"308":{"position":[[2503,2]]},"361":{"position":[[1584,2]]},"447":{"position":[[890,2]]},"449":{"position":[[79,2]]},"503":{"position":[[81,2]]},"554":{"position":[[66,2]]},"632":{"position":[[18,2]]},"780":{"position":[[330,2]]},"828":{"position":[[65,2]]}}}],["以备",{"_index":508,"t":{"57":{"position":[[87,2],[248,2]]},"272":{"position":[[83,2],[240,2]]},"301":{"position":[[63,2],[210,2]]},"308":{"position":[[84,2],[242,2]]},"347":{"position":[[84,2],[244,2]]}}}],["以往",{"_index":2211,"t":{"455":{"position":[[344,2]]}}}],["以此",{"_index":527,"t":{"57":{"position":[[408,2],[1034,2]]},"272":{"position":[[757,2]]},"308":{"position":[[393,2],[1395,2]]},"347":{"position":[[399,2],[1027,2],[1201,2],[1555,2]]},"546":{"position":[[66,2]]},"963":{"position":[[46,2]]},"971":{"position":[[63,2]]}}}],["以此类推",{"_index":2718,"t":{"615":{"position":[[51,4]]}}}],["以键",{"_index":3397,"t":{"932":{"position":[[11,2]]}}}],["价格",{"_index":731,"t":{"94":{"position":[[22,2]]},"961":{"position":[[280,2]]}}}],["任何",{"_index":65,"t":{"7":{"position":[[84,2]]},"60":{"position":[[10,2]]},"69":{"position":[[10,2]]},"80":{"position":[[40,2]]},"132":{"position":[[10,2]]},"159":{"position":[[86,2]]},"166":{"position":[[149,2]]},"235":{"position":[[1231,2]]},"252":{"position":[[149,2]]},"376":{"position":[[134,2]]},"440":{"position":[[28,2]]},"617":{"position":[[17,2]]},"623":{"position":[[104,2]]},"653":{"position":[[123,2]]},"872":{"position":[[642,2]]},"882":{"position":[[394,2]]},"963":{"position":[[34,2]]},"965":{"position":[[40,2]]},"976":{"position":[[27,2]]}}}],["任何人",{"_index":68,"t":{"7":{"position":[[97,3],[124,3]]}}}],["任务",{"_index":730,"t":{"94":{"position":[[19,2]]},"125":{"position":[[183,2]]},"657":{"position":[[24,2]]},"661":{"position":[[43,2],[66,2],[356,2]]},"663":{"position":[[9,2],[46,2],[430,2]]},"727":{"position":[[357,2]]}}}],["任意",{"_index":259,"t":{"32":{"position":[[90,2]]},"55":{"position":[[31,2]]},"182":{"position":[[37,2]]},"214":{"position":[[37,2]]},"235":{"position":[[1165,2]]},"270":{"position":[[33,2]]},"290":{"position":[[1090,2]]},"306":{"position":[[50,2]]},"345":{"position":[[30,2]]},"365":{"position":[[150,2]]},"395":{"position":[[22,2]]},"451":{"position":[[8,2]]},"539":{"position":[[173,2]]},"630":{"position":[[43,2]]},"707":{"position":[[102,2]]},"723":{"position":[[42,2]]},"748":{"position":[[499,2]]},"776":{"position":[[72,2]]},"780":{"position":[[73,2]]},"794":{"position":[[2,2]]},"798":{"position":[[4,2]]},"804":{"position":[[11,2]]},"826":{"position":[[85,2]]},"828":{"position":[[72,2],[191,2]]},"891":{"position":[[162,2]]},"913":{"position":[[41,2]]}}}],["企业",{"_index":132,"t":{"16":{"position":[[30,2]]},"389":{"position":[[11,2]]},"539":{"position":[[164,2]]},"597":{"position":[[0,2]]},"882":{"position":[[154,2],[176,2],[199,2]]},"884":{"position":[[141,2],[155,2]]},"935":{"position":[[118,2]]},"938":{"position":[[8,2],[19,2]]},"940":{"position":[[8,2]]},"944":{"position":[[6,2]]},"950":{"position":[[7,2],[17,2],[36,2],[53,2],[68,2]]},"954":{"position":[[20,2]]},"961":{"position":[[12,2],[17,2],[65,2]]},"965":{"position":[[37,2],[84,2],[117,2],[139,2],[151,2],[160,2],[185,2],[208,2]]},"967":{"position":[[6,2],[19,2],[57,2],[75,2]]},"971":{"position":[[41,2],[94,2]]}}}],["众所周知",{"_index":1294,"t":{"184":{"position":[[840,4],[1619,4]]},"218":{"position":[[840,4],[1619,4]]}}}],["优",{"_index":2084,"t":{"440":{"position":[[110,1]]}}}],["优于",{"_index":2627,"t":{"570":{"position":[[83,2]]}}}],["优劣",{"_index":2817,"t":{"677":{"position":[[42,2]]}}}],["优化",{"_index":1813,"t":{"365":{"position":[[1360,2],[1444,2]]},"868":{"position":[[26,2]]},"870":{"position":[[44,2],[73,2],[110,2]]},"872":{"position":[[55,2],[70,2]]},"874":{"position":[[58,2],[118,2]]},"876":{"position":[[52,2]]},"878":{"position":[[38,2]]},"880":{"position":[[39,2]]},"882":{"position":[[39,2]]},"884":{"position":[[33,2],[36,2],[45,2]]}}}],["优点",{"_index":1915,"t":{"378":{"position":[[0,2]]},"440":{"position":[[140,2]]},"455":{"position":[[964,2],[979,2]]},"505":{"position":[[1,2]]},"526":{"position":[[38,2]]},"689":{"position":[[62,2]]}}}],["优缺点",{"_index":2086,"t":{"440":{"position":[[119,3]]}}}],["优雅",{"_index":2298,"t":{"485":{"position":[[299,2]]},"617":{"position":[[283,2]]}}}],["会",{"_index":80,"t":{"7":{"position":[[156,1]]},"32":{"position":[[29,1]]},"34":{"position":[[7,1],[46,1]]},"46":{"position":[[355,1],[442,1],[463,1],[481,1],[501,1]]},"50":{"position":[[41,1],[150,1]]},"53":{"position":[[56,1]]},"57":{"position":[[697,1],[811,1]]},"62":{"position":[[37,1]]},"66":{"position":[[18,1]]},"71":{"position":[[37,1]]},"75":{"position":[[18,1]]},"80":{"position":[[34,1]]},"82":{"position":[[37,1]]},"86":{"position":[[18,1]]},"116":{"position":[[14,1]]},"120":{"position":[[70,1]]},"127":{"position":[[215,1],[491,1],[711,1]]},"134":{"position":[[53,1],[101,1]]},"153":{"position":[[110,1]]},"159":{"position":[[105,1],[265,1],[293,1]]},"166":{"position":[[118,1]]},"184":{"position":[[198,1],[708,1],[859,1],[1049,1],[1150,1],[1161,1],[1461,1],[1638,1],[1828,1],[1929,1],[1940,1]]},"186":{"position":[[334,1]]},"194":{"position":[[350,1]]},"196":{"position":[[59,1],[98,1],[313,1]]},"207":{"position":[[439,1]]},"216":{"position":[[14,1]]},"218":{"position":[[198,1],[708,1],[859,1],[1049,1],[1150,1],[1161,1],[1461,1],[1638,1],[1828,1],[1929,1],[1940,1]]},"220":{"position":[[341,1]]},"223":{"position":[[16,1]]},"225":{"position":[[705,1]]},"233":{"position":[[356,1]]},"235":{"position":[[761,1]]},"237":{"position":[[21,1]]},"241":{"position":[[51,1],[266,1],[457,1]]},"248":{"position":[[66,1]]},"252":{"position":[[118,1]]},"261":{"position":[[113,1]]},"268":{"position":[[64,1]]},"272":{"position":[[985,1]]},"286":{"position":[[11,1]]},"290":{"position":[[85,1]]},"292":{"position":[[109,1],[410,1]]},"297":{"position":[[170,1],[271,1],[343,1]]},"301":{"position":[[349,1],[427,1]]},"304":{"position":[[19,1]]},"308":{"position":[[2517,1]]},"321":{"position":[[105,1]]},"336":{"position":[[45,1],[153,1]]},"340":{"position":[[142,1],[226,1],[751,1],[869,1],[880,1]]},"365":{"position":[[1485,1]]},"393":{"position":[[229,1]]},"397":{"position":[[107,1]]},"409":{"position":[[50,1]]},"411":{"position":[[75,1]]},"413":{"position":[[75,1],[111,1]]},"415":{"position":[[94,1],[150,1],[159,1]]},"444":{"position":[[22,1],[45,1],[487,1]]},"447":{"position":[[56,1],[217,1],[859,1]]},"449":{"position":[[95,1],[187,1]]},"451":{"position":[[128,1]]},"455":{"position":[[931,1]]},"465":{"position":[[350,1],[383,1]]},"470":{"position":[[208,1],[435,1],[459,1],[621,1],[766,1]]},"475":{"position":[[13,1]]},"477":{"position":[[13,1]]},"485":{"position":[[119,1]]},"493":{"position":[[42,1]]},"514":{"position":[[81,1],[96,1]]},"516":{"position":[[41,1],[166,1],[193,1]]},"521":{"position":[[206,1]]},"528":{"position":[[673,1],[1387,1]]},"530":{"position":[[129,1]]},"535":{"position":[[76,1]]},"546":{"position":[[12,1],[44,1]]},"559":{"position":[[74,1],[146,1]]},"561":{"position":[[349,1],[416,1],[425,1],[463,1]]},"595":{"position":[[233,1]]},"597":{"position":[[256,1]]},"608":{"position":[[5,1]]},"613":{"position":[[14,1]]},"615":{"position":[[9,1]]},"634":{"position":[[35,1]]},"648":{"position":[[1207,1]]},"666":{"position":[[106,1]]},"672":{"position":[[1034,1]]},"674":{"position":[[941,1]]},"677":{"position":[[45,1]]},"697":{"position":[[77,1]]},"720":{"position":[[22,1]]},"727":{"position":[[935,1],[1898,1]]},"736":{"position":[[340,1]]},"738":{"position":[[104,1]]},"776":{"position":[[93,1]]},"778":{"position":[[71,1]]},"780":{"position":[[370,1],[554,1]]},"783":{"position":[[150,1],[347,1]]},"787":{"position":[[117,1]]},"790":{"position":[[42,1]]},"792":{"position":[[136,1]]},"818":{"position":[[5,1]]},"830":{"position":[[369,1],[398,1],[425,1]]},"832":{"position":[[1836,1],[2030,1],[2351,1]]},"836":{"position":[[72,1]]},"857":{"position":[[355,1],[393,1]]},"859":{"position":[[249,1],[287,1]]},"870":{"position":[[28,1]]},"872":{"position":[[578,1],[1006,1]]},"874":{"position":[[201,1],[352,1]]},"884":{"position":[[85,1]]},"891":{"position":[[299,1]]},"894":{"position":[[167,1]]},"959":{"position":[[43,1]]},"969":{"position":[[64,1]]},"971":{"position":[[80,1]]}}}],["传",{"_index":959,"t":{"127":{"position":[[263,1],[539,1]]},"385":{"position":[[32,1]]},"444":{"position":[[260,1]]},"830":{"position":[[128,1]]},"952":{"position":[[13,1]]}}}],["传入",{"_index":1329,"t":{"184":{"position":[[1302,2]]},"218":{"position":[[1302,2]]},"261":{"position":[[202,2]]},"359":{"position":[[99,2]]},"363":{"position":[[35,2]]},"365":{"position":[[14,2]]},"451":{"position":[[57,2]]},"641":{"position":[[11,2]]},"681":{"position":[[75,2]]}}}],["传到",{"_index":2992,"t":{"727":{"position":[[1839,2]]}}}],["传输",{"_index":1197,"t":{"166":{"position":[[266,2],[572,2]]},"252":{"position":[[266,2],[572,2]]},"526":{"position":[[24,2],[35,2],[102,2],[140,2],[145,2],[307,2],[325,2]]},"528":{"position":[[6,2],[90,2],[839,2],[1537,2]]},"530":{"position":[[13,2],[40,2],[60,2],[105,2],[430,2],[512,2],[1037,2],[1068,2]]},"666":{"position":[[10,2],[135,2],[162,2]]},"672":{"position":[[60,2],[199,2]]},"674":{"position":[[171,2]]},"689":{"position":[[9,2],[36,2],[71,2],[78,2],[87,2],[147,2],[246,2],[274,2]]},"693":{"position":[[13,2]]},"723":{"position":[[28,2]]},"727":{"position":[[798,2],[927,2],[1075,2],[1500,2],[1536,2]]},"783":{"position":[[39,2],[389,2]]},"794":{"position":[[23,2],[74,2],[91,2]]},"798":{"position":[[52,2]]},"814":{"position":[[38,2]]},"826":{"position":[[1,2],[33,2],[182,2]]},"828":{"position":[[270,2],[281,2],[320,2]]},"830":{"position":[[245,2],[260,2],[274,2],[614,2],[643,2],[678,2]]},"832":{"position":[[623,2],[801,2],[855,2],[1754,2],[1765,2],[2010,2],[2081,2],[2357,2]]},"836":{"position":[[10,2]]},"839":{"position":[[63,2]]},"872":{"position":[[353,2],[360,2],[389,2],[401,2],[423,2]]},"878":{"position":[[538,2],[650,2],[704,2]]},"932":{"position":[[127,2]]}}}],["传输层",{"_index":922,"t":{"125":{"position":[[126,3]]}}}],["传输数据",{"_index":3142,"t":{"816":{"position":[[76,4]]}}}],["传输方式",{"_index":2852,"t":{"689":{"position":[[262,4]]}}}],["传输速度",{"_index":2978,"t":{"727":{"position":[[392,4]]},"822":{"position":[[39,4]]}}}],["传输速率",{"_index":2449,"t":{"526":{"position":[[91,4]]}}}],["传递",{"_index":237,"t":{"28":{"position":[[94,2]]},"516":{"position":[[154,2]]},"570":{"position":[[162,2]]},"581":{"position":[[107,2]]},"610":{"position":[[290,2]]},"630":{"position":[[99,2]]},"666":{"position":[[70,2],[92,2]]},"670":{"position":[[47,2]]},"792":{"position":[[137,2]]},"832":{"position":[[1642,2],[1945,2]]}}}],["传递数据",{"_index":2792,"t":{"666":{"position":[[46,4]]}}}],["伪",{"_index":2213,"t":{"455":{"position":[[387,1]]}}}],["似乎",{"_index":1980,"t":{"409":{"position":[[31,2]]}}}],["但是",{"_index":335,"t":{"38":{"position":[[27,2]]},"42":{"position":[[20,2]]},"53":{"position":[[47,2]]},"136":{"position":[[22,2]]},"153":{"position":[[108,2]]},"159":{"position":[[117,2]]},"184":{"position":[[121,2],[869,2],[1064,2],[1648,2],[1843,2]]},"186":{"position":[[79,2]]},"218":{"position":[[121,2],[869,2],[1064,2],[1648,2],[1843,2]]},"220":{"position":[[84,2]]},"268":{"position":[[62,2]]},"290":{"position":[[1023,2]]},"308":{"position":[[1157,2]]},"347":{"position":[[947,2]]},"365":{"position":[[1468,2]]},"395":{"position":[[27,2]]},"409":{"position":[[38,2]]},"431":{"position":[[23,2],[553,2]]},"444":{"position":[[374,2],[457,2]]},"449":{"position":[[108,2],[177,2]]},"455":{"position":[[21,2],[463,2]]},"485":{"position":[[88,2],[205,2]]},"487":{"position":[[80,2]]},"503":{"position":[[114,2]]},"505":{"position":[[91,2]]},"521":{"position":[[164,2],[458,2]]},"523":{"position":[[2722,2]]},"526":{"position":[[152,2],[243,2]]},"546":{"position":[[32,2]]},"548":{"position":[[22,2]]},"639":{"position":[[59,2]]},"653":{"position":[[115,2],[208,2]]},"661":{"position":[[19,2]]},"663":{"position":[[26,2]]},"666":{"position":[[19,2]]},"679":{"position":[[128,2],[179,2],[243,2]]},"689":{"position":[[116,2]]},"697":{"position":[[70,2]]},"738":{"position":[[70,2]]},"778":{"position":[[86,2]]},"780":{"position":[[357,2]]},"806":{"position":[[444,2]]},"809":{"position":[[32,2]]},"814":{"position":[[25,2]]},"832":{"position":[[806,2]]},"862":{"position":[[60,2]]},"872":{"position":[[171,2]]},"878":{"position":[[655,2]]},"891":{"position":[[275,2]]},"957":{"position":[[101,2]]},"959":{"position":[[37,2]]},"978":{"position":[[36,2]]}}}],["位",{"_index":2283,"t":{"473":{"position":[[300,1]]},"702":{"position":[[979,1],[1446,1],[1460,1],[1473,1]]},"820":{"position":[[202,1],[213,1]]},"830":{"position":[[503,1]]}}}],["位置",{"_index":1122,"t":{"157":{"position":[[310,2]]},"301":{"position":[[527,2],[665,2]]},"347":{"position":[[1443,2]]},"473":{"position":[[245,2]]},"507":{"position":[[2130,2]]}}}],["低",{"_index":1299,"t":{"184":{"position":[[892,1],[1671,1]]},"218":{"position":[[892,1],[1671,1]]},"440":{"position":[[224,1]]},"679":{"position":[[248,1]]},"718":{"position":[[201,1]]},"761":{"position":[[51,1],[158,1],[197,1],[204,1]]}}}],["低位",{"_index":3059,"t":{"761":{"position":[[116,2]]}}}],["低字节",{"_index":3055,"t":{"761":{"position":[[60,3],[149,3]]}}}],["体",{"_index":549,"t":{"57":{"position":[[704,1],[797,1]]},"272":{"position":[[958,1]]},"343":{"position":[[40,1],[82,1]]},"427":{"position":[[64,1]]},"465":{"position":[[260,1]]},"655":{"position":[[375,1]]},"681":{"position":[[149,1]]},"917":{"position":[[44,1]]}}}],["体现",{"_index":3095,"t":{"783":{"position":[[408,2]]}}}],["体验",{"_index":2023,"t":{"427":{"position":[[34,2]]},"862":{"position":[[114,2]]}}}],["何时",{"_index":2016,"t":{"420":{"position":[[2,2]]}}}],["作为",{"_index":512,"t":{"57":{"position":[[151,2],[425,2]]},"110":{"position":[[92,2]]},"199":{"position":[[41,2]]},"207":{"position":[[375,2]]},"272":{"position":[[143,2]]},"292":{"position":[[120,2],[425,2]]},"301":{"position":[[113,2]]},"308":{"position":[[145,2],[410,2]]},"321":{"position":[[37,2],[120,2]]},"347":{"position":[[147,2],[416,2]]},"402":{"position":[[56,2]]},"404":{"position":[[15,2],[76,2],[141,2]]},"615":{"position":[[149,2]]},"617":{"position":[[110,2]]},"630":{"position":[[6,2],[16,2],[276,2]]},"684":{"position":[[88,2]]},"705":{"position":[[130,2]]},"707":{"position":[[59,2],[74,2],[124,2]]},"727":{"position":[[6,2],[190,2]]},"770":{"position":[[44,2]]},"868":{"position":[[256,2]]},"891":{"position":[[183,2]]}}}],["作出",{"_index":526,"t":{"57":{"position":[[403,2],[1029,2]]},"272":{"position":[[752,2]]},"308":{"position":[[388,2],[1390,2]]},"347":{"position":[[394,2],[939,2]]}}}],["作品",{"_index":105,"t":{"12":{"position":[[62,2],[69,2],[110,2]]}}}],["作用",{"_index":218,"t":{"28":{"position":[[23,2],[65,2],[132,2]]},"89":{"position":[[17,2]]},"120":{"position":[[339,2]]},"184":{"position":[[207,2]]},"218":{"position":[[207,2]]},"255":{"position":[[305,2]]},"301":{"position":[[1278,2],[1616,2]]},"340":{"position":[[85,2]]},"455":{"position":[[742,2]]},"832":{"position":[[2061,2]]}}}],["作者",{"_index":14,"t":{"5":{"position":[[13,2],[33,2]]},"10":{"position":[[47,2]]},"12":{"position":[[47,2],[73,2],[84,2],[147,2]]},"14":{"position":[[47,2]]},"16":{"position":[[63,2]]},"935":{"position":[[141,2]]},"965":{"position":[[199,2]]},"973":{"position":[[17,2]]}}}],["使得",{"_index":924,"t":{"125":{"position":[[137,2]]},"444":{"position":[[402,2]]},"503":{"position":[[97,2]]},"909":{"position":[[115,2]]}}}],["使用",{"_index":42,"t":{"5":{"position":[[102,2]]},"7":{"position":[[164,2]]},"10":{"position":[[67,2]]},"14":{"position":[[84,2]]},"18":{"position":[[20,2],[26,2],[38,2]]},"20":{"position":[[1,2],[43,2]]},"25":{"position":[[245,2]]},"36":{"position":[[6,2],[56,2],[66,2]]},"38":{"position":[[9,2]]},"42":{"position":[[0,2]]},"46":{"position":[[3,2]]},"48":{"position":[[2,2],[37,2]]},"57":{"position":[[89,2],[250,2],[618,2]]},"60":{"position":[[8,2],[26,2],[469,2]]},"69":{"position":[[8,2],[26,2],[156,2]]},"78":{"position":[[23,2]]},"80":{"position":[[38,2],[56,2]]},"110":{"position":[[84,2],[106,2]]},"114":{"position":[[6,2],[19,2]]},"132":{"position":[[8,2],[15,2],[34,2],[302,2]]},"134":{"position":[[3430,2]]},"140":{"position":[[152,2],[219,2]]},"146":{"position":[[31,2]]},"149":{"position":[[62,2]]},"151":{"position":[[110,2]]},"153":{"position":[[20,2]]},"155":{"position":[[2,2],[27,2]]},"159":{"position":[[120,2],[173,2],[617,2],[926,2]]},"166":{"position":[[159,2]]},"182":{"position":[[7,2],[20,2]]},"184":{"position":[[510,2],[833,2],[1035,2],[1292,2],[1329,2],[1442,2],[1462,2],[1612,2],[1814,2]]},"190":{"position":[[32,2]]},"192":{"position":[[1,2]]},"194":{"position":[[19,2],[537,2]]},"196":{"position":[[76,2]]},"203":{"position":[[5,2],[18,2]]},"207":{"position":[[440,2]]},"214":{"position":[[7,2],[20,2]]},"218":{"position":[[510,2],[833,2],[1035,2],[1292,2],[1329,2],[1442,2],[1462,2],[1612,2],[1814,2]]},"223":{"position":[[17,2]]},"225":{"position":[[414,2]]},"227":{"position":[[33,2]]},"229":{"position":[[1,2]]},"233":{"position":[[19,2],[543,2]]},"235":{"position":[[69,2],[192,2]]},"241":{"position":[[474,2]]},"252":{"position":[[159,2]]},"261":{"position":[[118,2],[149,2],[602,2],[901,2]]},"272":{"position":[[85,2],[242,2]]},"286":{"position":[[485,2]]},"288":{"position":[[88,2]]},"292":{"position":[[61,2]]},"301":{"position":[[65,2],[212,2]]},"304":{"position":[[12,2],[105,2]]},"308":{"position":[[86,2],[244,2]]},"319":{"position":[[681,2]]},"321":{"position":[[24,2]]},"323":{"position":[[16,2]]},"340":{"position":[[730,2]]},"343":{"position":[[122,2]]},"347":{"position":[[86,2],[246,2]]},"353":{"position":[[8,2]]},"363":{"position":[[7,2]]},"365":{"position":[[183,2],[1461,2]]},"378":{"position":[[122,2],[129,2]]},"389":{"position":[[58,2]]},"400":{"position":[[60,2]]},"402":{"position":[[73,2],[89,2]]},"409":{"position":[[101,2]]},"411":{"position":[[80,2]]},"413":{"position":[[80,2]]},"427":{"position":[[32,2]]},"431":{"position":[[7,2],[566,2]]},"440":{"position":[[0,2],[11,2],[273,2]]},"442":{"position":[[19,2],[120,2]]},"444":{"position":[[386,2]]},"447":{"position":[[39,2]]},"455":{"position":[[364,2]]},"461":{"position":[[42,2]]},"468":{"position":[[41,2],[63,2],[98,2]]},"470":{"position":[[224,2],[451,2],[836,2]]},"475":{"position":[[1,2]]},"477":{"position":[[1,2]]},"479":{"position":[[0,2]]},"485":{"position":[[66,2],[141,2],[233,2],[239,2],[297,2]]},"487":{"position":[[0,2]]},"493":{"position":[[457,2]]},"498":{"position":[[78,2]]},"503":{"position":[[126,2],[148,2]]},"509":{"position":[[15,2]]},"512":{"position":[[248,2],[430,2]]},"514":{"position":[[82,2],[491,2]]},"516":{"position":[[42,2],[69,2],[131,2],[513,2]]},"521":{"position":[[144,2],[207,2],[462,2]]},"528":{"position":[[32,2],[77,2]]},"530":{"position":[[16,2]]},"535":{"position":[[77,2]]},"539":{"position":[[169,2]]},"542":{"position":[[235,2]]},"546":{"position":[[45,2]]},"550":{"position":[[0,2],[59,2],[72,2]]},"552":{"position":[[0,2]]},"554":{"position":[[190,2]]},"568":{"position":[[5,2]]},"574":{"position":[[5,2],[246,2]]},"588":{"position":[[14,2]]},"595":{"position":[[0,2]]},"597":{"position":[[3,2],[43,2],[222,2]]},"610":{"position":[[13,2],[341,2]]},"615":{"position":[[143,2]]},"628":{"position":[[45,2],[103,2]]},"641":{"position":[[219,2]]},"646":{"position":[[13,2]]},"655":{"position":[[24,2],[329,2]]},"666":{"position":[[28,2],[127,2]]},"686":{"position":[[442,2]]},"693":{"position":[[16,2]]},"699":{"position":[[15,2]]},"718":{"position":[[74,2]]},"727":{"position":[[200,2]]},"736":{"position":[[267,2],[577,2],[618,2],[659,2]]},"738":{"position":[[131,2]]},"741":{"position":[[111,2]]},"748":{"position":[[232,2],[469,2]]},"750":{"position":[[4,2],[178,2],[231,2],[455,2],[522,2]]},"756":{"position":[[11,2]]},"758":{"position":[[92,2]]},"770":{"position":[[26,2]]},"774":{"position":[[0,2]]},"776":{"position":[[107,2]]},"778":{"position":[[74,2]]},"780":{"position":[[0,2],[80,2],[94,2]]},"783":{"position":[[121,2],[304,2],[327,2]]},"806":{"position":[[5,2],[62,2],[139,2],[294,2],[450,2]]},"811":{"position":[[0,2]]},"824":{"position":[[7,2],[14,2]]},"832":{"position":[[1828,2],[2365,2]]},"836":{"position":[[15,2],[60,2]]},"841":{"position":[[2,2]]},"847":{"position":[[2,2]]},"854":{"position":[[71,2]]},"857":{"position":[[451,2],[667,2]]},"859":{"position":[[345,2],[556,2],[1110,2]]},"862":{"position":[[112,2]]},"868":{"position":[[128,2]]},"872":{"position":[[671,2],[1130,2]]},"878":{"position":[[242,2],[292,2],[302,2]]},"880":{"position":[[140,2],[176,2]]},"882":{"position":[[211,2],[396,2]]},"891":{"position":[[48,2],[89,2],[160,2],[280,2]]},"894":{"position":[[382,2]]},"896":{"position":[[466,2]]},"913":{"position":[[11,2],[24,2]]},"917":{"position":[[125,2]]},"935":{"position":[[82,2]]},"961":{"position":[[40,2]]},"963":{"position":[[58,2]]},"969":{"position":[[133,2],[192,2]]},"971":{"position":[[92,2],[98,2]]}}}],["使用方便",{"_index":3178,"t":{"824":{"position":[[67,4]]}}}],["使用者",{"_index":3079,"t":{"780":{"position":[[66,3]]}}}],["例",{"_index":499,"t":{"57":{"position":[[18,1]]},"132":{"position":[[63,1]]},"140":{"position":[[64,1],[200,1]]},"159":{"position":[[160,1]]},"272":{"position":[[18,1],[368,1]]},"301":{"position":[[8,1]]},"308":{"position":[[18,1]]},"340":{"position":[[57,1]]},"347":{"position":[[18,1]]},"391":{"position":[[81,1]]},"406":{"position":[[18,1]]},"422":{"position":[[18,1]]},"554":{"position":[[53,1],[116,1]]},"581":{"position":[[9,1]]},"600":{"position":[[53,1]]},"745":{"position":[[18,1]]},"778":{"position":[[54,1]]},"874":{"position":[[204,1]]},"876":{"position":[[195,1]]},"880":{"position":[[143,1]]}}}],["例如",{"_index":262,"t":{"32":{"position":[[100,2]]},"34":{"position":[[89,2],[106,2],[212,2]]},"48":{"position":[[16,2]]},"125":{"position":[[83,2]]},"184":{"position":[[91,2]]},"218":{"position":[[91,2]]},"225":{"position":[[736,2]]},"235":{"position":[[1236,2]]},"248":{"position":[[28,2]]},"272":{"position":[[965,2]]},"292":{"position":[[361,2]]},"304":{"position":[[27,2]]},"306":{"position":[[15,2]]},"308":{"position":[[2422,2]]},"319":{"position":[[18,2],[703,2]]},"321":{"position":[[56,2]]},"340":{"position":[[99,2]]},"343":{"position":[[21,2]]},"359":{"position":[[15,2]]},"409":{"position":[[56,2]]},"440":{"position":[[255,2]]},"442":{"position":[[81,2]]},"447":{"position":[[1337,2]]},"449":{"position":[[196,2]]},"455":{"position":[[44,2]]},"468":{"position":[[50,2]]},"470":{"position":[[219,2],[446,2]]},"479":{"position":[[21,2]]},"526":{"position":[[212,2]]},"572":{"position":[[43,2]]},"574":{"position":[[64,2]]},"610":{"position":[[297,2]]},"617":{"position":[[96,2]]},"628":{"position":[[52,2]]},"783":{"position":[[288,2]]},"806":{"position":[[88,2]]},"826":{"position":[[121,2]]},"872":{"position":[[490,2]]},"878":{"position":[[352,2]]},"880":{"position":[[241,2]]},"925":{"position":[[134,2]]},"957":{"position":[[118,2]]},"969":{"position":[[122,2]]}}}],["供",{"_index":37,"t":{"5":{"position":[[87,1]]},"288":{"position":[[84,1]]}}}],["依托",{"_index":2782,"t":{"663":{"position":[[54,2]]}}}],["依次",{"_index":1125,"t":{"157":{"position":[[321,2]]},"365":{"position":[[2020,2]]},"447":{"position":[[756,2]]}}}],["依然",{"_index":2043,"t":{"431":{"position":[[564,2]]},"451":{"position":[[126,2]]},"548":{"position":[[32,2]]},"689":{"position":[[266,2]]}}}],["依赖",{"_index":171,"t":{"23":{"position":[[38,2]]},"374":{"position":[[12,2],[50,2]]},"376":{"position":[[88,2],[402,2],[649,2],[730,2]]},"378":{"position":[[131,2]]},"542":{"position":[[2,2],[65,2],[103,2],[141,2]]},"872":{"position":[[1083,2],[1106,2]]}}}],["依赖于",{"_index":2537,"t":{"542":{"position":[[47,3]]}}}],["依靠",{"_index":3042,"t":{"752":{"position":[[40,2]]}}}],["便捷",{"_index":617,"t":{"62":{"position":[[5,2]]},"71":{"position":[[5,2]]},"82":{"position":[[5,2]]},"134":{"position":[[5,2]]},"738":{"position":[[33,2]]},"783":{"position":[[16,2]]},"925":{"position":[[157,2]]}}}],["保",{"_index":2675,"t":{"595":{"position":[[238,1]]},"597":{"position":[[261,1]]},"752":{"position":[[49,1]]}}}],["保存",{"_index":550,"t":{"57":{"position":[[715,2]]},"301":{"position":[[352,2],[428,2]]},"528":{"position":[[814,2]]},"691":{"position":[[79,2],[199,2]]},"761":{"position":[[45,2],[63,2],[134,2],[152,2]]},"830":{"position":[[478,2]]},"832":{"position":[[1873,2]]}}}],["保持",{"_index":3099,"t":{"787":{"position":[[19,2]]}}}],["保持一致",{"_index":2361,"t":{"505":{"position":[[77,4]]}}}],["保留",{"_index":2828,"t":{"684":{"position":[[95,2]]},"745":{"position":[[528,2],[572,2]]},"748":{"position":[[228,2]]},"820":{"position":[[214,2]]},"884":{"position":[[300,2]]},"967":{"position":[[53,2]]}}}],["保证",{"_index":1300,"t":{"184":{"position":[[902,2],[1681,2]]},"218":{"position":[[902,2],[1681,2]]},"653":{"position":[[108,2],[154,2],[194,2]]},"770":{"position":[[8,2]]},"792":{"position":[[200,2]]}}}],["保障",{"_index":735,"t":{"94":{"position":[[57,2]]}}}],["信",{"_index":3468,"t":{"973":{"position":[[45,1]]}}}],["信使",{"_index":161,"t":{"23":{"position":[[2,2]]}}}],["信号",{"_index":3414,"t":{"957":{"position":[[123,2]]}}}],["信息",{"_index":95,"t":{"10":{"position":[[50,2]]},"12":{"position":[[50,2],[75,2]]},"14":{"position":[[50,2]]},"57":{"position":[[1476,2],[1653,2]]},"91":{"position":[[355,2]]},"125":{"position":[[103,2]]},"159":{"position":[[575,2],[974,2]]},"188":{"position":[[283,2],[383,2]]},"192":{"position":[[164,2],[264,2]]},"212":{"position":[[52,2]]},"223":{"position":[[348,2],[462,2],[497,2],[538,2],[615,2]]},"225":{"position":[[353,2]]},"229":{"position":[[167,2],[281,2]]},"272":{"position":[[1367,2],[1540,2]]},"290":{"position":[[81,2]]},"301":{"position":[[2431,2],[2580,2]]},"308":{"position":[[1888,2],[2059,2]]},"343":{"position":[[64,2]]},"347":{"position":[[2049,2],[2224,2]]},"393":{"position":[[379,2]]},"406":{"position":[[210,2]]},"422":{"position":[[223,2]]},"444":{"position":[[334,2]]},"447":{"position":[[921,2]]},"512":{"position":[[481,2]]},"574":{"position":[[77,2]]},"581":{"position":[[6,2],[114,2]]},"595":{"position":[[210,2]]},"597":{"position":[[233,2]]},"617":{"position":[[13,2],[93,2],[169,2]]},"630":{"position":[[256,2]]},"639":{"position":[[102,2]]},"648":{"position":[[1075,2]]},"653":{"position":[[140,2],[238,2],[254,2],[277,2]]},"725":{"position":[[10,2]]},"734":{"position":[[240,2],[512,2]]},"743":{"position":[[20,2]]},"745":{"position":[[223,2]]},"774":{"position":[[33,2]]},"790":{"position":[[12,2]]},"828":{"position":[[259,2],[283,2]]},"830":{"position":[[118,2],[651,2]]},"980":{"position":[[191,2]]}}}],["修复",{"_index":2115,"t":{"444":{"position":[[284,2]]},"866":{"position":[[45,2],[99,2]]},"868":{"position":[[45,2],[76,2],[112,2]]},"870":{"position":[[133,2]]},"872":{"position":[[95,2]]},"874":{"position":[[465,2]]},"876":{"position":[[183,2]]},"878":{"position":[[182,2],[185,2]]},"880":{"position":[[323,2]]},"882":{"position":[[271,2],[335,2],[358,2]]},"884":{"position":[[262,2],[265,2]]}}}],["修改",{"_index":693,"t":{"86":{"position":[[44,2],[65,2],[74,2]]},"297":{"position":[[150,2],[242,2],[314,2]]},"347":{"position":[[1601,2]]},"440":{"position":[[176,2]]},"570":{"position":[[152,2]]},"579":{"position":[[60,2],[91,2]]},"619":{"position":[[2,2]]},"668":{"position":[[37,2]]},"767":{"position":[[47,2]]},"776":{"position":[[76,2],[96,2]]},"816":{"position":[[84,2]]},"870":{"position":[[40,2],[196,2],[204,2]]},"874":{"position":[[226,2],[424,2],[443,2]]},"876":{"position":[[178,2]]},"878":{"position":[[177,2]]},"880":{"position":[[217,2]]},"882":{"position":[[215,2],[261,2]]},"884":{"position":[[178,2]]}}}],["修订",{"_index":3263,"t":{"866":{"position":[[76,2],[107,2],[141,2]]}}}],["倍",{"_index":2077,"t":{"436":{"position":[[2022,1],[2044,1],[2067,1]]},"509":{"position":[[53,1],[68,1]]},"872":{"position":[[365,1],[431,1]]}}}],["倒数",{"_index":3165,"t":{"820":{"position":[[265,2]]}}}],["倒置",{"_index":172,"t":{"23":{"position":[[40,2]]}}}],["倘若",{"_index":1816,"t":{"365":{"position":[[1367,2]]}}}],["值",{"_index":520,"t":{"57":{"position":[[246,1]]},"166":{"position":[[282,1],[588,1]]},"184":{"position":[[73,1],[110,1],[114,1],[197,1],[268,1],[329,1],[371,1],[388,1],[406,1],[2011,1]]},"194":{"position":[[186,1],[207,1],[356,1]]},"216":{"position":[[120,1]]},"218":{"position":[[73,1],[110,1],[114,1],[197,1],[268,1],[329,1],[371,1],[388,1],[406,1],[2011,1]]},"233":{"position":[[189,1],[210,1],[362,1]]},"235":{"position":[[767,1]]},"252":{"position":[[282,1],[588,1]]},"272":{"position":[[238,1],[771,1]]},"301":{"position":[[208,1]]},"308":{"position":[[240,1]]},"340":{"position":[[843,1]]},"343":{"position":[[108,1]]},"347":{"position":[[242,1],[977,1],[1513,1]]},"378":{"position":[[67,1]]},"451":{"position":[[65,1]]},"507":{"position":[[661,1],[785,1]]},"530":{"position":[[529,1]]},"663":{"position":[[467,1]]},"668":{"position":[[40,1]]},"727":{"position":[[1502,1]]},"741":{"position":[[49,1]]},"748":{"position":[[64,1],[422,1]]},"750":{"position":[[601,1]]},"756":{"position":[[72,1]]},"758":{"position":[[125,1]]},"761":{"position":[[194,1],[203,1]]},"822":{"position":[[91,1]]},"828":{"position":[[339,1]]},"830":{"position":[[361,1],[594,1]]},"832":{"position":[[1842,1]]},"932":{"position":[[14,1]]}}}],["值守",{"_index":2680,"t":{"597":{"position":[[28,2]]}}}],["值得注意",{"_index":3192,"t":{"828":{"position":[[287,4]]}}}],["假",{"_index":1722,"t":{"347":{"position":[[986,1]]}}}],["假如",{"_index":54,"t":{"7":{"position":[[43,2]]},"336":{"position":[[147,2]]},"451":{"position":[[79,2]]},"655":{"position":[[314,2]]}}}],["假定",{"_index":913,"t":{"125":{"position":[[73,2]]}}}],["假设",{"_index":1680,"t":{"336":{"position":[[0,2]]},"359":{"position":[[18,2]]},"365":{"position":[[77,2]]},"376":{"position":[[566,2]]},"444":{"position":[[54,2],[497,2]]},"628":{"position":[[55,2]]}}}],["偏移",{"_index":3083,"t":{"780":{"position":[[375,2],[559,2]]}}}],["做",{"_index":743,"t":{"102":{"position":[[157,1]]},"146":{"position":[[112,1]]},"297":{"position":[[76,1]]},"361":{"position":[[1175,1]]},"444":{"position":[[80,1],[523,1]]},"516":{"position":[[194,1]]},"630":{"position":[[31,1]]},"666":{"position":[[15,1],[156,1]]},"668":{"position":[[77,1]]},"720":{"position":[[26,1],[39,1]]},"752":{"position":[[64,1]]}}}],["做好",{"_index":625,"t":{"62":{"position":[[40,2]]},"71":{"position":[[40,2]]},"82":{"position":[[40,2]]},"120":{"position":[[486,2]]},"134":{"position":[[56,2]]},"235":{"position":[[262,2]]},"308":{"position":[[2550,2]]}}}],["停售",{"_index":3434,"t":{"961":{"position":[[289,2]]}}}],["停止",{"_index":721,"t":{"91":{"position":[[284,2]]}}}],["停顿",{"_index":3173,"t":{"822":{"position":[[76,2]]}}}],["储存",{"_index":1778,"t":{"361":{"position":[[1216,2]]}}}],["像",{"_index":275,"t":{"34":{"position":[[37,1]]},"235":{"position":[[208,1]]},"376":{"position":[[108,1]]},"440":{"position":[[10,1]]},"530":{"position":[[66,1]]},"785":{"position":[[8,1]]}}}],["允许",{"_index":427,"t":{"48":{"position":[[41,2],[218,2]]},"146":{"position":[[115,2]]},"164":{"position":[[193,2]]},"184":{"position":[[373,2]]},"218":{"position":[[373,2]]},"225":{"position":[[776,2]]},"250":{"position":[[193,2]]},"440":{"position":[[262,2]]},"648":{"position":[[270,2]]},"727":{"position":[[249,2]]},"770":{"position":[[54,2]]},"774":{"position":[[249,2]]},"836":{"position":[[85,2]]},"872":{"position":[[937,2]]},"909":{"position":[[138,2]]},"961":{"position":[[188,2],[191,2],[194,2]]}}}],["元",{"_index":2736,"t":{"630":{"position":[[103,1]]},"727":{"position":[[291,1],[1836,1]]},"774":{"position":[[44,1],[267,1]]},"832":{"position":[[1649,1],[1952,1]]}}}],["元素",{"_index":3329,"t":{"880":{"position":[[352,2]]}}}],["元组",{"_index":2025,"t":{"427":{"position":[[66,2]]},"868":{"position":[[41,2]]},"874":{"position":[[398,2]]}}}],["充分考虑",{"_index":3134,"t":{"809":{"position":[[63,4]]}}}],["充当",{"_index":1374,"t":{"199":{"position":[[32,2]]}}}],["先",{"_index":644,"t":{"69":{"position":[[160,1],[175,1]]},"102":{"position":[[156,1]]},"134":{"position":[[1484,1],[1982,1]]},"142":{"position":[[208,1]]},"157":{"position":[[298,1]]},"239":{"position":[[193,1]]},"261":{"position":[[148,1],[900,1]]},"292":{"position":[[411,1]]},"321":{"position":[[106,1]]},"336":{"position":[[46,1],[154,1]]},"340":{"position":[[143,1],[227,1]]},"361":{"position":[[659,1],[947,1],[1771,1],[1977,1]]},"365":{"position":[[1922,1]]},"444":{"position":[[83,1],[526,1]]},"465":{"position":[[351,1]]},"477":{"position":[[12,1]]},"487":{"position":[[102,1]]},"507":{"position":[[388,1],[458,1],[569,1],[639,1]]},"554":{"position":[[201,1]]},"559":{"position":[[75,1]]},"581":{"position":[[76,1]]},"670":{"position":[[5,1]]},"689":{"position":[[269,1]]},"702":{"position":[[2293,1]]},"778":{"position":[[153,1]]},"806":{"position":[[25,1]]},"832":{"position":[[2031,1]]},"973":{"position":[[14,1]]}}}],["先行",{"_index":2625,"t":{"570":{"position":[[58,2]]}}}],["光",{"_index":1888,"t":{"370":{"position":[[407,1]]}}}],["免费",{"_index":36,"t":{"5":{"position":[[85,2]]},"7":{"position":[[69,2]]},"18":{"position":[[6,2]]},"965":{"position":[[203,2]]}}}],["入",{"_index":2082,"t":{"440":{"position":[[67,1],[133,1]]},"872":{"position":[[233,1]]}}}],["入手",{"_index":1746,"t":{"357":{"position":[[12,2]]}}}],["入门",{"_index":2927,"t":{"705":{"position":[[132,2]]},"720":{"position":[[13,2]]}}}],["全",{"_index":963,"t":{"127":{"position":[[281,1],[557,1]]},"767":{"position":[[12,1]]},"792":{"position":[[117,1]]},"864":{"position":[[27,1]]},"872":{"position":[[657,1]]},"874":{"position":[[90,1]]},"878":{"position":[[144,1],[222,1]]}}}],["全双工",{"_index":3370,"t":{"909":{"position":[[23,3]]}}}],["全名",{"_index":962,"t":{"127":{"position":[[274,2],[550,2]]}}}],["全局",{"_index":2583,"t":{"554":{"position":[[69,2]]},"872":{"position":[[571,2],[999,2]]},"878":{"position":[[41,2]]},"891":{"position":[[302,2]]}}}],["全球",{"_index":48,"t":{"7":{"position":[[17,2]]}}}],["全部",{"_index":99,"t":{"10":{"position":[[60,2]]},"12":{"position":[[180,2]]},"14":{"position":[[79,2]]},"455":{"position":[[36,2]]},"465":{"position":[[256,2],[354,2]]},"672":{"position":[[1041,2]]},"674":{"position":[[948,2]]},"681":{"position":[[157,2]]},"872":{"position":[[175,2]]},"954":{"position":[[0,2]]},"961":{"position":[[25,2],[30,2],[35,2],[77,2]]}}}],["公共",{"_index":182,"t":{"25":{"position":[[37,2]]},"127":{"position":[[120,2]]},"444":{"position":[[700,2]]},"512":{"position":[[48,2]]},"732":{"position":[[67,2]]},"894":{"position":[[48,2]]},"925":{"position":[[105,2]]},"928":{"position":[[58,2]]}}}],["公司",{"_index":1669,"t":{"328":{"position":[[2,2]]},"906":{"position":[[17,2]]}}}],["公告",{"_index":0,"t":{"3":{"position":[[0,2]]}}}],["公开",{"_index":148,"t":{"18":{"position":[[75,2]]}}}],["共享",{"_index":1439,"t":{"235":{"position":[[1208,2]]},"882":{"position":[[209,2]]}}}],["共享资源",{"_index":1495,"t":{"263":{"position":[[34,4]]}}}],["共同",{"_index":2447,"t":{"526":{"position":[[22,2]]},"872":{"position":[[459,2]]}}}],["共用",{"_index":3133,"t":{"806":{"position":[[439,2]]}}}],["关于",{"_index":128,"t":{"14":{"position":[[65,2]]},"159":{"position":[[188,2]]}}}],["关心",{"_index":1036,"t":{"138":{"position":[[170,2]]}}}],["关注",{"_index":3259,"t":{"866":{"position":[[27,2]]}}}],["关系",{"_index":2123,"t":{"444":{"position":[[371,2]]},"542":{"position":[[67,2]]},"623":{"position":[[106,2]]},"776":{"position":[[57,2]]},"783":{"position":[[370,2]]}}}],["关联",{"_index":2722,"t":{"617":{"position":[[19,2],[37,2],[167,2]]},"623":{"position":[[83,2]]}}}],["关键字",{"_index":3114,"t":{"792":{"position":[[42,3]]}}}],["关闭",{"_index":3033,"t":{"748":{"position":[[277,2]]},"971":{"position":[[46,2]]}}}],["其中",{"_index":1949,"t":{"393":{"position":[[180,2]]},"544":{"position":[[23,2]]},"546":{"position":[[47,2]]},"548":{"position":[[0,2]]},"783":{"position":[[101,2]]},"891":{"position":[[235,2]]}}}],["其他",{"_index":38,"t":{"5":{"position":[[88,2]]},"34":{"position":[[38,2]]},"46":{"position":[[368,2]]},"110":{"position":[[74,2]]},"120":{"position":[[602,2]]},"129":{"position":[[21,2]]},"132":{"position":[[65,2]]},"134":{"position":[[454,2],[790,2],[1292,2],[2484,2]]},"194":{"position":[[490,2]]},"233":{"position":[[496,2]]},"288":{"position":[[10,2]]},"290":{"position":[[799,2]]},"359":{"position":[[82,2],[111,2]]},"363":{"position":[[56,2]]},"365":{"position":[[26,2],[71,2],[160,2]]},"400":{"position":[[68,2]]},"442":{"position":[[123,2]]},"444":{"position":[[143,2],[162,2],[191,2],[217,2]]},"449":{"position":[[139,2],[190,2]]},"451":{"position":[[111,2]]},"455":{"position":[[562,2]]},"470":{"position":[[825,2]]},"530":{"position":[[67,2]]},"610":{"position":[[354,2]]},"628":{"position":[[23,2]]},"655":{"position":[[359,2]]},"691":{"position":[[364,2]]},"707":{"position":[[146,2]]},"718":{"position":[[188,2]]},"720":{"position":[[85,2]]},"756":{"position":[[5,2]]},"770":{"position":[[61,2]]},"820":{"position":[[211,2]]},"859":{"position":[[1134,2]]},"891":{"position":[[199,2]]}}}],["其余",{"_index":1049,"t":{"140":{"position":[[202,2]]},"581":{"position":[[295,2]]},"866":{"position":[[152,2]]},"882":{"position":[[237,2]]},"938":{"position":[[23,2]]},"940":{"position":[[12,2]]},"944":{"position":[[10,2]]},"954":{"position":[[50,2]]}}}],["其实",{"_index":1032,"t":{"138":{"position":[[114,2]]},"485":{"position":[[163,2]]}}}],["其次",{"_index":1475,"t":{"261":{"position":[[600,2]]},"359":{"position":[[88,2]]},"444":{"position":[[484,2]]},"526":{"position":[[319,2]]},"787":{"position":[[47,2]]}}}],["具",{"_index":2999,"t":{"732":{"position":[[65,1]]},"925":{"position":[[103,1]]}}}],["具体",{"_index":659,"t":{"78":{"position":[[46,2]]},"194":{"position":[[358,2]]},"233":{"position":[[364,2]]},"235":{"position":[[769,2]]},"440":{"position":[[113,2]]},"530":{"position":[[532,2]]},"630":{"position":[[253,2]]},"727":{"position":[[939,2]]},"770":{"position":[[66,2]]},"828":{"position":[[323,2]]},"830":{"position":[[190,2]]},"874":{"position":[[312,2]]},"891":{"position":[[128,2]]},"935":{"position":[[85,2],[133,2]]}}}],["具体操作",{"_index":2032,"t":{"431":{"position":[[37,4]]},"574":{"position":[[123,4]]}}}],["具体步骤",{"_index":1037,"t":{"138":{"position":[[217,4]]},"142":{"position":[[521,4]]},"261":{"position":[[0,4]]}}}],["具备",{"_index":2244,"t":{"461":{"position":[[28,2]]},"661":{"position":[[104,2]]},"959":{"position":[[28,2]]}}}],["具有",{"_index":1646,"t":{"308":{"position":[[2386,2],[2425,2]]},"376":{"position":[[95,2]]},"413":{"position":[[47,2]]},"533":{"position":[[11,2]]},"653":{"position":[[164,2]]}}}],["兼容",{"_index":2678,"t":{"597":{"position":[[11,2]]},"679":{"position":[[130,2]]},"870":{"position":[[31,2]]}}}],["兼容性",{"_index":793,"t":{"110":{"position":[[112,3]]},"427":{"position":[[37,3]]},"461":{"position":[[33,3]]},"679":{"position":[[169,3],[202,3],[245,3]]},"806":{"position":[[308,3]]},"862":{"position":[[68,3]]},"868":{"position":[[19,3]]},"874":{"position":[[20,3]]},"876":{"position":[[20,3]]},"878":{"position":[[19,3]]},"880":{"position":[[20,3]]},"882":{"position":[[20,3]]},"884":{"position":[[20,3]]}}}],["内",{"_index":163,"t":{"23":{"position":[[8,1]]},"50":{"position":[[22,1],[312,1]]},"184":{"position":[[377,1]]},"218":{"position":[[377,1]]},"535":{"position":[[63,1],[83,1]]},"814":{"position":[[31,1]]},"839":{"position":[[121,1]]}}}],["内存",{"_index":312,"t":{"34":{"position":[[280,2],[290,2]]},"57":{"position":[[733,2]]},"149":{"position":[[0,2]]},"151":{"position":[[0,2],[21,2]]},"153":{"position":[[103,2]]},"180":{"position":[[15,2]]},"184":{"position":[[79,2]]},"201":{"position":[[11,2]]},"212":{"position":[[15,2]]},"218":{"position":[[79,2]]},"301":{"position":[[899,2]]},"361":{"position":[[758,2],[763,2],[785,2],[2945,2]]},"365":{"position":[[333,2],[592,2],[851,2],[1112,2],[1733,2],[1738,2],[1760,2]]},"378":{"position":[[57,2]]},"465":{"position":[[384,2]]},"761":{"position":[[48,2],[66,2],[137,2],[155,2]]},"874":{"position":[[321,2],[478,2]]},"911":{"position":[[11,2]]}}}],["内容",{"_index":97,"t":{"10":{"position":[[56,2]]},"12":{"position":[[176,2]]},"14":{"position":[[75,2]]},"458":{"position":[[37,2]]},"516":{"position":[[172,2]]},"720":{"position":[[97,2]]},"748":{"position":[[185,2]]},"874":{"position":[[35,2]]},"954":{"position":[[47,2]]}}}],["内核",{"_index":1253,"t":{"184":{"position":[[322,2],[399,2]]},"218":{"position":[[322,2],[399,2]]}}}],["内置",{"_index":1366,"t":{"196":{"position":[[18,2],[278,2]]},"241":{"position":[[21,2],[231,2]]},"485":{"position":[[179,2]]},"519":{"position":[[14,2]]},"542":{"position":[[197,2]]},"679":{"position":[[11,2]]}}}],["内部",{"_index":441,"t":{"48":{"position":[[318,2]]},"192":{"position":[[19,2]]},"229":{"position":[[25,2]]},"353":{"position":[[23,2]]},"365":{"position":[[1483,2]]},"376":{"position":[[120,2]]},"378":{"position":[[11,2]]},"473":{"position":[[22,2]]},"610":{"position":[[0,2],[251,2]]},"716":{"position":[[18,2]]},"770":{"position":[[22,2]]},"780":{"position":[[91,2]]},"854":{"position":[[88,2]]},"976":{"position":[[22,2]]}}}],["再有",{"_index":2114,"t":{"444":{"position":[[275,2]]}}}],["再次",{"_index":417,"t":{"46":{"position":[[453,2]]},"559":{"position":[[147,2]]},"593":{"position":[[27,2]]},"965":{"position":[[147,2]]},"971":{"position":[[55,2]]}}}],["冗余",{"_index":3328,"t":{"880":{"position":[[350,2]]},"882":{"position":[[380,2]]}}}],["写",{"_index":646,"t":{"69":{"position":[[216,1]]},"127":{"position":[[119,1]]},"361":{"position":[[948,1],[995,1]]},"365":{"position":[[1923,1]]},"409":{"position":[[6,1]]},"413":{"position":[[49,1]]},"444":{"position":[[320,1],[538,1],[544,1]]},"455":{"position":[[41,1],[64,1],[1017,1]]},"512":{"position":[[47,1]]},"626":{"position":[[36,1]]},"894":{"position":[[47,1]]},"928":{"position":[[57,1]]}}}],["写入",{"_index":1121,"t":{"157":{"position":[[307,2],[316,2]]},"365":{"position":[[2022,2]]},"413":{"position":[[32,2],[63,2]]},"507":{"position":[[291,2],[459,2],[476,2],[640,2],[662,2],[816,2]]},"691":{"position":[[69,2]]},"868":{"position":[[170,2]]},"880":{"position":[[53,2],[64,2]]},"884":{"position":[[56,2]]}}}],["写成",{"_index":2153,"t":{"447":{"position":[[172,2],[991,2]]}}}],["写法",{"_index":1771,"t":{"361":{"position":[[853,2]]},"365":{"position":[[1828,2]]},"758":{"position":[[87,2]]}}}],["冠名",{"_index":3448,"t":{"967":{"position":[[59,2]]}}}],["冤死",{"_index":1818,"t":{"365":{"position":[[1415,2]]}}}],["决定",{"_index":528,"t":{"57":{"position":[[411,2]]},"272":{"position":[[570,2]]},"308":{"position":[[396,2]]},"347":{"position":[[402,2]]},"413":{"position":[[126,2]]},"514":{"position":[[105,2]]},"681":{"position":[[35,2]]}}}],["减少",{"_index":2002,"t":{"415":{"position":[[55,2],[69,2],[151,2]]},"872":{"position":[[137,2]]}}}],["几个",{"_index":2352,"t":{"503":{"position":[[45,2],[51,2]]},"595":{"position":[[136,2]]},"597":{"position":[[196,2]]},"748":{"position":[[150,2],[168,2]]}}}],["几乎",{"_index":901,"t":{"122":{"position":[[17,2]]},"440":{"position":[[318,2]]},"444":{"position":[[12,2]]},"509":{"position":[[37,2]]},"570":{"position":[[33,2]]}}}],["几段",{"_index":1648,"t":{"308":{"position":[[2419,2]]}}}],["几百万",{"_index":1920,"t":{"378":{"position":[[92,3]]}}}],["几近",{"_index":2206,"t":{"455":{"position":[[9,2]]}}}],["凡是",{"_index":2229,"t":{"455":{"position":[[866,2]]}}}],["凭证",{"_index":3071,"t":{"770":{"position":[[48,2]]}}}],["凯",{"_index":3356,"t":{"906":{"position":[[4,1]]}}}],["出",{"_index":1678,"t":{"334":{"position":[[76,1]]},"338":{"position":[[46,1]]},"347":{"position":[[1463,1]]},"444":{"position":[[252,1]]},"542":{"position":[[95,1]]}}}],["出众",{"_index":2823,"t":{"679":{"position":[[191,2],[225,2]]}}}],["出去",{"_index":3255,"t":{"859":{"position":[[1178,2]]}}}],["出来",{"_index":369,"t":{"44":{"position":[[16,2]]}}}],["出现",{"_index":2363,"t":{"505":{"position":[[95,2]]},"959":{"position":[[21,2]]}}}],["出错",{"_index":1819,"t":{"365":{"position":[[1486,2]]}}}],["函数",{"_index":401,"t":{"46":{"position":[[373,2]]},"57":{"position":[[379,2]]},"69":{"position":[[187,2]]},"120":{"position":[[547,2]]},"127":{"position":[[248,2],[271,2],[524,2],[547,2]]},"166":{"position":[[447,2]]},"184":{"position":[[919,2],[1698,2]]},"218":{"position":[[919,2],[1698,2]]},"252":{"position":[[447,2]]},"284":{"position":[[433,2]]},"290":{"position":[[50,2],[61,2],[73,2],[780,2]]},"308":{"position":[[364,2]]},"347":{"position":[[370,2]]},"365":{"position":[[46,2],[181,2],[1301,2],[2084,2]]},"411":{"position":[[22,2]]},"413":{"position":[[22,2]]},"512":{"position":[[83,2]]},"672":{"position":[[623,2]]},"674":{"position":[[838,2]]},"684":{"position":[[65,2]]},"780":{"position":[[126,2]]},"830":{"position":[[561,2]]},"862":{"position":[[109,2]]},"894":{"position":[[82,2]]},"928":{"position":[[92,2]]},"969":{"position":[[128,2]]}}}],["函数调用",{"_index":1071,"t":{"146":{"position":[[35,4]]}}}],["分",{"_index":3147,"t":{"820":{"position":[[26,1]]}}}],["分享",{"_index":719,"t":{"91":{"position":[[217,2],[286,2]]},"932":{"position":[[265,2]]}}}],["分别",{"_index":220,"t":{"28":{"position":[[32,2]]},"363":{"position":[[43,2]]},"365":{"position":[[97,2],[122,2]]},"653":{"position":[[21,2]]},"679":{"position":[[22,2]]},"702":{"position":[[1366,2]]},"748":{"position":[[393,2]]},"806":{"position":[[167,2]]}}}],["分割",{"_index":1511,"t":{"268":{"position":[[112,2],[139,2]]},"308":{"position":[[2402,2],[2554,2]]},"347":{"position":[[1030,2]]},"418":{"position":[[20,2]]},"465":{"position":[[362,2]]},"738":{"position":[[82,2]]},"741":{"position":[[44,2],[87,2]]},"818":{"position":[[13,2]]},"957":{"position":[[74,2]]}}}],["分包",{"_index":235,"t":{"28":{"position":[[79,2]]},"180":{"position":[[37,2]]},"212":{"position":[[107,2]]},"292":{"position":[[356,2]]},"321":{"position":[[51,2]]},"336":{"position":[[109,2]]},"361":{"position":[[1498,2],[1788,2]]},"400":{"position":[[17,2]]},"402":{"position":[[9,2]]},"418":{"position":[[55,2]]},"727":{"position":[[1445,2]]},"741":{"position":[[33,2]]},"783":{"position":[[161,2],[222,2],[251,2],[300,2],[336,2]]},"976":{"position":[[48,2]]}}}],["分发",{"_index":1950,"t":{"393":{"position":[[230,2]]}}}],["分布式",{"_index":925,"t":{"125":{"position":[[146,3]]}}}],["分成",{"_index":2138,"t":{"444":{"position":[[553,2]]}}}],["分片",{"_index":1808,"t":{"365":{"position":[[1280,2],[1463,2]]}}}],["分离",{"_index":2235,"t":{"455":{"position":[[1006,2]]}}}],["分解",{"_index":1787,"t":{"361":{"position":[[2083,2]]}}}],["分辨",{"_index":3088,"t":{"783":{"position":[[172,2]]}}}],["分配",{"_index":1259,"t":{"184":{"position":[[438,2]]},"218":{"position":[[438,2]]},"613":{"position":[[23,2]]},"615":{"position":[[27,2]]}}}],["切换",{"_index":290,"t":{"34":{"position":[[100,2],[182,2]]}}}],["列表",{"_index":3327,"t":{"880":{"position":[[319,2]]}}}],["刚好",{"_index":1775,"t":{"361":{"position":[[1101,2],[1113,2]]}}}],["创建",{"_index":582,"t":{"57":{"position":[[1967,2]]},"116":{"position":[[15,2]]},"120":{"position":[[12,2]]},"127":{"position":[[712,2]]},"129":{"position":[[31,2]]},"153":{"position":[[15,2],[45,2],[73,2]]},"159":{"position":[[25,2],[91,2],[107,2]]},"169":{"position":[[2,2],[9,2]]},"171":{"position":[[2,2],[9,2]]},"173":{"position":[[2,2]]},"192":{"position":[[12,2]]},"194":{"position":[[535,2]]},"216":{"position":[[15,2]]},"225":{"position":[[4,2],[44,2],[431,2],[829,2],[1349,2]]},"229":{"position":[[18,2]]},"233":{"position":[[541,2]]},"237":{"position":[[22,2]]},"246":{"position":[[29,2]]},"248":{"position":[[67,2]]},"272":{"position":[[1761,2]]},"284":{"position":[[4,2]]},"288":{"position":[[0,2],[307,2]]},"301":{"position":[[2880,2]]},"308":{"position":[[2565,2]]},"347":{"position":[[2537,2]]},"361":{"position":[[3,2]]},"374":{"position":[[39,2]]},"376":{"position":[[625,2]]},"378":{"position":[[40,2]]},"391":{"position":[[4,2]]},"413":{"position":[[114,2]]},"415":{"position":[[85,2]]},"477":{"position":[[20,2]]},"485":{"position":[[155,2]]},"516":{"position":[[62,2]]},"528":{"position":[[111,2]]},"542":{"position":[[38,2]]},"554":{"position":[[210,2]]},"561":{"position":[[783,2]]},"579":{"position":[[98,2],[109,2]]},"626":{"position":[[8,2]]},"630":{"position":[[84,2]]},"632":{"position":[[16,2]]},"672":{"position":[[47,2],[186,2],[783,2]]},"674":{"position":[[158,2],[682,2]]},"707":{"position":[[106,2]]},"758":{"position":[[133,2]]},"796":{"position":[[2,2]]},"802":{"position":[[5,2]]},"843":{"position":[[2,2]]},"849":{"position":[[20,2]]},"872":{"position":[[139,2]]},"874":{"position":[[249,2]]},"909":{"position":[[196,2]]},"969":{"position":[[324,2]]}}}],["创建对象",{"_index":2351,"t":{"503":{"position":[[40,4]]}}}],["初始",{"_index":248,"t":{"32":{"position":[[17,2]]},"157":{"position":[[305,2]]},"184":{"position":[[433,2]]},"218":{"position":[[433,2]]},"301":{"position":[[1193,2]]},"378":{"position":[[30,2]]},"615":{"position":[[151,2]]}}}],["初始值",{"_index":3293,"t":{"872":{"position":[[668,3]]}}}],["初始化",{"_index":331,"t":{"38":{"position":[[16,3]]},"134":{"position":[[1485,3],[1983,3]]},"166":{"position":[[500,3]]},"186":{"position":[[75,3]]},"223":{"position":[[2,3]]},"225":{"position":[[732,3]]},"252":{"position":[[500,3]]},"523":{"position":[[1069,3]]},"552":{"position":[[49,3]]},"681":{"position":[[159,3]]},"886":{"position":[[20,3]]},"969":{"position":[[118,3]]}}}],["初步",{"_index":3070,"t":{"770":{"position":[[6,2]]}}}],["删除",{"_index":2646,"t":{"579":{"position":[[116,2]]},"586":{"position":[[70,2]]},"796":{"position":[[14,2]]},"872":{"position":[[479,2],[547,2],[1047,2]]},"874":{"position":[[492,2]]},"876":{"position":[[212,2]]},"878":{"position":[[211,2]]},"880":{"position":[[347,2]]},"882":{"position":[[377,2]]},"884":{"position":[[281,2]]},"891":{"position":[[73,2]]},"969":{"position":[[14,2]]}}}],["判定",{"_index":2405,"t":{"516":{"position":[[167,2]]}}}],["判断",{"_index":1198,"t":{"166":{"position":[[285,2],[591,2]]},"252":{"position":[[285,2],[591,2]]},"336":{"position":[[59,2],[182,2]]},"340":{"position":[[156,2],[253,2],[611,2]]},"361":{"position":[[706,2]]},"365":{"position":[[1681,2]]},"415":{"position":[[160,2]]},"485":{"position":[[129,2]]},"493":{"position":[[444,2]]},"507":{"position":[[389,2],[570,2]]},"574":{"position":[[231,2]]},"727":{"position":[[953,2]]},"774":{"position":[[29,2]]},"780":{"position":[[325,2]]},"828":{"position":[[342,2]]},"832":{"position":[[825,2]]},"874":{"position":[[482,2]]},"878":{"position":[[674,2]]}}}],["利于",{"_index":2541,"t":{"542":{"position":[[120,2]]}}}],["利用",{"_index":2801,"t":{"670":{"position":[[6,2]]},"754":{"position":[[0,2]]}}}],["别的",{"_index":2191,"t":{"449":{"position":[[260,2]]}}}],["到期",{"_index":2677,"t":{"595":{"position":[[240,2]]},"597":{"position":[[263,2]]}}}],["到达",{"_index":1152,"t":{"159":{"position":[[228,2]]},"559":{"position":[[70,2]]},"653":{"position":[[203,2]]}}}],["制作",{"_index":769,"t":{"104":{"position":[[196,2]]}}}],["制定",{"_index":3091,"t":{"783":{"position":[[249,2]]}}}],["刷新",{"_index":2165,"t":{"447":{"position":[[862,2]]}}}],["前",{"_index":1162,"t":{"159":{"position":[[611,1],[802,1]]},"194":{"position":[[213,1]]},"233":{"position":[[216,1]]},"284":{"position":[[30,1]]},"304":{"position":[[40,1]]},"336":{"position":[[186,1]]},"340":{"position":[[257,1],[747,1],[790,1]]},"365":{"position":[[1397,1]]},"404":{"position":[[56,1],[122,1]]},"455":{"position":[[0,1],[1008,1]]},"554":{"position":[[150,1]]},"780":{"position":[[568,1]]},"783":{"position":[[76,1]]},"866":{"position":[[24,1]]},"973":{"position":[[12,1]]}}}],["前后",{"_index":2342,"t":{"498":{"position":[[72,2]]},"917":{"position":[[119,2]]}}}],["前往",{"_index":2947,"t":{"716":{"position":[[136,2]]}}}],["前期",{"_index":62,"t":{"7":{"position":[[77,2]]},"334":{"position":[[33,2]]}}}],["前端",{"_index":2236,"t":{"455":{"position":[[1023,2]]}}}],["前缀",{"_index":2224,"t":{"455":{"position":[[607,2]]}}}],["前面",{"_index":1404,"t":{"223":{"position":[[884,2]]},"225":{"position":[[1220,2],[1774,2]]},"229":{"position":[[476,2]]},"507":{"position":[[1258,2]]},"514":{"position":[[296,2]]},"859":{"position":[[930,2]]}}}],["剩下",{"_index":1786,"t":{"361":{"position":[[1785,2]]}}}],["剩余",{"_index":1780,"t":{"361":{"position":[[1286,2],[1574,2],[1766,2],[1962,2]]}}}],["功能",{"_index":135,"t":{"16":{"position":[[39,2]]},"23":{"position":[[18,2]]},"42":{"position":[[7,2]]},"106":{"position":[[4,2]]},"118":{"position":[[75,2]]},"132":{"position":[[296,2]]},"151":{"position":[[68,2],[78,2]]},"166":{"position":[[84,2]]},"186":{"position":[[50,2]]},"199":{"position":[[21,2]]},"205":{"position":[[87,2]]},"220":{"position":[[50,2]]},"225":{"position":[[29,2],[238,2]]},"246":{"position":[[38,2]]},"252":{"position":[[84,2]]},"284":{"position":[[374,2]]},"389":{"position":[[8,2],[16,2]]},"391":{"position":[[55,2]]},"455":{"position":[[898,2],[916,2]]},"493":{"position":[[13,2]]},"530":{"position":[[1,2],[537,2]]},"533":{"position":[[15,2]]},"559":{"position":[[30,2]]},"586":{"position":[[17,2]]},"602":{"position":[[0,2]]},"628":{"position":[[48,2],[106,2]]},"657":{"position":[[29,2]]},"661":{"position":[[69,2],[108,2]]},"693":{"position":[[1,2]]},"778":{"position":[[4,2]]},"787":{"position":[[171,2]]},"806":{"position":[[217,2],[267,2],[383,2],[491,2]]},"814":{"position":[[79,2]]},"824":{"position":[[39,2]]},"828":{"position":[[13,2]]},"836":{"position":[[1,2]]},"872":{"position":[[162,2]]},"878":{"position":[[70,2],[318,2]]},"884":{"position":[[312,2]]},"901":{"position":[[29,2]]},"925":{"position":[[504,2]]},"935":{"position":[[36,2],[65,2]]},"938":{"position":[[25,2]]},"940":{"position":[[14,2]]},"942":{"position":[[2,2]]},"944":{"position":[[12,2]]},"946":{"position":[[2,2]]},"948":{"position":[[2,2]]},"950":{"position":[[25,2],[65,2]]},"954":{"position":[[2,2],[11,2],[52,2]]},"959":{"position":[[18,2],[67,2],[75,2]]},"961":{"position":[[22,2],[27,2],[32,2],[37,2],[81,2],[89,2],[200,2]]},"965":{"position":[[190,2]]},"971":{"position":[[32,2],[44,2]]}}}],["功能丰富",{"_index":3177,"t":{"824":{"position":[[62,4]]}}}],["加",{"_index":6,"t":{"3":{"position":[[16,1]]},"866":{"position":[[113,1],[147,1]]}}}],["加上",{"_index":1654,"t":{"308":{"position":[[2506,2]]}}}],["加入",{"_index":459,"t":{"50":{"position":[[130,2]]},"839":{"position":[[104,2]]},"841":{"position":[[69,2]]},"843":{"position":[[333,2]]},"849":{"position":[[10,2]]},"872":{"position":[[742,2]]}}}],["加密",{"_index":1733,"t":{"350":{"position":[[27,2],[92,2],[178,2]]},"790":{"position":[[64,2]]}}}],["加强",{"_index":3406,"t":{"935":{"position":[[28,2]]}}}],["加强版",{"_index":3470,"t":{"978":{"position":[[25,3]]}}}],["加法",{"_index":3003,"t":{"734":{"position":[[285,2]]}}}],["加载",{"_index":770,"t":{"104":{"position":[[203,2]]},"120":{"position":[[151,2]]},"166":{"position":[[310,2]]},"225":{"position":[[556,2]]},"252":{"position":[[310,2]]},"284":{"position":[[166,2]]},"286":{"position":[[192,2]]},"447":{"position":[[1255,2]]},"521":{"position":[[171,2],[308,2],[341,2],[431,2],[435,2]]},"816":{"position":[[362,2]]}}}],["加速",{"_index":2249,"t":{"463":{"position":[[22,2]]},"718":{"position":[[81,2]]}}}],["务必",{"_index":2866,"t":{"699":{"position":[[19,2]]}}}],["动作",{"_index":2766,"t":{"653":{"position":[[168,2]]}}}],["动力",{"_index":1829,"t":{"368":{"position":[[12,2]]}}}],["动态",{"_index":1192,"t":{"166":{"position":[[171,2]]},"252":{"position":[[171,2]]},"440":{"position":[[57,2],[123,2],[143,2],[264,2]]},"455":{"position":[[368,2],[378,2]]},"790":{"position":[[10,2]]},"872":{"position":[[583,2],[1011,2]]}}}],["包",{"_index":454,"t":{"50":{"position":[[108,1],[302,1]]},"166":{"position":[[422,1]]},"180":{"position":[[41,1]]},"184":{"position":[[1112,1],[1118,1],[1166,1],[1891,1],[1897,1],[1945,1]]},"212":{"position":[[111,1]]},"218":{"position":[[1112,1],[1118,1],[1166,1],[1891,1],[1897,1],[1945,1]]},"252":{"position":[[422,1]]},"292":{"position":[[428,1],[448,1]]},"321":{"position":[[123,1],[143,1]]},"336":{"position":[[209,1]]},"340":{"position":[[280,1]]},"361":{"position":[[1207,1],[1210,1],[1285,1],[1493,1],[1774,1],[1780,1],[1971,1],[1980,1],[2085,1]]},"400":{"position":[[15,1]]},"402":{"position":[[7,1]]},"418":{"position":[[53,1]]},"468":{"position":[[14,1]]},"485":{"position":[[271,1],[280,1]]},"503":{"position":[[0,1],[158,1]]},"507":{"position":[[1743,1]]},"509":{"position":[[8,1]]},"702":{"position":[[1553,1]]},"707":{"position":[[198,1]]},"736":{"position":[[342,1]]},"738":{"position":[[106,1]]},"741":{"position":[[31,1]]},"809":{"position":[[13,1]]}}}],["包包",{"_index":2913,"t":{"702":{"position":[[1645,2]]}}}],["包含",{"_index":632,"t":{"66":{"position":[[73,2]]},"75":{"position":[[73,2]]},"86":{"position":[[118,2]]},"184":{"position":[[1336,2]]},"218":{"position":[[1336,2]]},"225":{"position":[[835,2]]},"301":{"position":[[1406,2]]},"444":{"position":[[159,2],[177,2]]},"449":{"position":[[86,2]]},"516":{"position":[[175,2]]},"581":{"position":[[50,2],[155,2]]},"780":{"position":[[132,2]]},"935":{"position":[[40,2]]},"954":{"position":[[44,2]]}}}],["包头",{"_index":423,"t":{"46":{"position":[[506,2]]},"53":{"position":[[5,2],[13,2],[28,2],[85,2]]},"57":{"position":[[355,2],[1040,2],[1078,2]]},"304":{"position":[[92,2],[109,2]]},"308":{"position":[[340,2],[1401,2],[1557,2],[2381,2]]},"340":{"position":[[46,2],[736,2],[756,2]]},"343":{"position":[[14,2]]},"347":{"position":[[346,2],[916,2],[953,2]]},"365":{"position":[[1434,2]]},"400":{"position":[[2,2]]},"402":{"position":[[32,2],[58,2],[114,2]]},"404":{"position":[[4,2],[51,2],[111,2]]},"470":{"position":[[228,2],[456,2],[811,2]]},"666":{"position":[[33,2]]},"668":{"position":[[8,2]]},"697":{"position":[[90,2]]},"741":{"position":[[107,2]]},"783":{"position":[[310,2]]},"957":{"position":[[64,2]]}}}],["包括",{"_index":108,"t":{"12":{"position":[[78,2]]},"125":{"position":[[142,2]]},"359":{"position":[[41,2]]},"444":{"position":[[127,2],[153,2]]},"455":{"position":[[620,2]]},"579":{"position":[[19,2]]},"586":{"position":[[20,2]]},"653":{"position":[[257,2]]}}}],["包装",{"_index":89,"t":{"10":{"position":[[24,2]]},"12":{"position":[[24,2]]},"14":{"position":[[24,2]]}}}],["化",{"_index":196,"t":{"25":{"position":[[220,1]]},"301":{"position":[[339,1],[793,1]]},"361":{"position":[[790,1]]},"365":{"position":[[1765,1]]},"554":{"position":[[65,1]]},"804":{"position":[[39,1]]},"832":{"position":[[1751,1]]},"880":{"position":[[167,1]]}}}],["区",{"_index":1694,"t":{"340":{"position":[[97,1]]},"347":{"position":[[1212,1],[1427,1],[1566,1]]},"702":{"position":[[1742,1]]}}}],["区分",{"_index":1028,"t":{"138":{"position":[[45,2],[154,2]]},"705":{"position":[[67,2]]},"748":{"position":[[431,2]]}}}],["区别",{"_index":2231,"t":{"455":{"position":[[955,2],[973,2]]},"653":{"position":[[54,2]]},"935":{"position":[[89,2]]}}}],["区域",{"_index":2584,"t":{"554":{"position":[[113,2],[204,2],[231,2]]}}}],["区间",{"_index":1500,"t":{"268":{"position":[[0,2],[47,2],[96,2],[165,2]]},"404":{"position":[[33,2],[94,2],[159,2]]}}}],["千万",{"_index":1285,"t":{"184":{"position":[[724,2]]},"218":{"position":[[724,2]]},"378":{"position":[[117,2]]}}}],["升级",{"_index":1457,"t":{"257":{"position":[[8,2]]},"275":{"position":[[19,2]]},"440":{"position":[[301,2]]},"866":{"position":[[14,2],[22,2],[57,2]]},"872":{"position":[[38,2]]},"961":{"position":[[130,2],[138,2],[146,2],[154,2]]},"965":{"position":[[205,2]]}}}],["半",{"_index":1268,"t":{"184":{"position":[[539,1]]},"218":{"position":[[539,1]]}}}],["半包",{"_index":1790,"t":{"361":{"position":[[2542,2]]}}}],["华丽",{"_index":1859,"t":{"370":{"position":[[218,2]]}}}],["协作",{"_index":2208,"t":{"455":{"position":[[30,2]]}}}],["协助",{"_index":2533,"t":{"542":{"position":[[28,2]]},"935":{"position":[[130,2]]},"961":{"position":[[68,2],[83,2]]}}}],["协同",{"_index":3284,"t":{"872":{"position":[[399,2]]}}}],["协议",{"_index":33,"t":{"5":{"position":[[74,2],[80,2]]},"18":{"position":[[40,2]]},"55":{"position":[[12,2],[24,2]]},"78":{"position":[[14,2],[72,2],[84,2],[186,2],[199,2],[299,2],[317,2]]},"80":{"position":[[68,2],[988,2],[1642,2]]},"125":{"position":[[32,2],[66,2],[77,2]]},"129":{"position":[[10,2],[23,2]]},"162":{"position":[[21,2]]},"166":{"position":[[343,2]]},"182":{"position":[[27,2]]},"184":{"position":[[1338,2]]},"199":{"position":[[11,2]]},"214":{"position":[[27,2]]},"218":{"position":[[1338,2]]},"248":{"position":[[21,2],[37,2]]},"252":{"position":[[343,2]]},"255":{"position":[[7,2]]},"257":{"position":[[10,2]]},"259":{"position":[[7,2]]},"270":{"position":[[14,2],[26,2]]},"275":{"position":[[16,2],[21,2]]},"306":{"position":[[12,2],[43,2]]},"345":{"position":[[11,2],[23,2]]},"347":{"position":[[995,2]]},"391":{"position":[[24,2],[46,2]]},"402":{"position":[[19,2]]},"498":{"position":[[113,2]]},"514":{"position":[[87,2]]},"516":{"position":[[58,2]]},"568":{"position":[[14,2]]},"579":{"position":[[26,2]]},"581":{"position":[[85,2]]},"630":{"position":[[60,2]]},"653":{"position":[[103,2],[149,2]]},"697":{"position":[[8,2],[12,2]]},"729":{"position":[[86,2]]},"748":{"position":[[133,2],[191,2]]},"752":{"position":[[5,2]]},"778":{"position":[[0,2],[29,2],[148,2],[171,2],[183,2],[202,2]]},"780":{"position":[[135,2],[328,2]]},"783":{"position":[[41,2],[46,2],[66,2],[107,2],[133,2],[157,2],[202,2],[212,2],[267,2],[391,2]]},"785":{"position":[[34,2],[101,2]]},"790":{"position":[[70,2]]},"806":{"position":[[188,2],[239,2]]},"820":{"position":[[73,2]]},"874":{"position":[[420,2]]},"909":{"position":[[29,2]]},"913":{"position":[[31,2]]},"932":{"position":[[129,2]]},"963":{"position":[[60,2]]}}}],["卓越",{"_index":3176,"t":{"824":{"position":[[59,2]]}}}],["单",{"_index":1384,"t":{"212":{"position":[[30,1]]},"442":{"position":[[71,1]]},"521":{"position":[[56,1]]},"544":{"position":[[70,1]]},"550":{"position":[[63,1]]},"554":{"position":[[52,1],[115,1]]},"668":{"position":[[20,1]]},"874":{"position":[[203,1]]},"876":{"position":[[194,1]]},"880":{"position":[[142,1]]}}}],["单一",{"_index":334,"t":{"38":{"position":[[24,2]]},"357":{"position":[[193,2]]},"413":{"position":[[121,2]]}}}],["单个",{"_index":2448,"t":{"526":{"position":[[75,2],[86,2],[119,2],[231,2]]},"723":{"position":[[12,2]]},"729":{"position":[[10,2]]},"909":{"position":[[13,2]]}}}],["单位",{"_index":1227,"t":{"184":{"position":[[32,2],[172,2]]},"218":{"position":[[32,2],[172,2]]},"581":{"position":[[130,2]]},"659":{"position":[[31,2]]}}}],["单体",{"_index":1088,"t":{"151":{"position":[[18,2]]}}}],["单元测试",{"_index":1497,"t":{"265":{"position":[[2,4]]},"542":{"position":[[127,4]]}}}],["单击",{"_index":2941,"t":{"716":{"position":[[0,2]]}}}],["单功能",{"_index":2963,"t":{"720":{"position":[[62,3]]}}}],["单核",{"_index":2459,"t":{"526":{"position":[[222,2]]}}}],["单独",{"_index":88,"t":{"10":{"position":[[22,2]]},"12":{"position":[[22,2]]},"14":{"position":[[22,2]]},"110":{"position":[[90,2]]},"444":{"position":[[84,2]]},"447":{"position":[[1237,2]]},"468":{"position":[[39,2]]},"686":{"position":[[476,2]]}}}],["单线程",{"_index":1385,"t":{"212":{"position":[[34,3]]},"225":{"position":[[222,3]]},"340":{"position":[[16,3]]},"530":{"position":[[131,3]]}}}],["单项",{"_index":3103,"t":{"787":{"position":[[54,2]]}}}],["博客地址",{"_index":2329,"t":{"495":{"position":[[28,4]]}}}],["占",{"_index":2359,"t":{"505":{"position":[[46,1]]},"526":{"position":[[125,1]]},"748":{"position":[[210,1]]},"820":{"position":[[167,1],[195,1]]}}}],["占位",{"_index":1730,"t":{"347":{"position":[[1511,2]]}}}],["占用",{"_index":1916,"t":{"378":{"position":[[53,2]]},"783":{"position":[[113,2]]},"820":{"position":[[100,2]]}}}],["印度",{"_index":58,"t":{"7":{"position":[[54,2]]}}}],["危险",{"_index":1598,"t":{"297":{"position":[[178,2],[279,2],[351,2]]}}}],["即使",{"_index":1377,"t":{"207":{"position":[[344,2]]},"400":{"position":[[55,2]]},"544":{"position":[[96,2]]},"689":{"position":[[172,2]]},"828":{"position":[[90,2]]}}}],["即可",{"_index":344,"t":{"40":{"position":[[74,2]]},"60":{"position":[[490,2]]},"69":{"position":[[220,2]]},"78":{"position":[[214,2],[335,2]]},"118":{"position":[[27,2],[66,2]]},"120":{"position":[[550,2]]},"142":{"position":[[560,2]]},"146":{"position":[[39,2]]},"153":{"position":[[22,2]]},"166":{"position":[[31,2],[75,2]]},"184":{"position":[[330,2],[407,2],[1325,2]]},"186":{"position":[[41,2]]},"205":{"position":[[33,2],[78,2]]},"218":{"position":[[330,2],[407,2],[1325,2]]},"220":{"position":[[41,2]]},"237":{"position":[[50,2]]},"252":{"position":[[31,2],[75,2]]},"261":{"position":[[617,2],[975,2]]},"288":{"position":[[41,2]]},"290":{"position":[[1099,2]]},"292":{"position":[[59,2]]},"295":{"position":[[64,2]]},"301":{"position":[[1444,2]]},"308":{"position":[[2556,2]]},"319":{"position":[[44,2]]},"321":{"position":[[22,2]]},"340":{"position":[[19,2],[769,2]]},"447":{"position":[[915,2]]},"449":{"position":[[68,2]]},"473":{"position":[[18,2]]},"485":{"position":[[281,2]]},"516":{"position":[[108,2],[160,2]]},"526":{"position":[[123,2]]},"530":{"position":[[47,2]]},"542":{"position":[[233,2]]},"550":{"position":[[50,2]]},"552":{"position":[[23,2]]},"554":{"position":[[289,2]]},"561":{"position":[[493,2]]},"572":{"position":[[16,2]]},"595":{"position":[[114,2]]},"610":{"position":[[19,2]]},"615":{"position":[[116,2]]},"632":{"position":[[21,2]]},"641":{"position":[[93,2]]},"659":{"position":[[28,2]]},"661":{"position":[[153,2]]},"681":{"position":[[81,2]]},"686":{"position":[[176,2]]},"693":{"position":[[35,2]]},"707":{"position":[[199,2]]},"718":{"position":[[39,2],[204,2],[242,2]]},"738":{"position":[[9,2],[141,2]]},"750":{"position":[[221,2]]},"772":{"position":[[27,2]]},"780":{"position":[[148,2]]},"811":{"position":[[22,2]]},"816":{"position":[[34,2]]},"834":{"position":[[30,2]]},"836":{"position":[[35,2]]},"841":{"position":[[67,2]]},"870":{"position":[[206,2]]},"872":{"position":[[1099,2]]},"925":{"position":[[68,2],[142,2]]},"932":{"position":[[34,2]]},"969":{"position":[[139,2]]},"971":{"position":[[53,2],[105,2]]}}}],["即将",{"_index":1195,"t":{"166":{"position":[[223,2],[474,2]]},"252":{"position":[[223,2],[474,2]]},"281":{"position":[[17,2]]},"648":{"position":[[383,2]]},"727":{"position":[[1319,2]]}}}],["即时",{"_index":207,"t":{"25":{"position":[[375,2]]},"235":{"position":[[174,2]]}}}],["卸载",{"_index":3318,"t":{"878":{"position":[[66,2]]},"969":{"position":[[12,2]]}}}],["历史",{"_index":2717,"t":{"615":{"position":[[12,2]]}}}],["压缩",{"_index":1323,"t":{"184":{"position":[[1167,2],[1946,2]]},"218":{"position":[[1167,2],[1946,2]]},"586":{"position":[[80,2]]},"610":{"position":[[10,2],[177,2],[246,2],[275,2],[292,2],[356,2],[461,2],[561,2]]},"689":{"position":[[270,2]]},"798":{"position":[[54,2]]},"876":{"position":[[60,2],[94,2],[118,2]]}}}],["压缩工具",{"_index":2954,"t":{"718":{"position":[[104,4]]}}}],["原",{"_index":1,"t":{"3":{"position":[[3,1]]},"889":{"position":[[0,1]]},"891":{"position":[[2,1]]}}}],["原则",{"_index":2079,"t":{"440":{"position":[[6,2]]}}}],["原则上",{"_index":3427,"t":{"961":{"position":[[219,3]]}}}],["原因",{"_index":1151,"t":{"159":{"position":[[209,2]]},"442":{"position":[[1,2],[32,2],[64,2],[102,2]]}}}],["原始",{"_index":250,"t":{"32":{"position":[[22,2]]},"295":{"position":[[1,2]]},"357":{"position":[[51,2]]},"588":{"position":[[16,2]]},"965":{"position":[[188,2]]}}}],["原始数据",{"_index":1347,"t":{"186":{"position":[[200,4]]},"220":{"position":[[207,4]]}}}],["原有",{"_index":1486,"t":{"261":{"position":[[955,2]]}}}],["原理",{"_index":2799,"t":{"668":{"position":[[2,2]]},"670":{"position":[[2,2]]}}}],["原生",{"_index":1773,"t":{"361":{"position":[[1062,2]]},"468":{"position":[[82,2]]}}}],["参",{"_index":960,"t":{"127":{"position":[[264,1],[540,1]]}}}],["参与",{"_index":141,"t":{"18":{"position":[[16,2]]},"210":{"position":[[23,2]]}}}],["参数",{"_index":257,"t":{"32":{"position":[[63,2]]},"34":{"position":[[30,2],[204,2]]},"62":{"position":[[18,2]]},"71":{"position":[[18,2]]},"78":{"position":[[55,2]]},"82":{"position":[[18,2]]},"91":{"position":[[175,2]]},"132":{"position":[[21,2],[259,2],[271,2],[278,2],[339,2],[344,2]]},"134":{"position":[[34,2]]},"286":{"position":[[31,2]]},"301":{"position":[[770,2]]},"340":{"position":[[818,2],[893,2]]},"391":{"position":[[301,2]]},"395":{"position":[[3,2],[16,2],[36,2]]},"440":{"position":[[169,2],[192,2],[230,2]]},"442":{"position":[[15,2],[40,2]]},"444":{"position":[[221,2],[614,2]]},"449":{"position":[[117,2]]},"451":{"position":[[117,2]]},"455":{"position":[[596,2],[788,2],[1037,2]]},"544":{"position":[[114,2],[124,2],[134,2]]},"552":{"position":[[43,2],[119,2]]},"574":{"position":[[174,2],[179,2],[195,2]]},"641":{"position":[[43,2],[56,2]]},"655":{"position":[[361,2]]},"681":{"position":[[62,2],[79,2]]},"686":{"position":[[471,2]]},"691":{"position":[[368,2]]},"738":{"position":[[115,2]]},"780":{"position":[[55,2],[137,2]]},"792":{"position":[[29,2],[45,2]]},"830":{"position":[[198,2],[201,2],[208,2],[306,2]]},"870":{"position":[[219,2]]},"872":{"position":[[761,2],[928,2],[1040,2],[1056,2]]},"874":{"position":[[190,2]]},"880":{"position":[[317,2]]},"925":{"position":[[739,2]]}}}],["参考",{"_index":1937,"t":{"389":{"position":[[67,2]]},"528":{"position":[[109,2]]},"702":{"position":[[1085,2],[1172,2]]}}}],["参阅",{"_index":2306,"t":{"487":{"position":[[61,2]]}}}],["及其",{"_index":18,"t":{"5":{"position":[[19,2]]}}}],["及时",{"_index":1999,"t":{"415":{"position":[[7,2]]}}}],["及时性",{"_index":1311,"t":{"184":{"position":[[1060,3],[1839,3]]},"218":{"position":[[1060,3],[1839,3]]}}}],["双",{"_index":1845,"t":{"370":{"position":[[126,1]]}}}],["双向",{"_index":3384,"t":{"909":{"position":[[208,2]]}}}],["双端",{"_index":3286,"t":{"872":{"position":[[457,2]]}}}],["反",{"_index":2022,"t":{"427":{"position":[[23,1]]},"434":{"position":[[133,1]]},"505":{"position":[[70,1]]},"507":{"position":[[2209,1]]},"519":{"position":[[25,1],[146,1]]},"523":{"position":[[350,1],[2704,1]]}}}],["反向",{"_index":1026,"t":{"136":{"position":[[45,2]]},"138":{"position":[[109,2]]},"140":{"position":[[144,2],[211,2]]},"144":{"position":[[8,2]]},"806":{"position":[[141,2]]}}}],["反咬",{"_index":1854,"t":{"370":{"position":[[186,2]]}}}],["反射",{"_index":2348,"t":{"503":{"position":[[32,2]]},"868":{"position":[[119,2]]}}}],["反应",{"_index":2773,"t":{"659":{"position":[[126,2]]}}}],["反编译",{"_index":2133,"t":{"444":{"position":[[441,3]]}}}],["反馈",{"_index":2343,"t":{"500":{"position":[[2,2]]},"514":{"position":[[20,2]]},"653":{"position":[[118,2]]},"792":{"position":[[120,2]]},"864":{"position":[[30,2]]},"919":{"position":[[2,2]]},"930":{"position":[[20,2]]}}}],["发",{"_index":1402,"t":{"223":{"position":[[664,1]]},"370":{"position":[[320,1]]},"444":{"position":[[643,1]]},"859":{"position":[[1176,1]]},"866":{"position":[[17,1],[104,1],[138,1]]}}}],["发布",{"_index":116,"t":{"12":{"position":[[133,2]]},"138":{"position":[[374,2],[380,2]]},"389":{"position":[[29,2]]},"391":{"position":[[290,2]]},"397":{"position":[[85,2],[90,2]]},"705":{"position":[[23,2]]},"707":{"position":[[78,2]]},"866":{"position":[[159,2]]},"886":{"position":[[25,2]]}}}],["发现",{"_index":3018,"t":{"741":{"position":[[85,2]]}}}],["发生",{"_index":1144,"t":{"159":{"position":[[58,2],[186,2],[326,2]]},"220":{"position":[[376,2]]},"268":{"position":[[68,2]]},"297":{"position":[[171,2],[272,2],[344,2]]},"338":{"position":[[41,2]]},"455":{"position":[[862,2]]},"743":{"position":[[61,2]]},"792":{"position":[[127,2]]},"820":{"position":[[32,2]]}}}],["发票",{"_index":3426,"t":{"961":{"position":[[216,2]]}}}],["发给",{"_index":3105,"t":{"787":{"position":[[73,2]]}}}],["发起",{"_index":633,"t":{"66":{"position":[[95,2]]},"75":{"position":[[95,2]]},"86":{"position":[[140,2]]},"136":{"position":[[13,2]]},"593":{"position":[[24,2]]},"828":{"position":[[262,2]]},"830":{"position":[[37,2],[70,2],[172,2],[471,2]]},"836":{"position":[[73,2]]}}}],["发送",{"_index":222,"t":{"28":{"position":[[38,2]]},"50":{"position":[[78,2],[81,2],[103,2],[142,2]]},"178":{"position":[[32,2]]},"180":{"position":[[68,2],[73,2]]},"184":{"position":[[22,2],[837,2],[854,2],[888,2],[907,2],[964,2],[1007,2],[1057,2],[1101,2],[1107,2],[1173,2],[1616,2],[1633,2],[1667,2],[1686,2],[1743,2],[1786,2],[1836,2],[1880,2],[1886,2],[1952,2],[2016,2]]},"196":{"position":[[3,2],[25,2],[37,2],[53,2],[72,2],[92,2],[263,2],[285,2],[297,2],[302,2]]},"212":{"position":[[138,2],[143,2]]},"218":{"position":[[22,2],[837,2],[854,2],[888,2],[907,2],[964,2],[1007,2],[1057,2],[1101,2],[1107,2],[1173,2],[1616,2],[1633,2],[1667,2],[1686,2],[1743,2],[1786,2],[1836,2],[1880,2],[1886,2],[1952,2],[2016,2]]},"223":{"position":[[504,2]]},"241":{"position":[[3,2],[28,2],[40,2],[45,2],[216,2],[238,2],[250,2],[255,2],[450,2],[470,2]]},"292":{"position":[[70,2],[126,2],[134,2],[358,2],[364,2],[412,2],[432,2]]},"321":{"position":[[33,2],[43,2],[53,2],[59,2],[107,2],[127,2]]},"336":{"position":[[21,2]]},"340":{"position":[[720,2],[745,2],[788,2],[862,2]]},"359":{"position":[[94,2]]},"361":{"position":[[664,2]]},"365":{"position":[[44,2],[1282,2],[1373,2],[1465,2]]},"418":{"position":[[13,2],[34,2]]},"420":{"position":[[5,2]]},"470":{"position":[[211,2],[232,2],[641,2]]},"485":{"position":[[16,2]]},"495":{"position":[[1140,2]]},"653":{"position":[[89,2],[110,2],[156,2],[174,2],[241,2]]},"668":{"position":[[23,2]]},"672":{"position":[[1043,2]]},"723":{"position":[[9,2],[46,2]]},"727":{"position":[[23,2],[1321,2]]},"743":{"position":[[46,2]]},"758":{"position":[[9,2]]},"787":{"position":[[63,2]]},"794":{"position":[[43,2],[61,2]]},"798":{"position":[[2,2]]},"814":{"position":[[12,2],[53,2]]},"816":{"position":[[399,2]]},"818":{"position":[[1,2],[8,2],[34,2]]},"828":{"position":[[80,2],[101,2]]},"851":{"position":[[102,2],[335,2],[343,2]]},"854":{"position":[[18,2],[43,2],[110,2]]},"857":{"position":[[346,2]]},"859":{"position":[[240,2],[1119,2],[1152,2]]},"872":{"position":[[64,2]]},"874":{"position":[[277,2]]},"876":{"position":[[66,2],[174,2],[219,2]]},"882":{"position":[[47,2],[77,2],[220,2],[229,2],[370,2],[383,2]]},"978":{"position":[[40,2]]}}}],["发送信息",{"_index":3218,"t":{"839":{"position":[[41,4]]}}}],["发送到",{"_index":672,"t":{"78":{"position":[[329,3]]}}}],["发送数据",{"_index":1352,"t":{"186":{"position":[[312,4],[335,4]]},"220":{"position":[[319,4],[342,4]]},"243":{"position":[[4,4]]},"336":{"position":[[2,4]]},"338":{"position":[[27,4]]},"340":{"position":[[105,4],[765,4],[805,4]]},"361":{"position":[[523,4],[533,4],[742,4]]},"363":{"position":[[27,4]]},"365":{"position":[[7,4],[1304,4],[1717,4]]},"485":{"position":[[60,4],[104,4]]},"495":{"position":[[1201,4]]},"756":{"position":[[18,4]]}}}],["发送至",{"_index":1442,"t":{"237":{"position":[[55,3]]}}}],["取",{"_index":2478,"t":{"528":{"position":[[537,1]]},"691":{"position":[[2,1],[146,1],[193,1]]},"826":{"position":[[101,1]]},"828":{"position":[[199,1]]}}}],["取值",{"_index":2911,"t":{"702":{"position":[[1562,2],[1655,2]]}}}],["取得",{"_index":2765,"t":{"653":{"position":[[131,2],[229,2]]}}}],["取消",{"_index":72,"t":{"7":{"position":[[129,2]]},"132":{"position":[[291,2]]},"159":{"position":[[622,2],[931,2]]},"397":{"position":[[88,2],[96,2]]},"442":{"position":[[88,2]]},"581":{"position":[[160,2]]},"657":{"position":[[26,2]]},"661":{"position":[[64,2],[354,2]]},"663":{"position":[[7,2],[21,2],[67,2],[79,2],[166,2],[427,2],[456,2]]},"727":{"position":[[355,2],[1534,2]]},"802":{"position":[[11,2]]},"830":{"position":[[272,2],[721,2]]},"872":{"position":[[757,2]]},"884":{"position":[[252,2]]}}}],["受",{"_index":2822,"t":{"679":{"position":[[181,1],[215,1]]},"750":{"position":[[40,1],[603,1]]}}}],["受限于",{"_index":2294,"t":{"485":{"position":[[210,3]]}}}],["受限制",{"_index":2824,"t":{"679":{"position":[[198,3],[232,3]]}}}],["变",{"_index":2217,"t":{"455":{"position":[[470,1]]}}}],["变得",{"_index":2219,"t":{"455":{"position":[[488,2]]},"891":{"position":[[300,2]]},"909":{"position":[[131,2]]}}}],["变成",{"_index":952,"t":{"127":{"position":[[216,2],[492,2]]}}}],["变更",{"_index":3266,"t":{"866":{"position":[[132,2]]},"891":{"position":[[50,2]]}}}],["变量",{"_index":2380,"t":{"507":{"position":[[1261,2]]}}}],["叠加",{"_index":3199,"t":{"830":{"position":[[501,2]]}}}],["口令",{"_index":1172,"t":{"164":{"position":[[80,2]]},"250":{"position":[[80,2]]},"255":{"position":[[302,2]]},"350":{"position":[[94,2],[174,2]]},"832":{"position":[[261,2]]}}}],["只不过",{"_index":902,"t":{"122":{"position":[[22,3]]}}}],["只是",{"_index":658,"t":{"78":{"position":[[41,2]]},"210":{"position":[[33,2]]},"365":{"position":[[1338,2]]},"787":{"position":[[66,2]]},"976":{"position":[[55,2]]}}}],["只有",{"_index":2192,"t":{"449":{"position":[[272,2]]},"526":{"position":[[237,2]]},"689":{"position":[[178,2]]},"806":{"position":[[468,2]]}}}],["只能",{"_index":375,"t":{"46":{"position":[[9,2]]},"184":{"position":[[876,2],[1655,2]]},"218":{"position":[[876,2],[1655,2]]},"284":{"position":[[9,2]]},"963":{"position":[[24,2]]}}}],["只要",{"_index":476,"t":{"50":{"position":[[270,2]]},"261":{"position":[[968,2]]},"537":{"position":[[499,2]]},"539":{"position":[[14,2]]},"689":{"position":[[224,2]]},"859":{"position":[[1067,2]]},"866":{"position":[[82,2]]}}}],["只读",{"_index":3273,"t":{"870":{"position":[[127,2]]}}}],["叫做",{"_index":1635,"t":{"304":{"position":[[87,2]]},"376":{"position":[[27,2]]}}}],["可以",{"_index":5,"t":{"3":{"position":[[14,2]]},"7":{"position":[[101,2],[127,2]]},"25":{"position":[[241,2]]},"28":{"position":[[68,2],[92,2]]},"44":{"position":[[6,2],[23,2],[42,2],[55,2]]},"48":{"position":[[52,2]]},"53":{"position":[[77,2]]},"55":{"position":[[0,2],[16,2],[28,2],[44,2]]},"57":{"position":[[1619,2]]},"78":{"position":[[19,2]]},"110":{"position":[[82,2]]},"112":{"position":[[24,2]]},"120":{"position":[[32,2]]},"127":{"position":[[726,2]]},"132":{"position":[[311,2]]},"140":{"position":[[150,2],[217,2]]},"142":{"position":[[0,2],[206,2]]},"146":{"position":[[99,2]]},"151":{"position":[[118,2]]},"153":{"position":[[49,2]]},"166":{"position":[[157,2]]},"184":{"position":[[471,2],[1231,2],[2014,2]]},"190":{"position":[[28,2]]},"192":{"position":[[42,2]]},"196":{"position":[[35,2],[295,2]]},"207":{"position":[[425,2]]},"212":{"position":[[79,2]]},"218":{"position":[[471,2],[1231,2],[2014,2]]},"223":{"position":[[985,2]]},"225":{"position":[[10,2],[406,2],[563,2],[738,2],[1321,2],[1875,2],[1908,2],[1918,2]]},"227":{"position":[[29,2]]},"229":{"position":[[48,2]]},"231":{"position":[[8,2]]},"235":{"position":[[65,2],[1143,2]]},"239":{"position":[[151,2]]},"241":{"position":[[38,2],[248,2]]},"252":{"position":[[157,2]]},"255":{"position":[[37,2]]},"268":{"position":[[156,2]]},"270":{"position":[[0,2],[18,2],[30,2]]},"272":{"position":[[1067,2],[1506,2]]},"290":{"position":[[35,2],[750,2],[1258,2]]},"292":{"position":[[94,2]]},"301":{"position":[[2560,2]]},"304":{"position":[[103,2]]},"306":{"position":[[0,2],[35,2],[47,2]]},"308":{"position":[[2028,2],[2464,2]]},"340":{"position":[[585,2]]},"343":{"position":[[118,2]]},"345":{"position":[[0,2],[15,2],[27,2]]},"347":{"position":[[2191,2]]},"357":{"position":[[45,2],[60,2]]},"365":{"position":[[148,2],[175,2],[339,2],[598,2],[857,2],[1118,2],[1459,2]]},"376":{"position":[[106,2],[129,2],[659,2]]},"378":{"position":[[4,2],[18,2],[48,2],[98,2]]},"389":{"position":[[63,2]]},"395":{"position":[[19,2]]},"397":{"position":[[83,2]]},"400":{"position":[[80,2]]},"406":{"position":[[47,2]]},"411":{"position":[[86,2]]},"413":{"position":[[86,2]]},"415":{"position":[[28,2],[164,2],[183,2]]},"420":{"position":[[28,2]]},"431":{"position":[[10,2],[539,2],[858,2]]},"444":{"position":[[536,2],[551,2]]},"447":{"position":[[37,2],[962,2],[977,2],[1007,2],[1230,2]]},"453":{"position":[[25,2]]},"455":{"position":[[784,2],[1069,2]]},"468":{"position":[[61,2],[96,2]]},"470":{"position":[[834,2]]},"479":{"position":[[10,2]]},"485":{"position":[[139,2]]},"487":{"position":[[59,2]]},"505":{"position":[[14,2],[82,2]]},"507":{"position":[[386,2],[567,2],[812,2]]},"512":{"position":[[443,2]]},"521":{"position":[[304,2]]},"526":{"position":[[272,2],[291,2]]},"537":{"position":[[526,2]]},"539":{"position":[[41,2]]},"544":{"position":[[19,2]]},"546":{"position":[[57,2]]},"548":{"position":[[34,2]]},"561":{"position":[[291,2]]},"581":{"position":[[31,2],[41,2],[102,2]]},"610":{"position":[[337,2],[348,2]]},"615":{"position":[[61,2]]},"617":{"position":[[126,2]]},"619":{"position":[[59,2]]},"626":{"position":[[0,2]]},"628":{"position":[[43,2],[101,2]]},"630":{"position":[[29,2],[64,2],[97,2]]},"639":{"position":[[86,2]]},"646":{"position":[[11,2]]},"655":{"position":[[18,2]]},"668":{"position":[[35,2]]},"677":{"position":[[11,2],[34,2]]},"686":{"position":[[496,2]]},"689":{"position":[[242,2]]},"691":{"position":[[75,2],[370,2]]},"705":{"position":[[33,2]]},"707":{"position":[[89,2]]},"718":{"position":[[70,2]]},"723":{"position":[[20,2],[40,2]]},"727":{"position":[[198,2]]},"748":{"position":[[373,2],[496,2]]},"752":{"position":[[38,2],[82,2],[98,2],[170,2]]},"770":{"position":[[4,2]]},"774":{"position":[[25,2]]},"776":{"position":[[113,2]]},"778":{"position":[[143,2]]},"780":{"position":[[69,2],[345,2]]},"785":{"position":[[38,2],[80,2]]},"806":{"position":[[137,2]]},"816":{"position":[[72,2]]},"820":{"position":[[42,2]]},"822":{"position":[[4,2]]},"828":{"position":[[70,2],[99,2],[189,2],[217,2]]},"832":{"position":[[2363,2]]},"839":{"position":[[31,2],[114,2]]},"854":{"position":[[69,2]]},"857":{"position":[[665,2]]},"859":{"position":[[554,2],[1031,2],[1108,2]]},"878":{"position":[[323,2]]},"880":{"position":[[120,2],[138,2],[189,2]]},"882":{"position":[[73,2],[138,2]]},"891":{"position":[[69,2],[109,2],[158,2],[208,2],[255,2]]},"909":{"position":[[194,2]]},"911":{"position":[[52,2]]},"935":{"position":[[137,2]]},"957":{"position":[[17,2],[139,2]]},"959":{"position":[[59,2]]},"963":{"position":[[44,2]]}}}],["可定义",{"_index":3324,"t":{"880":{"position":[[162,3]]}}}],["可怕",{"_index":2136,"t":{"444":{"position":[[473,2]]}}}],["可控",{"_index":3464,"t":{"971":{"position":[[83,2]]}}}],["可是",{"_index":2293,"t":{"485":{"position":[[125,2]]}}}],["可爱",{"_index":1883,"t":{"370":{"position":[[348,2]]}}}],["可用",{"_index":1171,"t":{"164":{"position":[[54,2]]},"250":{"position":[[54,2]]},"756":{"position":[[52,2]]},"878":{"position":[[448,2]]},"891":{"position":[[304,2]]}}}],["可知",{"_index":2000,"t":{"415":{"position":[[17,2]]}}}],["可能",{"_index":270,"t":{"34":{"position":[[5,2]]},"50":{"position":[[91,2]]},"57":{"position":[[730,2]]},"134":{"position":[[3666,2]]},"184":{"position":[[384,2]]},"186":{"position":[[265,2]]},"218":{"position":[[384,2]]},"220":{"position":[[272,2]]},"444":{"position":[[248,2]]},"449":{"position":[[10,2]]},"455":{"position":[[929,2]]},"468":{"position":[[75,2]]},"530":{"position":[[993,2]]},"574":{"position":[[28,2]]},"617":{"position":[[279,2]]},"628":{"position":[[15,2]]},"648":{"position":[[1205,2]]},"663":{"position":[[71,2],[84,2]]},"716":{"position":[[125,2]]},"720":{"position":[[20,2]]},"778":{"position":[[66,2],[205,2]]},"783":{"position":[[148,2],[207,2],[273,2],[342,2]]},"830":{"position":[[423,2]]},"832":{"position":[[582,2],[590,2],[2028,2]]},"859":{"position":[[1142,2]]},"866":{"position":[[29,2]]},"870":{"position":[[26,2]]},"878":{"position":[[498,2],[506,2]]},"896":{"position":[[359,2]]}}}],["可见",{"_index":126,"t":{"14":{"position":[[59,2]]}}}],["可读性",{"_index":2821,"t":{"679":{"position":[[174,3],[208,3]]}}}],["可调",{"_index":989,"t":{"134":{"position":[[22,2]]}}}],["可靠",{"_index":336,"t":{"38":{"position":[[30,2]]},"400":{"position":[[27,2]]},"505":{"position":[[8,2]]},"783":{"position":[[35,2],[387,2],[405,2]]},"787":{"position":[[14,2],[28,2],[40,2],[51,2]]}}}],["右",{"_index":3082,"t":{"780":{"position":[[374,1],[558,1]]}}}],["右击",{"_index":2162,"t":{"447":{"position":[[762,2]]},"714":{"position":[[0,2]]}}}],["号",{"_index":2897,"t":{"702":{"position":[[1336,1],[1447,1],[1461,1],[1474,1],[1647,1]]}}}],["各位朋友",{"_index":2632,"t":{"574":{"position":[[1,4]]}}}],["各种",{"_index":2665,"t":{"588":{"position":[[22,2]]}}}],["各种各样",{"_index":1150,"t":{"159":{"position":[[200,4]]}}}],["各类",{"_index":3330,"t":{"882":{"position":[[42,2],[218,2]]}}}],["合作",{"_index":2112,"t":{"444":{"position":[[242,2]]}}}],["合理",{"_index":1981,"t":{"409":{"position":[[34,2]]},"776":{"position":[[105,2]]}}}],["合适",{"_index":2637,"t":{"574":{"position":[[226,2]]}}}],["同一",{"_index":1462,"t":{"261":{"position":[[120,2]]},"449":{"position":[[53,2],[170,2]]},"552":{"position":[[103,2]]},"570":{"position":[[18,2]]}}}],["同一个",{"_index":395,"t":{"46":{"position":[[336,3]]},"184":{"position":[[1225,3]]},"218":{"position":[[1225,3]]},"409":{"position":[[81,3]]},"447":{"position":[[29,3],[1288,3]]},"729":{"position":[[34,3]]},"839":{"position":[[107,3]]},"872":{"position":[[403,3]]}}}],["同一时间",{"_index":1986,"t":{"409":{"position":[[73,4]]},"826":{"position":[[23,4]]}}}],["同事",{"_index":2111,"t":{"444":{"position":[[240,2],[258,2],[317,2],[421,2],[638,2]]}}}],["同学",{"_index":2586,"t":{"554":{"position":[[160,2]]}}}],["同意",{"_index":1072,"t":{"146":{"position":[[93,2]]},"220":{"position":[[112,2]]},"530":{"position":[[148,2]]},"693":{"position":[[48,2]]},"836":{"position":[[48,2]]}}}],["同时",{"_index":413,"t":{"46":{"position":[[425,2]]},"223":{"position":[[838,2]]},"225":{"position":[[1174,2],[1728,2]]},"229":{"position":[[430,2]]},"235":{"position":[[133,2]]},"365":{"position":[[1470,2]]},"406":{"position":[[49,2]]},"422":{"position":[[47,2]]},"451":{"position":[[54,2]]},"479":{"position":[[12,2],[29,2]]},"495":{"position":[[419,2]]},"552":{"position":[[32,2],[82,2]]},"561":{"position":[[635,2]]},"597":{"position":[[18,2]]},"630":{"position":[[95,2]]},"723":{"position":[[22,2]]},"736":{"position":[[168,2]]},"745":{"position":[[47,2]]},"774":{"position":[[276,2]]},"776":{"position":[[94,2]]},"816":{"position":[[70,2]]},"857":{"position":[[624,2]]},"859":{"position":[[513,2],[884,2]]},"935":{"position":[[99,2]]},"965":{"position":[[102,2]]}}}],["同样",{"_index":2221,"t":{"455":{"position":[[496,2]]},"655":{"position":[[0,2]]},"661":{"position":[[112,2]]},"668":{"position":[[88,2]]},"679":{"position":[[213,2]]}}}],["同步",{"_index":1220,"t":{"180":{"position":[[66,2]]},"184":{"position":[[334,2],[927,2],[1706,2]]},"196":{"position":[[1,2],[23,2]]},"212":{"position":[[136,2]]},"218":{"position":[[334,2],[927,2],[1706,2]]},"241":{"position":[[1,2],[26,2]]},"383":{"position":[[31,2]]},"385":{"position":[[2,2]]},"663":{"position":[[283,2]]},"790":{"position":[[22,2],[49,2]]},"857":{"position":[[833,2]]},"859":{"position":[[730,2]]},"874":{"position":[[46,2]]},"906":{"position":[[196,2]]}}}],["名",{"_index":110,"t":{"12":{"position":[[86,1]]},"106":{"position":[[2,1]]},"127":{"position":[[279,1],[555,1]]},"146":{"position":[[27,1]]},"391":{"position":[[306,1]]},"395":{"position":[[8,1]]},"453":{"position":[[34,1]]},"455":{"position":[[615,1],[626,1]]},"820":{"position":[[75,1]]}}}],["名为",{"_index":938,"t":{"127":{"position":[[11,2]]},"376":{"position":[[636,2]]}}}],["名称",{"_index":1265,"t":{"184":{"position":[[504,2]]},"218":{"position":[[504,2]]},"512":{"position":[[252,2]]},"579":{"position":[[75,2]]},"732":{"position":[[71,2]]},"870":{"position":[[194,2]]},"889":{"position":[[3,2],[9,2]]},"925":{"position":[[109,2]]}}}],["后期",{"_index":63,"t":{"7":{"position":[[80,2]]}}}],["后继",{"_index":1588,"t":{"292":{"position":[[446,2]]},"321":{"position":[[141,2]]}}}],["后续",{"_index":529,"t":{"57":{"position":[[414,2]]},"116":{"position":[[58,2]]},"132":{"position":[[337,2]]},"210":{"position":[[117,2]]},"216":{"position":[[56,2]]},"248":{"position":[[125,2]]},"304":{"position":[[56,2]]},"308":{"position":[[399,2],[1147,2],[1173,2]]},"347":{"position":[[405,2],[1464,2]]},"359":{"position":[[76,2]]},"404":{"position":[[17,2],[78,2],[143,2]]},"554":{"position":[[266,2]]},"570":{"position":[[150,2],[205,2]]},"670":{"position":[[34,2]]},"748":{"position":[[347,2]]},"783":{"position":[[125,2]]},"932":{"position":[[22,2]]},"961":{"position":[[128,2]]}}}],["后缀",{"_index":2950,"t":{"718":{"position":[[45,2],[89,2]]}}}],["向下",{"_index":2619,"t":{"561":{"position":[[366,2]]}}}],["君",{"_index":1885,"t":{"370":{"position":[[363,1]]}}}],["否则",{"_index":559,"t":{"57":{"position":[[826,2]]}}}],["含",{"_index":1418,"t":{"225":{"position":[[1356,1]]}}}],["含义",{"_index":2890,"t":{"702":{"position":[[1095,2],[1182,2]]}}}],["启动",{"_index":579,"t":{"57":{"position":[[1959,2]]},"129":{"position":[[366,2]]},"220":{"position":[[89,2],[120,2]]},"223":{"position":[[1007,2]]},"225":{"position":[[1343,2],[1897,2]]},"229":{"position":[[550,2]]},"255":{"position":[[393,2]]},"257":{"position":[[367,2]]},"259":{"position":[[342,2]]},"272":{"position":[[1753,2]]},"284":{"position":[[566,2]]},"286":{"position":[[481,2]]},"301":{"position":[[2872,2]]},"308":{"position":[[2362,2]]},"347":{"position":[[2529,2]]},"406":{"position":[[522,2]]},"422":{"position":[[506,2]]},"444":{"position":[[654,2]]},"447":{"position":[[848,2]]},"458":{"position":[[381,2]]},"495":{"position":[[637,2],[666,2]]},"537":{"position":[[240,2]]},"561":{"position":[[758,2]]},"736":{"position":[[503,2],[549,2]]},"745":{"position":[[511,2]]},"816":{"position":[[388,2]]},"832":{"position":[[374,2]]},"841":{"position":[[43,2]]},"859":{"position":[[1053,2]]},"868":{"position":[[217,2]]},"925":{"position":[[619,2]]},"932":{"position":[[528,2]]},"980":{"position":[[461,2]]}}}],["启用",{"_index":468,"t":{"50":{"position":[[195,2]]},"184":{"position":[[697,2],[703,2],[773,2],[862,2],[1194,2],[1422,2],[1641,2]]},"194":{"position":[[56,2]]},"218":{"position":[[697,2],[703,2],[773,2],[862,2],[1194,2],[1422,2],[1641,2]]},"233":{"position":[[56,2]]},"261":{"position":[[578,2],[588,2]]},"286":{"position":[[58,2]]},"516":{"position":[[501,2]]},"570":{"position":[[63,2]]},"832":{"position":[[2017,2]]},"841":{"position":[[13,2]]},"847":{"position":[[13,2]]},"872":{"position":[[735,2]]}}}],["呀",{"_index":1629,"t":{"301":{"position":[[1426,1]]}}}],["呆",{"_index":1984,"t":{"409":{"position":[[54,1]]}}}],["呈现",{"_index":1365,"t":{"194":{"position":[[351,2]]},"233":{"position":[[357,2]]},"235":{"position":[[762,2]]}}}],["告知",{"_index":3442,"t":{"965":{"position":[[124,2],[149,2]]}}}],["呢",{"_index":2190,"t":{"449":{"position":[[257,1]]},"485":{"position":[[143,1]]},"778":{"position":[[177,1]]},"783":{"position":[[415,1]]},"787":{"position":[[2,1]]},"806":{"position":[[18,1]]}}}],["周期",{"_index":443,"t":{"50":{"position":[[20,2],[154,2],[310,2]]}}}],["命令",{"_index":700,"t":{"89":{"position":[[11,2]]},"91":{"position":[[66,2],[240,2],[313,2],[372,2],[480,2]]},"734":{"position":[[18,2]]}}}],["命令行",{"_index":2997,"t":{"732":{"position":[[20,3]]},"736":{"position":[[263,3]]},"925":{"position":[[19,3],[544,3],[698,3]]}}}],["命名",{"_index":1023,"t":{"134":{"position":[[3674,2]]},"481":{"position":[[2,2]]},"826":{"position":[[79,2]]},"868":{"position":[[39,2]]},"872":{"position":[[474,2],[485,2]]}}}],["和解",{"_index":227,"t":{"28":{"position":[[53,2]]},"507":{"position":[[1741,2]]}}}],["咨询",{"_index":147,"t":{"18":{"position":[[45,2]]},"94":{"position":[[26,2]]},"935":{"position":[[139,2]]}}}],["响应",{"_index":841,"t":{"120":{"position":[[815,2]]},"136":{"position":[[19,2]]},"164":{"position":[[129,2],[196,2]]},"250":{"position":[[129,2],[196,2]]},"458":{"position":[[39,2]]},"485":{"position":[[278,2]]},"570":{"position":[[172,2]]},"630":{"position":[[18,2],[211,2],[216,2]]},"634":{"position":[[24,2]]},"830":{"position":[[64,2]]},"832":{"position":[[2041,2]]},"894":{"position":[[390,2]]}}}],["哪些",{"_index":988,"t":{"134":{"position":[[18,2]]},"526":{"position":[[57,2]]}}}],["哪里",{"_index":2841,"t":{"689":{"position":[[65,2]]}}}],["售卖",{"_index":90,"t":{"10":{"position":[[26,2]]},"12":{"position":[[26,2]]},"14":{"position":[[26,2]]},"965":{"position":[[176,2],[180,2]]}}}],["唯一",{"_index":2509,"t":{"530":{"position":[[990,2]]},"554":{"position":[[71,2],[144,2]]},"613":{"position":[[27,2]]},"617":{"position":[[112,2]]}}}],["唯一性",{"_index":3152,"t":{"820":{"position":[[111,3]]}}}],["商业",{"_index":41,"t":{"5":{"position":[[99,2]]},"18":{"position":[[18,2]]}}}],["啊",{"_index":2962,"t":{"720":{"position":[[40,1]]},"783":{"position":[[165,1]]}}}],["善良",{"_index":1884,"t":{"370":{"position":[[351,2]]}}}],["喜欢",{"_index":2209,"t":{"455":{"position":[[34,2],[60,2]]}}}],["嗷",{"_index":2131,"t":{"444":{"position":[[434,1]]}}}],["器",{"_index":701,"t":{"89":{"position":[[13,1]]},"376":{"position":[[22,1]]},"411":{"position":[[41,1]]},"413":{"position":[[36,1],[45,1]]},"415":{"position":[[91,1]]},"431":{"position":[[5,1]]},"528":{"position":[[657,1],[1371,1]]},"586":{"position":[[47,1]]},"727":{"position":[[350,1]]},"830":{"position":[[252,1]]}}}],["器具",{"_index":1990,"t":{"411":{"position":[[46,2]]}}}],["嚎",{"_index":2132,"t":{"444":{"position":[[435,1]]}}}],["四",{"_index":2101,"t":{"442":{"position":[[104,1]]}}}],["四个",{"_index":3130,"t":{"806":{"position":[[162,2]]},"826":{"position":[[170,2]]}}}],["四种",{"_index":1165,"t":{"162":{"position":[[17,2]]},"679":{"position":[[14,2],[59,2]]}}}],["回复",{"_index":2321,"t":{"493":{"position":[[43,2]]},"787":{"position":[[124,2]]}}}],["回应",{"_index":846,"t":{"120":{"position":[[872,2],[975,2],[1130,2]]},"292":{"position":[[116,2]]},"463":{"position":[[294,2]]},"750":{"position":[[251,2],[542,2]]},"854":{"position":[[32,2],[57,2]]},"857":{"position":[[576,2]]},"859":{"position":[[465,2]]}}}],["回收",{"_index":1093,"t":{"151":{"position":[[87,2]]},"874":{"position":[[476,2]]}}}],["回调",{"_index":1043,"t":{"140":{"position":[[3,2]]},"284":{"position":[[431,2],[446,2]]},"290":{"position":[[1,2],[59,2]]},"470":{"position":[[209,2],[436,2]]},"639":{"position":[[47,2]]}}}],["回退",{"_index":1625,"t":{"301":{"position":[[1210,2],[1564,2]]}}}],["因为",{"_index":362,"t":{"42":{"position":[[22,2]]},"46":{"position":[[400,2]]},"62":{"position":[[27,2]]},"71":{"position":[[27,2]]},"78":{"position":[[0,2]]},"82":{"position":[[27,2]]},"110":{"position":[[109,2]]},"134":{"position":[[43,2]]},"138":{"position":[[134,2]]},"140":{"position":[[98,2]]},"184":{"position":[[897,2],[1676,2]]},"218":{"position":[[897,2],[1676,2]]},"235":{"position":[[56,2]]},"259":{"position":[[38,2]]},"295":{"position":[[49,2]]},"301":{"position":[[1371,2]]},"340":{"position":[[22,2],[726,2]]},"343":{"position":[[56,2]]},"357":{"position":[[88,2]]},"361":{"position":[[767,2]]},"365":{"position":[[1395,2],[1430,2],[1742,2]]},"444":{"position":[[376,2],[598,2],[619,2],[681,2]]},"507":{"position":[[783,2]]},"528":{"position":[[0,2]]},"530":{"position":[[78,2]]},"548":{"position":[[24,2]]},"632":{"position":[[36,2]]},"655":{"position":[[369,2]]},"666":{"position":[[21,2]]},"686":{"position":[[137,2],[440,2]]},"778":{"position":[[111,2]]},"780":{"position":[[87,2],[566,2]]},"783":{"position":[[116,2]]},"806":{"position":[[37,2]]},"822":{"position":[[79,2]]},"862":{"position":[[62,2]]},"906":{"position":[[53,2]]}}}],["因子",{"_index":1510,"t":{"268":{"position":[[110,2],[137,2]]},"741":{"position":[[2,2],[46,2],[89,2]]},"743":{"position":[[78,2]]},"745":{"position":[[524,2],[576,2]]}}}],["因素",{"_index":1255,"t":{"184":{"position":[[351,2]]},"218":{"position":[[351,2]]}}}],["困难",{"_index":1750,"t":{"357":{"position":[[85,2]]}}}],["固定",{"_index":422,"t":{"46":{"position":[[504,2]]},"53":{"position":[[3,2],[10,2],[26,2],[83,2]]},"57":{"position":[[353,2],[1038,2],[1076,2]]},"184":{"position":[[1586,2]]},"218":{"position":[[1586,2]]},"304":{"position":[[46,2],[90,2],[107,2]]},"308":{"position":[[338,2],[1399,2],[1555,2],[2379,2]]},"340":{"position":[[44,2],[734,2]]},"343":{"position":[[76,2]]},"347":{"position":[[344,2],[914,2],[951,2]]},"400":{"position":[[0,2]]},"418":{"position":[[0,2],[44,2]]},"420":{"position":[[55,2]]},"422":{"position":[[482,2]]},"470":{"position":[[226,2],[454,2],[809,2]]},"487":{"position":[[47,2]]},"666":{"position":[[31,2]]},"668":{"position":[[6,2]]},"697":{"position":[[88,2]]},"741":{"position":[[105,2]]},"783":{"position":[[308,2]]},"957":{"position":[[62,2],[67,2]]}}}],["国",{"_index":2869,"t":{"702":{"position":[[99,1]]}}}],["国家",{"_index":51,"t":{"7":{"position":[[28,2],[40,2]]}}}],["图",{"_index":2742,"t":{"636":{"position":[[0,1]]},"679":{"position":[[267,1]]}}}],["图片",{"_index":2815,"t":{"677":{"position":[[4,2]]}}}],["圆角",{"_index":3361,"t":{"906":{"position":[[141,2]]}}}],["在于",{"_index":618,"t":{"62":{"position":[[7,2]]},"71":{"position":[[7,2]]},"82":{"position":[[7,2]]},"134":{"position":[[7,2]]}}}],["在内",{"_index":926,"t":{"125":{"position":[[152,2]]}}}],["在线",{"_index":1401,"t":{"223":{"position":[[620,2]]},"239":{"position":[[9,2],[42,2],[217,2]]},"485":{"position":[[36,2]]},"752":{"position":[[160,2]]}}}],["在读",{"_index":1978,"t":{"409":{"position":[[2,2]]}}}],["地",{"_index":3064,"t":{"761":{"position":[[182,1]]},"880":{"position":[[60,1]]}}}],["地址",{"_index":113,"t":{"12":{"position":[[101,2]]},"112":{"position":[[19,2]]},"173":{"position":[[157,2]]},"184":{"position":[[480,2],[1570,2]]},"207":{"position":[[349,2]]},"212":{"position":[[74,2]]},"218":{"position":[[480,2],[1570,2]]},"223":{"position":[[844,2]]},"225":{"position":[[746,2],[1180,2],[1734,2]]},"229":{"position":[[436,2]]},"286":{"position":[[489,2]]},"495":{"position":[[425,2]]},"516":{"position":[[106,2]]},"537":{"position":[[283,2]]},"561":{"position":[[641,2]]},"736":{"position":[[174,2]]},"761":{"position":[[52,2],[70,2],[100,2],[141,2],[159,2],[170,2],[189,2],[198,2]]},"774":{"position":[[41,2]]},"859":{"position":[[890,2]]},"911":{"position":[[47,2]]}}}],["地方",{"_index":1438,"t":{"235":{"position":[[1167,2],[1233,2]]},"376":{"position":[[136,2]]},"783":{"position":[[413,2]]}}}],["场景",{"_index":322,"t":{"36":{"position":[[32,2]]},"48":{"position":[[5,2]]},"114":{"position":[[8,2]]},"182":{"position":[[9,2],[31,2]]},"203":{"position":[[7,2]]},"214":{"position":[[9,2],[31,2]]},"400":{"position":[[52,2]]},"418":{"position":[[79,2]]},"420":{"position":[[57,2]]},"444":{"position":[[58,2],[501,2]]},"526":{"position":[[54,2]]},"535":{"position":[[2,2],[51,2],[67,2]]},"568":{"position":[[7,2],[18,2]]},"741":{"position":[[113,2]]},"787":{"position":[[152,2],[180,2]]},"806":{"position":[[60,2]]},"824":{"position":[[9,2],[54,2]]},"913":{"position":[[13,2],[35,2]]}}}],["均",{"_index":64,"t":{"7":{"position":[[82,1]]},"20":{"position":[[66,1]]},"57":{"position":[[7,1],[1980,1]]},"91":{"position":[[172,1]]},"116":{"position":[[65,1]]},"186":{"position":[[213,1]]},"216":{"position":[[63,1]]},"220":{"position":[[220,1]]},"248":{"position":[[132,1]]},"272":{"position":[[7,1],[1774,1]]},"301":{"position":[[2893,1]]},"308":{"position":[[7,1],[2578,1]]},"347":{"position":[[7,1],[2550,1]]},"365":{"position":[[156,1]]},"391":{"position":[[51,1]]},"397":{"position":[[60,1],[82,1]]},"402":{"position":[[72,1]]},"406":{"position":[[7,1],[593,1]]},"422":{"position":[[7,1],[577,1]]},"447":{"position":[[1271,1]]},"470":{"position":[[833,1]]},"521":{"position":[[205,1]]},"561":{"position":[[796,1]]},"570":{"position":[[16,1]]},"579":{"position":[[15,1]]},"588":{"position":[[29,1]]},"630":{"position":[[63,1]]},"634":{"position":[[34,1]]},"732":{"position":[[87,1]]},"745":{"position":[[7,1],[648,1]]},"758":{"position":[[146,1]]},"816":{"position":[[406,1]]},"826":{"position":[[63,1],[93,1],[178,1]]},"859":{"position":[[1107,1]]},"878":{"position":[[290,1]]},"880":{"position":[[235,1]]},"925":{"position":[[125,1]]},"954":{"position":[[28,1],[66,1]]},"959":{"position":[[24,1]]},"967":{"position":[[30,1]]},"980":{"position":[[479,1]]}}}],["均衡",{"_index":2456,"t":{"526":{"position":[[167,2]]}}}],["块",{"_index":551,"t":{"57":{"position":[[735,1]]},"151":{"position":[[23,1]]},"301":{"position":[[721,1]]},"361":{"position":[[765,1],[2947,1]]},"365":{"position":[[1740,1]]},"376":{"position":[[189,1]]},"872":{"position":[[131,1]]}}}],["坚持",{"_index":3465,"t":{"971":{"position":[[90,2]]}}}],["型",{"_index":205,"t":{"25":{"position":[[371,1]]},"34":{"position":[[58,1],[78,1]]},"57":{"position":[[154,1],[1549,1]]},"132":{"position":[[351,1]]},"225":{"position":[[3,1],[43,1],[428,1]]},"229":{"position":[[16,1]]},"272":{"position":[[146,1],[1440,1]]},"301":{"position":[[116,1],[2504,1]]},"308":{"position":[[148,1],[1961,1]]},"347":{"position":[[150,1],[2122,1]]},"544":{"position":[[143,1]]},"574":{"position":[[286,1]]},"756":{"position":[[196,1]]},"872":{"position":[[178,1],[1096,1]]},"882":{"position":[[286,1]]}}}],["域",{"_index":830,"t":{"120":{"position":[[383,1],[494,1]]},"473":{"position":[[301,1]]},"830":{"position":[[504,1]]}}}],["域名",{"_index":1327,"t":{"184":{"position":[[1283,2],[1331,2],[1454,2]]},"218":{"position":[[1283,2],[1331,2],[1454,2]]},"319":{"position":[[683,2],[700,2]]}}}],["基于",{"_index":74,"t":{"7":{"position":[[136,2]]},"42":{"position":[[25,2]]},"129":{"position":[[5,2]]},"180":{"position":[[83,2]]},"199":{"position":[[6,2]]},"212":{"position":[[153,2]]},"248":{"position":[[32,2]]},"255":{"position":[[2,2]]},"257":{"position":[[2,2]]},"259":{"position":[[2,2]]},"275":{"position":[[10,2]]},"526":{"position":[[73,2]]},"574":{"position":[[69,2]]},"579":{"position":[[21,2]]},"705":{"position":[[17,2]]},"707":{"position":[[19,2]]},"718":{"position":[[153,2]]},"748":{"position":[[87,2]]},"785":{"position":[[40,2],[58,2]]},"806":{"position":[[183,2],[226,2],[277,2]]},"826":{"position":[[6,2]]}}}],["基准",{"_index":2390,"t":{"509":{"position":[[0,2]]}}}],["基本",{"_index":819,"t":{"120":{"position":[[15,2]]},"169":{"position":[[0,2]]},"171":{"position":[[0,2]]},"173":{"position":[[0,2]]},"523":{"position":[[2724,2]]},"586":{"position":[[7,2]]},"785":{"position":[[43,2]]},"809":{"position":[[21,2]]},"820":{"position":[[40,2]]}}}],["基本一致",{"_index":1450,"t":{"246":{"position":[[40,4]]},"347":{"position":[[920,4]]},"530":{"position":[[20,4]]},"581":{"position":[[299,4]]},"693":{"position":[[20,4]]},"836":{"position":[[19,4]]}}}],["基本上",{"_index":1284,"t":{"184":{"position":[[719,3]]},"218":{"position":[[719,3]]},"400":{"position":[[44,3]]},"822":{"position":[[56,3]]}}}],["基础",{"_index":788,"t":{"110":{"position":[[25,2]]},"114":{"position":[[4,2]]},"155":{"position":[[0,2]]},"182":{"position":[[5,2]]},"199":{"position":[[15,2]]},"203":{"position":[[3,2]]},"214":{"position":[[5,2]]},"248":{"position":[[19,2]]},"255":{"position":[[31,2]]},"427":{"position":[[50,2]]},"507":{"position":[[285,2],[872,2]]},"568":{"position":[[3,2]]},"679":{"position":[[146,2]]},"882":{"position":[[234,2]]},"906":{"position":[[87,2]]},"913":{"position":[[9,2]]},"935":{"position":[[34,2]]},"959":{"position":[[9,2]]}}}],["基类",{"_index":1211,"t":{"178":{"position":[[17,2]]},"210":{"position":[[18,2]]},"290":{"position":[[790,2]]}}}],["填充",{"_index":763,"t":{"104":{"position":[[52,2]]},"301":{"position":[[1286,2],[1360,2],[1624,2]]}}}],["填写",{"_index":1665,"t":{"319":{"position":[[746,2]]}}}],["填补",{"_index":2011,"t":{"418":{"position":[[23,2]]}}}],["增加",{"_index":179,"t":{"25":{"position":[[22,2]]},"122":{"position":[[25,2]]},"455":{"position":[[888,2]]},"491":{"position":[[18,2]]},"761":{"position":[[106,2]]},"836":{"position":[[29,2],[95,2]]},"872":{"position":[[1093,2]]},"874":{"position":[[275,2]]},"878":{"position":[[64,2]]},"880":{"position":[[208,2]]},"884":{"position":[[130,2]]}}}],["增强",{"_index":1091,"t":{"151":{"position":[[76,2]]}}}],["增强型",{"_index":3307,"t":{"874":{"position":[[26,3]]},"876":{"position":[[26,3]]},"878":{"position":[[25,3]]},"880":{"position":[[26,3]]},"882":{"position":[[26,3]]}}}],["声明",{"_index":173,"t":{"25":{"position":[[1,2]]},"57":{"position":[[24,2],[80,2],[93,2],[147,2],[233,2]]},"118":{"position":[[0,2]]},"127":{"position":[[61,2]]},"138":{"position":[[203,2]]},"166":{"position":[[0,2]]},"188":{"position":[[400,2]]},"192":{"position":[[281,2]]},"194":{"position":[[92,2]]},"205":{"position":[[0,2]]},"233":{"position":[[92,2]]},"235":{"position":[[303,2]]},"252":{"position":[[0,2]]},"272":{"position":[[24,2],[76,2],[89,2],[139,2],[225,2]]},"290":{"position":[[1088,2]]},"301":{"position":[[14,2],[56,2],[69,2],[109,2],[195,2]]},"308":{"position":[[24,2],[77,2],[90,2],[141,2],[227,2]]},"347":{"position":[[24,2],[77,2],[90,2],[143,2],[229,2]]},"376":{"position":[[116,2],[131,2]]},"378":{"position":[[7,2]]},"431":{"position":[[45,2]]},"449":{"position":[[74,2]]},"453":{"position":[[9,2]]},"507":{"position":[[1268,2]]},"561":{"position":[[502,2]]},"574":{"position":[[131,2],[155,2]]},"686":{"position":[[473,2]]},"732":{"position":[[62,2]]},"872":{"position":[[1088,2]]},"891":{"position":[[84,2]]},"925":{"position":[[100,2],[709,2]]}}}],["处理",{"_index":233,"t":{"28":{"position":[[75,2]]},"32":{"position":[[53,2]]},"57":{"position":[[1621,2]]},"120":{"position":[[364,2],[552,2]]},"125":{"position":[[178,2]]},"178":{"position":[[38,2]]},"184":{"position":[[306,2],[336,2],[663,2]]},"188":{"position":[[3,2]]},"194":{"position":[[23,2],[308,2],[481,2],[541,2]]},"218":{"position":[[306,2],[336,2],[663,2]]},"223":{"position":[[39,2]]},"225":{"position":[[225,2],[233,2],[709,2]]},"231":{"position":[[51,2]]},"233":{"position":[[23,2],[314,2],[487,2],[547,2]]},"235":{"position":[[285,2],[719,2],[1145,2]]},"272":{"position":[[1508,2]]},"295":{"position":[[62,2]]},"301":{"position":[[2562,2]]},"308":{"position":[[2030,2]]},"347":{"position":[[2193,2]]},"357":{"position":[[201,2]]},"361":{"position":[[1588,2],[1778,2],[1969,2],[2758,2]]},"400":{"position":[[12,2]]},"418":{"position":[[50,2]]},"516":{"position":[[197,2]]},"741":{"position":[[28,2]]},"752":{"position":[[76,2]]},"761":{"position":[[97,2]]},"774":{"position":[[310,2]]},"787":{"position":[[84,2]]},"874":{"position":[[353,2]]},"976":{"position":[[11,2],[67,2]]}}}],["处理器",{"_index":355,"t":{"40":{"position":[[307,3]]}}}],["处理完毕",{"_index":847,"t":{"120":{"position":[[894,4]]}}}],["处理结果",{"_index":3107,"t":{"787":{"position":[[92,4]]}}}],["备注",{"_index":994,"t":{"134":{"position":[[93,2]]},"623":{"position":[[31,2]]}}}],["复制",{"_index":1811,"t":{"365":{"position":[[1346,2],[1406,2],[1438,2]]},"447":{"position":[[979,2]]},"579":{"position":[[125,2]]},"586":{"position":[[73,2]]}}}],["复制到",{"_index":631,"t":{"66":{"position":[[55,3]]},"75":{"position":[[55,3]]},"86":{"position":[[100,3]]}}}],["复刻",{"_index":2182,"t":{"449":{"position":[[97,2],[153,2]]}}}],["复杂",{"_index":1508,"t":{"268":{"position":[[93,2]]},"523":{"position":[[376,2]]},"743":{"position":[[74,2]]},"778":{"position":[[43,2]]}}}],["复杂度",{"_index":3432,"t":{"961":{"position":[[267,3]]}}}],["复用",{"_index":1325,"t":{"184":{"position":[[1198,2]]},"218":{"position":[[1198,2]]},"507":{"position":[[1256,2]]},"776":{"position":[[117,2]]},"884":{"position":[[134,2]]}}}],["外",{"_index":1939,"t":{"391":{"position":[[26,1]]},"530":{"position":[[90,1]]}}}],["外置",{"_index":1355,"t":{"192":{"position":[[29,2]]},"229":{"position":[[35,2]]}}}],["外部",{"_index":428,"t":{"48":{"position":[[43,2]]},"378":{"position":[[21,2]]},"542":{"position":[[50,2]]}}}],["多",{"_index":795,"t":{"112":{"position":[[18,1]]},"125":{"position":[[149,1]]},"212":{"position":[[73,1]]},"263":{"position":[[47,1]]},"301":{"position":[[896,1]]},"338":{"position":[[61,1]]},"357":{"position":[[98,1]]},"361":{"position":[[1081,1]]},"378":{"position":[[56,1]]},"436":{"position":[[2045,1]]},"485":{"position":[[242,1]]},"509":{"position":[[54,1]]},"528":{"position":[[3,1]]},"544":{"position":[[74,1]]},"550":{"position":[[66,1]]},"581":{"position":[[110,1]]},"720":{"position":[[30,1]]},"729":{"position":[[81,1],[85,1]]},"794":{"position":[[84,1]]},"872":{"position":[[386,1]]},"874":{"position":[[297,1]]},"911":{"position":[[46,1]]}}}],["多个",{"_index":797,"t":{"112":{"position":[[31,2]]},"184":{"position":[[478,2]]},"194":{"position":[[198,2]]},"212":{"position":[[86,2]]},"218":{"position":[[478,2]]},"233":{"position":[[201,2]]},"286":{"position":[[38,2]]},"361":{"position":[[1118,2],[1129,2]]},"409":{"position":[[77,2]]},"415":{"position":[[87,2]]},"447":{"position":[[1297,2]]},"479":{"position":[[16,2]]},"526":{"position":[[15,2]]},"528":{"position":[[17,2],[88,2]]},"530":{"position":[[1057,2],[1063,2]]},"533":{"position":[[42,2],[53,2]]},"723":{"position":[[26,2]]},"826":{"position":[[31,2]]},"870":{"position":[[136,2],[189,2],[213,2]]},"872":{"position":[[98,2],[394,2]]},"891":{"position":[[147,2]]},"911":{"position":[[59,2]]}}}],["多出",{"_index":627,"t":{"66":{"position":[[19,2]]},"75":{"position":[[19,2]]},"86":{"position":[[19,2]]}}}],["多功能",{"_index":2964,"t":{"720":{"position":[[71,3]]}}}],["多少",{"_index":530,"t":{"57":{"position":[[421,2],[1046,2]]},"308":{"position":[[406,2],[1407,2]]},"347":{"position":[[412,2]]}}}],["多播",{"_index":3222,"t":{"839":{"position":[[73,2]]}}}],["多次",{"_index":1687,"t":{"338":{"position":[[14,2]]},"778":{"position":[[123,2]]}}}],["多种",{"_index":324,"t":{"36":{"position":[[48,2]]},"112":{"position":[[9,2]]},"190":{"position":[[21,2],[24,2]]},"227":{"position":[[22,2],[25,2]]},"783":{"position":[[200,2]]},"911":{"position":[[19,2]]}}}],["多种形式",{"_index":1447,"t":{"246":{"position":[[13,4]]}}}],["多种类型",{"_index":2282,"t":{"473":{"position":[[291,4]]}}}],["多线程",{"_index":1138,"t":{"159":{"position":[[1,3],[130,3]]},"180":{"position":[[10,3]]},"184":{"position":[[261,3],[904,3],[1683,3]]},"201":{"position":[[6,3]]},"212":{"position":[[10,3]]},"218":{"position":[[261,3],[904,3],[1683,3]]},"225":{"position":[[706,3]]},"526":{"position":[[0,3],[32,3],[137,3],[304,3],[322,3]]},"530":{"position":[[51,3]]},"570":{"position":[[1,3]]},"794":{"position":[[88,3]]},"809":{"position":[[48,3]]},"911":{"position":[[6,3]]},"950":{"position":[[28,3]]}}}],["多通道",{"_index":3411,"t":{"952":{"position":[[7,3]]}}}],["大",{"_index":284,"t":{"34":{"position":[[82,1]]},"53":{"position":[[0,1],[80,1]]},"57":{"position":[[1073,1]]},"184":{"position":[[108,1],[386,1],[994,1],[1773,1]]},"194":{"position":[[209,1]]},"218":{"position":[[108,1],[386,1],[994,1],[1773,1]]},"233":{"position":[[212,1]]},"301":{"position":[[897,1]]},"370":{"position":[[299,1]]},"465":{"position":[[320,1],[379,1]]},"526":{"position":[[208,1]]},"666":{"position":[[131,1],[158,1]]},"668":{"position":[[64,1]]},"748":{"position":[[215,1],[442,1],[457,1]]},"761":{"position":[[32,1],[105,1]]},"767":{"position":[[50,1]]},"814":{"position":[[41,1]]},"832":{"position":[[2012,1]]},"872":{"position":[[19,1]]},"906":{"position":[[125,1]]}}}],["大于",{"_index":1315,"t":{"184":{"position":[[1085,2],[1864,2]]},"218":{"position":[[1085,2],[1864,2]]},"361":{"position":[[1764,2]]},"702":{"position":[[1567,2],[1660,2]]}}}],["大力支持",{"_index":2354,"t":{"503":{"position":[[86,4]]}}}],["大同小异",{"_index":1449,"t":{"246":{"position":[[32,4]]}}}],["大型",{"_index":2247,"t":{"463":{"position":[[5,2]]},"874":{"position":[[99,2]]}}}],["大多数",{"_index":2415,"t":{"521":{"position":[[79,3]]}}}],["大大",{"_index":3322,"t":{"880":{"position":[[58,2]]}}}],["大家",{"_index":241,"t":{"28":{"position":[[118,2]]},"34":{"position":[[0,2]]},"44":{"position":[[4,2]]},"69":{"position":[[126,2]]},"225":{"position":[[1943,2]]},"263":{"position":[[42,2]]},"336":{"position":[[104,2]]},"449":{"position":[[8,2]]},"455":{"position":[[28,2],[927,2],[1059,2]]},"468":{"position":[[77,2]]},"485":{"position":[[231,2],[237,2]]},"574":{"position":[[60,2]]},"610":{"position":[[346,2]]},"666":{"position":[[176,2]]},"778":{"position":[[68,2]]},"971":{"position":[[3,2]]}}}],["大小",{"_index":2644,"t":{"579":{"position":[[57,2],[78,2]]},"689":{"position":[[17,2]]},"761":{"position":[[0,2]]},"794":{"position":[[4,2]]},"816":{"position":[[81,2]]},"868":{"position":[[180,2]]},"874":{"position":[[314,2],[484,2]]}}}],["大概",{"_index":2179,"t":{"449":{"position":[[12,2]]},"455":{"position":[[361,2]]}}}],["大约",{"_index":2793,"t":{"666":{"position":[[76,2]]},"689":{"position":[[83,2],[151,2]]},"822":{"position":[[31,2]]}}}],["大部分",{"_index":3257,"t":{"864":{"position":[[37,3]]}}}],["大量",{"_index":488,"t":{"53":{"position":[[58,2]]},"378":{"position":[[42,2]]}}}],["天下无敌",{"_index":2441,"t":{"523":{"position":[[1210,4]]}}}],["太",{"_index":283,"t":{"34":{"position":[[81,1]]},"361":{"position":[[746,1]]},"365":{"position":[[1721,1]]},"378":{"position":[[55,1]]},"442":{"position":[[153,1]]}}}],["失效",{"_index":696,"t":{"86":{"position":[[61,2]]},"965":{"position":[[99,2]]}}}],["失败",{"_index":1370,"t":{"196":{"position":[[94,2],[304,2]]},"241":{"position":[[47,2],[257,2]]},"868":{"position":[[68,2]]},"874":{"position":[[109,2]]},"882":{"position":[[287,2]]}}}],["头",{"_index":309,"t":{"34":{"position":[[253,1]]},"292":{"position":[[427,1]]},"321":{"position":[[122,1]]},"343":{"position":[[36,1],[54,1],[92,1]]},"702":{"position":[[758,1]]}}}],["头部",{"_index":561,"t":{"57":{"position":[[896,2]]},"301":{"position":[[1149,2]]},"343":{"position":[[70,2]]}}}],["套",{"_index":2291,"t":{"485":{"position":[[94,1],[133,1]]},"752":{"position":[[43,1]]}}}],["好处",{"_index":2540,"t":{"542":{"position":[[110,2]]}}}],["好多",{"_index":3093,"t":{"783":{"position":[[344,2]]}}}],["好奇",{"_index":2961,"t":{"720":{"position":[[23,2]]}}}],["如下",{"_index":429,"t":{"48":{"position":[[54,2]]},"104":{"position":[[29,2]]},"169":{"position":[[4,2]]},"171":{"position":[[4,2]]},"173":{"position":[[4,2]]},"188":{"position":[[50,2]]},"194":{"position":[[47,2],[85,2]]},"223":{"position":[[86,2]]},"225":{"position":[[53,2]]},"233":{"position":[[47,2],[85,2]]},"235":{"position":[[244,2],[296,2]]},"290":{"position":[[64,2]]},"359":{"position":[[20,2]]},"361":{"position":[[546,2]]},"376":{"position":[[171,2]]},"431":{"position":[[41,2]]},"440":{"position":[[115,2]]},"455":{"position":[[390,2],[508,2]]},"487":{"position":[[118,2]]},"574":{"position":[[127,2]]},"718":{"position":[[113,2]]},"748":{"position":[[193,2]]},"770":{"position":[[68,2]]},"787":{"position":[[187,2]]},"935":{"position":[[91,2]]},"969":{"position":[[213,2],[417,2]]}}}],["如何",{"_index":1411,"t":{"225":{"position":[[38,2]]},"295":{"position":[[60,2]]},"485":{"position":[[127,2]]},"729":{"position":[[6,2],[30,2]]},"778":{"position":[[175,2]]},"787":{"position":[[96,2]]}}}],["如果",{"_index":266,"t":{"32":{"position":[[166,2]]},"46":{"position":[[359,2],[449,2]]},"50":{"position":[[9,2],[76,2],[140,2]]},"66":{"position":[[38,2]]},"69":{"position":[[190,2],[206,2]]},"75":{"position":[[38,2]]},"86":{"position":[[83,2]]},"104":{"position":[[0,2],[33,2],[185,2]]},"110":{"position":[[58,2],[87,2]]},"120":{"position":[[473,2]]},"151":{"position":[[94,2]]},"159":{"position":[[162,2]]},"166":{"position":[[135,2]]},"184":{"position":[[57,2],[83,2],[365,2],[390,2],[1080,2],[1105,2],[1859,2],[1884,2]]},"196":{"position":[[66,2],[90,2],[300,2]]},"207":{"position":[[388,2],[413,2]]},"218":{"position":[[57,2],[83,2],[365,2],[390,2],[1080,2],[1105,2],[1859,2],[1884,2]]},"225":{"position":[[391,2]]},"241":{"position":[[43,2],[253,2],[464,2]]},"252":{"position":[[135,2]]},"284":{"position":[[23,2]]},"340":{"position":[[575,2],[775,2]]},"361":{"position":[[1487,2]]},"389":{"position":[[54,2]]},"409":{"position":[[40,2]]},"444":{"position":[[175,2],[230,2],[313,2],[354,2],[459,2]]},"447":{"position":[[7,2]]},"449":{"position":[[131,2]]},"485":{"position":[[90,2]]},"493":{"position":[[447,2]]},"507":{"position":[[446,2],[627,2]]},"512":{"position":[[69,2]]},"516":{"position":[[66,2],[128,2],[170,2]]},"528":{"position":[[665,2],[1379,2]]},"542":{"position":[[17,2]]},"559":{"position":[[121,2]]},"561":{"position":[[445,2],[469,2]]},"570":{"position":[[176,2]]},"595":{"position":[[160,2]]},"663":{"position":[[36,2]]},"666":{"position":[[88,2]]},"707":{"position":[[133,2]]},"718":{"position":[[61,2]]},"741":{"position":[[80,2]]},"750":{"position":[[176,2],[453,2]]},"756":{"position":[[0,2],[24,2]]},"758":{"position":[[90,2]]},"830":{"position":[[410,2]]},"857":{"position":[[627,2]]},"859":{"position":[[516,2],[1130,2]]},"866":{"position":[[118,2]]},"878":{"position":[[311,2]]},"891":{"position":[[53,2],[143,2]]},"894":{"position":[[68,2]]},"928":{"position":[[78,2]]},"971":{"position":[[88,2]]}}}],["如此一来",{"_index":3076,"t":{"778":{"position":[[88,4]]}}}],["始终",{"_index":217,"t":{"28":{"position":[[19,2]]},"149":{"position":[[55,2]]}}}],["委托",{"_index":1221,"t":{"180":{"position":[[85,2]]},"188":{"position":[[40,2]]},"192":{"position":[[31,2],[47,2]]},"212":{"position":[[155,2]]},"223":{"position":[[76,2]]},"225":{"position":[[251,2]]},"229":{"position":[[37,2],[53,2]]},"393":{"position":[[199,2]]},"874":{"position":[[233,2]]},"878":{"position":[[268,2]]}}}],["子",{"_index":2645,"t":{"579":{"position":[[81,1]]},"702":{"position":[[1644,1]]}}}],["字",{"_index":539,"t":{"57":{"position":[[620,1]]},"376":{"position":[[24,1]]}}}],["字典",{"_index":1394,"t":{"216":{"position":[[95,2]]},"427":{"position":[[72,2]]},"507":{"position":[[562,2],[642,2]]},"679":{"position":[[166,2]]}}}],["字母",{"_index":2633,"t":{"574":{"position":[[88,2]]}}}],["字符",{"_index":1514,"t":{"268":{"position":[[163,2]]},"272":{"position":[[763,2],[768,2]]},"606":{"position":[[7,2],[111,2]]},"738":{"position":[[80,2]]},"745":{"position":[[485,2]]}}}],["字符串",{"_index":608,"t":{"60":{"position":[[471,3]]},"78":{"position":[[29,3],[38,3]]},"132":{"position":[[17,3]]},"184":{"position":[[1322,3]]},"218":{"position":[[1322,3]]},"268":{"position":[[10,3]]},"270":{"position":[[9,3]]},"447":{"position":[[72,3],[168,3]]},"516":{"position":[[96,3]]},"679":{"position":[[182,3],[216,3]]},"743":{"position":[[4,3]]},"761":{"position":[[92,3]]},"772":{"position":[[31,3]]},"925":{"position":[[735,3]]},"957":{"position":[[81,3]]}}}],["字节",{"_index":1389,"t":{"212":{"position":[[49,2]]},"272":{"position":[[1073,2]]},"301":{"position":[[719,2],[1376,2]]},"304":{"position":[[43,2],[65,2]]},"308":{"position":[[1143,2]]},"336":{"position":[[51,2],[79,2],[188,2],[197,2]]},"340":{"position":[[148,2],[176,2],[259,2],[268,2]]},"359":{"position":[[30,2],[56,2],[67,2],[78,2]]},"365":{"position":[[1400,2]]},"404":{"position":[[13,2],[59,2],[125,2]]},"422":{"position":[[491,2]]},"431":{"position":[[689,2]]},"487":{"position":[[138,2],[150,2],[160,2]]},"628":{"position":[[89,2]]},"689":{"position":[[31,2],[181,2]]},"748":{"position":[[115,2],[125,2],[147,2],[152,2],[170,2],[212,2],[377,2],[381,2],[385,2],[417,2],[426,2],[438,2],[453,2],[472,2]]},"750":{"position":[[74,2]]},"780":{"position":[[379,2],[563,2],[571,2]]},"783":{"position":[[55,2],[61,2],[79,2],[127,2]]},"820":{"position":[[103,2],[169,2],[197,2],[269,2]]},"857":{"position":[[644,2]]},"859":{"position":[[533,2]]}}}],["存储",{"_index":504,"t":{"57":{"position":[[66,2]]},"272":{"position":[[62,2]]},"301":{"position":[[42,2]]},"308":{"position":[[63,2]]},"347":{"position":[[63,2]]},"761":{"position":[[77,2],[165,2]]},"804":{"position":[[29,2],[35,2]]},"872":{"position":[[461,2]]}}}],["存储器",{"_index":3053,"t":{"761":{"position":[[21,3]]}}}],["存在",{"_index":315,"t":{"34":{"position":[[288,2]]},"125":{"position":[[80,2]]},"365":{"position":[[1403,2]]},"505":{"position":[[84,2]]},"776":{"position":[[11,2]]},"870":{"position":[[66,2]]}}}],["存放",{"_index":2187,"t":{"449":{"position":[[223,2]]},"761":{"position":[[26,2]]}}}],["学习",{"_index":2178,"t":{"449":{"position":[[5,2]]}}}],["安",{"_index":1838,"t":{"370":{"position":[[67,1]]}}}],["安全",{"_index":734,"t":{"94":{"position":[[54,2]]},"411":{"position":[[32,2]]},"413":{"position":[[39,2]]}}}],["安全性",{"_index":2091,"t":{"440":{"position":[[204,3]]},"770":{"position":[[16,3]]}}}],["安全隐患",{"_index":3198,"t":{"830":{"position":[[429,4]]}}}],["安装",{"_index":1426,"t":{"235":{"position":[[4,2],[81,2],[139,2]]},"261":{"position":[[11,2]]},"707":{"position":[[172,2]]},"714":{"position":[[64,2]]},"969":{"position":[[37,2]]}}}],["完",{"_index":415,"t":{"46":{"position":[[440,1]]},"361":{"position":[[1151,1],[1581,1]]},"561":{"position":[[456,1]]},"758":{"position":[[2,1]]},"780":{"position":[[327,1]]},"806":{"position":[[34,1]]},"859":{"position":[[1121,1]]}}}],["完全",{"_index":1094,"t":{"151":{"position":[[120,2]]},"301":{"position":[[584,2]]},"455":{"position":[[1004,2]]},"526":{"position":[[351,2]]},"681":{"position":[[29,2]]},"824":{"position":[[41,2]]},"935":{"position":[[38,2]]},"969":{"position":[[10,2]]}}}],["完全一致",{"_index":3075,"t":{"776":{"position":[[64,4]]},"978":{"position":[[46,4]]}}}],["完成",{"_index":104,"t":{"12":{"position":[[58,2],[106,2]]},"34":{"position":[[157,2]]},"50":{"position":[[35,2],[313,2]]},"159":{"position":[[619,2],[928,2]]},"166":{"position":[[193,2],[264,2],[570,2]]},"186":{"position":[[73,2],[109,2]]},"210":{"position":[[133,2]]},"220":{"position":[[79,2]]},"225":{"position":[[1950,2]]},"252":{"position":[[193,2],[264,2],[570,2]]},"281":{"position":[[41,2]]},"297":{"position":[[102,2]]},"347":{"position":[[1580,2]]},"411":{"position":[[82,2]]},"413":{"position":[[82,2],[402,2]]},"447":{"position":[[878,2]]},"559":{"position":[[127,2]]},"586":{"position":[[9,2]]},"595":{"position":[[16,2],[144,2]]},"597":{"position":[[56,2]]},"610":{"position":[[21,2]]},"619":{"position":[[35,2]]},"648":{"position":[[721,2]]},"672":{"position":[[1045,2],[1068,2]]},"674":{"position":[[950,2],[973,2]]},"689":{"position":[[244,2]]},"720":{"position":[[10,2]]},"776":{"position":[[115,2]]},"828":{"position":[[318,2]]},"830":{"position":[[141,2],[542,2]]},"854":{"position":[[112,2]]},"878":{"position":[[454,2]]},"909":{"position":[[180,2]]},"925":{"position":[[70,2]]}}}],["完整",{"_index":1683,"t":{"336":{"position":[[90,2]]},"359":{"position":[[148,2]]},"361":{"position":[[1142,2]]},"783":{"position":[[182,2]]}}}],["完毕",{"_index":557,"t":{"57":{"position":[[800,2]]}}}],["完美",{"_index":2207,"t":{"455":{"position":[[11,2]]},"661":{"position":[[24,2]]}}}],["宏观",{"_index":2462,"t":{"526":{"position":[[256,2]]}}}],["官",{"_index":2948,"t":{"716":{"position":[[143,1]]},"718":{"position":[[6,1]]}}}],["官方",{"_index":2341,"t":{"498":{"position":[[51,2]]},"872":{"position":[[168,2]]}}}],["定",{"_index":1748,"t":{"357":{"position":[[63,1]]}}}],["定为",{"_index":3375,"t":{"909":{"position":[[56,2],[101,2]]}}}],["定义",{"_index":570,"t":{"57":{"position":[[1545,2]]},"138":{"position":[[230,2]]},"144":{"position":[[43,2]]},"192":{"position":[[23,2]]},"229":{"position":[[29,2]]},"272":{"position":[[1436,2]]},"301":{"position":[[217,2],[2500,2]]},"308":{"position":[[1957,2]]},"347":{"position":[[2118,2]]},"431":{"position":[[842,2]]},"444":{"position":[[86,2],[96,2],[527,2]]},"455":{"position":[[1027,2]]},"574":{"position":[[34,2]]},"610":{"position":[[254,2]]},"615":{"position":[[66,2]]},"630":{"position":[[219,2]]},"641":{"position":[[47,2]]},"691":{"position":[[374,2]]},"748":{"position":[[7,2],[250,2]]},"752":{"position":[[9,2]]}}}],["定位",{"_index":3368,"t":{"906":{"position":[[184,2]]}}}],["定制",{"_index":494,"t":{"55":{"position":[[20,2]]},"270":{"position":[[22,2]]},"306":{"position":[[39,2]]},"345":{"position":[[19,2]]},"588":{"position":[[6,2]]},"906":{"position":[[0,2]]},"935":{"position":[[120,2]]},"959":{"position":[[63,2]]}}}],["定向",{"_index":3367,"t":{"906":{"position":[[176,2]]}}}],["定时",{"_index":2288,"t":{"485":{"position":[[14,2]]},"832":{"position":[[2072,2]]},"872":{"position":[[698,2],[1117,2]]}}}],["实体模型",{"_index":2188,"t":{"449":{"position":[[228,4]]}}}],["实体类",{"_index":505,"t":{"57":{"position":[[71,3]]},"272":{"position":[[67,3]]},"301":{"position":[[47,3]]},"308":{"position":[[68,3]]},"347":{"position":[[68,3]]},"427":{"position":[[58,3]]},"507":{"position":[[1,3]]},"679":{"position":[[154,3]]},"738":{"position":[[123,3]]}}}],["实例",{"_index":195,"t":{"25":{"position":[[218,2],[269,2]]},"46":{"position":[[342,2]]},"116":{"position":[[39,2],[68,2]]},"118":{"position":[[5,2]]},"166":{"position":[[5,2]]},"205":{"position":[[5,2]]},"210":{"position":[[62,2],[113,2],[131,2]]},"216":{"position":[[35,2],[66,2]]},"237":{"position":[[42,2],[48,2]]},"239":{"position":[[148,2]]},"248":{"position":[[96,2],[135,2]]},"252":{"position":[[5,2]]},"301":{"position":[[337,2],[791,2]]},"308":{"position":[[1637,2]]},"361":{"position":[[1214,2]]},"447":{"position":[[86,2]]},"455":{"position":[[884,2]]},"542":{"position":[[100,2]]},"544":{"position":[[90,2]]},"548":{"position":[[27,2]]},"554":{"position":[[11,2],[63,2],[73,2],[97,2],[102,2],[142,2],[268,2]]},"561":{"position":[[438,2]]},"570":{"position":[[20,2]]},"613":{"position":[[58,2]]},"832":{"position":[[1749,2]]},"868":{"position":[[241,2],[254,2]]},"874":{"position":[[199,2]]},"891":{"position":[[97,2],[139,2],[180,2]]}}}],["实施",{"_index":3121,"t":{"798":{"position":[[50,2]]}}}],["实时",{"_index":2968,"t":{"725":{"position":[[0,2]]}}}],["实测",{"_index":1383,"t":{"212":{"position":[[25,2]]},"465":{"position":[[14,2]]},"874":{"position":[[326,2]]}}}],["实现",{"_index":175,"t":{"25":{"position":[[7,2]]},"42":{"position":[[4,2]]},"48":{"position":[[56,2]]},"53":{"position":[[87,2]]},"57":{"position":[[30,2],[157,2],[320,2],[388,2],[459,2],[622,2],[710,2]]},"69":{"position":[[42,2]]},"89":{"position":[[25,2]]},"118":{"position":[[11,2],[29,2]]},"120":{"position":[[38,2],[49,2],[510,2]]},"127":{"position":[[41,2]]},"138":{"position":[[89,2]]},"140":{"position":[[125,2]]},"151":{"position":[[16,2]]},"166":{"position":[[11,2],[33,2]]},"188":{"position":[[44,2]]},"205":{"position":[[11,2],[35,2]]},"223":{"position":[[80,2]]},"225":{"position":[[12,2],[1925,2]]},"235":{"position":[[239,2]]},"252":{"position":[[11,2],[33,2]]},"263":{"position":[[22,2]]},"272":{"position":[[30,2],[149,2],[304,2]]},"284":{"position":[[47,2]]},"286":{"position":[[36,2],[50,2]]},"290":{"position":[[1094,2]]},"301":{"position":[[20,2],[119,2]]},"308":{"position":[[30,2],[151,2],[308,2],[373,2],[529,2],[1550,2]]},"323":{"position":[[12,2],[20,2],[277,2]]},"347":{"position":[[30,2],[153,2],[312,2],[379,2],[539,2],[989,2]]},"357":{"position":[[64,2],[79,2]]},"359":{"position":[[2,2]]},"361":{"position":[[32,2]]},"365":{"position":[[85,2],[336,2],[595,2],[854,2],[1115,2]]},"376":{"position":[[193,2],[602,2],[666,2]]},"397":{"position":[[62,2]]},"420":{"position":[[35,2]]},"431":{"position":[[110,2]]},"440":{"position":[[238,2]]},"444":{"position":[[100,2],[135,2]]},"455":{"position":[[349,2],[380,2],[868,2]]},"468":{"position":[[90,2]]},"473":{"position":[[11,2],[20,2],[45,2]]},"485":{"position":[[84,2],[174,2],[302,2]]},"489":{"position":[[6,2]]},"491":{"position":[[9,2]]},"493":{"position":[[6,2]]},"507":{"position":[[798,2]]},"512":{"position":[[27,2]]},"530":{"position":[[493,2],[534,2],[544,2],[1000,2],[1054,2]]},"539":{"position":[[179,2]]},"542":{"position":[[113,2]]},"544":{"position":[[75,2]]},"550":{"position":[[67,2]]},"552":{"position":[[110,2],[114,2]]},"561":{"position":[[6,2]]},"572":{"position":[[4,2]]},"574":{"position":[[67,2],[99,2]]},"610":{"position":[[459,2],[559,2]]},"617":{"position":[[277,2]]},"630":{"position":[[246,2]]},"643":{"position":[[26,2]]},"646":{"position":[[15,2]]},"663":{"position":[[15,2]]},"668":{"position":[[41,2]]},"672":{"position":[[54,2],[193,2]]},"674":{"position":[[165,2]]},"684":{"position":[[2,2],[24,2]]},"729":{"position":[[49,2],[79,2]]},"732":{"position":[[39,2]]},"743":{"position":[[35,2]]},"772":{"position":[[29,2]]},"780":{"position":[[39,2]]},"806":{"position":[[146,2]]},"814":{"position":[[76,2]]},"816":{"position":[[423,2]]},"854":{"position":[[90,2]]},"859":{"position":[[1069,2]]},"862":{"position":[[51,2]]},"872":{"position":[[455,2]]},"878":{"position":[[306,2],[349,2]]},"882":{"position":[[254,2]]},"894":{"position":[[27,2],[184,2]]},"901":{"position":[[9,2]]},"925":{"position":[[44,2]]},"928":{"position":[[32,2]]},"969":{"position":[[208,2]]}}}],["实现需求",{"_index":2728,"t":{"619":{"position":[[75,4]]}}}],["实际",{"_index":1266,"t":{"184":{"position":[[508,2]]},"210":{"position":[[25,2]]},"218":{"position":[[508,2]]},"272":{"position":[[954,2]]},"308":{"position":[[895,2]]},"340":{"position":[[604,2]]},"347":{"position":[[664,2]]},"361":{"position":[[667,2],[851,2]]},"365":{"position":[[1826,2]]},"470":{"position":[[792,2]]},"473":{"position":[[240,2]]},"514":{"position":[[6,2],[23,2]]},"535":{"position":[[32,2],[49,2]]},"634":{"position":[[37,2]]},"681":{"position":[[40,2]]},"691":{"position":[[48,2]]},"750":{"position":[[30,2]]},"780":{"position":[[349,2]]},"783":{"position":[[275,2]]},"874":{"position":[[317,2]]},"906":{"position":[[103,2]]},"930":{"position":[[6,2],[23,2]]}}}],["实际上",{"_index":198,"t":{"25":{"position":[[235,3]]},"28":{"position":[[25,3]]},"42":{"position":[[10,3]]},"44":{"position":[[0,3]]},"132":{"position":[[308,3]]},"138":{"position":[[0,3],[385,3]]},"159":{"position":[[61,3]]},"184":{"position":[[944,3],[1723,3]]},"218":{"position":[[944,3],[1723,3]]},"220":{"position":[[74,3]]},"225":{"position":[[388,3],[1931,3]]},"290":{"position":[[725,3]]},"301":{"position":[[1272,3],[1610,3]]},"397":{"position":[[0,3]]},"444":{"position":[[36,3]]},"447":{"position":[[866,3]]},"455":{"position":[[968,3]]},"470":{"position":[[820,3]]},"537":{"position":[[518,3]]},"539":{"position":[[33,3]]},"554":{"position":[[187,3]]},"561":{"position":[[160,3]]},"630":{"position":[[22,3]]},"663":{"position":[[0,3],[452,3]]},"666":{"position":[[120,3]]},"681":{"position":[[68,3]]},"752":{"position":[[53,3]]},"806":{"position":[[150,3]]},"828":{"position":[[152,3]]},"859":{"position":[[1059,3]]},"876":{"position":[[198,3]]}}}],["实际操作",{"_index":1099,"t":{"153":{"position":[[62,4]]}}}],["实际效果",{"_index":3360,"t":{"906":{"position":[[65,4]]}}}],["客户端",{"_index":327,"t":{"36":{"position":[[63,3]]},"57":{"position":[[0,3],[1973,3]]},"66":{"position":[[4,3],[12,3],[58,3]]},"69":{"position":[[122,3]]},"75":{"position":[[4,3],[12,3],[58,3]]},"80":{"position":[[24,3]]},"86":{"position":[[4,3],[12,3],[103,3]]},"91":{"position":[[352,3]]},"97":{"position":[[15,3]]},"116":{"position":[[7,3]]},"125":{"position":[[231,3],[242,3]]},"132":{"position":[[67,3]]},"134":{"position":[[10,3]]},"136":{"position":[[10,3],[37,3]]},"138":{"position":[[10,3],[47,3],[137,3],[158,3],[200,3],[224,3],[371,3]]},"140":{"position":[[5,3],[21,3],[69,3]]},"144":{"position":[[25,3]]},"146":{"position":[[0,3],[6,3],[71,3]]},"162":{"position":[[8,3]]},"166":{"position":[[101,3],[190,3],[430,3]]},"178":{"position":[[14,3]]},"184":{"position":[[1211,3],[1405,3],[1588,3]]},"186":{"position":[[138,3],[170,3]]},"192":{"position":[[14,3]]},"194":{"position":[[544,3]]},"199":{"position":[[43,3]]},"207":{"position":[[377,3]]},"210":{"position":[[90,3]]},"212":{"position":[[31,3]]},"216":{"position":[[7,3],[39,3]]},"218":{"position":[[1211,3],[1405,3],[1588,3]]},"220":{"position":[[145,3],[177,3]]},"223":{"position":[[172,3],[222,3],[275,3],[343,3],[548,3],[625,3]]},"225":{"position":[[725,3],[779,3],[929,3],[979,3],[1032,3],[1483,3],[1533,3],[1586,3]]},"229":{"position":[[162,3]]},"235":{"position":[[588,3]]},"237":{"position":[[8,3],[58,3]]},"239":{"position":[[11,3],[47,3],[222,3],[268,3]]},"248":{"position":[[59,3],[100,3]]},"252":{"position":[[101,3],[190,3],[430,3]]},"272":{"position":[[0,3],[1767,3]]},"301":{"position":[[2886,3]]},"308":{"position":[[0,3],[2571,3]]},"311":{"position":[[15,3]]},"340":{"position":[[25,3]]},"347":{"position":[[0,3],[2543,3]]},"383":{"position":[[19,3],[23,3]]},"393":{"position":[[0,3]]},"402":{"position":[[65,3]]},"406":{"position":[[0,3],[205,3],[586,3]]},"422":{"position":[[0,3],[218,3],[570,3]]},"444":{"position":[[70,3],[115,3],[183,3],[513,3],[580,3],[621,3]]},"447":{"position":[[13,3],[196,3],[736,3],[1017,3],[1258,3]]},"449":{"position":[[28,3],[159,3],[240,3]]},"461":{"position":[[9,3]]},"485":{"position":[[7,3]]},"495":{"position":[[674,3],[1049,3]]},"526":{"position":[[265,3],[283,3]]},"528":{"position":[[19,3],[92,3],[99,3],[121,3]]},"530":{"position":[[6,3],[55,3],[107,3],[432,3],[508,3],[514,3],[1031,3],[1039,3],[1059,3],[1065,3]]},"533":{"position":[[68,3]]},"535":{"position":[[16,3]]},"537":{"position":[[306,3],[982,3],[1442,3]]},"539":{"position":[[183,3]]},"561":{"position":[[789,3]]},"574":{"position":[[252,3]]},"581":{"position":[[36,3]]},"590":{"position":[[1,3],[12,3]]},"593":{"position":[[11,3]]},"595":{"position":[[163,3]]},"613":{"position":[[2,3],[19,3]]},"615":{"position":[[23,3],[127,3]]},"617":{"position":[[100,3],[258,3]]},"623":{"position":[[63,3],[87,3]]},"628":{"position":[[72,3]]},"630":{"position":[[3,3]]},"663":{"position":[[18,3],[422,3],[460,3]]},"668":{"position":[[83,3]]},"670":{"position":[[12,3]]},"686":{"position":[[7,3],[486,3]]},"693":{"position":[[6,3]]},"723":{"position":[[31,3]]},"727":{"position":[[19,3],[1101,3]]},"729":{"position":[[12,3]]},"738":{"position":[[17,3]]},"745":{"position":[[0,3],[218,3],[641,3]]},"748":{"position":[[245,3]]},"750":{"position":[[224,3]]},"752":{"position":[[79,3],[106,3],[178,3]]},"758":{"position":[[139,3]]},"770":{"position":[[12,3]]},"772":{"position":[[5,3]]},"776":{"position":[[20,3],[41,3]]},"778":{"position":[[98,3]]},"780":{"position":[[21,3]]},"790":{"position":[[27,3]]},"792":{"position":[[60,3],[64,3]]},"794":{"position":[[37,3],[51,3]]},"796":{"position":[[34,3],[46,3]]},"800":{"position":[[24,3],[28,3],[32,3]]},"804":{"position":[[26,3]]},"828":{"position":[[57,3],[93,3]]},"830":{"position":[[51,3]]},"832":{"position":[[618,3],[852,3],[1059,3],[1213,3],[1274,3]]},"836":{"position":[[5,3]]},"854":{"position":[[15,3],[40,3],[54,3]]},"864":{"position":[[8,3]]},"870":{"position":[[91,3],[152,3]]},"872":{"position":[[296,3],[396,3]]},"874":{"position":[[39,3],[187,3]]},"878":{"position":[[110,3],[191,3]]},"882":{"position":[[44,3]]},"884":{"position":[[122,3],[171,3],[284,3]]},"909":{"position":[[117,3],[146,3]]},"925":{"position":[[149,3]]},"940":{"position":[[2,3]]},"980":{"position":[[186,3],[472,3]]}}}],["容器",{"_index":1403,"t":{"223":{"position":[[873,2]]},"225":{"position":[[1209,2],[1763,2]]},"229":{"position":[[465,2]]},"235":{"position":[[1213,2]]},"261":{"position":[[436,2]]},"361":{"position":[[1183,2]]},"542":{"position":[[73,2],[89,2],[209,2]]},"554":{"position":[[233,2]]},"727":{"position":[[194,2]]},"859":{"position":[[919,2]]},"874":{"position":[[207,2]]},"882":{"position":[[206,2]]},"884":{"position":[[41,2]]},"891":{"position":[[27,2],[252,2],[289,2]]}}}],["容易",{"_index":929,"t":{"125":{"position":[[161,2]]},"485":{"position":[[221,2]]}}}],["容量",{"_index":1226,"t":{"184":{"position":[[29,2]]},"218":{"position":[[29,2]]},"301":{"position":[[878,2]]}}}],["宽带网",{"_index":3220,"t":{"839":{"position":[[59,3]]}}}],["密封性",{"_index":2090,"t":{"440":{"position":[[199,3]]}}}],["密码",{"_index":1559,"t":{"288":{"position":[[68,2]]}}}],["密钥",{"_index":1935,"t":{"389":{"position":[[60,2]]},"935":{"position":[[75,2]]},"961":{"position":[[108,2],[113,2],[118,2]]},"969":{"position":[[59,2],[110,2],[176,2],[379,2]]}}}],["察觉",{"_index":2130,"t":{"444":{"position":[[431,2]]}}}],["对",{"_index":221,"t":{"28":{"position":[[37,1]]},"40":{"position":[[34,1],[304,1]]},"53":{"position":[[9,1]]},"57":{"position":[[387,1],[1016,1]]},"166":{"position":[[491,1],[539,1]]},"225":{"position":[[720,1]]},"252":{"position":[[491,1],[539,1]]},"272":{"position":[[734,1]]},"308":{"position":[[372,1],[1377,1]]},"347":{"position":[[378,1],[928,1]]},"374":{"position":[[11,1]]},"378":{"position":[[79,1]]},"440":{"position":[[246,1]]},"444":{"position":[[426,1]]},"489":{"position":[[8,1]]},"491":{"position":[[11,1]]},"552":{"position":[[25,1]]},"554":{"position":[[5,1]]},"564":{"position":[[3,1]]},"655":{"position":[[358,1]]},"659":{"position":[[2,1]]},"661":{"position":[[119,1]]},"666":{"position":[[9,1]]},"727":{"position":[[1834,1]]},"752":{"position":[[156,1]]},"774":{"position":[[271,1]]},"778":{"position":[[9,1]]},"796":{"position":[[33,1]]},"826":{"position":[[82,1],[89,1],[175,1]]},"828":{"position":[[47,1],[185,1],[215,1],[264,1]]},"830":{"position":[[82,1],[150,1],[174,1],[353,1],[373,1],[414,1],[473,1],[755,1]]},"957":{"position":[[24,1]]}}}],["对于",{"_index":1752,"t":{"357":{"position":[[196,2]]},"376":{"position":[[574,2]]},"378":{"position":[[65,2]]},"455":{"position":[[48,2]]},"468":{"position":[[54,2]]},"470":{"position":[[823,2]]},"503":{"position":[[116,2]]},"526":{"position":[[335,2]]},"528":{"position":[[97,2]]},"546":{"position":[[0,2]]},"554":{"position":[[148,2]]},"689":{"position":[[253,2]]},"868":{"position":[[156,2]]}}}],["对应",{"_index":280,"t":{"34":{"position":[[67,2]]},"57":{"position":[[159,2]]},"116":{"position":[[55,2]]},"120":{"position":[[554,2]]},"162":{"position":[[11,2]]},"272":{"position":[[151,2]]},"301":{"position":[[121,2]]},"308":{"position":[[153,2]]},"347":{"position":[[155,2]]},"361":{"position":[[34,2]]},"530":{"position":[[506,2],[1027,2]]},"705":{"position":[[38,2]]},"718":{"position":[[137,2]]},"748":{"position":[[395,2],[420,2]]},"891":{"position":[[91,2]]}}}],["对接",{"_index":496,"t":{"55":{"position":[[38,2]]},"270":{"position":[[40,2]]},"306":{"position":[[57,2]]},"345":{"position":[[37,2]]}}}],["对方",{"_index":1070,"t":{"146":{"position":[[18,2]]},"485":{"position":[[265,2]]},"581":{"position":[[105,2]]},"626":{"position":[[5,2]]},"748":{"position":[[301,2]]},"756":{"position":[[2,2]]}}}],["对象",{"_index":503,"t":{"57":{"position":[[62,2],[224,2]]},"127":{"position":[[721,2]]},"153":{"position":[[56,2]]},"159":{"position":[[225,2]]},"180":{"position":[[43,2]]},"212":{"position":[[113,2]]},"272":{"position":[[58,2],[216,2]]},"292":{"position":[[38,2]]},"297":{"position":[[134,2]]},"301":{"position":[[38,2],[186,2],[765,2],[795,2],[833,2],[1084,2]]},"308":{"position":[[59,2],[218,2]]},"321":{"position":[[7,2]]},"340":{"position":[[606,2]]},"347":{"position":[[59,2],[220,2]]},"376":{"position":[[597,2]]},"378":{"position":[[44,2]]},"523":{"position":[[5,2],[378,2]]},"542":{"position":[[26,2]]},"857":{"position":[[228,2],[661,2]]},"859":{"position":[[127,2],[550,2]]},"882":{"position":[[91,2]]},"957":{"position":[[33,2],[91,2],[152,2]]}}}],["导出",{"_index":2139,"t":{"444":{"position":[[568,2]]},"447":{"position":[[67,2],[1030,2],[1273,2]]},"932":{"position":[[340,2]]}}}],["导致",{"_index":455,"t":{"50":{"position":[[111,2]]}}}],["封",{"_index":228,"t":{"28":{"position":[[55,1]]}}}],["封包",{"_index":2268,"t":{"468":{"position":[[108,2]]}}}],["封装",{"_index":226,"t":{"28":{"position":[[51,2]]},"48":{"position":[[13,2],[21,2]]},"340":{"position":[[793,2]]},"359":{"position":[[128,2]]},"361":{"position":[[521,2],[531,2]]},"365":{"position":[[69,2],[177,2],[1298,2],[1455,2],[2082,2]]},"470":{"position":[[242,2]]},"498":{"position":[[69,2]]},"528":{"position":[[36,2]]},"574":{"position":[[18,2]]},"600":{"position":[[31,2]]},"602":{"position":[[3,2]]},"610":{"position":[[2,2]]},"783":{"position":[[234,2]]},"785":{"position":[[28,2]]},"917":{"position":[[116,2]]}}}],["封装数据",{"_index":1817,"t":{"365":{"position":[[1389,4]]}}}],["将",{"_index":84,"t":{"10":{"position":[[2,1],[18,1]]},"12":{"position":[[2,1],[18,1],[132,1]]},"14":{"position":[[2,1],[18,1]]},"28":{"position":[[84,1]]},"32":{"position":[[158,1],[224,1]]},"57":{"position":[[1522,1],[1540,1]]},"127":{"position":[[57,1]]},"134":{"position":[[73,1]]},"157":{"position":[[299,1]]},"184":{"position":[[986,1],[1162,1],[1765,1],[1941,1]]},"186":{"position":[[311,1]]},"207":{"position":[[407,1]]},"218":{"position":[[986,1],[1162,1],[1765,1],[1941,1]]},"220":{"position":[[318,1]]},"223":{"position":[[493,1],[534,1],[611,1]]},"237":{"position":[[52,1]]},"272":{"position":[[1413,1],[1431,1]]},"290":{"position":[[801,1]]},"292":{"position":[[31,1],[351,1]]},"297":{"position":[[27,1],[202,1]]},"301":{"position":[[633,1],[787,1],[1299,1],[1635,1],[2477,1],[2495,1]]},"304":{"position":[[18,1]]},"308":{"position":[[1934,1],[1952,1],[2534,1]]},"321":{"position":[[0,1],[46,1]]},"340":{"position":[[587,1],[859,1]]},"347":{"position":[[1424,1],[2095,1],[2113,1]]},"357":{"position":[[177,1]]},"361":{"position":[[1784,1],[2944,1]]},"365":{"position":[[1303,1]]},"418":{"position":[[12,1]]},"431":{"position":[[563,1]]},"447":{"position":[[57,1],[165,1],[190,1],[1234,1],[1248,1]]},"455":{"position":[[487,1]]},"507":{"position":[[472,1],[653,1],[2128,1]]},"516":{"position":[[89,1]]},"521":{"position":[[473,1]]},"533":{"position":[[30,1],[52,1]]},"535":{"position":[[31,1]]},"537":{"position":[[244,1]]},"570":{"position":[[199,1]]},"606":{"position":[[1,1],[105,1]]},"684":{"position":[[73,1]]},"686":{"position":[[464,1]]},"691":{"position":[[66,1],[191,1]]},"697":{"position":[[78,1]]},"705":{"position":[[116,1]]},"707":{"position":[[116,1]]},"718":{"position":[[85,1]]},"727":{"position":[[1831,1]]},"748":{"position":[[96,1]]},"761":{"position":[[169,1]]},"787":{"position":[[42,1],[70,1]]},"798":{"position":[[19,1]]},"826":{"position":[[77,1]]},"868":{"position":[[226,1]]},"872":{"position":[[41,1],[697,1]]},"917":{"position":[[76,1]]},"963":{"position":[[19,1]]},"965":{"position":[[19,1],[90,1],[109,1]]},"976":{"position":[[59,1]]}}}],["将要",{"_index":3144,"t":{"818":{"position":[[6,2]]}}}],["小于",{"_index":1317,"t":{"184":{"position":[[1124,2],[1903,2]]},"218":{"position":[[1124,2],[1903,2]]},"272":{"position":[[961,2]]},"361":{"position":[[1960,2]]},"689":{"position":[[13,2]]},"780":{"position":[[82,2]]},"783":{"position":[[103,2]]},"872":{"position":[[345,2]]}}}],["小伙伴",{"_index":1896,"t":{"374":{"position":[[6,3]]},"661":{"position":[[79,3]]},"783":{"position":[[145,3]]},"787":{"position":[[113,3]]},"854":{"position":[[3,3]]}}}],["小写",{"_index":964,"t":{"127":{"position":[[282,2],[558,2]]}}}],["小时",{"_index":3460,"t":{"971":{"position":[[27,2],[60,2]]}}}],["少数",{"_index":486,"t":{"53":{"position":[[50,2]]}}}],["尚未",{"_index":1731,"t":{"347":{"position":[[1578,2]]}}}],["尝试",{"_index":2003,"t":{"415":{"position":[[61,2]]},"595":{"position":[[96,2]]},"830":{"position":[[509,2]]},"832":{"position":[[1821,2]]}}}],["就",{"_index":314,"t":{"34":{"position":[[286,1]]},"44":{"position":[[34,1],[54,1]]},"50":{"position":[[252,1]]},"138":{"position":[[151,1],[190,1]]},"151":{"position":[[117,1]]},"159":{"position":[[45,1]]},"196":{"position":[[34,1],[294,1],[312,1]]},"207":{"position":[[438,1]]},"225":{"position":[[34,1]]},"235":{"position":[[1142,1]]},"241":{"position":[[37,1],[247,1],[265,1]]},"248":{"position":[[44,1]]},"304":{"position":[[102,1]]},"340":{"position":[[798,1]]},"361":{"position":[[1170,1]]},"365":{"position":[[1384,1]]},"378":{"position":[[36,1]]},"393":{"position":[[228,1]]},"400":{"position":[[79,1]]},"402":{"position":[[94,1]]},"409":{"position":[[49,1],[112,1]]},"440":{"position":[[36,1]]},"444":{"position":[[401,1],[664,1]]},"447":{"position":[[36,1],[858,1]]},"455":{"position":[[1068,1]]},"479":{"position":[[28,1]]},"485":{"position":[[116,1],[148,1]]},"503":{"position":[[164,1]]},"507":{"position":[[457,1],[638,1]]},"526":{"position":[[290,1],[309,1]]},"528":{"position":[[12,1]]},"530":{"position":[[1053,1]]},"535":{"position":[[30,1]]},"537":{"position":[[511,1]]},"539":{"position":[[26,1]]},"554":{"position":[[174,1]]},"617":{"position":[[25,1]]},"628":{"position":[[42,1]]},"661":{"position":[[53,1]]},"663":{"position":[[51,1]]},"689":{"position":[[150,1],[167,1],[241,1]]},"720":{"position":[[9,1]]},"778":{"position":[[102,1]]},"783":{"position":[[216,1]]},"787":{"position":[[116,1]]},"909":{"position":[[191,1]]},"976":{"position":[[36,1]]}}}],["就是",{"_index":247,"t":{"28":{"position":[[140,2]]},"80":{"position":[[1789,2]]},"89":{"position":[[19,2]]},"125":{"position":[[174,2],[192,2],[197,2]]},"127":{"position":[[702,2]]},"159":{"position":[[76,2]]},"308":{"position":[[2437,2]]},"336":{"position":[[102,2],[113,2]]},"340":{"position":[[570,2]]},"368":{"position":[[4,2]]},"376":{"position":[[9,2]]},"383":{"position":[[29,2]]},"391":{"position":[[6,2]]},"440":{"position":[[8,2]]},"444":{"position":[[250,2]]},"455":{"position":[[58,2]]},"473":{"position":[[236,2]]},"485":{"position":[[245,2]]},"514":{"position":[[32,2]]},"526":{"position":[[13,2],[98,2],[260,2]]},"530":{"position":[[1014,2]]},"542":{"position":[[61,2]]},"554":{"position":[[208,2]]},"613":{"position":[[60,2]]},"615":{"position":[[47,2],[141,2]]},"679":{"position":[[67,2]]},"697":{"position":[[43,2]]},"778":{"position":[[7,2],[35,2]]},"783":{"position":[[168,2],[330,2],[385,2]]},"787":{"position":[[139,2]]},"806":{"position":[[424,2]]},"839":{"position":[[102,2]]},"917":{"position":[[38,2]]},"930":{"position":[[32,2]]},"976":{"position":[[9,2]]}}}],["就行了",{"_index":3110,"t":{"787":{"position":[[131,3]]}}}],["就要",{"_index":298,"t":{"34":{"position":[[164,2]]}}}],["尽可能",{"_index":1499,"t":{"265":{"position":[[10,3]]}}}],["尽量",{"_index":1445,"t":{"239":{"position":[[139,2]]},"290":{"position":[[784,2]]}}}],["尾",{"_index":2916,"t":{"702":{"position":[[1923,1]]}}}],["局域网",{"_index":2450,"t":{"526":{"position":[[113,3]]},"689":{"position":[[105,3]]},"814":{"position":[[28,3]]}}}],["局限于",{"_index":2183,"t":{"449":{"position":[[114,3]]}}}],["届时",{"_index":264,"t":{"32":{"position":[[144,2]]},"308":{"position":[[2548,2]]},"738":{"position":[[127,2]]}}}],["屏幕",{"_index":2657,"t":{"586":{"position":[[29,2],[34,2]]}}}],["展示",{"_index":1493,"t":{"263":{"position":[[3,2]]},"334":{"position":[[74,2]]},"906":{"position":[[63,2]]},"952":{"position":[[19,2]]}}}],["属",{"_index":2118,"t":{"444":{"position":[[299,1]]}}}],["属性",{"_index":465,"t":{"50":{"position":[[168,2]]},"57":{"position":[[84,2],[244,2],[401,2]]},"127":{"position":[[135,2]]},"166":{"position":[[280,2],[586,2]]},"184":{"position":[[805,2],[1503,2],[1984,2]]},"218":{"position":[[805,2],[1503,2],[1984,2]]},"252":{"position":[[280,2],[586,2]]},"272":{"position":[[80,2],[236,2]]},"297":{"position":[[165,2],[257,2],[329,2]]},"301":{"position":[[60,2],[206,2],[1982,2],[2068,2],[2158,2],[2250,2]]},"308":{"position":[[81,2],[238,2],[386,2],[651,2],[771,2],[890,2]]},"347":{"position":[[81,2],[240,2],[392,2],[659,2]]},"361":{"position":[[36,2]]},"374":{"position":[[14,2],[52,2]]},"376":{"position":[[6,2],[29,2],[90,2],[102,2],[111,2],[177,2],[249,2],[652,2]]},"378":{"position":[[111,2],[133,2]]},"406":{"position":[[64,2]]},"411":{"position":[[57,2]]},"413":{"position":[[57,2]]},"447":{"position":[[103,2]]},"512":{"position":[[62,2]]},"521":{"position":[[276,2],[516,2]]},"530":{"position":[[467,2],[496,2]]},"544":{"position":[[7,2]]},"546":{"position":[[20,2],[108,2]]},"550":{"position":[[47,2]]},"552":{"position":[[20,2]]},"570":{"position":[[109,2],[113,2]]},"574":{"position":[[270,2]]},"641":{"position":[[91,2]]},"659":{"position":[[24,2]]},"745":{"position":[[561,2]]},"767":{"position":[[44,2]]},"816":{"position":[[88,2]]},"828":{"position":[[337,2]]},"830":{"position":[[203,2],[210,2],[343,2],[468,2]]},"870":{"position":[[129,2]]},"872":{"position":[[1085,2],[1108,2]]},"891":{"position":[[114,2],[178,2]]},"894":{"position":[[61,2]]},"928":{"position":[[71,2]]}}}],["嵌入",{"_index":3290,"t":{"872":{"position":[[568,2],[996,2]]},"906":{"position":[[154,2]]}}}],["嵌套",{"_index":2042,"t":{"431":{"position":[[543,2]]},"500":{"position":[[26,2]]},"552":{"position":[[87,2]]},"919":{"position":[[20,2]]}}}],["工作",{"_index":306,"t":{"34":{"position":[[230,2]]},"50":{"position":[[5,2]]},"53":{"position":[[36,2]]},"184":{"position":[[1030,2],[1809,2]]},"218":{"position":[[1030,2],[1809,2]]},"334":{"position":[[20,2],[61,2],[85,2]]},"340":{"position":[[7,2]]},"359":{"position":[[12,2]]},"444":{"position":[[234,2]]},"509":{"position":[[24,2]]},"530":{"position":[[134,2]]},"783":{"position":[[269,2],[295,2],[323,2]]},"785":{"position":[[53,2],[74,2]]},"787":{"position":[[149,2]]},"826":{"position":[[15,2]]},"917":{"position":[[10,2]]},"965":{"position":[[33,2],[62,2]]}}}],["工作日",{"_index":3441,"t":{"965":{"position":[[95,3]]}}}],["工具",{"_index":623,"t":{"62":{"position":[[34,2]]},"71":{"position":[[34,2]]},"82":{"position":[[34,2]]},"134":{"position":[[50,2]]},"461":{"position":[[24,2]]},"521":{"position":[[72,2],[465,2]]},"707":{"position":[[151,2]]},"718":{"position":[[79,2]]},"872":{"position":[[595,2],[1023,2]]}}}],["工具箱",{"_index":1744,"t":{"353":{"position":[[30,3]]}}}],["工程师",{"_index":1742,"t":{"353":{"position":[[25,3]]}}}],["左右",{"_index":1232,"t":{"184":{"position":[[70,2],[326,2],[403,2],[1156,2],[1935,2]]},"218":{"position":[[70,2],[326,2],[403,2],[1156,2],[1935,2]]}}}],["巧合",{"_index":1689,"t":{"338":{"position":[[39,2]]}}}],["巨大",{"_index":1302,"t":{"184":{"position":[[949,2],[1728,2]]},"218":{"position":[[949,2],[1728,2]]}}}],["差",{"_index":1684,"t":{"336":{"position":[[124,1]]},"340":{"position":[[201,1]]},"906":{"position":[[117,1]]}}}],["差异",{"_index":2362,"t":{"505":{"position":[[88,2]]}}}],["差距",{"_index":643,"t":{"69":{"position":[[135,2]]},"526":{"position":[[203,2]]}}}],["已经",{"_index":1354,"t":{"192":{"position":[[21,2]]},"194":{"position":[[475,2]]},"196":{"position":[[16,2],[276,2]]},"220":{"position":[[77,2]]},"229":{"position":[[27,2]]},"233":{"position":[[481,2]]},"241":{"position":[[19,2],[229,2]]},"297":{"position":[[148,2],[240,2],[262,2],[312,2],[334,2]]},"301":{"position":[[1404,2]]},"376":{"position":[[600,2]]},"431":{"position":[[840,2]]},"455":{"position":[[5,2]]},"485":{"position":[[98,2],[169,2]]},"528":{"position":[[34,2]]},"537":{"position":[[1016,2]]},"663":{"position":[[90,2],[425,2]]},"666":{"position":[[154,2]]},"752":{"position":[[62,2]]},"780":{"position":[[130,2]]},"783":{"position":[[217,2]]}}}],["希望",{"_index":1421,"t":{"225":{"position":[[1941,2]]},"359":{"position":[[91,2],[134,2]]},"376":{"position":[[623,2]]},"409":{"position":[[70,2]]},"574":{"position":[[95,2]]},"617":{"position":[[64,2]]},"619":{"position":[[28,2]]},"661":{"position":[[32,2]]},"666":{"position":[[169,2]]},"814":{"position":[[36,2]]}}}],["带",{"_index":2908,"t":{"702":{"position":[[1464,1]]}}}],["带宽",{"_index":2453,"t":{"526":{"position":[[129,2],[187,2],[247,2],[278,2]]}}}],["带有",{"_index":3412,"t":{"954":{"position":[[17,2]]}}}],["带来",{"_index":1281,"t":{"184":{"position":[[709,2]]},"218":{"position":[[709,2]]},"639":{"position":[[50,2]]}}}],["帧",{"_index":2887,"t":{"702":{"position":[[1081,1],[1255,1]]},"820":{"position":[[174,1],[245,1],[262,1]]}}}],["帮",{"_index":2134,"t":{"444":{"position":[[447,1]]}}}],["帮助",{"_index":710,"t":{"91":{"position":[[64,2],[501,2]]}}}],["常",{"_index":2931,"t":{"707":{"position":[[61,1]]}}}],["常用",{"_index":2688,"t":{"600":{"position":[[44,2]]}}}],["常见",{"_index":2080,"t":{"440":{"position":[[48,2]]}}}],["常规",{"_index":1428,"t":{"235":{"position":[[268,2]]},"376":{"position":[[4,2]]},"503":{"position":[[20,2]]},"526":{"position":[[45,2],[66,2],[100,2],[143,2]]},"689":{"position":[[53,2],[69,2]]},"792":{"position":[[2,2]]},"824":{"position":[[0,2]]},"872":{"position":[[358,2],[421,2],[897,2]]}}}],["平",{"_index":1841,"t":{"370":{"position":[[105,1]]}}}],["平台",{"_index":1336,"t":{"184":{"position":[[1521,2]]},"218":{"position":[[1521,2]]},"440":{"position":[[249,2]]},"444":{"position":[[214,2]]},"521":{"position":[[28,2],[135,2],[198,2]]},"707":{"position":[[57,2],[65,2],[80,2]]},"718":{"position":[[139,2]]}}}],["平均",{"_index":2846,"t":{"689":{"position":[[134,2]]}}}],["平等权利",{"_index":3181,"t":{"826":{"position":[[65,4]]}}}],["年",{"_index":3373,"t":{"909":{"position":[[50,1]]}}}],["并不知道",{"_index":2781,"t":{"663":{"position":[[31,4]]}}}],["并且",{"_index":510,"t":{"57":{"position":[[141,2]]},"261":{"position":[[247,2]]},"272":{"position":[[133,2]]},"301":{"position":[[103,2]]},"308":{"position":[[135,2]]},"347":{"position":[[137,2],[970,2],[1596,2]]},"554":{"position":[[61,2]]},"653":{"position":[[182,2]]},"684":{"position":[[93,2]]},"734":{"position":[[505,2]]},"750":{"position":[[247,2],[538,2]]},"872":{"position":[[729,2],[1146,2]]},"906":{"position":[[71,2]]},"969":{"position":[[28,2]]}}}],["并发",{"_index":1561,"t":{"290":{"position":[[89,2]]},"570":{"position":[[4,2],[37,2],[49,2]]},"809":{"position":[[67,2]]},"820":{"position":[[12,2]]}}}],["并存",{"_index":1362,"t":{"194":{"position":[[202,2]]},"233":{"position":[[205,2]]}}}],["并未",{"_index":1342,"t":{"186":{"position":[[81,2]]},"783":{"position":[[247,2]]}}}],["并用",{"_index":947,"t":{"127":{"position":[[125,2]]},"512":{"position":[[53,2]]},"894":{"position":[[53,2]]},"928":{"position":[[63,2]]}}}],["并行",{"_index":3179,"t":{"826":{"position":[[35,2]]}}}],["并非",{"_index":2281,"t":{"473":{"position":[[277,2]]}}}],["广东",{"_index":1893,"t":{"370":{"position":[[471,2]]}}}],["广播",{"_index":1341,"t":{"184":{"position":[[2021,2]]},"218":{"position":[[2021,2]]},"292":{"position":[[132,2],[139,2]]},"778":{"position":[[60,2],[83,2],[94,2],[162,2]]},"802":{"position":[[31,2]]},"839":{"position":[[0,2],[46,2],[66,2]]},"841":{"position":[[15,2]]},"847":{"position":[[0,2],[15,2]]},"849":{"position":[[0,2]]},"851":{"position":[[104,2],[324,2],[337,2]]}}}],["广播者",{"_index":3217,"t":{"839":{"position":[[28,3]]}}}],["广泛",{"_index":2245,"t":{"461":{"position":[[30,2]]},"741":{"position":[[118,2]]}}}],["序",{"_index":1971,"t":{"404":{"position":[[67,1],[133,1]]},"748":{"position":[[217,1],[434,1],[444,1],[459,1]]},"783":{"position":[[85,1]]},"820":{"position":[[175,1]]}}}],["序列",{"_index":2053,"t":{"434":{"position":[[134,2]]}}}],["序列化",{"_index":1182,"t":{"164":{"position":[[166,3]]},"250":{"position":[[166,3]]},"427":{"position":[[1,3],[12,3],[19,3],[24,3]]},"431":{"position":[[19,3],[549,3]]},"434":{"position":[[129,3]]},"442":{"position":[[93,3]]},"503":{"position":[[1,3],[13,3],[22,3],[159,3]]},"505":{"position":[[65,3],[71,3]]},"507":{"position":[[2104,3],[2210,3]]},"509":{"position":[[9,3]]},"519":{"position":[[21,3],[26,3],[86,3],[147,3]]},"521":{"position":[[32,3],[63,3],[76,3],[139,3],[201,3],[467,3]]},"523":{"position":[[346,3],[351,3],[2700,3],[2705,3]]},"677":{"position":[[16,3],[38,3]]},"679":{"position":[[16,3],[70,3],[114,3],[236,3]]},"681":{"position":[[13,3],[24,3]]},"684":{"position":[[7,3],[17,3],[85,3],[100,3]]},"686":{"position":[[456,3],[504,3]]},"778":{"position":[[105,3],[125,3],[154,3]]},"792":{"position":[[154,3],[162,3],[169,3],[177,3],[186,3]]},"868":{"position":[[115,3]]},"870":{"position":[[117,3],[124,3]]},"872":{"position":[[209,3]]},"874":{"position":[[68,3],[77,3]]},"876":{"position":[[148,3]]},"884":{"position":[[188,3]]},"932":{"position":[[132,3]]}}}],["序列号",{"_index":2893,"t":{"702":{"position":[[1256,3]]}}}],["序号",{"_index":2863,"t":{"697":{"position":[[32,2],[79,2],[93,2]]},"884":{"position":[[91,2]]}}}],["库",{"_index":2957,"t":{"718":{"position":[[184,1],[203,1],[229,1]]}}}],["应",{"_index":2663,"t":{"588":{"position":[[5,1]]}}}],["应对",{"_index":448,"t":{"50":{"position":[[66,2]]},"619":{"position":[[16,2]]},"778":{"position":[[39,2]]}}}],["应当",{"_index":661,"t":{"78":{"position":[[58,2]]},"159":{"position":[[12,2]]},"184":{"position":[[345,2],[379,2]]},"218":{"position":[[345,2],[379,2]]},"268":{"position":[[88,2]]},"275":{"position":[[26,2]]},"308":{"position":[[1176,2]]},"319":{"position":[[744,2]]},"363":{"position":[[33,2]]},"365":{"position":[[12,2]]},"570":{"position":[[45,2]]},"809":{"position":[[61,2]]},"965":{"position":[[145,2]]}}}],["应用",{"_index":160,"t":{"23":{"position":[[0,2]]},"48":{"position":[[7,2]]},"444":{"position":[[365,2],[696,2]]},"521":{"position":[[168,2]]},"824":{"position":[[5,2]]},"906":{"position":[[40,2]]},"963":{"position":[[26,2]]},"965":{"position":[[24,2],[114,2]]}}}],["应用层",{"_index":923,"t":{"125":{"position":[[130,3]]},"785":{"position":[[31,3],[98,3]]}}}],["应用程序",{"_index":927,"t":{"125":{"position":[[155,4]]}}}],["应该",{"_index":297,"t":{"34":{"position":[[141,2],[180,2]]},"57":{"position":[[417,2]]},"120":{"position":[[331,2]]},"223":{"position":[[880,2]]},"225":{"position":[[1216,2],[1770,2]]},"229":{"position":[[472,2]]},"235":{"position":[[206,2],[226,2]]},"272":{"position":[[493,2]]},"301":{"position":[[892,2]]},"308":{"position":[[402,2]]},"328":{"position":[[0,2]]},"338":{"position":[[12,2],[59,2]]},"347":{"position":[[408,2]]},"383":{"position":[[0,2]]},"455":{"position":[[557,2],[777,2]]},"586":{"position":[[0,2]]},"619":{"position":[[10,2]]},"655":{"position":[[356,2]]},"836":{"position":[[90,2]]},"859":{"position":[[926,2]]},"901":{"position":[[0,2]]},"906":{"position":[[15,2]]}}}],["底层",{"_index":911,"t":{"125":{"position":[[59,2]]},"653":{"position":[[101,2],[147,2]]},"778":{"position":[[200,2]]}}}],["延时",{"_index":3212,"t":{"832":{"position":[[2039,2]]}}}],["延迟",{"_index":1293,"t":{"184":{"position":[[835,2],[864,2],[1096,2],[1614,2],[1643,2],[1875,2]]},"218":{"position":[[835,2],[864,2],[1096,2],[1614,2],[1643,2],[1875,2]]},"689":{"position":[[132,2]]},"876":{"position":[[170,2]]},"884":{"position":[[254,2]]}}}],["建立",{"_index":1034,"t":{"138":{"position":[[144,2]]},"225":{"position":[[60,2],[372,2]]},"449":{"position":[[207,2]]},"528":{"position":[[15,2],[674,2],[1388,2]]},"581":{"position":[[77,2]]},"689":{"position":[[74,2],[143,2]]}}}],["建议",{"_index":1229,"t":{"184":{"position":[[53,2],[65,2],[99,2],[300,2]]},"218":{"position":[[53,2],[65,2],[99,2],[300,2]]},"225":{"position":[[1900,2]]},"235":{"position":[[2,2],[77,2]]},"378":{"position":[[127,2]]},"666":{"position":[[166,2]]},"668":{"position":[[73,2]]},"806":{"position":[[56,2]]},"891":{"position":[[278,2]]},"969":{"position":[[196,2]]}}}],["开具",{"_index":3425,"t":{"961":{"position":[[214,2],[223,2],[226,2],[229,2]]}}}],["开发",{"_index":20,"t":{"5":{"position":[[25,2]]},"7":{"position":[[143,2]]},"94":{"position":[[17,2]]},"125":{"position":[[139,2]]},"328":{"position":[[7,2]]},"353":{"position":[[18,2]]},"383":{"position":[[9,2]]},"444":{"position":[[64,2],[507,2]]},"447":{"position":[[1,2],[23,2]]},"824":{"position":[[12,2]]},"906":{"position":[[22,2]]}}}],["开发者",{"_index":39,"t":{"5":{"position":[[90,3]]},"353":{"position":[[4,3]]},"440":{"position":[[21,3]]}}}],["开头",{"_index":1503,"t":{"268":{"position":[[35,2],[160,2]]}}}],["开始",{"_index":2969,"t":{"725":{"position":[[30,2]]},"727":{"position":[[856,2]]},"830":{"position":[[133,2]]}}}],["开放",{"_index":3310,"t":{"874":{"position":[[237,2]]},"961":{"position":[[169,2],[173,2],[177,2],[180,2]]}}}],["开源",{"_index":32,"t":{"5":{"position":[[72,2]]},"18":{"position":[[77,2]]}}}],["开辟",{"_index":3189,"t":{"828":{"position":[[44,2]]}}}],["异常",{"_index":398,"t":{"46":{"position":[[356,2]]},"50":{"position":[[84,2]]},"91":{"position":[[130,2]]},"134":{"position":[[400,2],[456,2],[736,2],[792,2],[1238,2],[1294,2],[2430,2],[2486,2]]},"159":{"position":[[205,2],[328,2]]},"196":{"position":[[103,2],[316,2]]},"241":{"position":[[56,2],[269,2]]},"301":{"position":[[490,2]]},"415":{"position":[[19,2]]},"500":{"position":[[0,2]]},"648":{"position":[[1072,2]]},"653":{"position":[[137,2],[235,2],[274,2]]},"659":{"position":[[152,2]]},"666":{"position":[[109,2]]},"734":{"position":[[228,2],[238,2],[823,2],[935,2]]},"736":{"position":[[669,2]]},"741":{"position":[[65,2]]},"792":{"position":[[118,2],[132,2]]},"830":{"position":[[144,2]]},"857":{"position":[[440,2]]},"859":{"position":[[334,2]]},"864":{"position":[[28,2]]},"870":{"position":[[106,2]]},"919":{"position":[[0,2]]},"971":{"position":[[85,2]]}}}],["异步",{"_index":1139,"t":{"159":{"position":[[4,2],[128,2],[179,2],[256,2],[289,2],[609,2],[800,2]]},"180":{"position":[[71,2]]},"184":{"position":[[304,2]]},"196":{"position":[[261,2],[283,2]]},"212":{"position":[[141,2]]},"218":{"position":[[304,2]]},"241":{"position":[[214,2],[236,2]]},"672":{"position":[[821,2],[1064,2]]},"674":{"position":[[720,2],[969,2]]},"792":{"position":[[96,2]]},"872":{"position":[[62,2]]}}}],["式",{"_index":957,"t":{"127":{"position":[[256,1],[532,1]]},"180":{"position":[[34,1]]},"212":{"position":[[104,1]]},"343":{"position":[[110,1]]},"535":{"position":[[81,1]]},"595":{"position":[[206,1]]},"597":{"position":[[39,1],[229,1]]},"884":{"position":[[147,1]]},"938":{"position":[[2,1]]}}}],["引入",{"_index":2109,"t":{"444":{"position":[[141,2],[189,2]]},"447":{"position":[[733,2],[1014,2]]},"449":{"position":[[136,2],[168,2],[188,2],[246,2]]},"481":{"position":[[0,2]]},"542":{"position":[[215,2]]}}}],["引用",{"_index":555,"t":{"57":{"position":[[751,2]]},"239":{"position":[[145,2],[153,2]]},"415":{"position":[[57,2],[71,2],[98,2],[103,2],[153,2]]},"442":{"position":[[107,2],[147,2]]},"444":{"position":[[112,2],[145,2],[577,2],[593,2],[662,2]]},"686":{"position":[[500,2]]},"716":{"position":[[20,2]]},"718":{"position":[[176,2],[237,2]]},"961":{"position":[[125,2]]},"969":{"position":[[222,2],[394,2]]}}}],["张",{"_index":1056,"t":{"142":{"position":[[196,1],[496,1]]},"436":{"position":[[726,1]]}}}],["弱",{"_index":2443,"t":{"523":{"position":[[2720,1]]}}}],["弹性",{"_index":2460,"t":{"526":{"position":[[245,2]]}}}],["强",{"_index":517,"t":{"57":{"position":[[227,1]]},"142":{"position":[[558,1]]},"272":{"position":[[219,1]]},"301":{"position":[[189,1]]},"308":{"position":[[221,1]]},"347":{"position":[[223,1]]},"370":{"position":[[153,1]]},"440":{"position":[[155,1],[202,1]]},"679":{"position":[[177,1],[211,1]]},"806":{"position":[[311,1]]}}}],["强制",{"_index":1700,"t":{"340":{"position":[[599,2]]},"415":{"position":[[173,2]]},"686":{"position":[[170,2]]}}}],["强大",{"_index":2930,"t":{"705":{"position":[[154,2]]}}}],["强悍",{"_index":3171,"t":{"822":{"position":[[68,2]]}}}],["强迫症",{"_index":2095,"t":{"440":{"position":[[287,3]]}}}],["归",{"_index":23,"t":{"5":{"position":[[32,1]]},"16":{"position":[[62,1]]},"699":{"position":[[7,1]]}}}],["归属",{"_index":3421,"t":{"961":{"position":[[56,2]]},"967":{"position":[[39,2]]}}}],["归属于",{"_index":3436,"t":{"963":{"position":[[2,3]]},"965":{"position":[[2,3]]},"967":{"position":[[3,3]]}}}],["当下",{"_index":2610,"t":{"559":{"position":[[136,2]]}}}],["当中",{"_index":2451,"t":{"526":{"position":[[116,2]]}}}],["当作",{"_index":3057,"t":{"761":{"position":[[90,2]]}}}],["当前",{"_index":662,"t":{"78":{"position":[[62,2]]},"127":{"position":[[750,2]]},"239":{"position":[[40,2],[215,2]]},"347":{"position":[[1208,2],[1562,2]]},"361":{"position":[[1212,2]]},"473":{"position":[[266,2]]},"521":{"position":[[280,2]]},"574":{"position":[[233,2]]},"639":{"position":[[15,2]]},"832":{"position":[[2078,2]]},"932":{"position":[[220,2]]}}}],["当即",{"_index":1351,"t":{"186":{"position":[[309,2]]},"220":{"position":[[316,2]]}}}],["当天",{"_index":3264,"t":{"866":{"position":[[97,2],[102,2],[136,2]]}}}],["当然",{"_index":1504,"t":{"268":{"position":[[44,2]]},"444":{"position":[[548,2]]},"610":{"position":[[344,2]]},"615":{"position":[[57,2]]},"689":{"position":[[250,2]]},"770":{"position":[[51,2]]},"787":{"position":[[159,2]]},"891":{"position":[[205,2]]}}}],["形",{"_index":1330,"t":{"184":{"position":[[1304,1],[1343,1]]},"218":{"position":[[1304,1],[1343,1]]}}}],["形式",{"_index":2154,"t":{"447":{"position":[[187,2]]},"516":{"position":[[151,2]]},"748":{"position":[[110,2]]},"830":{"position":[[506,2]]}}}],["影响",{"_index":1103,"t":{"153":{"position":[[111,2]]},"261":{"position":[[953,2]]},"378":{"position":[[87,2]]},"535":{"position":[[47,2]]},"677":{"position":[[51,2]]},"679":{"position":[[185,2],[219,2]]},"750":{"position":[[58,2],[621,2]]},"826":{"position":[[43,2]]},"882":{"position":[[389,2]]}}}],["往复",{"_index":3462,"t":{"971":{"position":[[65,2]]}}}],["往往",{"_index":2184,"t":{"449":{"position":[[180,2]]},"617":{"position":[[55,2]]},"957":{"position":[[103,2]]}}}],["往返",{"_index":2843,"t":{"689":{"position":[[92,2],[236,2]]}}}],["待",{"_index":2049,"t":{"434":{"position":[[0,1]]},"436":{"position":[[0,1]]}}}],["很多",{"_index":1408,"t":{"225":{"position":[[14,2],[1935,2]]},"235":{"position":[[63,2]]},"270":{"position":[[6,2]]},"295":{"position":[[46,2]]},"639":{"position":[[53,2]]},"854":{"position":[[1,2]]},"862":{"position":[[53,2]]}}}],["很大",{"_index":2356,"t":{"503":{"position":[[106,2]]},"677":{"position":[[46,2]]}}}],["很小",{"_index":3021,"t":{"743":{"position":[[56,2]]}}}],["很少",{"_index":2296,"t":{"485":{"position":[[228,2]]}}}],["得不到",{"_index":2790,"t":{"663":{"position":[[463,3]]}}}],["得到",{"_index":2355,"t":{"503":{"position":[[103,2]]},"641":{"position":[[95,2]]},"718":{"position":[[111,2]]},"859":{"position":[[1144,2]]}}}],["得知",{"_index":2743,"t":{"639":{"position":[[26,2]]},"653":{"position":[[212,2]]}}}],["循环",{"_index":1597,"t":{"297":{"position":[[175,2],[276,2],[348,2]]},"340":{"position":[[860,2]]},"727":{"position":[[796,2]]}}}],["微",{"_index":3129,"t":{"806":{"position":[[131,1]]},"973":{"position":[[44,1]]}}}],["微秒",{"_index":1322,"t":{"184":{"position":[[1154,2],[1933,2]]},"218":{"position":[[1154,2],[1933,2]]}}}],["微软",{"_index":884,"t":{"120":{"position":[[1684,2]]},"503":{"position":[[84,2]]},"509":{"position":[[57,2]]},"872":{"position":[[166,2]]}}}],["德",{"_index":1871,"t":{"370":{"position":[[279,1]]}}}],["心跳",{"_index":1174,"t":{"164":{"position":[[109,2]]},"250":{"position":[[109,2]]},"485":{"position":[[0,2],[157,2],[181,2],[259,2],[269,2]]},"487":{"position":[[2,2]]},"491":{"position":[[56,2]]},"493":{"position":[[8,2],[459,2]]},"495":{"position":[[20,2],[1142,2]]},"874":{"position":[[107,2]]}}}],["必定",{"_index":1157,"t":{"159":{"position":[[324,2]]}}}],["必定会",{"_index":1149,"t":{"159":{"position":[[183,3]]}}}],["必要",{"_index":771,"t":{"104":{"position":[[211,2]]},"409":{"position":[[117,2]]},"778":{"position":[[134,2]]},"935":{"position":[[125,2]]},"965":{"position":[[122,2]]}}}],["必选",{"_index":2647,"t":{"581":{"position":[[74,2]]}}}],["必须",{"_index":98,"t":{"10":{"position":[[58,2]]},"12":{"position":[[64,2],[130,2],[178,2]]},"14":{"position":[[54,2],[77,2]]},"50":{"position":[[304,2]]},"69":{"position":[[198,2]]},"104":{"position":[[17,2]]},"120":{"position":[[1014,2],[2175,2]]},"140":{"position":[[11,2]]},"153":{"position":[[85,2]]},"184":{"position":[[1334,2]]},"207":{"position":[[365,2]]},"218":{"position":[[1334,2]]},"261":{"position":[[146,2],[586,2],[898,2]]},"272":{"position":[[1152,2]]},"284":{"position":[[40,2]]},"286":{"position":[[56,2],[63,2],[97,2]]},"357":{"position":[[151,2]]},"361":{"position":[[1171,2],[1975,2]]},"440":{"position":[[37,2],[305,2]]},"449":{"position":[[244,2]]},"463":{"position":[[228,2]]},"487":{"position":[[7,2]]},"505":{"position":[[75,2]]},"514":{"position":[[292,2],[502,2]]},"516":{"position":[[377,2]]},"528":{"position":[[13,2]]},"574":{"position":[[170,2],[197,2],[297,2]]},"595":{"position":[[130,2],[142,2],[152,2],[202,2]]},"597":{"position":[[190,2],[225,2]]},"641":{"position":[[58,2]]},"657":{"position":[[14,2]]},"663":{"position":[[52,2]]},"668":{"position":[[86,2]]},"672":{"position":[[617,2],[818,2]]},"674":{"position":[[717,2],[832,2]]},"679":{"position":[[254,2]]},"681":{"position":[[155,2]]},"684":{"position":[[11,2]]},"686":{"position":[[0,2]]},"720":{"position":[[82,2]]},"727":{"position":[[1029,2]]},"732":{"position":[[49,2]]},"734":{"position":[[27,2]]},"738":{"position":[[67,2],[90,2]]},"748":{"position":[[306,2]]},"814":{"position":[[48,2]]},"816":{"position":[[407,2]]},"851":{"position":[[108,2],[361,2]]},"872":{"position":[[306,2]]},"925":{"position":[[87,2],[714,2]]},"963":{"position":[[52,2]]}}}],["快",{"_index":2075,"t":{"436":{"position":[[2018,1],[2041,1],[2062,1]]},"509":{"position":[[49,1],[64,1]]},"679":{"position":[[121,1],[241,1]]}}}],["快捷",{"_index":1751,"t":{"357":{"position":[[132,2]]},"481":{"position":[[8,2]]},"577":{"position":[[15,2]]},"732":{"position":[[35,2],[90,2]]},"738":{"position":[[2,2]]},"925":{"position":[[40,2],[128,2]]}}}],["快捷方式",{"_index":3331,"t":{"882":{"position":[[112,4]]}}}],["快速",{"_index":463,"t":{"50":{"position":[[158,2]]},"376":{"position":[[191,2]]},"487":{"position":[[71,2]]},"794":{"position":[[72,2]]}}}],["忽略",{"_index":1921,"t":{"378":{"position":[[100,2]]}}}],["忽略不计",{"_index":3148,"t":{"820":{"position":[[44,4]]}}}],["怕",{"_index":2146,"t":{"444":{"position":[[672,1]]}}}],["思路",{"_index":534,"t":{"57":{"position":[[467,2]]},"301":{"position":[[1067,2]]},"485":{"position":[[291,2]]},"666":{"position":[[164,2]]}}}],["性能",{"_index":304,"t":{"34":{"position":[[209,2]]},"153":{"position":[[113,2]]},"184":{"position":[[714,2],[952,2],[1731,2]]},"218":{"position":[[714,2],[952,2],[1731,2]]},"334":{"position":[[87,2]]},"365":{"position":[[1334,2]]},"378":{"position":[[80,2],[85,2]]},"521":{"position":[[88,2]]},"523":{"position":[[2717,2]]},"546":{"position":[[70,2]]},"650":{"position":[[14,2]]},"677":{"position":[[58,2]]},"679":{"position":[[188,2],[222,2]]},"806":{"position":[[193,2],[302,2]]},"822":{"position":[[64,2]]},"824":{"position":[[57,2]]},"828":{"position":[[24,2]]}}}],["总",{"_index":2910,"t":{"702":{"position":[[1552,1]]}}}],["恢复",{"_index":464,"t":{"50":{"position":[[160,2]]}}}],["恭喜",{"_index":2959,"t":{"720":{"position":[[0,2]]}}}],["悦",{"_index":1863,"t":{"370":{"position":[[233,1]]}}}],["情况",{"_index":487,"t":{"53":{"position":[[52,2]]},"159":{"position":[[56,2]]},"166":{"position":[[112,2]]},"252":{"position":[[112,2]]},"268":{"position":[[75,2]]},"297":{"position":[[180,2],[281,2],[353,2]]},"334":{"position":[[14,2]]},"338":{"position":[[68,2]]},"357":{"position":[[94,2],[189,2]]},"361":{"position":[[1077,2],[1095,2],[1161,2]]},"365":{"position":[[81,2]]},"376":{"position":[[570,2]]},"444":{"position":[[148,2]]},"468":{"position":[[47,2]]},"521":{"position":[[2,2]]},"535":{"position":[[54,2]]},"546":{"position":[[8,2]]},"615":{"position":[[2,2]]},"619":{"position":[[20,2]]},"743":{"position":[[68,2]]},"745":{"position":[[519,2]]},"792":{"position":[[209,2],[230,2]]},"806":{"position":[[2,2]]},"866":{"position":[[154,2]]}}}],["想",{"_index":792,"t":{"110":{"position":[[89,1]]},"125":{"position":[[199,1]]},"284":{"position":[[25,1]]},"468":{"position":[[80,1]]},"516":{"position":[[68,1],[130,1]]},"561":{"position":[[471,1]]},"628":{"position":[[31,1]]},"663":{"position":[[38,1]]}}}],["想到",{"_index":2265,"t":{"468":{"position":[[36,2]]},"778":{"position":[[72,2]]},"787":{"position":[[118,2]]}}}],["想要",{"_index":1368,"t":{"196":{"position":[[68,2]]},"239":{"position":[[265,2]]},"241":{"position":[[466,2]]},"455":{"position":[[1002,2]]},"535":{"position":[[12,2]]},"684":{"position":[[0,2]]},"957":{"position":[[114,2]]}}}],["意",{"_index":1709,"t":{"340":{"position":[[852,1]]}}}],["意义",{"_index":1241,"t":{"184":{"position":[[138,2],[512,2]]},"218":{"position":[[138,2],[512,2]]}}}],["意味",{"_index":1962,"t":{"397":{"position":[[80,2]]}}}],["意味着",{"_index":475,"t":{"50":{"position":[[267,3]]},"138":{"position":[[106,3]]},"140":{"position":[[140,3]]},"166":{"position":[[261,3],[567,3]]},"252":{"position":[[261,3],[567,3]]},"272":{"position":[[1076,3]]},"378":{"position":[[15,3],[37,3]]},"449":{"position":[[237,3]]},"617":{"position":[[26,3]]},"689":{"position":[[168,3]]},"828":{"position":[[315,3]]},"830":{"position":[[675,3]]},"976":{"position":[[37,3]]}}}],["意思",{"_index":2005,"t":{"415":{"position":[[74,2]]}}}],["感受",{"_index":2928,"t":{"705":{"position":[[141,2]]}}}],["感知",{"_index":1279,"t":{"184":{"position":[[676,2]]},"218":{"position":[[676,2]]},"663":{"position":[[44,2]]}}}],["感觉",{"_index":1812,"t":{"365":{"position":[[1358,2]]},"440":{"position":[[24,2]]}}}],["慎重",{"_index":2246,"t":{"461":{"position":[[40,2]]}}}],["懒",{"_index":2124,"t":{"444":{"position":[[379,1]]}}}],["成",{"_index":1527,"t":{"272":{"position":[[988,1]]},"449":{"position":[[99,1]]},"818":{"position":[[15,1]]}}}],["成功",{"_index":606,"t":{"60":{"position":[[433,2]]},"66":{"position":[[489,2]]},"69":{"position":[[388,2],[550,2],[691,2]]},"75":{"position":[[187,2]]},"80":{"position":[[269,2],[1247,2],[1950,2]]},"186":{"position":[[115,2]]},"188":{"position":[[137,2],[206,2]]},"210":{"position":[[94,2]]},"220":{"position":[[118,2]]},"223":{"position":[[225,2]]},"225":{"position":[[982,2],[1536,2]]},"237":{"position":[[11,2]]},"301":{"position":[[359,2],[1906,2]]},"317":{"position":[[406,2]]},"319":{"position":[[611,2]]},"336":{"position":[[84,2],[180,2]]},"340":{"position":[[181,2]]},"495":{"position":[[664,2],[1052,2]]},"521":{"position":[[429,2]]},"544":{"position":[[104,2]]},"548":{"position":[[36,2]]},"632":{"position":[[14,2]]},"653":{"position":[[112,2],[158,2],[221,2],[261,2]]},"691":{"position":[[257,2]]},"727":{"position":[[929,2]]},"736":{"position":[[547,2]]},"832":{"position":[[372,2],[811,2],[1062,2],[1599,2]]},"878":{"position":[[660,2]]}}}],["成员",{"_index":552,"t":{"57":{"position":[[737,2]]},"681":{"position":[[153,2]]}}}],["成熟",{"_index":2713,"t":{"610":{"position":[[286,2]]}}}],["成立",{"_index":103,"t":{"10":{"position":[[72,2]]},"12":{"position":[[192,2]]},"14":{"position":[[89,2]]}}}],["我们",{"_index":1420,"t":{"225":{"position":[[1939,2]]},"304":{"position":[[74,2]]},"308":{"position":[[2462,2]]},"343":{"position":[[4,2]]},"365":{"position":[[65,2],[173,2],[1369,2],[1452,2]]},"376":{"position":[[0,2]]},"409":{"position":[[59,2]]},"447":{"position":[[19,2]]},"449":{"position":[[199,2]]},"455":{"position":[[473,2],[499,2]]},"468":{"position":[[26,2]]},"485":{"position":[[172,2],[295,2]]},"487":{"position":[[98,2]]},"542":{"position":[[80,2]]},"615":{"position":[[59,2]]},"617":{"position":[[62,2]]},"619":{"position":[[26,2],[57,2]]},"661":{"position":[[30,2]]},"705":{"position":[[114,2]]},"707":{"position":[[114,2]]},"761":{"position":[[207,2]]},"787":{"position":[[4,2]]},"957":{"position":[[112,2],[137,2]]},"959":{"position":[[56,2]]}}}],["或者",{"_index":607,"t":{"60":{"position":[[465,2]]},"66":{"position":[[36,2]]},"75":{"position":[[36,2]]},"86":{"position":[[81,2]]},"118":{"position":[[39,2]]},"120":{"position":[[600,2]]},"127":{"position":[[55,2]]},"134":{"position":[[1488,2],[1986,2]]},"166":{"position":[[44,2]]},"184":{"position":[[1362,2]]},"186":{"position":[[15,2],[277,2]]},"205":{"position":[[45,2]]},"218":{"position":[[1362,2]]},"220":{"position":[[15,2],[284,2]]},"235":{"position":[[28,2],[105,2],[152,2]]},"252":{"position":[[44,2]]},"261":{"position":[[35,2]]},"290":{"position":[[1062,2]]},"297":{"position":[[297,2]]},"415":{"position":[[12,2]]},"431":{"position":[[108,2]]},"447":{"position":[[89,2],[982,2],[1024,2],[1201,2]]},"468":{"position":[[106,2]]},"503":{"position":[[122,2]]},"526":{"position":[[161,2]]},"550":{"position":[[27,2]]},"628":{"position":[[21,2]]},"634":{"position":[[6,2]]},"643":{"position":[[24,2]]},"657":{"position":[[22,2]]},"691":{"position":[[24,2],[227,2]]},"705":{"position":[[90,2]]},"736":{"position":[[318,2]]},"756":{"position":[[69,2]]},"780":{"position":[[24,2]]},"787":{"position":[[90,2]]},"878":{"position":[[240,2]]},"932":{"position":[[334,2]]},"965":{"position":[[195,2]]},"973":{"position":[[48,2]]}}}],["或者说",{"_index":2232,"t":{"455":{"position":[[958,3]]},"783":{"position":[[373,3]]}}}],["或许",{"_index":1280,"t":{"184":{"position":[[706,2]]},"218":{"position":[[706,2]]}}}],["截图",{"_index":698,"t":{"86":{"position":[[70,2]]}}}],["所以",{"_index":295,"t":{"34":{"position":[[136,2],[176,2]]},"42":{"position":[[30,2]]},"53":{"position":[[68,2]]},"57":{"position":[[740,2]]},"78":{"position":[[17,2]]},"136":{"position":[[41,2]]},"138":{"position":[[122,2]]},"146":{"position":[[105,2]]},"149":{"position":[[58,2]]},"151":{"position":[[92,2]]},"159":{"position":[[321,2]]},"184":{"position":[[930,2],[970,2],[1010,2],[1709,2],[1749,2],[1789,2]]},"218":{"position":[[930,2],[970,2],[1010,2],[1709,2],[1749,2],[1789,2]]},"239":{"position":[[135,2]]},"259":{"position":[[49,2]]},"268":{"position":[[78,2]]},"275":{"position":[[24,2]]},"297":{"position":[[227,2]]},"304":{"position":[[72,2]]},"308":{"position":[[1171,2]]},"340":{"position":[[759,2]]},"343":{"position":[[115,2]]},"347":{"position":[[1586,2]]},"361":{"position":[[781,2],[1168,2],[1973,2]]},"365":{"position":[[1450,2],[1756,2]]},"374":{"position":[[20,2]]},"415":{"position":[[118,2]]},"440":{"position":[[34,2]]},"442":{"position":[[50,2]]},"449":{"position":[[71,2],[156,2]]},"455":{"position":[[1046,2]]},"461":{"position":[[37,2]]},"465":{"position":[[370,2]]},"473":{"position":[[284,2]]},"485":{"position":[[226,2]]},"487":{"position":[[96,2]]},"503":{"position":[[152,2]]},"507":{"position":[[810,2]]},"526":{"position":[[83,2],[132,2],[333,2]]},"528":{"position":[[9,2]]},"548":{"position":[[30,2]]},"550":{"position":[[70,2]]},"561":{"position":[[289,2]]},"570":{"position":[[23,2]]},"666":{"position":[[56,2],[85,2],[148,2]]},"668":{"position":[[33,2]]},"681":{"position":[[151,2]]},"686":{"position":[[166,2],[460,2]]},"689":{"position":[[192,2],[204,2]]},"705":{"position":[[30,2]]},"707":{"position":[[86,2]]},"720":{"position":[[78,2]]},"752":{"position":[[36,2]]},"776":{"position":[[69,2],[103,2]]},"778":{"position":[[121,2]]},"780":{"position":[[140,2]]},"783":{"position":[[227,2],[237,2],[254,2]]},"785":{"position":[[77,2]]},"806":{"position":[[53,2]]},"814":{"position":[[46,2]]},"826":{"position":[[19,2],[71,2]]},"832":{"position":[[2044,2]]},"836":{"position":[[80,2]]},"862":{"position":[[76,2]]},"878":{"position":[[299,2]]},"915":{"position":[[21,2]]},"959":{"position":[[14,2]]}}}],["所属",{"_index":1452,"t":{"248":{"position":[[16,2]]},"963":{"position":[[29,2]]}}}],["所有",{"_index":21,"t":{"5":{"position":[[28,2],[39,2]]},"7":{"position":[[38,2]]},"10":{"position":[[43,2]]},"12":{"position":[[43,2],[71,2]]},"14":{"position":[[43,2]]},"16":{"position":[[58,2],[69,2]]},"20":{"position":[[61,2]]},"50":{"position":[[44,2]]},"66":{"position":[[76,2]]},"75":{"position":[[76,2]]},"86":{"position":[[121,2]]},"91":{"position":[[350,2]]},"138":{"position":[[4,2],[125,2]]},"140":{"position":[[159,2],[226,2]]},"142":{"position":[[4,2]]},"166":{"position":[[427,2]]},"169":{"position":[[21,2]]},"171":{"position":[[21,2]]},"173":{"position":[[11,2]]},"182":{"position":[[0,2]]},"186":{"position":[[208,2]]},"210":{"position":[[120,2]]},"214":{"position":[[0,2]]},"220":{"position":[[215,2]]},"223":{"position":[[623,2]]},"239":{"position":[[7,2],[45,2],[220,2]]},"252":{"position":[[427,2]]},"297":{"position":[[58,2]]},"301":{"position":[[1380,2],[1422,2]]},"308":{"position":[[1150,2]]},"345":{"position":[[6,2]]},"400":{"position":[[50,2]]},"431":{"position":[[14,2],[686,2]]},"447":{"position":[[62,2],[1275,2]]},"449":{"position":[[225,2]]},"455":{"position":[[617,2]]},"470":{"position":[[827,2]]},"505":{"position":[[18,2]]},"521":{"position":[[195,2]]},"526":{"position":[[127,2]]},"530":{"position":[[1035,2]]},"570":{"position":[[11,2],[43,2]]},"579":{"position":[[5,2]]},"586":{"position":[[15,2]]},"619":{"position":[[18,2]]},"653":{"position":[[252,2]]},"686":{"position":[[469,2]]},"699":{"position":[[3,2],[12,2]]},"718":{"position":[[151,2]]},"806":{"position":[[215,2],[381,2],[464,2],[489,2]]},"839":{"position":[[19,2],[37,2],[123,2]]},"872":{"position":[[293,2],[472,2],[481,2],[922,2],[1074,2]]},"874":{"position":[[211,2],[228,2]]},"932":{"position":[[226,2]]},"942":{"position":[[0,2]]},"946":{"position":[[0,2]]},"948":{"position":[[0,2]]},"954":{"position":[[15,2]]},"967":{"position":[[8,2],[26,2]]},"969":{"position":[[5,2]]},"978":{"position":[[4,2]]}}}],["所有人",{"_index":1584,"t":{"292":{"position":[[142,3]]}}}],["所示",{"_index":1425,"t":{"231":{"position":[[5,2]]},"290":{"position":[[66,2]]},"636":{"position":[[23,2]]},"935":{"position":[[95,2]]}}}],["所说",{"_index":1633,"t":{"304":{"position":[[32,2]]},"336":{"position":[[106,2]]}}}],["所谓",{"_index":2530,"t":{"542":{"position":[[0,2]]},"593":{"position":[[0,2]]}}}],["所购",{"_index":3439,"t":{"963":{"position":[[20,2]]},"965":{"position":[[20,2],[110,2]]}}}],["手动",{"_index":757,"t":{"104":{"position":[[19,2]]},"166":{"position":[[548,2]]},"252":{"position":[[548,2]]},"301":{"position":[[363,2]]},"521":{"position":[[306,2],[339,2]]},"661":{"position":[[35,2]]},"727":{"position":[[1031,2]]},"872":{"position":[[740,2],[944,2]]}}}],["才",{"_index":102,"t":{"10":{"position":[[71,1]]},"12":{"position":[[191,1]]},"14":{"position":[[88,1]]},"146":{"position":[[98,1]]},"415":{"position":[[158,1]]},"561":{"position":[[363,1]]},"641":{"position":[[224,1]]},"787":{"position":[[27,1]]}}}],["才能",{"_index":1306,"t":{"184":{"position":[[1000,2],[1779,2]]},"218":{"position":[[1000,2],[1779,2]]},"449":{"position":[[253,2]]},"935":{"position":[[80,2]]}}}],["打包",{"_index":2386,"t":{"507":{"position":[[1739,2],[2098,2]]}}}],["打开",{"_index":2160,"t":{"447":{"position":[[729,2]]},"716":{"position":[[5,2]]}}}],["打破",{"_index":3102,"t":{"787":{"position":[[44,2]]}}}],["托管",{"_index":2240,"t":{"458":{"position":[[24,2]]}}}],["执行",{"_index":414,"t":{"46":{"position":[[438,2]]},"57":{"position":[[381,2]]},"91":{"position":[[128,2]]},"134":{"position":[[1581,2],[2079,2],[2777,2],[3279,2]]},"180":{"position":[[99,2]]},"194":{"position":[[192,2],[214,2]]},"212":{"position":[[169,2]]},"233":{"position":[[195,2],[217,2]]},"272":{"position":[[575,2]]},"275":{"position":[[38,2]]},"308":{"position":[[366,2]]},"347":{"position":[[372,2]]},"434":{"position":[[121,2]]},"447":{"position":[[213,2],[758,2]]},"561":{"position":[[368,2]]},"570":{"position":[[90,2],[121,2],[133,2]]},"648":{"position":[[272,2],[385,2],[682,2],[1033,2]]},"653":{"position":[[223,2],[266,2]]},"686":{"position":[[168,2]]},"727":{"position":[[936,2]]},"732":{"position":[[23,2],[92,2]]},"734":{"position":[[20,2],[226,2],[442,2],[761,2]]},"738":{"position":[[4,2]]},"783":{"position":[[37,2]]},"806":{"position":[[198,2],[246,2],[358,2],[446,2]]},"917":{"position":[[73,2],[77,2]]},"925":{"position":[[22,2],[77,2],[130,2]]}}}],["扩展",{"_index":1021,"t":{"134":{"position":[[3434,2],[3661,2]]},"225":{"position":[[1927,2]]},"292":{"position":[[63,2]]},"321":{"position":[[26,2]]},"455":{"position":[[891,2],[908,2]]},"491":{"position":[[25,2],[61,2]]},"564":{"position":[[20,2]]},"566":{"position":[[7,2]]},"610":{"position":[[352,2]]},"778":{"position":[[2,2],[27,2]]},"783":{"position":[[24,2]]},"790":{"position":[[72,2]]},"792":{"position":[[189,2]]},"806":{"position":[[129,2]]},"882":{"position":[[243,2]]},"961":{"position":[[91,2],[202,2]]},"969":{"position":[[345,2],[371,2]]}}}],["扫描",{"_index":3467,"t":{"973":{"position":[[40,2]]}}}],["找",{"_index":825,"t":{"120":{"position":[[348,1]]}}}],["承担",{"_index":158,"t":{"20":{"position":[[69,2]]},"809":{"position":[[10,2]]}}}],["承接",{"_index":727,"t":{"94":{"position":[[4,2]]}}}],["技术",{"_index":912,"t":{"125":{"position":[[63,2]]},"906":{"position":[[29,2],[132,2]]}}}],["投入使用",{"_index":2174,"t":{"447":{"position":[[1224,4]]}}}],["投递",{"_index":261,"t":{"32":{"position":[[94,2],[130,2],[200,2]]},"34":{"position":[[32,2],[249,2],[265,2]]},"166":{"position":[[151,2]]},"184":{"position":[[630,2]]},"194":{"position":[[487,2]]},"218":{"position":[[630,2]]},"233":{"position":[[493,2]]},"252":{"position":[[151,2]]},"297":{"position":[[120,2],[224,2]]},"308":{"position":[[2545,2]]},"357":{"position":[[71,2],[149,2]]},"561":{"position":[[426,2],[466,2]]}}}],["抛出",{"_index":279,"t":{"34":{"position":[[65,2]]},"196":{"position":[[101,2]]},"241":{"position":[[54,2]]},"659":{"position":[[130,2]]},"870":{"position":[[104,2]]},"971":{"position":[[81,2]]}}}],["抛弃",{"_index":3019,"t":{"741":{"position":[[93,2]]}}}],["报文",{"_index":738,"t":{"97":{"position":[[30,2]]},"182":{"position":[[49,2]]},"184":{"position":[[850,2],[1629,2]]},"214":{"position":[[49,2]]},"218":{"position":[[850,2],[1629,2]]},"702":{"position":[[756,2],[859,2],[1167,2],[1921,2]]},"748":{"position":[[80,2]]},"874":{"position":[[360,2]]},"913":{"position":[[59,2]]},"976":{"position":[[19,2]]},"978":{"position":[[9,2]]}}}],["报错",{"_index":3303,"t":{"872":{"position":[[1042,2],[1090,2]]}}}],["抵达",{"_index":2611,"t":{"559":{"position":[[142,2]]}}}],["抽象",{"_index":513,"t":{"57":{"position":[[161,2]]},"272":{"position":[[153,2]]},"301":{"position":[[123,2]]},"308":{"position":[[155,2]]},"347":{"position":[[157,2]]}}}],["抽象类",{"_index":2998,"t":{"732":{"position":[[45,3]]},"925":{"position":[[83,3]]}}}],["担心",{"_index":79,"t":{"7":{"position":[[154,2]]}}}],["拆",{"_index":1918,"t":{"378":{"position":[[73,1]]}}}],["拉",{"_index":2477,"t":{"528":{"position":[[536,1]]},"691":{"position":[[1,1],[145,1],[192,1]]},"826":{"position":[[100,1]]},"828":{"position":[[198,1]]}}}],["拒绝",{"_index":1190,"t":{"166":{"position":[[143,2]]},"252":{"position":[[143,2]]},"465":{"position":[[271,2]]}}}],["拓展",{"_index":2542,"t":{"542":{"position":[[124,2]]}}}],["拔",{"_index":2673,"t":{"595":{"position":[[220,1]]},"597":{"position":[[243,1]]}}}],["拖拽",{"_index":3364,"t":{"906":{"position":[[157,2]]}}}],["拥有",{"_index":47,"t":{"7":{"position":[[13,2]]},"138":{"position":[[408,2]]},"151":{"position":[[50,2],[83,2]]},"376":{"position":[[11,2]]},"628":{"position":[[5,2]]},"957":{"position":[[54,2]]}}}],["拦截",{"_index":3466,"t":{"971":{"position":[[103,2]]}}}],["拼接",{"_index":1593,"t":{"297":{"position":[[77,2]]}}}],["拿到",{"_index":2142,"t":{"444":{"position":[[624,2]]},"780":{"position":[[347,2]]}}}],["持久",{"_index":3124,"t":{"804":{"position":[[37,2]]},"880":{"position":[[165,2]]}}}],["持久性",{"_index":3383,"t":{"909":{"position":[[198,3]]}}}],["挂",{"_index":1269,"t":{"184":{"position":[[542,1]]},"218":{"position":[[542,1]]}}}],["挂载",{"_index":1530,"t":{"275":{"position":[[28,2]]},"915":{"position":[[5,2]]}}}],["指",{"_index":2531,"t":{"542":{"position":[[8,1]]},"689":{"position":[[6,1]]},"761":{"position":[[38,1],[127,1]]}}}],["指令",{"_index":1589,"t":{"297":{"position":[[2,2],[303,2]]},"308":{"position":[[776,2]]},"359":{"position":[[48,2],[71,2],[106,2]]},"363":{"position":[[51,2]]},"365":{"position":[[21,2],[114,2],[144,2]]},"672":{"position":[[621,2]]},"674":{"position":[[836,2]]}}}],["指南",{"_index":3302,"t":{"872":{"position":[[1031,2]]},"886":{"position":[[47,2]]}}}],["指定",{"_index":958,"t":{"127":{"position":[[257,2],[533,2]]},"184":{"position":[[2012,2]]},"218":{"position":[[2012,2]]},"284":{"position":[[11,2]]},"301":{"position":[[525,2],[663,2]]},"343":{"position":[[111,2]]},"402":{"position":[[30,2]]},"406":{"position":[[51,2]]},"422":{"position":[[49,2]]},"453":{"position":[[29,2]]},"477":{"position":[[15,2]]},"512":{"position":[[81,2]]},"530":{"position":[[29,2],[84,2],[95,2]]},"679":{"position":[[265,2]]},"681":{"position":[[64,2]]},"693":{"position":[[29,2]]},"745":{"position":[[49,2]]},"748":{"position":[[370,2]]},"868":{"position":[[183,2]]},"894":{"position":[[80,2]]},"928":{"position":[[90,2]]}}}],["指导",{"_index":1618,"t":{"301":{"position":[[880,2]]}}}],["指标",{"_index":3188,"t":{"828":{"position":[[32,2]]}}}],["指示",{"_index":1250,"t":{"184":{"position":[[277,2]]},"218":{"position":[[277,2]]},"225":{"position":[[772,2]]},"301":{"position":[[883,2]]},"308":{"position":[[1553,2]]},"521":{"position":[[425,2]]}}}],["按",{"_index":1123,"t":{"157":{"position":[[315,1]]},"376":{"position":[[170,1]]},"477":{"position":[[33,1]]},"485":{"position":[[288,1]]},"748":{"position":[[359,1]]},"870":{"position":[[35,1]]},"880":{"position":[[107,1]]}}}],["按序",{"_index":2375,"t":{"507":{"position":[[876,2]]}}}],["按照",{"_index":664,"t":{"78":{"position":[[88,2]]},"194":{"position":[[0,2]]},"233":{"position":[[0,2]]},"237":{"position":[[0,2]]},"328":{"position":[[22,2]]},"455":{"position":[[1057,2]]},"475":{"position":[[14,2]]},"870":{"position":[[200,2]]}}}],["按键",{"_index":2371,"t":{"507":{"position":[[658,2]]}}}],["捕获",{"_index":1533,"t":{"284":{"position":[[90,2]]}}}],["损失",{"_index":156,"t":{"20":{"position":[[63,2]]}}}],["损耗",{"_index":1283,"t":{"184":{"position":[[716,2]]},"218":{"position":[[716,2]]}}}],["换",{"_index":1930,"t":{"385":{"position":[[29,1]]},"526":{"position":[[342,1]]}}}],["换行",{"_index":2612,"t":{"561":{"position":[[12,2],[353,2],[360,2]]}}}],["授权",{"_index":46,"t":{"7":{"position":[[8,2],[32,2],[56,2],[67,2],[90,2],[105,2],[108,2],[119,2]]},"10":{"position":[[69,2]]},"12":{"position":[[189,2]]},"14":{"position":[[86,2]]},"385":{"position":[[40,2]]},"961":{"position":[[7,2],[14,2],[19,2],[54,2]]},"963":{"position":[[0,2]]},"965":{"position":[[0,2],[51,2],[88,2]]},"967":{"position":[[1,2],[14,2],[23,2],[32,2],[37,2],[49,2],[66,2],[77,2]]}}}],["掉",{"_index":2741,"t":{"634":{"position":[[47,1]]}}}],["掉线",{"_index":2783,"t":{"663":{"position":[[92,2]]}}}],["排他性",{"_index":67,"t":{"7":{"position":[[93,3]]}}}],["排列",{"_index":1972,"t":{"404":{"position":[[73,2],[138,2]]}}}],["探视",{"_index":829,"t":{"120":{"position":[[380,2]]}}}],["接下来",{"_index":1353,"t":{"186":{"position":[[330,3]]},"220":{"position":[[337,3]]},"295":{"position":[[57,3]]},"554":{"position":[[171,3]]}}}],["接受",{"_index":3224,"t":{"839":{"position":[[116,2]]}}}],["接口",{"_index":177,"t":{"25":{"position":[[17,2]]},"57":{"position":[[58,2],[357,2]]},"101":{"position":[[12,2]]},"118":{"position":[[24,2]]},"138":{"position":[[102,2]]},"140":{"position":[[137,2]]},"166":{"position":[[28,2]]},"186":{"position":[[12,2]]},"205":{"position":[[30,2]]},"220":{"position":[[12,2]]},"252":{"position":[[28,2]]},"272":{"position":[[54,2],[328,2]]},"284":{"position":[[65,2]]},"290":{"position":[[1097,2]]},"301":{"position":[[34,2]]},"308":{"position":[[55,2],[342,2],[527,2],[1548,2]]},"347":{"position":[[55,2],[348,2],[537,2]]},"376":{"position":[[595,2]]},"397":{"position":[[76,2]]},"440":{"position":[[61,2],[127,2]]},"442":{"position":[[57,2],[116,2],[137,2]]},"444":{"position":[[7,2],[25,2],[90,2],[107,2],[130,2],[156,2],[205,2],[383,2],[539,2]]},"455":{"position":[[66,2],[382,2],[505,2],[555,2],[881,2],[1031,2]]},"473":{"position":[[6,2]]},"544":{"position":[[71,2]]},"550":{"position":[[64,2]]},"552":{"position":[[105,2]]},"574":{"position":[[109,2],[141,2],[162,2]]},"610":{"position":[[248,2],[277,2]]},"643":{"position":[[47,2]]},"780":{"position":[[48,2]]},"854":{"position":[[104,2]]},"859":{"position":[[1103,2]]},"876":{"position":[[96,2]]},"880":{"position":[[238,2]]},"882":{"position":[[251,2]]}}}],["接口类型",{"_index":2640,"t":{"574":{"position":[[300,4]]}}}],["接字",{"_index":2292,"t":{"485":{"position":[[95,2],[134,2]]}}}],["接收",{"_index":223,"t":{"28":{"position":[[41,2]]},"50":{"position":[[37,2],[55,2],[115,2],[162,2],[250,2],[275,2],[315,2]]},"55":{"position":[[46,2]]},"57":{"position":[[419,2],[798,2],[1371,2],[1474,2]]},"112":{"position":[[13,2]]},"159":{"position":[[572,2],[971,2]]},"166":{"position":[[476,2]]},"178":{"position":[[35,2]]},"180":{"position":[[76,2]]},"184":{"position":[[25,2],[605,2],[618,2],[634,2],[665,2],[2019,2]]},"188":{"position":[[380,2]]},"192":{"position":[[261,2]]},"194":{"position":[[312,2]]},"207":{"position":[[335,2],[410,2]]},"212":{"position":[[41,2],[146,2]]},"218":{"position":[[25,2],[605,2],[618,2],[634,2],[665,2],[2019,2]]},"220":{"position":[[91,2],[122,2]]},"223":{"position":[[459,2]]},"225":{"position":[[350,2]]},"229":{"position":[[278,2]]},"233":{"position":[[318,2]]},"235":{"position":[[723,2]]},"252":{"position":[[476,2]]},"272":{"position":[[1262,2],[1365,2]]},"290":{"position":[[3,2],[721,2],[1002,2]]},"292":{"position":[[3,2]]},"301":{"position":[[2326,2],[2429,2]]},"308":{"position":[[404,2],[1178,2],[1783,2],[1886,2]]},"336":{"position":[[47,2],[74,2],[155,2],[203,2]]},"340":{"position":[[93,2],[144,2],[171,2],[228,2],[274,2],[572,2],[870,2]]},"347":{"position":[[410,2],[1576,2],[1944,2],[2047,2]]},"359":{"position":[[143,2]]},"361":{"position":[[1103,2],[1115,2],[1126,2],[1149,2],[1566,2],[1760,2],[1956,2],[1987,2]]},"393":{"position":[[197,2],[209,2]]},"406":{"position":[[528,2]]},"418":{"position":[[37,2]]},"420":{"position":[[8,2]]},"422":{"position":[[512,2]]},"465":{"position":[[273,2],[352,2]]},"470":{"position":[[438,2]]},"485":{"position":[[57,2]]},"493":{"position":[[29,2]]},"514":{"position":[[11,2]]},"559":{"position":[[125,2],[133,2],[151,2]]},"561":{"position":[[20,2]]},"572":{"position":[[18,2]]},"666":{"position":[[115,2]]},"672":{"position":[[1066,2]]},"674":{"position":[[971,2]]},"727":{"position":[[15,2],[192,2],[251,2],[858,2]]},"745":{"position":[[583,2]]},"780":{"position":[[100,2]]},"787":{"position":[[75,2],[81,2],[121,2]]},"818":{"position":[[40,2]]},"828":{"position":[[213,2]]},"830":{"position":[[80,2],[135,2],[139,2],[148,2],[280,2],[351,2],[371,2],[760,2]]},"849":{"position":[[2,2]]},"857":{"position":[[349,2]]},"859":{"position":[[243,2]]},"874":{"position":[[280,2]]},"911":{"position":[[23,2]]},"930":{"position":[[11,2]]},"976":{"position":[[64,2]]},"978":{"position":[[2,2],[43,2]]}}}],["接收数据",{"_index":449,"t":{"50":{"position":[[70,4]]},"184":{"position":[[308,4],[338,4]]},"190":{"position":[[12,4]]},"192":{"position":[[51,4]]},"212":{"position":[[55,4]]},"218":{"position":[[308,4],[338,4]]},"227":{"position":[[13,4]]},"229":{"position":[[57,4]]},"235":{"position":[[1147,4]]},"297":{"position":[[72,4]]},"361":{"position":[[1055,4],[1176,4]]},"485":{"position":[[109,4]]}}}],["接收端",{"_index":1754,"t":{"359":{"position":[[137,3]]},"727":{"position":[[1841,3]]},"816":{"position":[[403,3]]}}}],["接触",{"_index":1747,"t":{"357":{"position":[[47,2]]}}}],["接近",{"_index":3077,"t":{"778":{"position":[[197,2]]},"862":{"position":[[116,2]]}}}],["控件",{"_index":2664,"t":{"588":{"position":[[18,2]]}}}],["控制",{"_index":704,"t":{"89":{"position":[[30,2]]},"239":{"position":[[131,2]]},"418":{"position":[[76,2]]},"590":{"position":[[7,2]]}}}],["控制协议",{"_index":1638,"t":{"306":{"position":[[27,4]]}}}],["控制台",{"_index":699,"t":{"89":{"position":[[8,3],[27,3]]},"223":{"position":[[916,3],[933,3]]},"225":{"position":[[1252,3],[1269,3],[1806,3],[1823,3]]},"229":{"position":[[508,3],[525,3]]},"475":{"position":[[3,3]]},"479":{"position":[[32,3]]},"586":{"position":[[51,3]]},"705":{"position":[[74,3],[125,3]]},"859":{"position":[[962,3],[979,3]]}}}],["控制器",{"_index":3191,"t":{"828":{"position":[[272,3]]},"830":{"position":[[181,3],[284,3]]},"832":{"position":[[1757,3]]}}}],["推断出",{"_index":1728,"t":{"347":{"position":[[1203,3],[1557,3]]}}}],["推荐",{"_index":3046,"t":{"756":{"position":[[80,2]]},"758":{"position":[[85,2]]},"878":{"position":[[230,2]]}}}],["推送",{"_index":2500,"t":{"528":{"position":[[1250,2]]},"674":{"position":[[32,2]]},"691":{"position":[[204,2]]},"826":{"position":[[112,2]]},"828":{"position":[[207,2]]},"882":{"position":[[345,2]]},"909":{"position":[[149,2]]}}}],["措施",{"_index":2008,"t":{"415":{"position":[[189,2]]}}}],["描述",{"_index":951,"t":{"127":{"position":[[205,2],[481,2]]},"830":{"position":[[212,2]]},"868":{"position":[[16,2]]},"870":{"position":[[17,2]]},"872":{"position":[[16,2]]},"874":{"position":[[17,2]]},"876":{"position":[[17,2]]},"878":{"position":[[16,2]]},"880":{"position":[[17,2]]},"882":{"position":[[17,2]]},"884":{"position":[[17,2]]},"886":{"position":[[17,2]]}}}],["提",{"_index":2234,"t":{"455":{"position":[[997,1]]}}}],["提交",{"_index":119,"t":{"12":{"position":[[141,2]]},"263":{"position":[[44,2]]}}}],["提供",{"_index":673,"t":{"80":{"position":[[11,2]]},"110":{"position":[[14,2]]},"138":{"position":[[175,2],[410,2]]},"521":{"position":[[53,2]]},"935":{"position":[[116,2]]},"957":{"position":[[143,2]]},"959":{"position":[[7,2]]},"971":{"position":[[22,2]]}}}],["提前",{"_index":2629,"t":{"570":{"position":[[131,2]]},"743":{"position":[[63,2]]}}}],["提升",{"_index":3323,"t":{"880":{"position":[[61,2]]}}}],["提名",{"_index":130,"t":{"14":{"position":[[69,2]]}}}],["提示",{"_index":580,"t":{"57":{"position":[[1962,2]]},"120":{"position":[[435,2]]},"127":{"position":[[686,2]]},"140":{"position":[[208,2]]},"146":{"position":[[43,2]]},"235":{"position":[[1178,2]]},"241":{"position":[[441,2]]},"272":{"position":[[1756,2]]},"301":{"position":[[2875,2]]},"308":{"position":[[2365,2],[2560,2]]},"347":{"position":[[2532,2]]},"406":{"position":[[578,2]]},"422":{"position":[[562,2]]},"447":{"position":[[1263,2]]},"455":{"position":[[924,2]]},"470":{"position":[[800,2]]},"537":{"position":[[291,2]]},"561":{"position":[[778,2]]},"617":{"position":[[266,2]]},"648":{"position":[[1186,2]]},"686":{"position":[[437,2]]},"716":{"position":[[107,2]]},"718":{"position":[[58,2],[143,2]]},"738":{"position":[[109,2]]},"745":{"position":[[514,2],[633,2]]},"758":{"position":[[128,2]]},"859":{"position":[[1056,2]]},"870":{"position":[[38,2],[69,2],[202,2]]},"954":{"position":[[5,2]]},"980":{"position":[[464,2]]}}}],["提高",{"_index":303,"t":{"34":{"position":[[207,2]]},"872":{"position":[[425,2]]}}}],["插件",{"_index":359,"t":{"42":{"position":[[2,2],[27,2]]},"46":{"position":[[6,2]]},"57":{"position":[[208,2]]},"118":{"position":[[70,2]]},"120":{"position":[[73,2],[329,2],[462,2],[469,2],[500,2]]},"166":{"position":[[79,2]]},"180":{"position":[[88,2]]},"184":{"position":[[699,2]]},"186":{"position":[[45,2]]},"194":{"position":[[21,2],[58,2],[74,2],[80,2],[94,2],[189,2],[200,2],[479,2],[492,2],[539,2]]},"205":{"position":[[82,2]]},"212":{"position":[[158,2]]},"218":{"position":[[699,2]]},"220":{"position":[[45,2]]},"223":{"position":[[989,2]]},"225":{"position":[[1325,2],[1879,2],[1948,2]]},"233":{"position":[[21,2],[58,2],[74,2],[80,2],[94,2],[192,2],[203,2],[485,2],[498,2],[545,2]]},"235":{"position":[[231,2],[282,2],[305,2],[1140,2],[1239,2]]},"252":{"position":[[79,2]]},"272":{"position":[[200,2]]},"284":{"position":[[2,2],[68,2],[521,2]]},"286":{"position":[[60,2]]},"290":{"position":[[31,2],[719,2],[797,2],[1020,2]]},"301":{"position":[[170,2]]},"308":{"position":[[202,2]]},"323":{"position":[[18,2],[275,2]]},"347":{"position":[[204,2]]},"406":{"position":[[85,2]]},"422":{"position":[[75,2]]},"458":{"position":[[26,2]]},"493":{"position":[[10,2]]},"500":{"position":[[7,2]]},"514":{"position":[[61,2]]},"516":{"position":[[20,2],[380,2]]},"564":{"position":[[0,2]]},"570":{"position":[[8,2],[56,2],[65,2],[69,2],[98,2],[118,2],[169,2],[208,2]]},"572":{"position":[[35,2]]},"574":{"position":[[36,2],[82,2],[111,2],[241,2]]},"617":{"position":[[275,2]]},"630":{"position":[[223,2]]},"732":{"position":[[25,2]]},"734":{"position":[[22,2]]},"738":{"position":[[6,2]]},"745":{"position":[[75,2]]},"750":{"position":[[189,2],[201,2],[219,2],[233,2],[466,2],[524,2]]},"752":{"position":[[58,2]]},"754":{"position":[[24,2]]},"774":{"position":[[2,2]]},"859":{"position":[[1035,2]]},"868":{"position":[[204,2]]},"872":{"position":[[726,2],[924,2],[1127,2]]},"874":{"position":[[197,2],[348,2],[364,2]]},"878":{"position":[[234,2],[294,2],[304,2],[347,2],[450,2]]},"882":{"position":[[95,2],[136,2]]},"896":{"position":[[354,2]]},"925":{"position":[[24,2],[139,2],[701,2]]},"980":{"position":[[43,2]]}}}],["插件接口",{"_index":1579,"t":{"290":{"position":[[998,4],[1029,4],[1040,4]]},"572":{"position":[[11,4]]}}}],["握手",{"_index":293,"t":{"34":{"position":[[121,2],[159,2]]},"281":{"position":[[19,2],[43,2]]},"806":{"position":[[283,2]]},"909":{"position":[[184,2]]}}}],["搜索",{"_index":2197,"t":{"451":{"position":[[73,2]]},"714":{"position":[[32,2],[52,2]]},"906":{"position":[[173,2],[178,2],[181,2]]}}}],["搜集",{"_index":2684,"t":{"600":{"position":[[14,2]]}}}],["携带",{"_index":918,"t":{"125":{"position":[[101,2]]},"365":{"position":[[158,2]]}}}],["摄像",{"_index":2907,"t":{"702":{"position":[[1452,2]]}}}],["摄像机",{"_index":2899,"t":{"702":{"position":[[1346,3],[1361,3],[1467,3]]}}}],["撤消",{"_index":71,"t":{"7":{"position":[[112,2]]}}}],["播",{"_index":3225,"t":{"841":{"position":[[1,1],[72,1],[98,1]]},"843":{"position":[[336,1]]},"845":{"position":[[288,1]]},"849":{"position":[[13,1]]}}}],["操作",{"_index":1033,"t":{"138":{"position":[[127,2]]},"146":{"position":[[117,2]]},"159":{"position":[[134,2]]},"166":{"position":[[369,2],[397,2]]},"180":{"position":[[79,2]]},"184":{"position":[[355,2],[362,2]]},"212":{"position":[[149,2]]},"218":{"position":[[355,2],[362,2]]},"252":{"position":[[369,2],[397,2]]},"261":{"position":[[949,2]]},"299":{"position":[[6,2]]},"301":{"position":[[1270,2],[1608,2]]},"323":{"position":[[281,2]]},"365":{"position":[[1316,2]]},"378":{"position":[[76,2],[95,2]]},"397":{"position":[[104,2],[110,2]]},"411":{"position":[[55,2]]},"413":{"position":[[55,2]]},"418":{"position":[[26,2]]},"444":{"position":[[324,2]]},"463":{"position":[[1,2]]},"465":{"position":[[1,2],[348,2]]},"473":{"position":[[302,2]]},"526":{"position":[[347,2]]},"530":{"position":[[69,2],[987,2]]},"577":{"position":[[17,2]]},"579":{"position":[[32,2]]},"581":{"position":[[297,2]]},"586":{"position":[[36,2],[60,2],[67,2]]},"588":{"position":[[26,2]]},"626":{"position":[[38,2]]},"646":{"position":[[55,2]]},"668":{"position":[[0,2]]},"670":{"position":[[0,2]]},"727":{"position":[[348,2]]},"752":{"position":[[91,2]]},"776":{"position":[[110,2]]},"792":{"position":[[7,2]]},"796":{"position":[[24,2],[40,2],[52,2]]},"800":{"position":[[36,2]]},"809":{"position":[[51,2]]},"828":{"position":[[181,2]]},"830":{"position":[[250,2],[277,2]]},"832":{"position":[[576,2]]},"834":{"position":[[9,2]]},"872":{"position":[[903,2],[939,2]]},"878":{"position":[[152,2],[227,2],[308,2]]},"950":{"position":[[4,2]]}}}],["操作系统",{"_index":2290,"t":{"485":{"position":[[68,4],[213,4]]},"498":{"position":[[25,4]]},"862":{"position":[[25,4]]},"917":{"position":[[103,4]]}}}],["擦除",{"_index":93,"t":{"10":{"position":[[38,2]]},"12":{"position":[[38,2]]},"14":{"position":[[38,2]]}}}],["支付",{"_index":732,"t":{"94":{"position":[[46,2]]}}}],["支持",{"_index":323,"t":{"36":{"position":[[46,2]]},"101":{"position":[[0,2]]},"110":{"position":[[47,2]]},"112":{"position":[[0,2]]},"120":{"position":[[578,2]]},"125":{"position":[[225,2],[240,2]]},"144":{"position":[[23,2]]},"146":{"position":[[56,2]]},"169":{"position":[[7,2]]},"171":{"position":[[7,2]]},"173":{"position":[[7,2]]},"180":{"position":[[18,2]]},"184":{"position":[[1281,2],[1286,2]]},"186":{"position":[[0,2]]},"212":{"position":[[18,2]]},"218":{"position":[[1281,2],[1286,2]]},"220":{"position":[[0,2]]},"279":{"position":[[0,2]]},"311":{"position":[[0,2]]},"315":{"position":[[0,2]]},"365":{"position":[[1478,2]]},"368":{"position":[[2,2]]},"391":{"position":[[52,2]]},"395":{"position":[[32,2]]},"402":{"position":[[28,2]]},"427":{"position":[[48,2]]},"440":{"position":[[243,2]]},"442":{"position":[[6,2],[42,2],[69,2]]},"463":{"position":[[3,2],[11,2],[18,2]]},"465":{"position":[[6,2]]},"498":{"position":[[91,2]]},"500":{"position":[[9,2],[13,2],[22,2],[30,2]]},"505":{"position":[[16,2]]},"512":{"position":[[88,2]]},"521":{"position":[[284,2]]},"530":{"position":[[4,2]]},"537":{"position":[[304,2],[318,2]]},"544":{"position":[[0,2],[31,2],[68,2],[81,2],[110,2],[120,2],[130,2],[140,2],[148,2]]},"546":{"position":[[13,2],[101,2]]},"554":{"position":[[32,2]]},"572":{"position":[[37,2]]},"574":{"position":[[239,2]]},"577":{"position":[[0,2]]},"579":{"position":[[16,2],[47,2],[67,2],[102,2],[113,2],[119,2],[122,2],[128,2],[131,2],[137,2],[140,2]]},"597":{"position":[[22,2]]},"639":{"position":[[71,2]]},"679":{"position":[[144,2]]},"693":{"position":[[4,2]]},"705":{"position":[[108,2]]},"707":{"position":[[63,2]]},"738":{"position":[[118,2]]},"750":{"position":[[33,2],[590,2]]},"783":{"position":[[198,2]]},"790":{"position":[[0,2],[8,2],[18,2],[53,2],[59,2],[68,2]]},"792":{"position":[[0,2],[11,2],[21,2],[33,2],[49,2],[76,2],[94,2],[102,2],[115,2],[145,2]]},"794":{"position":[[0,2],[13,2],[21,2],[29,2],[49,2],[67,2],[78,2]]},"796":{"position":[[0,2],[9,2],[28,2],[44,2]]},"798":{"position":[[0,2],[17,2],[48,2]]},"800":{"position":[[0,2],[18,2]]},"802":{"position":[[0,2],[19,2],[27,2]]},"804":{"position":[[0,2],[20,2],[33,2]]},"806":{"position":[[205,2],[253,2],[313,2],[371,2],[479,2]]},"836":{"position":[[3,2]]},"862":{"position":[[99,2]]},"864":{"position":[[35,2],[46,2]]},"868":{"position":[[37,2],[178,2]]},"872":{"position":[[173,2],[252,2],[392,2]]},"874":{"position":[[72,2],[183,2],[216,2],[295,2],[306,2],[366,2],[378,2],[396,2],[409,2]]},"876":{"position":[[112,2]]},"878":{"position":[[125,2]]},"880":{"position":[[105,2]]},"884":{"position":[[106,2]]},"894":{"position":[[87,2]]},"896":{"position":[[345,2]]},"919":{"position":[[7,2],[16,2],[24,2]]},"925":{"position":[[180,2],[729,2]]},"928":{"position":[[97,2]]},"954":{"position":[[67,2]]},"961":{"position":[[94,2],[97,2],[100,2],[205,2],[208,2],[211,2]]}}}],["收到",{"_index":252,"t":{"32":{"position":[[30,2]]},"116":{"position":[[4,2]]},"118":{"position":[[88,2],[107,2],[126,2],[145,2],[184,2]]},"159":{"position":[[167,2]]},"166":{"position":[[341,2]]},"186":{"position":[[198,2],[244,2]]},"188":{"position":[[281,2]]},"192":{"position":[[162,2]]},"205":{"position":[[106,2]]},"207":{"position":[[158,2]]},"216":{"position":[[4,2]]},"220":{"position":[[205,2],[251,2]]},"223":{"position":[[346,2],[494,2],[535,2],[612,2]]},"229":{"position":[[165,2]]},"235":{"position":[[287,2]]},"248":{"position":[[56,2]]},"252":{"position":[[341,2]]},"281":{"position":[[69,2]]},"284":{"position":[[439,2]]},"290":{"position":[[79,2],[240,2],[426,2],[498,2]]},"393":{"position":[[349,2]]},"406":{"position":[[208,2]]},"422":{"position":[[221,2]]},"470":{"position":[[789,2]]},"485":{"position":[[267,2]]},"493":{"position":[[32,2]]},"533":{"position":[[31,2]]},"537":{"position":[[1214,2],[1445,2]]},"574":{"position":[[86,2]]},"653":{"position":[[186,2]]},"745":{"position":[[221,2]]},"748":{"position":[[303,2]]},"857":{"position":[[574,2],[632,2],[835,2]]},"859":{"position":[[463,2],[521,2],[732,2],[1132,2]]},"980":{"position":[[189,2]]}}}],["收费",{"_index":3409,"t":{"935":{"position":[[135,2]]}}}],["改为",{"_index":3325,"t":{"880":{"position":[[251,2]]},"882":{"position":[[241,2]]},"884":{"position":[[228,2]]},"891":{"position":[[25,2]]}}}],["改变",{"_index":1398,"t":{"220":{"position":[[378,2]]},"830":{"position":[[186,2]]}}}],["改名",{"_index":3297,"t":{"872":{"position":[[776,2],[806,2],[829,2],[863,2]]},"884":{"position":[[192,2]]}}}],["放",{"_index":3060,"t":{"761":{"position":[[118,1]]}}}],["放到",{"_index":2539,"t":{"542":{"position":[[71,2]]}}}],["放在",{"_index":2122,"t":{"444":{"position":[[338,2]]}}}],["放置",{"_index":1557,"t":{"288":{"position":[[55,2]]}}}],["效果",{"_index":1814,"t":{"365":{"position":[[1362,2]]},"431":{"position":[[558,2]]},"906":{"position":[[159,2]]}}}],["效率",{"_index":1295,"t":{"184":{"position":[[856,2],[890,2],[1635,2],[1669,2]]},"218":{"position":[[856,2],[890,2],[1635,2],[1669,2]]},"436":{"position":[[2005,2]]},"440":{"position":[[221,2]]},"442":{"position":[[25,2]]},"523":{"position":[[364,2]]},"778":{"position":[[173,2],[186,2],[226,2]]},"806":{"position":[[200,2],[360,2],[466,2]]},"872":{"position":[[66,2],[201,2],[355,2],[418,2]]},"876":{"position":[[62,2],[68,2]]},"880":{"position":[[66,2]]}}}],["效率高",{"_index":2089,"t":{"440":{"position":[[184,3],[211,3]]},"806":{"position":[[248,3]]}}}],["教学",{"_index":2960,"t":{"720":{"position":[[16,2]]}}}],["散",{"_index":1869,"t":{"370":{"position":[[270,1]]}}}],["数",{"_index":2006,"t":{"415":{"position":[[100,1],[105,1]]},"702":{"position":[[1554,1]]}}}],["数值",{"_index":2628,"t":{"570":{"position":[[126,2]]},"741":{"position":[[19,2]]},"780":{"position":[[75,2]]}}}],["数据",{"_index":224,"t":{"28":{"position":[[44,2],[62,2],[87,2],[107,2],[144,2]]},"32":{"position":[[43,2],[96,2],[141,2]]},"34":{"position":[[133,2]]},"40":{"position":[[305,2]]},"50":{"position":[[86,2],[119,2],[273,2]]},"53":{"position":[[1,2],[44,2],[81,2]]},"55":{"position":[[10,2],[22,2],[40,2],[54,2]]},"57":{"position":[[68,2],[423,2],[702,2],[712,2],[795,2],[1074,2],[1081,2]]},"106":{"position":[[23,2]]},"112":{"position":[[11,2]]},"125":{"position":[[105,2]]},"159":{"position":[[169,2]]},"166":{"position":[[345,2],[479,2]]},"182":{"position":[[47,2]]},"184":{"position":[[726,2],[848,2],[886,2],[988,2],[995,2],[1627,2],[1665,2],[1767,2],[1774,2]]},"186":{"position":[[211,2],[249,2],[263,2]]},"194":{"position":[[25,2],[310,2],[473,2]]},"196":{"position":[[56,2]]},"205":{"position":[[108,2]]},"210":{"position":[[28,2]]},"214":{"position":[[47,2]]},"218":{"position":[[726,2],[848,2],[886,2],[988,2],[995,2],[1627,2],[1665,2],[1767,2],[1774,2]]},"220":{"position":[[218,2],[256,2],[270,2]]},"225":{"position":[[235,2]]},"231":{"position":[[53,2]]},"233":{"position":[[25,2],[316,2],[479,2]]},"235":{"position":[[290,2],[721,2]]},"237":{"position":[[53,2]]},"241":{"position":[[453,2]]},"252":{"position":[[345,2],[479,2]]},"268":{"position":[[31,2],[59,2]]},"270":{"position":[[12,2],[24,2],[42,2]]},"272":{"position":[[64,2],[956,2],[979,2]]},"281":{"position":[[73,2]]},"284":{"position":[[441,2]]},"290":{"position":[[244,2],[431,2],[507,2]]},"292":{"position":[[114,2],[354,2],[367,2]]},"297":{"position":[[60,2],[106,2],[220,2]]},"299":{"position":[[8,2],[24,2]]},"301":{"position":[[5,2],[44,2],[334,2],[465,2],[486,2],[1536,2]]},"304":{"position":[[95,2],[111,2]]},"306":{"position":[[10,2],[41,2],[59,2]]},"308":{"position":[[65,2],[408,2],[534,2],[897,2],[1152,2],[2373,2],[2415,2],[2433,2],[2479,2],[2552,2]]},"321":{"position":[[49,2],[62,2]]},"328":{"position":[[15,2]]},"340":{"position":[[613,2],[723,2],[857,2]]},"343":{"position":[[11,2],[34,2],[38,2],[52,2],[80,2],[90,2]]},"345":{"position":[[9,2],[21,2],[39,2]]},"347":{"position":[[65,2],[414,2],[544,2],[666,2],[1236,2]]},"357":{"position":[[57,2],[66,2],[146,2],[198,2]]},"359":{"position":[[36,2],[84,2],[113,2],[117,2],[151,2]]},"361":{"position":[[669,2],[771,2],[996,2],[1069,2],[1107,2],[1120,2],[1131,2],[1139,2],[1154,2],[1582,2],[1590,2],[2760,2]]},"363":{"position":[[58,2]]},"365":{"position":[[28,2],[162,2],[1349,2],[1376,2],[1412,2],[1432,2],[1746,2]]},"385":{"position":[[0,2],[9,2],[16,2]]},"404":{"position":[[21,2],[29,2],[82,2],[90,2],[147,2],[155,2]]},"406":{"position":[[531,2]]},"418":{"position":[[16,2],[40,2]]},"420":{"position":[[11,2],[53,2]]},"422":{"position":[[51,2],[97,2],[484,2],[515,2]]},"444":{"position":[[303,2],[450,2],[676,2]]},"465":{"position":[[258,2],[317,2],[356,2],[364,2],[626,2]]},"470":{"position":[[235,2],[466,2],[644,2],[794,2]]},"487":{"position":[[25,2],[76,2],[122,2],[134,2]]},"489":{"position":[[1313,2]]},"505":{"position":[[86,2],[97,2]]},"523":{"position":[[3,2]]},"533":{"position":[[37,2],[61,2]]},"535":{"position":[[34,2]]},"537":{"position":[[1217,2],[1448,2]]},"559":{"position":[[68,2],[118,2],[140,2]]},"561":{"position":[[458,2]]},"570":{"position":[[197,2]]},"628":{"position":[[12,2],[37,2],[94,2]]},"630":{"position":[[89,2],[104,2]]},"666":{"position":[[13,2],[99,2],[132,2],[159,2]]},"668":{"position":[[65,2]]},"670":{"position":[[36,2]]},"672":{"position":[[57,2],[196,2]]},"674":{"position":[[168,2]]},"691":{"position":[[53,2],[67,2],[195,2]]},"702":{"position":[[1740,2]]},"727":{"position":[[292,2],[861,2],[1036,2],[1324,2],[1837,2]]},"741":{"position":[[67,2],[95,2]]},"743":{"position":[[51,2]]},"745":{"position":[[51,2],[97,2],[531,2],[586,2]]},"748":{"position":[[34,2],[46,2],[61,2],[78,2],[97,2],[142,2],[174,2],[182,2],[189,2],[203,2],[493,2]]},"750":{"position":[[37,2]]},"752":{"position":[[3,2]]},"756":{"position":[[38,2],[48,2]]},"758":{"position":[[3,2]]},"761":{"position":[[18,2],[39,2],[57,2],[88,2],[110,2],[128,2],[146,2]]},"774":{"position":[[45,2],[268,2]]},"778":{"position":[[113,2],[164,2]]},"780":{"position":[[352,2],[368,2],[552,2]]},"783":{"position":[[138,2],[155,2]]},"787":{"position":[[71,2]]},"798":{"position":[[24,2]]},"800":{"position":[[6,2],[12,2]]},"804":{"position":[[16,2]]},"806":{"position":[[288,2],[448,2]]},"809":{"position":[[17,2],[57,2]]},"814":{"position":[[43,2]]},"818":{"position":[[11,2],[22,2]]},"820":{"position":[[230,2],[255,2]]},"826":{"position":[[39,2]]},"830":{"position":[[765,2]]},"832":{"position":[[1650,2],[1953,2]]},"839":{"position":[[125,2]]},"851":{"position":[[339,2]]},"854":{"position":[[22,2],[47,2]]},"857":{"position":[[352,2],[634,2]]},"859":{"position":[[246,2],[523,2],[1122,2],[1138,2]]},"868":{"position":[[167,2]]},"872":{"position":[[703,2]]},"876":{"position":[[114,2],[152,2]]},"901":{"position":[[15,2]]},"906":{"position":[[194,2],[203,2],[210,2]]},"909":{"position":[[151,2]]},"911":{"position":[[21,2]]},"913":{"position":[[57,2]]},"957":{"position":[[25,2]]},"976":{"position":[[60,2]]},"978":{"position":[[38,2]]},"980":{"position":[[65,2]]}}}],["数据业务",{"_index":3174,"t":{"824":{"position":[[26,4]]}}}],["数据交换",{"_index":3381,"t":{"909":{"position":[[127,4]]}}}],["数据传输",{"_index":489,"t":{"53":{"position":[[61,4]]},"166":{"position":[[436,4],[556,4]]},"252":{"position":[[436,4],[556,4]]},"748":{"position":[[129,4]]},"876":{"position":[[90,4]]},"909":{"position":[[210,4]]}}}],["数据位",{"_index":3062,"t":{"761":{"position":[[176,3]]}}}],["数据包",{"_index":442,"t":{"50":{"position":[[13,3]]},"184":{"position":[[59,3],[85,3],[165,3],[2023,3]]},"218":{"position":[[59,3],[85,3],[165,3],[2023,3]]},"336":{"position":[[92,3]]},"485":{"position":[[23,3],[251,3]]},"666":{"position":[[73,3]]},"668":{"position":[[25,3]]},"783":{"position":[[176,3]]},"814":{"position":[[15,3]]},"820":{"position":[[108,3]]}}}],["数据处理",{"_index":243,"t":{"28":{"position":[[124,4]]},"34":{"position":[[149,4],[190,4],[218,4]]},"36":{"position":[[8,4]]},"166":{"position":[[525,4]]},"252":{"position":[[525,4]]},"268":{"position":[[141,4]]},"340":{"position":[[48,4]]},"400":{"position":[[4,4]]},"418":{"position":[[4,4]]},"487":{"position":[[63,4]]},"741":{"position":[[4,4]]},"976":{"position":[[2,4],[29,4]]}}}],["数据库",{"_index":2121,"t":{"444":{"position":[[321,3]]}}}],["数据格式",{"_index":300,"t":{"34":{"position":[[170,4]]},"182":{"position":[[39,4]]},"214":{"position":[[39,4]]},"304":{"position":[[35,4],[82,4]]},"343":{"position":[[28,4]]},"359":{"position":[[22,4]]},"487":{"position":[[12,4],[50,4],[112,4]]},"489":{"position":[[11,4]]},"679":{"position":[[133,4]]},"738":{"position":[[41,4],[137,4]]},"783":{"position":[[30,4],[278,4]]},"913":{"position":[[43,4]]},"925":{"position":[[165,4],[186,4]]},"957":{"position":[[129,4],[147,4]]}}}],["数据类型",{"_index":1642,"t":{"308":{"position":[[656,4]]},"359":{"position":[[43,4],[60,4],[101,4]]},"363":{"position":[[46,4]]},"365":{"position":[[16,4],[89,4],[139,4]]},"449":{"position":[[60,4]]},"487":{"position":[[127,4]]},"489":{"position":[[1292,4]]},"748":{"position":[[157,4]]},"750":{"position":[[595,4]]}}}],["数据结构",{"_index":238,"t":{"28":{"position":[[97,4]]},"440":{"position":[[91,4]]},"442":{"position":[[129,4]]},"444":{"position":[[170,4],[395,4],[589,4]]},"449":{"position":[[45,4],[145,4]]},"521":{"position":[[82,4]]}}}],["数据通信",{"_index":805,"t":{"116":{"position":[[61,4]]},"216":{"position":[[59,4]]},"248":{"position":[[128,4]]}}}],["数据量",{"_index":1716,"t":{"343":{"position":[[72,3]]},"505":{"position":[[33,3],[47,3]]},"679":{"position":[[123,3],[195,3],[229,3]]}}}],["数组",{"_index":2026,"t":{"427":{"position":[[69,2]]},"606":{"position":[[12,2]]},"679":{"position":[[158,2]]},"748":{"position":[[117,2]]}}}],["数量",{"_index":1248,"t":{"184":{"position":[[264,2],[287,2],[294,2],[317,2]]},"218":{"position":[[264,2],[287,2],[294,2],[317,2]]},"615":{"position":[[16,2]]},"729":{"position":[[42,2]]}}}],["敲",{"_index":2210,"t":{"455":{"position":[[40,1]]}}}],["整个",{"_index":456,"t":{"50":{"position":[[113,2]]},"235":{"position":[[1195,2]]},"359":{"position":[[34,2]]},"404":{"position":[[19,2],[27,2],[80,2],[88,2],[145,2],[153,2]]},"455":{"position":[[599,2]]}}}],["整体",{"_index":2662,"t":{"588":{"position":[[0,2]]},"780":{"position":[[371,2],[555,2]]},"906":{"position":[[136,2]]}}}],["整型",{"_index":3032,"t":{"748":{"position":[[221,2],[448,2],[463,2]]}}}],["整数",{"_index":2895,"t":{"702":{"position":[[1263,2],[1559,2],[1652,2]]}}}],["整洁",{"_index":2107,"t":{"444":{"position":[[30,2],[47,2],[489,2]]}}}],["整理",{"_index":2135,"t":{"444":{"position":[[452,2]]}}}],["整除",{"_index":1688,"t":{"338":{"position":[[24,2]]}}}],["文",{"_index":1839,"t":{"370":{"position":[[75,1]]},"641":{"position":[[225,1]]}}}],["文件",{"_index":10,"t":{"3":{"position":[[36,2]]},"64":{"position":[[4,2]]},"66":{"position":[[33,2],[68,2]]},"73":{"position":[[4,2]]},"75":{"position":[[33,2],[68,2]]},"84":{"position":[[4,2]]},"86":{"position":[[54,2],[78,2],[113,2]]},"104":{"position":[[207,2]]},"120":{"position":[[977,2]]},"134":{"position":[[70,2],[79,2]]},"383":{"position":[[35,2]]},"385":{"position":[[14,2],[21,2]]},"409":{"position":[[0,2],[64,2],[84,2]]},"411":{"position":[[35,2]]},"413":{"position":[[30,2],[109,2]]},"415":{"position":[[3,2],[81,2],[179,2]]},"447":{"position":[[177,2],[247,2],[789,2],[818,2],[999,2],[1034,2]]},"463":{"position":[[7,2],[296,2]]},"465":{"position":[[9,2],[374,2]]},"477":{"position":[[3,2],[44,2]]},"479":{"position":[[36,2]]},"521":{"position":[[57,2]]},"526":{"position":[[28,2]]},"528":{"position":[[538,2],[1252,2]]},"530":{"position":[[62,2],[1070,2]]},"577":{"position":[[8,2]]},"579":{"position":[[35,2],[104,2]]},"586":{"position":[[41,2],[65,2]]},"628":{"position":[[18,2],[68,2]]},"636":{"position":[[21,2]]},"689":{"position":[[11,2],[176,2],[226,2],[256,2]]},"691":{"position":[[3,2],[51,2],[71,2],[147,2],[206,2]]},"718":{"position":[[54,2],[99,2],[235,2]]},"794":{"position":[[45,2],[63,2],[70,2],[82,2]]},"796":{"position":[[11,2]]},"822":{"position":[[86,2]]},"826":{"position":[[118,2],[184,2]]},"828":{"position":[[82,2],[103,2],[210,2]]},"830":{"position":[[60,2],[116,2],[348,2],[405,2],[427,2]]},"832":{"position":[[625,2],[857,2],[2013,2]]},"836":{"position":[[12,2]]},"866":{"position":[[129,2]]},"872":{"position":[[343,2],[384,2],[406,2]]},"874":{"position":[[298,2],[309,2]]},"878":{"position":[[150,2],[540,2],[706,2]]},"882":{"position":[[347,2]]},"884":{"position":[[76,2],[89,2]]},"894":{"position":[[392,2]]},"906":{"position":[[94,2],[208,2]]},"932":{"position":[[272,2],[344,2]]},"950":{"position":[[2,2]]},"952":{"position":[[10,2]]}}}],["文件传输",{"_index":1194,"t":{"166":{"position":[[219,4],[250,4]]},"184":{"position":[[93,4]]},"218":{"position":[[93,4]]},"252":{"position":[[219,4],[250,4]]},"526":{"position":[[3,4],[47,4],[68,4]]},"689":{"position":[[1,4],[47,4],[55,4],[219,4]]},"794":{"position":[[7,4]]},"824":{"position":[[31,4]]},"826":{"position":[[48,4]]},"828":{"position":[[0,4],[49,4]]},"836":{"position":[[65,4]]},"870":{"position":[[56,4]]},"872":{"position":[[337,4],[899,4]]},"874":{"position":[[94,4]]},"906":{"position":[[126,4]]},"950":{"position":[[21,4],[31,4],[41,4],[46,4]]},"952":{"position":[[2,4],[22,4]]}}}],["文件名",{"_index":2260,"t":{"465":{"position":[[578,3]]},"832":{"position":[[667,3],[899,3]]},"878":{"position":[[580,3],[748,3]]}}}],["文件名称",{"_index":2643,"t":{"579":{"position":[[52,4],[86,4]]}}}],["文件夹",{"_index":2242,"t":{"458":{"position":[[315,3]]},"577":{"position":[[11,3]]},"579":{"position":[[38,3],[72,3],[82,3]]},"581":{"position":[[3,3]]},"718":{"position":[[131,3]]},"796":{"position":[[4,3]]},"870":{"position":[[62,3]]}}}],["文字",{"_index":842,"t":{"120":{"position":[[817,2]]},"925":{"position":[[64,2]]}}}],["文本",{"_index":671,"t":{"78":{"position":[[322,2]]},"516":{"position":[[149,2]]},"925":{"position":[[55,2]]}}}],["文档",{"_index":4,"t":{"3":{"position":[[11,2]]},"194":{"position":[[361,2]]},"233":{"position":[[367,2]]},"235":{"position":[[772,2]]},"498":{"position":[[53,2]]}}}],["断",{"_index":3101,"t":{"787":{"position":[[34,1]]}}}],["断层",{"_index":2364,"t":{"505":{"position":[[99,2]]}}}],["断开",{"_index":1180,"t":{"164":{"position":[[134,2]]},"178":{"position":[[41,2]]},"184":{"position":[[680,2]]},"218":{"position":[[680,2]]},"250":{"position":[[134,2]]},"290":{"position":[[602,2],[622,2]]},"485":{"position":[[100,2]]},"593":{"position":[[15,2]]},"595":{"position":[[157,2],[191,2],[208,2]]},"597":{"position":[[231,2]]},"832":{"position":[[1216,2]]},"857":{"position":[[389,2],[432,2]]},"859":{"position":[[283,2],[326,2]]}}}],["断开连接",{"_index":1345,"t":{"186":{"position":[[173,4]]},"188":{"position":[[197,4]]},"220":{"position":[[180,4]]},"223":{"position":[[278,4]]},"225":{"position":[[1035,4],[1589,4]]},"537":{"position":[[1018,4]]},"634":{"position":[[1,4]]},"870":{"position":[[94,4]]},"874":{"position":[[112,4]]}}}],["断点续传",{"_index":1929,"t":{"385":{"position":[[24,4]]},"463":{"position":[[13,4]]},"794":{"position":[[15,4]]},"830":{"position":[[511,4]]},"832":{"position":[[1823,4],[1830,4],[2019,4]]}}}],["断线",{"_index":2466,"t":{"526":{"position":[[337,2]]},"539":{"position":[[187,2]]},"593":{"position":[[2,2]]},"595":{"position":[[2,2],[125,2]]},"597":{"position":[[5,2],[185,2]]},"882":{"position":[[365,2]]},"884":{"position":[[148,2]]},"891":{"position":[[33,2]]},"938":{"position":[[3,2]]}}}],["新",{"_index":194,"t":{"25":{"position":[[217,1]]},"40":{"position":[[35,1]]},"116":{"position":[[6,1]]},"127":{"position":[[716,1]]},"216":{"position":[[6,1]]},"225":{"position":[[721,1]]},"248":{"position":[[58,1]]},"308":{"position":[[1636,1]]},"554":{"position":[[101,1]]},"561":{"position":[[428,1]]},"613":{"position":[[22,1]]},"615":{"position":[[26,1],[111,1]]},"617":{"position":[[145,1]]},"619":{"position":[[50,1]]},"889":{"position":[[6,1]]}}}],["新增",{"_index":2850,"t":{"689":{"position":[[215,2]]},"868":{"position":[[144,2],[187,2]]},"870":{"position":[[146,2],[155,2]]},"872":{"position":[[108,2],[145,2],[181,2],[214,2],[242,2],[267,2],[324,2],[370,2],[434,2]]},"874":{"position":[[194,2]]},"876":{"position":[[72,2]]},"878":{"position":[[52,2],[82,2],[146,2],[169,2]]},"880":{"position":[[70,2]]},"882":{"position":[[67,2],[97,2]]},"884":{"position":[[87,2],[95,2]]}}}],["新建",{"_index":500,"t":{"57":{"position":[[26,2],[95,2],[287,2],[929,2]]},"127":{"position":[[6,2]]},"194":{"position":[[72,2]]},"210":{"position":[[108,2]]},"233":{"position":[[72,2]]},"235":{"position":[[280,2]]},"272":{"position":[[26,2],[91,2],[275,2],[655,2]]},"301":{"position":[[16,2],[71,2]]},"308":{"position":[[26,2],[92,2],[278,2],[1296,2]]},"347":{"position":[[26,2],[92,2],[282,2],[1627,2]]},"512":{"position":[[6,2]]},"894":{"position":[[6,2]]},"928":{"position":[[6,2]]},"969":{"position":[[217,2],[292,2],[396,2]]}}}],["新手",{"_index":2936,"t":{"707":{"position":[[163,2]]}}}],["方",{"_index":450,"t":{"50":{"position":[[80,1]]},"223":{"position":[[506,1]]},"444":{"position":[[419,1]]},"493":{"position":[[31,1]]},"514":{"position":[[501,1]]},"588":{"position":[[8,1]]},"634":{"position":[[10,1],[26,1]]},"727":{"position":[[17,1],[25,1]]},"736":{"position":[[332,1]]},"780":{"position":[[102,1]]},"787":{"position":[[65,1],[77,1],[83,1],[123,1]]},"792":{"position":[[126,1],[142,1]]},"818":{"position":[[42,1]]},"830":{"position":[[282,1],[762,1]]},"906":{"position":[[2,1]]}}}],["方便",{"_index":703,"t":{"89":{"position":[[22,2]]},"286":{"position":[[20,2]]},"288":{"position":[[94,2]]},"444":{"position":[[33,2],[50,2],[493,2]]},"491":{"position":[[30,2]]},"498":{"position":[[82,2]]},"824":{"position":[[18,2]]},"917":{"position":[[129,2]]},"932":{"position":[[20,2]]},"971":{"position":[[1,2]]}}}],["方式",{"_index":325,"t":{"36":{"position":[[50,2]]},"60":{"position":[[488,2]]},"78":{"position":[[212,2]]},"120":{"position":[[514,2]]},"190":{"position":[[17,2],[26,2]]},"194":{"position":[[42,2]]},"227":{"position":[[18,2],[27,2]]},"233":{"position":[[42,2]]},"235":{"position":[[237,2]]},"286":{"position":[[9,2]]},"334":{"position":[[27,2]]},"357":{"position":[[73,2]]},"427":{"position":[[8,2]]},"431":{"position":[[571,2]]},"440":{"position":[[51,2],[76,2],[106,2]]},"442":{"position":[[96,2]]},"455":{"position":[[3,2],[353,2],[1054,2]]},"509":{"position":[[22,2],[47,2]]},"516":{"position":[[86,2]]},"521":{"position":[[35,2],[142,2]]},"539":{"position":[[175,2]]},"544":{"position":[[16,2]]},"546":{"position":[[29,2],[51,2]]},"597":{"position":[[33,2]]},"617":{"position":[[32,2]]},"619":{"position":[[7,2]]},"679":{"position":[[19,2],[61,2],[117,2]]},"681":{"position":[[27,2]]},"689":{"position":[[277,2]]},"741":{"position":[[22,2]]},"756":{"position":[[16,2]]},"836":{"position":[[63,2]]},"878":{"position":[[237,2]]},"884":{"position":[[58,2],[296,2]]},"932":{"position":[[15,2],[135,2]]},"961":{"position":[[105,2]]},"969":{"position":[[206,2]]},"973":{"position":[[7,2]]}}}],["方案",{"_index":1966,"t":{"400":{"position":[[40,2]]},"418":{"position":[[62,2]]},"455":{"position":[[18,2]]}}}],["方法",{"_index":183,"t":{"25":{"position":[[39,2]]},"40":{"position":[[16,2]]},"57":{"position":[[163,2],[205,2],[789,2]]},"66":{"position":[[81,2]]},"75":{"position":[[81,2]]},"86":{"position":[[126,2]]},"91":{"position":[[178,2]]},"106":{"position":[[0,2]]},"118":{"position":[[64,2],[72,2]]},"125":{"position":[[204,2]]},"127":{"position":[[122,2],[277,2],[553,2]]},"134":{"position":[[3663,2]]},"146":{"position":[[11,2],[25,2]]},"159":{"position":[[597,2]]},"166":{"position":[[73,2],[81,2]]},"186":{"position":[[39,2],[47,2],[321,2]]},"196":{"position":[[27,2],[51,2],[287,2]]},"205":{"position":[[76,2],[84,2]]},"220":{"position":[[39,2],[47,2],[328,2]]},"239":{"position":[[35,2],[210,2],[259,2]]},"241":{"position":[[30,2],[240,2],[448,2]]},"252":{"position":[[73,2],[81,2]]},"272":{"position":[[155,2],[197,2]]},"284":{"position":[[87,2]]},"290":{"position":[[792,2],[1256,2]]},"292":{"position":[[65,2]]},"301":{"position":[[125,2],[167,2]]},"308":{"position":[[157,2],[199,2]]},"321":{"position":[[28,2]]},"347":{"position":[[159,2],[201,2]]},"361":{"position":[[40,2]]},"365":{"position":[[73,2]]},"393":{"position":[[205,2],[224,2]]},"406":{"position":[[82,2]]},"422":{"position":[[72,2]]},"440":{"position":[[15,2]]},"447":{"position":[[956,2],[1330,2]]},"449":{"position":[[262,2]]},"455":{"position":[[613,2],[734,2],[775,2],[893,2],[913,2]]},"473":{"position":[[15,2]]},"491":{"position":[[27,2]]},"512":{"position":[[50,2],[71,2],[250,2]]},"530":{"position":[[18,2]]},"537":{"position":[[524,2]]},"539":{"position":[[39,2]]},"544":{"position":[[10,2]]},"546":{"position":[[23,2]]},"552":{"position":[[26,2]]},"561":{"position":[[412,2]]},"570":{"position":[[77,2],[216,2]]},"574":{"position":[[119,2],[164,2],[168,2],[279,2]]},"595":{"position":[[187,2]]},"597":{"position":[[15,2]]},"610":{"position":[[294,2],[358,2]]},"619":{"position":[[71,2]]},"648":{"position":[[1191,2]]},"668":{"position":[[48,2]]},"672":{"position":[[1029,2]]},"674":{"position":[[936,2]]},"691":{"position":[[63,2]]},"693":{"position":[[18,2]]},"727":{"position":[[1896,2]]},"732":{"position":[[84,2]]},"734":{"position":[[25,2]]},"745":{"position":[[72,2]]},"752":{"position":[[164,2]]},"761":{"position":[[212,2]]},"780":{"position":[[46,2]]},"832":{"position":[[2349,2]]},"836":{"position":[[17,2]]},"870":{"position":[[217,2]]},"882":{"position":[[231,2],[239,2],[245,2],[385,2]]},"891":{"position":[[22,2]]},"894":{"position":[[50,2],[70,2]]},"917":{"position":[[66,2]]},"925":{"position":[[122,2],[712,2]]},"928":{"position":[[60,2],[80,2]]},"969":{"position":[[347,2],[373,2]]},"980":{"position":[[40,2]]}}}],["方面",{"_index":1745,"t":{"357":{"position":[[10,2]]},"503":{"position":[[47,2]]}}}],["施",{"_index":1844,"t":{"370":{"position":[[124,1]]}}}],["无人",{"_index":2679,"t":{"597":{"position":[[26,2]]}}}],["无关",{"_index":159,"t":{"20":{"position":[[77,2]]},"498":{"position":[[22,2],[29,2]]},"862":{"position":[[21,2],[29,2]]},"917":{"position":[[99,2],[107,2]]},"978":{"position":[[18,2]]}}}],["无差别",{"_index":2454,"t":{"526":{"position":[[148,3]]}}}],["无感",{"_index":2467,"t":{"526":{"position":[[353,2]]}}}],["无所谓",{"_index":2844,"t":{"689":{"position":[[112,3]]}}}],["无效",{"_index":453,"t":{"50":{"position":[[106,2],[121,2]]},"514":{"position":[[367,2]]},"570":{"position":[[154,2]]}}}],["无条件",{"_index":3034,"t":{"748":{"position":[[308,3]]}}}],["无比",{"_index":2220,"t":{"455":{"position":[[490,2]]}}}],["无法",{"_index":1014,"t":{"134":{"position":[[1579,2],[2077,2],[2775,2],[3277,2]]},"301":{"position":[[1152,2],[1204,2]]},"336":{"position":[[61,2]]},"340":{"position":[[158,2]]},"361":{"position":[[1967,2]]},"431":{"position":[[845,2]]},"442":{"position":[[52,2]]},"503":{"position":[[124,2],[146,2]]},"617":{"position":[[35,2]]},"639":{"position":[[24,2]]},"666":{"position":[[113,2]]},"783":{"position":[[170,2]]},"806":{"position":[[47,2]]},"882":{"position":[[325,2]]}}}],["无用",{"_index":3274,"t":{"870":{"position":[[215,2]]}}}],["无疑",{"_index":1796,"t":{"365":{"position":[[61,2],[1329,2]]}}}],["无论",{"_index":2015,"t":{"420":{"position":[[0,2]]}}}],["无限",{"_index":1596,"t":{"297":{"position":[[173,2],[274,2],[346,2]]}}}],["无限大",{"_index":498,"t":{"55":{"position":[[50,3]]}}}],["无需",{"_index":1097,"t":{"153":{"position":[[13,2]]},"194":{"position":[[484,2]]},"233":{"position":[[490,2]]}}}],["无须",{"_index":2534,"t":{"542":{"position":[[32,2]]}}}],["日后",{"_index":3444,"t":{"965":{"position":[[172,2]]}}}],["日志",{"_index":1405,"t":{"223":{"position":[[919,2],[936,2]]},"225":{"position":[[1255,2],[1272,2],[1809,2],[1826,2]]},"229":{"position":[[511,2],[528,2]]},"473":{"position":[[25,2],[38,2],[238,2],[268,2]]},"475":{"position":[[6,2]]},"477":{"position":[[5,2]]},"479":{"position":[[2,2],[18,2],[40,2]]},"481":{"position":[[12,2]]},"639":{"position":[[39,2]]},"859":{"position":[[965,2],[982,2]]},"872":{"position":[[34,2],[607,2]]},"880":{"position":[[116,2],[124,2],[220,2]]},"884":{"position":[[74,2]]},"896":{"position":[[216,2]]}}}],["日期",{"_index":2286,"t":{"477":{"position":[[34,2]]},"868":{"position":[[2,2]]},"870":{"position":[[2,2]]},"872":{"position":[[2,2]]},"874":{"position":[[2,2]]},"876":{"position":[[2,2]]},"878":{"position":[[2,2]]},"880":{"position":[[2,2]]},"882":{"position":[[2,2]]},"884":{"position":[[2,2]]},"886":{"position":[[2,2]]}}}],["时",{"_index":117,"t":{"12":{"position":[[135,1]]},"25":{"position":[[214,1],[368,1]]},"38":{"position":[[11,1]]},"46":{"position":[[388,1]]},"50":{"position":[[7,1],[74,1],[97,1],[295,1]]},"57":{"position":[[385,1],[791,1],[809,1]]},"69":{"position":[[173,1]]},"78":{"position":[[86,1],[201,1],[319,1]]},"116":{"position":[[12,1]]},"118":{"position":[[98,1],[116,1],[136,1],[154,1],[214,1]]},"127":{"position":[[213,1],[489,1]]},"132":{"position":[[254,1]]},"157":{"position":[[296,1]]},"159":{"position":[[6,1],[171,1],[248,1]]},"166":{"position":[[227,1],[313,1],[423,1]]},"184":{"position":[[705,1],[770,1],[1219,1],[1419,1],[1456,1]]},"186":{"position":[[85,1],[150,1],[204,1],[251,1],[316,1]]},"188":{"position":[[208,1]]},"192":{"position":[[17,1]]},"194":{"position":[[204,1]]},"205":{"position":[[110,1]]},"207":{"position":[[380,1]]},"216":{"position":[[12,1]]},"218":{"position":[[705,1],[770,1],[1219,1],[1419,1],[1456,1]]},"220":{"position":[[157,1],[211,1],[258,1],[323,1],[380,1]]},"233":{"position":[[207,1]]},"248":{"position":[[39,1],[64,1]]},"252":{"position":[[227,1],[313,1],[423,1]]},"261":{"position":[[229,1]]},"268":{"position":[[86,1]]},"281":{"position":[[23,1],[75,1]]},"284":{"position":[[443,1]]},"290":{"position":[[83,1]]},"292":{"position":[[408,1]]},"297":{"position":[[305,1]]},"301":{"position":[[387,1],[492,1],[592,1],[777,1],[890,1],[1156,1],[1208,1]]},"308":{"position":[[370,1],[2532,1]]},"319":{"position":[[34,1],[687,1],[732,1]]},"321":{"position":[[103,1]]},"336":{"position":[[43,1],[145,1]]},"340":{"position":[[121,1],[140,1],[224,1],[1016,1]]},"347":{"position":[[376,1]]},"359":{"position":[[96,1]]},"361":{"position":[[537,1]]},"363":{"position":[[31,1]]},"365":{"position":[[11,1],[1393,1],[1457,1]]},"378":{"position":[[46,1],[124,1]]},"393":{"position":[[226,1]]},"402":{"position":[[88,1]]},"415":{"position":[[26,1],[92,1],[109,1],[146,1],[181,1]]},"431":{"position":[[856,1]]},"442":{"position":[[23,1]]},"444":{"position":[[329,1]]},"447":{"position":[[1306,1]]},"449":{"position":[[40,1],[164,1]]},"451":{"position":[[124,1]]},"455":{"position":[[32,1]]},"473":{"position":[[40,1],[295,1]]},"475":{"position":[[11,1]]},"477":{"position":[[10,1]]},"479":{"position":[[8,1]]},"485":{"position":[[272,1]]},"487":{"position":[[41,1]]},"503":{"position":[[58,1]]},"512":{"position":[[245,1]]},"514":{"position":[[497,1]]},"521":{"position":[[30,1],[137,1],[470,1]]},"526":{"position":[[270,1],[288,1]]},"542":{"position":[[30,1],[87,1],[112,1]]},"544":{"position":[[94,1]]},"546":{"position":[[55,1]]},"554":{"position":[[140,1],[198,1]]},"559":{"position":[[72,1],[144,1]]},"561":{"position":[[14,1],[414,1]]},"570":{"position":[[31,1],[67,1],[174,1]]},"574":{"position":[[26,1],[93,1]]},"613":{"position":[[8,1]]},"628":{"position":[[26,1]]},"634":{"position":[[22,1]]},"653":{"position":[[6,1]]},"661":{"position":[[6,1],[353,1]]},"663":{"position":[[458,1]]},"686":{"position":[[141,1]]},"689":{"position":[[34,1]]},"697":{"position":[[75,1]]},"699":{"position":[[17,1]]},"738":{"position":[[87,1]]},"741":{"position":[[78,1]]},"743":{"position":[[53,1]]},"748":{"position":[[428,1],[440,1],[455,1]]},"752":{"position":[[17,1],[29,1],[154,1]]},"756":{"position":[[50,1]]},"778":{"position":[[64,1]]},"783":{"position":[[271,1],[297,1],[325,1]]},"787":{"position":[[36,1]]},"792":{"position":[[220,1],[235,1]]},"809":{"position":[[59,1]]},"818":{"position":[[3,1]]},"820":{"position":[[16,1],[246,1],[263,1]]},"826":{"position":[[52,1]]},"830":{"position":[[45,1],[367,1],[395,1],[673,1]]},"832":{"position":[[1834,1],[2023,1]]},"836":{"position":[[69,1]]},"849":{"position":[[4,1]]},"851":{"position":[[106,1],[341,1]]},"857":{"position":[[391,1],[434,1],[663,1]]},"859":{"position":[[285,1],[328,1],[552,1],[1128,1]]},"864":{"position":[[21,1]]},"868":{"position":[[98,1]]},"870":{"position":[[60,1],[98,1],[120,1],[181,1]]},"872":{"position":[[350,1],[663,1]]},"874":{"position":[[103,1],[480,1]]},"876":{"position":[[196,1]]},"878":{"position":[[204,1]]},"880":{"position":[[187,1]]},"884":{"position":[[83,1],[217,1]]},"932":{"position":[[8,1]]},"965":{"position":[[119,1],[142,1]]},"967":{"position":[[10,1],[45,1]]},"969":{"position":[[131,1],[194,1]]},"971":{"position":[[40,1],[78,1]]}}}],["时代",{"_index":2216,"t":{"455":{"position":[[468,2]]}}}],["时会",{"_index":410,"t":{"46":{"position":[[417,2]]}}}],["时候",{"_index":961,"t":{"127":{"position":[[266,2],[542,2]]},"146":{"position":[[80,2]]},"288":{"position":[[301,2],[320,2]]},"409":{"position":[[8,2],[67,2]]},"447":{"position":[[842,2]]},"449":{"position":[[128,2]]},"468":{"position":[[32,2]]},"485":{"position":[[114,2]]},"530":{"position":[[124,2]]},"574":{"position":[[228,2]]},"655":{"position":[[353,2]]},"734":{"position":[[231,2]]},"787":{"position":[[24,2]]},"868":{"position":[[176,2]]}}}],["时刻",{"_index":2193,"t":{"451":{"position":[[10,2]]}}}],["时间",{"_index":470,"t":{"50":{"position":[[220,2],[257,2]]},"132":{"position":[[288,2]]},"164":{"position":[[29,2]]},"184":{"position":[[202,2],[1120,2],[1136,2],[1141,2],[1899,2],[1915,2],[1920,2]]},"218":{"position":[[202,2],[1120,2],[1136,2],[1141,2],[1899,2],[1915,2],[1920,2]]},"250":{"position":[[29,2]]},"340":{"position":[[903,2]]},"442":{"position":[[85,2]]},"561":{"position":[[224,2]]},"579":{"position":[[62,2],[93,2]]},"581":{"position":[[127,2]]},"602":{"position":[[27,2]]},"689":{"position":[[189,2]]},"832":{"position":[[2052,2]]},"874":{"position":[[285,2]]},"971":{"position":[[36,2]]}}}],["明显",{"_index":240,"t":{"28":{"position":[[115,2]]},"308":{"position":[[2400,2]]},"689":{"position":[[196,2]]}}}],["明白",{"_index":2180,"t":{"449":{"position":[[14,2]]}}}],["明确",{"_index":2299,"t":{"487":{"position":[[10,2]]},"546":{"position":[[36,2]]},"554":{"position":[[202,2]]},"787":{"position":[[7,2]]}}}],["明确指出",{"_index":3050,"t":{"758":{"position":[[105,4]]}}}],["易",{"_index":2624,"t":{"566":{"position":[[6,1]]}}}],["易于",{"_index":3084,"t":{"783":{"position":[[22,2]]}}}],["易用",{"_index":1214,"t":{"180":{"position":[[2,2]]},"199":{"position":[[26,2]]},"201":{"position":[[2,2]]},"212":{"position":[[2,2]]},"566":{"position":[[2,2]]},"783":{"position":[[13,2]]},"911":{"position":[[2,2]]}}}],["星",{"_index":1851,"t":{"370":{"position":[[177,1]]}}}],["映射",{"_index":1395,"t":{"216":{"position":[[97,2]]},"626":{"position":[[21,2]]},"630":{"position":[[91,2]]},"798":{"position":[[26,2]]},"884":{"position":[[112,2]]}}}],["是不是",{"_index":2189,"t":{"449":{"position":[[234,3]]},"783":{"position":[[179,3]]}}}],["是从",{"_index":57,"t":{"7":{"position":[[52,2]]},"34":{"position":[[278,2]]},"357":{"position":[[102,2]]}}}],["是否",{"_index":467,"t":{"50":{"position":[[193,2],[246,2]]},"78":{"position":[[98,2]]},"166":{"position":[[130,2]]},"184":{"position":[[357,2],[695,2]]},"218":{"position":[[357,2],[695,2]]},"225":{"position":[[774,2]]},"252":{"position":[[130,2]]},"272":{"position":[[573,2]]},"301":{"position":[[758,2]]},"413":{"position":[[118,2],[128,2]]},"415":{"position":[[162,2]]},"451":{"position":[[69,2]]},"485":{"position":[[136,2]]},"507":{"position":[[391,2],[572,2]]},"514":{"position":[[107,2]]},"521":{"position":[[282,2],[427,2]]},"574":{"position":[[237,2]]},"653":{"position":[[219,2],[259,2]]},"691":{"position":[[255,2]]},"734":{"position":[[234,2]]},"820":{"position":[[205,2]]},"830":{"position":[[125,2]]},"857":{"position":[[436,2]]},"859":{"position":[[330,2]]},"870":{"position":[[102,2]]}}}],["是因为",{"_index":281,"t":{"34":{"position":[[74,3]]},"455":{"position":[[990,3]]},"720":{"position":[[43,3]]},"783":{"position":[[187,3]]}}}],["显",{"_index":956,"t":{"127":{"position":[[255,1],[531,1]]},"343":{"position":[[109,1]]},"595":{"position":[[205,1]]},"597":{"position":[[228,1]]}}}],["显得",{"_index":1983,"t":{"409":{"position":[[51,2],[113,2]]},"503":{"position":[[165,2]]},"526":{"position":[[310,2]]},"689":{"position":[[110,2]]},"778":{"position":[[128,2]]}}}],["显示",{"_index":3271,"t":{"868":{"position":[[209,2]]}}}],["普适性",{"_index":3417,"t":{"959":{"position":[[33,3]]}}}],["普通",{"_index":419,"t":{"46":{"position":[[484,2]]},"235":{"position":[[209,2]]},"376":{"position":[[109,2]]},"738":{"position":[[12,2]]},"743":{"position":[[48,2]]},"925":{"position":[[145,2]]},"976":{"position":[[13,2]]}}}],["更",{"_index":932,"t":{"125":{"position":[[186,1]]},"184":{"position":[[107,1],[383,1],[1002,1],[1781,1]]},"218":{"position":[[107,1],[383,1],[1002,1],[1781,1]]},"263":{"position":[[46,1]]},"444":{"position":[[29,1],[46,1],[488,1],[492,1]]},"581":{"position":[[109,1]]},"814":{"position":[[40,1]]},"891":{"position":[[277,1]]},"906":{"position":[[116,1]]}}}],["更为",{"_index":3097,"t":{"785":{"position":[[93,2]]}}}],["更加",{"_index":928,"t":{"125":{"position":[[159,2]]},"184":{"position":[[75,2]]},"218":{"position":[[75,2]]},"225":{"position":[[1920,2]]},"286":{"position":[[12,2]]},"299":{"position":[[0,2]]},"304":{"position":[[20,2]]},"498":{"position":[[80,2]]},"617":{"position":[[281,2]]},"778":{"position":[[41,2]]},"909":{"position":[[133,2]]},"917":{"position":[[127,2]]}}}],["更好",{"_index":363,"t":{"42":{"position":[[32,2]]},"263":{"position":[[31,2]]},"959":{"position":[[30,2]]}}}],["更新",{"_index":473,"t":{"50":{"position":[[253,2]]},"235":{"position":[[171,2]]},"444":{"position":[[660,2]]},"447":{"position":[[839,2]]},"586":{"position":[[24,2]]},"868":{"position":[[0,2],[14,2],[22,2]]},"870":{"position":[[0,2],[15,2]]},"872":{"position":[[0,2],[14,2],[32,2],[1027,2]]},"874":{"position":[[0,2],[15,2],[23,2],[29,2],[48,2],[52,2]]},"876":{"position":[[0,2],[15,2],[23,2],[29,2],[46,2]]},"878":{"position":[[0,2],[14,2],[22,2],[28,2],[32,2],[272,2]]},"880":{"position":[[0,2],[15,2],[23,2],[29,2],[33,2]]},"882":{"position":[[0,2],[15,2],[23,2],[29,2],[33,2]]},"884":{"position":[[0,2],[15,2],[23,2],[27,2]]},"886":{"position":[[0,2],[15,2]]}}}],["替",{"_index":624,"t":{"62":{"position":[[38,1]]},"71":{"position":[[38,1]]},"82":{"position":[[38,1]]},"134":{"position":[[54,1]]}}}],["替代",{"_index":1095,"t":{"151":{"position":[[132,2]]},"878":{"position":[[452,2]]}}}],["替换",{"_index":372,"t":{"44":{"position":[[47,2]]},"440":{"position":[[309,2]]},"872":{"position":[[624,2],[710,2]]}}}],["最后",{"_index":823,"t":{"120":{"position":[[333,2]]},"159":{"position":[[112,2]]},"301":{"position":[[631,2]]},"308":{"position":[[2515,2]]},"340":{"position":[[889,2]]},"347":{"position":[[1449,2]]},"359":{"position":[[131,2]]},"361":{"position":[[1135,2]]},"447":{"position":[[814,2]]},"514":{"position":[[505,2]]},"641":{"position":[[80,2]]},"670":{"position":[[50,2]]},"714":{"position":[[60,2]]},"748":{"position":[[179,2]]},"818":{"position":[[37,2]]},"834":{"position":[[18,2]]},"874":{"position":[[283,2]]}}}],["最大",{"_index":969,"t":{"127":{"position":[[697,2]]},"184":{"position":[[549,2],[573,2]]},"218":{"position":[[549,2],[573,2]]},"340":{"position":[[899,2]]},"365":{"position":[[1351,2]]},"526":{"position":[[181,2],[190,2]]},"542":{"position":[[107,2]]},"727":{"position":[[390,2],[1498,2]]},"750":{"position":[[35,2],[593,2]]},"814":{"position":[[18,2]]}}}],["最大值",{"_index":1244,"t":{"184":{"position":[[168,3]]},"218":{"position":[[168,3]]},"668":{"position":[[29,3]]}}}],["最好",{"_index":406,"t":{"46":{"position":[[390,2]]},"110":{"position":[[102,2]]},"120":{"position":[[464,2],[482,2]]},"235":{"position":[[136,2]]},"239":{"position":[[137,2]]},"338":{"position":[[20,2]]},"402":{"position":[[62,2]]},"686":{"position":[[462,2]]},"718":{"position":[[174,2]]},"806":{"position":[[195,2]]}}}],["最小",{"_index":1087,"t":{"151":{"position":[[14,2]]}}}],["最小化",{"_index":3333,"t":{"882":{"position":[[226,3]]},"906":{"position":[[151,3]]}}}],["最少",{"_index":1251,"t":{"184":{"position":[[283,2]]},"218":{"position":[[283,2]]},"505":{"position":[[36,2]]}}}],["最新",{"_index":118,"t":{"12":{"position":[[136,2]]},"707":{"position":[[76,2],[191,2]]},"716":{"position":[[129,2]]},"961":{"position":[[161,2]]}}}],["最终",{"_index":1044,"t":{"140":{"position":[[9,2]]},"184":{"position":[[981,2],[1760,2]]},"218":{"position":[[981,2],[1760,2]]},"440":{"position":[[83,2]]},"470":{"position":[[214,2],[441,2],[638,2],[787,2]]}}}],["最近",{"_index":2958,"t":{"718":{"position":[[196,2]]}}}],["最高",{"_index":3131,"t":{"806":{"position":[[202,2]]},"820":{"position":[[200,2]]},"872":{"position":[[42,2]]}}}],["月华",{"_index":1868,"t":{"370":{"position":[[268,2]]}}}],["有人",{"_index":2105,"t":{"444":{"position":[[20,2]]},"455":{"position":[[995,2]]}}}],["有关",{"_index":94,"t":{"10":{"position":[[45,2]]},"12":{"position":[[45,2]]},"14":{"position":[[45,2]]}}}],["有力",{"_index":1963,"t":{"400":{"position":[[23,2]]},"402":{"position":[[1,2]]}}}],["有序性",{"_index":1301,"t":{"184":{"position":[[910,3],[1689,3]]},"218":{"position":[[910,3],[1689,3]]}}}],["有意思",{"_index":1409,"t":{"225":{"position":[[16,3]]}}}],["有效",{"_index":2798,"t":{"666":{"position":[[172,2]]},"761":{"position":[[180,2]]},"872":{"position":[[135,2]]}}}],["有效值",{"_index":1529,"t":{"272":{"position":[[1155,3]]},"363":{"position":[[39,3]]},"365":{"position":[[32,3]]}}}],["有效性",{"_index":2289,"t":{"485":{"position":[[45,3]]},"554":{"position":[[14,3]]}}}],["有效载荷",{"_index":3164,"t":{"820":{"position":[[226,4]]}}}],["有时候",{"_index":269,"t":{"34":{"position":[[2,3]]},"136":{"position":[[24,3]]},"308":{"position":[[2407,3]]},"343":{"position":[[0,3]]},"455":{"position":[[23,3],[55,3]]},"468":{"position":[[72,3]]},"617":{"position":[[58,3]]},"619":{"position":[[23,3]]},"661":{"position":[[27,3]]},"814":{"position":[[33,3]]},"959":{"position":[[39,3]]}}}],["有点",{"_index":1927,"t":{"383":{"position":[[41,2]]}}}],["有点儿",{"_index":3056,"t":{"761":{"position":[[81,3]]}}}],["有用",{"_index":1410,"t":{"225":{"position":[[26,2]]},"581":{"position":[[112,2]]}}}],["有限",{"_index":2820,"t":{"679":{"position":[[140,2]]}}}],["有限公司",{"_index":1668,"t":{"326":{"position":[[4,4]]},"906":{"position":[[7,4]]}}}],["服务",{"_index":787,"t":{"110":{"position":[[22,2],[55,2]]},"125":{"position":[[50,2]]},"127":{"position":[[69,2],[203,2],[243,2],[479,2],[519,2],[694,2],[718,2]]},"129":{"position":[[252,2]]},"134":{"position":[[20,2]]},"136":{"position":[[6,2]]},"138":{"position":[[177,2],[184,2],[205,2],[213,2],[232,2],[376,2],[382,2]]},"144":{"position":[[40,2]]},"146":{"position":[[91,2]]},"235":{"position":[[869,2],[1174,2],[1260,2]]},"261":{"position":[[323,2]]},"440":{"position":[[40,2],[293,2]]},"442":{"position":[[114,2]]},"444":{"position":[[656,2]]},"447":{"position":[[64,2],[518,2],[836,2],[880,2],[1281,2]]},"449":{"position":[[77,2],[82,2],[120,2],[133,2],[183,2]]},"451":{"position":[[1,2]]},"455":{"position":[[52,2],[622,2],[1019,2],[1029,2]]},"514":{"position":[[0,2],[9,2]]},"639":{"position":[[3,2],[17,2]]},"641":{"position":[[50,2]]},"646":{"position":[[3,2]]},"653":{"position":[[205,2],[217,2]]},"663":{"position":[[285,2]]},"792":{"position":[[87,2]]},"806":{"position":[[132,2]]},"876":{"position":[[191,2],[204,2]]},"880":{"position":[[152,2],[185,2]]},"882":{"position":[[169,2],[192,2]]},"891":{"position":[[104,2],[297,2]]},"896":{"position":[[282,2]]},"930":{"position":[[0,2],[9,2]]},"932":{"position":[[32,2],[146,2],[228,2]]},"935":{"position":[[122,2]]},"957":{"position":[[156,2]]},"959":{"position":[[11,2]]},"961":{"position":[[70,2],[276,2]]},"965":{"position":[[30,2],[59,2],[81,2],[136,2]]},"969":{"position":[[201,2],[404,2]]}}}],["服务器",{"_index":326,"t":{"36":{"position":[[59,3]]},"48":{"position":[[25,3]]},"57":{"position":[[4,3],[14,3],[1977,3]]},"66":{"position":[[41,3]]},"75":{"position":[[41,3]]},"78":{"position":[[332,3]]},"86":{"position":[[86,3]]},"104":{"position":[[12,3],[35,3],[187,3]]},"110":{"position":[[97,3]]},"116":{"position":[[0,3]]},"122":{"position":[[5,3],[14,3]]},"125":{"position":[[227,3]]},"127":{"position":[[58,3]]},"129":{"position":[[26,3],[41,3]]},"136":{"position":[[16,3],[30,3]]},"138":{"position":[[141,3],[164,3],[208,3]]},"140":{"position":[[0,3],[15,3]]},"142":{"position":[[547,3]]},"146":{"position":[[65,3],[107,3]]},"178":{"position":[[50,3]]},"184":{"position":[[499,3],[1206,3]]},"188":{"position":[[142,3],[194,3],[278,3]]},"192":{"position":[[159,3]]},"194":{"position":[[51,3]]},"199":{"position":[[34,3]]},"210":{"position":[[15,3],[98,3],[105,3]]},"212":{"position":[[27,3]]},"216":{"position":[[0,3]]},"218":{"position":[[499,3],[1206,3]]},"225":{"position":[[6,3],[46,3],[398,3],[831,3],[1351,3]]},"233":{"position":[[51,3],[550,3]]},"235":{"position":[[270,3]]},"237":{"position":[[17,3]]},"239":{"position":[[176,3]]},"246":{"position":[[9,3],[25,3]]},"248":{"position":[[8,3],[49,3]]},"272":{"position":[[4,3],[14,3],[1771,3]]},"275":{"position":[[35,3]]},"284":{"position":[[562,3]]},"286":{"position":[[477,3]]},"288":{"position":[[312,3],[329,3]]},"290":{"position":[[76,3],[1008,3]]},"292":{"position":[[129,3]]},"301":{"position":[[2890,3]]},"308":{"position":[[4,3],[14,3],[2575,3]]},"323":{"position":[[284,3]]},"328":{"position":[[18,3]]},"347":{"position":[[4,3],[14,3],[2547,3]]},"383":{"position":[[13,3],[37,3]]},"391":{"position":[[0,3],[16,3],[287,3]]},"393":{"position":[[218,3]]},"402":{"position":[[69,3]]},"406":{"position":[[4,3],[14,3],[590,3]]},"422":{"position":[[4,3],[14,3],[574,3]]},"444":{"position":[[66,3],[362,3],[509,3]]},"447":{"position":[[9,3],[203,3],[210,3],[780,3],[852,3]]},"449":{"position":[[32,3]]},"455":{"position":[[902,3]]},"458":{"position":[[377,3]]},"461":{"position":[[5,3]]},"485":{"position":[[11,3],[28,3]]},"493":{"position":[[450,3]]},"495":{"position":[[248,3],[661,3]]},"514":{"position":[[36,3]]},"516":{"position":[[157,3],[163,3]]},"526":{"position":[[157,3],[225,3]]},"528":{"position":[[26,3]]},"530":{"position":[[142,3]]},"533":{"position":[[21,3],[46,3],[57,3]]},"535":{"position":[[24,3]]},"537":{"position":[[236,3],[507,3],[1211,3]]},"539":{"position":[[22,3]]},"561":{"position":[[793,3]]},"570":{"position":[[26,3]]},"574":{"position":[[248,3]]},"581":{"position":[[46,3]]},"590":{"position":[[33,3]]},"593":{"position":[[17,3]]},"613":{"position":[[10,3],[39,3]]},"615":{"position":[[5,3]]},"617":{"position":[[123,3]]},"623":{"position":[[45,3]]},"628":{"position":[[58,3]]},"630":{"position":[[13,3],[25,3]]},"653":{"position":[[120,3]]},"663":{"position":[[28,3],[40,3]]},"670":{"position":[[16,3]]},"672":{"position":[[1038,3]]},"674":{"position":[[945,3]]},"686":{"position":[[3,3],[490,3]]},"693":{"position":[[42,3]]},"727":{"position":[[3,3],[29,3]]},"729":{"position":[[27,3],[55,3],[76,3]]},"736":{"position":[[544,3]]},"745":{"position":[[4,3],[14,3],[645,3]]},"752":{"position":[[94,3],[166,3]]},"758":{"position":[[143,3]]},"772":{"position":[[1,3]]},"776":{"position":[[14,3]]},"790":{"position":[[33,3],[44,3]]},"792":{"position":[[51,3]]},"794":{"position":[[31,3]]},"796":{"position":[[30,3]]},"800":{"position":[[20,3]]},"804":{"position":[[22,3]]},"826":{"position":[[60,3]]},"828":{"position":[[62,3]]},"830":{"position":[[55,3],[89,3]]},"832":{"position":[[1,3],[369,3],[1645,3],[1948,3],[2025,3]]},"836":{"position":[[42,3]]},"854":{"position":[[29,3],[36,3]]},"868":{"position":[[213,3]]},"872":{"position":[[693,3]]},"874":{"position":[[43,3],[260,3]]},"878":{"position":[[533,3],[701,3]]},"884":{"position":[[118,3]]},"909":{"position":[[174,3]]},"915":{"position":[[0,3]]},"925":{"position":[[154,3],[615,3]]},"930":{"position":[[36,3]]},"932":{"position":[[524,3]]},"980":{"position":[[476,3]]}}}],["服务器之间",{"_index":2967,"t":{"723":{"position":[[35,5]]},"806":{"position":[[120,5]]},"909":{"position":[[121,5]]}}}],["服务器时",{"_index":1422,"t":{"229":{"position":[[20,4]]},"288":{"position":[[5,4]]},"514":{"position":[[76,4]]},"516":{"position":[[36,4]]}}}],["服务器端",{"_index":2393,"t":{"512":{"position":[[1,4]]},"894":{"position":[[1,4]]},"917":{"position":[[69,4]]},"928":{"position":[[1,4]]}}}],["服务器进行",{"_index":3072,"t":{"770":{"position":[[56,5]]}}}],["服务端",{"_index":2177,"t":{"447":{"position":[[1291,3]]},"455":{"position":[[944,3]]},"780":{"position":[[34,3]]},"872":{"position":[[1114,3]]},"909":{"position":[[140,3]]}}}],["服务项目",{"_index":2137,"t":{"444":{"position":[[531,4]]}}}],["期",{"_index":2932,"t":{"707":{"position":[[62,1]]}}}],["期望",{"_index":1707,"t":{"340":{"position":[[833,2]]}}}],["期间",{"_index":140,"t":{"18":{"position":[[13,2]]},"20":{"position":[[45,2]]}}}],["期限",{"_index":3420,"t":{"961":{"position":[[42,2]]},"965":{"position":[[53,2],[65,2]]}}}],["未",{"_index":1143,"t":{"159":{"position":[[52,1]]},"290":{"position":[[500,1]]},"361":{"position":[[1148,1]]},"561":{"position":[[451,1]]}}}],["未知",{"_index":3108,"t":{"787":{"position":[[101,2]]}}}],["本",{"_index":121,"t":{"12":{"position":[[146,1]]},"20":{"position":[[49,1],[73,1]]},"194":{"position":[[478,1]]},"233":{"position":[[484,1]]},"361":{"position":[[1084,1]]},"697":{"position":[[0,1]]},"718":{"position":[[208,1]]}}}],["本地",{"_index":630,"t":{"66":{"position":[[47,2]]},"75":{"position":[[47,2]]},"86":{"position":[[92,2]]},"125":{"position":[[202,2]]},"184":{"position":[[1566,2]]},"218":{"position":[[1566,2]]},"383":{"position":[[33,2]]},"440":{"position":[[13,2],[45,2],[89,2]]},"447":{"position":[[41,2],[1028,2]]},"528":{"position":[[812,2]]},"626":{"position":[[24,2],[28,2]]},"628":{"position":[[28,2]]},"689":{"position":[[103,2]]},"798":{"position":[[29,2]]},"830":{"position":[[475,2]]},"932":{"position":[[338,2]]}}}],["本文",{"_index":2307,"t":{"487":{"position":[[83,2]]}}}],["本次",{"_index":1594,"t":{"297":{"position":[[104,2]]},"301":{"position":[[1202,2]]},"340":{"position":[[855,2]]},"559":{"position":[[123,2]]},"561":{"position":[[18,2]]},"783":{"position":[[131,2]]},"830":{"position":[[243,2]]},"832":{"position":[[1752,2]]}}}],["本身",{"_index":1396,"t":{"216":{"position":[[117,2]]},"444":{"position":[[352,2]]},"783":{"position":[[383,2]]}}}],["机制",{"_index":2263,"t":{"468":{"position":[[4,2],[15,2],[23,2]]},"485":{"position":[[2,2],[49,2],[159,2],[183,2],[208,2]]},"752":{"position":[[44,2]]},"783":{"position":[[224,2]]},"862":{"position":[[35,2],[57,2]]},"884":{"position":[[258,2]]}}}],["机器人",{"_index":2014,"t":{"418":{"position":[[73,3]]}}}],["机构",{"_index":760,"t":{"104":{"position":[[44,2]]},"319":{"position":[[10,2]]}}}],["机械",{"_index":2012,"t":{"418":{"position":[[69,2]]}}}],["权",{"_index":3063,"t":{"761":{"position":[[179,1],[193,1],[202,1]]}}}],["权利",{"_index":44,"t":{"7":{"position":[[2,2],[22,2]]}}}],["权益",{"_index":3449,"t":{"967":{"position":[[61,2]]}}}],["权限",{"_index":1942,"t":{"391":{"position":[[314,2]]},"397":{"position":[[112,2]]},"802":{"position":[[23,2]]}}}],["杜",{"_index":1842,"t":{"370":{"position":[[112,1]]}}}],["束",{"_index":3430,"t":{"961":{"position":[[238,1],[245,1],[252,1]]}}}],["条",{"_index":1388,"t":{"212":{"position":[[47,1]]}}}],["条件",{"_index":1610,"t":{"301":{"position":[[385,2],[590,2]]},"830":{"position":[[418,2]]},"880":{"position":[[108,2]]}}}],["条款",{"_index":3451,"t":{"967":{"position":[[80,2]]}}}],["来不及",{"_index":1326,"t":{"184":{"position":[[1241,3]]},"218":{"position":[[1241,3]]}}}],["来源",{"_index":2719,"t":{"615":{"position":[[114,2]]},"677":{"position":[[6,2]]}}}],["来自",{"_index":2549,"t":{"542":{"position":[[180,2]]}}}],["来讲",{"_index":2538,"t":{"542":{"position":[[58,2]]}}}],["来说",{"_index":1313,"t":{"184":{"position":[[1076,2],[1855,2]]},"218":{"position":[[1076,2],[1855,2]]},"455":{"position":[[346,2]]},"505":{"position":[[42,2]]},"514":{"position":[[30,2]]},"930":{"position":[[30,2]]}}}],["极短",{"_index":1320,"t":{"184":{"position":[[1143,2],[1922,2]]},"218":{"position":[[1143,2],[1922,2]]}}}],["极端",{"_index":1674,"t":{"334":{"position":[[18,2],[51,2],[59,2]]},"338":{"position":[[47,2]]}}}],["极限",{"_index":2346,"t":{"503":{"position":[[11,2]]}}}],["构建",{"_index":1705,"t":{"340":{"position":[[803,2]]},"440":{"position":[[87,2],[145,2],[235,2]]},"455":{"position":[[370,2]]},"544":{"position":[[122,2]]},"756":{"position":[[36,2],[46,2],[66,2],[75,2],[197,2]]},"758":{"position":[[0,2]]}}}],["构成",{"_index":3027,"t":{"748":{"position":[[73,2]]}}}],["构造",{"_index":2555,"t":{"544":{"position":[[106,2]]},"548":{"position":[[38,2]]},"552":{"position":[[121,2]]},"554":{"position":[[8,2]]},"561":{"position":[[308,2]]},"756":{"position":[[103,2]]}}}],["构造函数",{"_index":399,"t":{"46":{"position":[[362,4]]},"544":{"position":[[2,4]]},"546":{"position":[[15,4],[103,4]]},"891":{"position":[[237,4]]}}}],["枚举",{"_index":2835,"t":{"686":{"position":[[161,2]]}}}],["架构",{"_index":1140,"t":{"159":{"position":[[10,2]]},"248":{"position":[[12,2],[23,2],[42,2]]},"397":{"position":[[12,2]]},"826":{"position":[[3,2]]},"915":{"position":[[23,2]]}}}],["架构图",{"_index":1441,"t":{"237":{"position":[[2,3]]}}}],["某个",{"_index":1998,"t":{"415":{"position":[[1,2],[79,2],[177,2]]},"444":{"position":[[315,2],[346,2]]},"570":{"position":[[167,2]]},"661":{"position":[[39,2]]},"959":{"position":[[16,2],[65,2],[73,2]]}}}],["某些",{"_index":914,"t":{"125":{"position":[[75,2]]}}}],["某种",{"_index":2726,"t":{"619":{"position":[[41,2]]}}}],["查找",{"_index":1446,"t":{"239":{"position":[[179,2]]},"932":{"position":[[24,2]]}}}],["查看",{"_index":2759,"t":{"648":{"position":[[1203,2]]},"716":{"position":[[145,2]]},"720":{"position":[[90,2]]},"872":{"position":[[1104,2]]}}}],["标准",{"_index":3376,"t":{"909":{"position":[[58,2],[103,2]]}}}],["标准版",{"_index":2872,"t":{"702":{"position":[[105,3]]}}}],["标号",{"_index":2903,"t":{"702":{"position":[[1368,2]]}}}],["标签",{"_index":948,"t":{"127":{"position":[[137,2]]},"453":{"position":[[19,2]]},"512":{"position":[[64,2]]},"544":{"position":[[132,2]]},"641":{"position":[[7,2]]},"866":{"position":[[39,2]]},"882":{"position":[[323,2]]},"894":{"position":[[63,2]]},"928":{"position":[[73,2]]}}}],["标记",{"_index":181,"t":{"25":{"position":[[34,2]]},"69":{"position":[[176,2]]},"127":{"position":[[139,2]]},"138":{"position":[[244,2]]},"512":{"position":[[66,2],[238,2]]},"550":{"position":[[45,2],[98,2]]},"552":{"position":[[18,2]]},"894":{"position":[[65,2]]},"928":{"position":[[75,2]]}}}],["标识",{"_index":1264,"t":{"184":{"position":[[502,2]]},"218":{"position":[[502,2]]},"268":{"position":[[70,2],[98,2]]},"272":{"position":[[1083,2]]},"308":{"position":[[532,2],[654,2],[774,2],[893,2]]},"347":{"position":[[542,2],[662,2]]},"455":{"position":[[548,2]]},"514":{"position":[[116,2]]},"623":{"position":[[39,2]]},"748":{"position":[[201,2],[345,2]]},"783":{"position":[[163,2]]},"820":{"position":[[106,2],[172,2],[203,2]]},"954":{"position":[[25,2]]}}}],["树",{"_index":2350,"t":{"503":{"position":[[38,1]]},"906":{"position":[[166,1],[187,1]]}}}],["校验",{"_index":1650,"t":{"308":{"position":[[2430,2]]},"702":{"position":[[2298,2]]},"820":{"position":[[277,2]]}}}],["校验位",{"_index":2915,"t":{"702":{"position":[[1844,3]]}}}],["样式",{"_index":3366,"t":{"906":{"position":[[170,2]]}}}],["根",{"_index":1186,"t":{"164":{"position":[[216,1]]},"250":{"position":[[216,1]]},"679":{"position":[[268,1]]},"716":{"position":[[17,1]]}}}],["根据",{"_index":1349,"t":{"186":{"position":[[255,2]]},"194":{"position":[[317,2]]},"220":{"position":[[262,2]]},"233":{"position":[[323,2]]},"235":{"position":[[728,2]]},"413":{"position":[[112,2]]},"514":{"position":[[97,2]]},"615":{"position":[[10,2]]},"816":{"position":[[74,2]]},"872":{"position":[[579,2],[1007,2]]},"932":{"position":[[125,2]]}}}],["根本",{"_index":1287,"t":{"184":{"position":[[730,2]]},"218":{"position":[[730,2]]},"444":{"position":[[477,2]]}}}],["格外",{"_index":2465,"t":{"526":{"position":[[312,2]]}}}],["格式",{"_index":1645,"t":{"308":{"position":[[2383,2],[2455,2]]},"376":{"position":[[173,2]]},"475":{"position":[[18,2]]},"485":{"position":[[261,2]]},"487":{"position":[[93,2]]},"783":{"position":[[48,2],[68,2]]},"917":{"position":[[85,2]]}}}],["格式化",{"_index":3317,"t":{"876":{"position":[[154,3]]}}}],["框",{"_index":2940,"t":{"714":{"position":[[34,1]]}}}],["框架",{"_index":408,"t":{"46":{"position":[[402,2]]},"55":{"position":[[36,2]]},"166":{"position":[[116,2]]},"239":{"position":[[129,2]]},"252":{"position":[[116,2]]},"270":{"position":[[38,2]]},"306":{"position":[[55,2]]},"345":{"position":[[35,2]]},"361":{"position":[[2940,2]]},"374":{"position":[[47,2]]},"420":{"position":[[42,2]]},"572":{"position":[[6,2]]},"588":{"position":[[40,2]]},"610":{"position":[[288,2]]},"743":{"position":[[42,2]]},"770":{"position":[[20,2]]},"780":{"position":[[89,2]]},"783":{"position":[[118,2]]},"828":{"position":[[7,2],[22,2]]},"866":{"position":[[12,2],[89,2]]},"872":{"position":[[603,2]]},"906":{"position":[[31,2]]},"978":{"position":[[16,2]]}}}],["案例",{"_index":1494,"t":{"263":{"position":[[28,2]]},"363":{"position":[[23,2]]},"365":{"position":[[3,2],[1342,2]]}}}],["桌面",{"_index":3357,"t":{"906":{"position":[[34,2]]}}}],["梦想",{"_index":1879,"t":{"370":{"position":[[332,2]]}}}],["检查",{"_index":2528,"t":{"539":{"position":[[255,2]]},"597":{"position":[[159,2]]}}}],["检测",{"_index":416,"t":{"46":{"position":[[443,2]]},"725":{"position":[[2,2]]}}}],["检验",{"_index":2481,"t":{"528":{"position":[[652,2],[1366,2]]},"828":{"position":[[18,2]]},"830":{"position":[[123,2]]}}}],["棋",{"_index":16,"t":{"5":{"position":[[17,1],[37,1]]},"16":{"position":[[67,1]]},"18":{"position":[[49,1]]},"94":{"position":[[30,1]]},"436":{"position":[[958,1]]},"507":{"position":[[1807,1]]},"699":{"position":[[10,1]]},"935":{"position":[[145,1]]},"973":{"position":[[21,1]]}}}],["概率",{"_index":1506,"t":{"268":{"position":[[66,2]]},"743":{"position":[[59,2]]},"820":{"position":[[30,2]]}}}],["概览",{"_index":3113,"t":{"787":{"position":[[185,2]]}}}],["模仿",{"_index":1898,"t":{"374":{"position":[[33,2]]},"862":{"position":[[37,2]]}}}],["模块",{"_index":2304,"t":{"487":{"position":[[39,2]]},"720":{"position":[[87,2]]}}}],["模型",{"_index":921,"t":{"125":{"position":[[116,2]]},"559":{"position":[[22,2]]},"880":{"position":[[168,2]]}}}],["模式",{"_index":307,"t":{"34":{"position":[[232,2]]},"112":{"position":[[15,2]]},"184":{"position":[[274,2],[620,2]]},"218":{"position":[[274,2],[620,2]]},"336":{"position":[[97,2]]},"340":{"position":[[190,2]]},"389":{"position":[[33,2],[51,2]]},"503":{"position":[[4,2],[162,2]]},"509":{"position":[[12,2]]},"761":{"position":[[34,2],[79,2],[123,2],[167,2]]},"767":{"position":[[21,2]]},"816":{"position":[[395,2]]},"839":{"position":[[25,2],[98,2]]},"911":{"position":[[25,2]]}}}],["模拟",{"_index":1675,"t":{"334":{"position":[[57,2]]},"336":{"position":[[119,2]]},"338":{"position":[[64,2]]},"340":{"position":[[88,2],[196,2]]},"470":{"position":[[616,2]]},"530":{"position":[[527,2],[1114,2]]},"537":{"position":[[495,2]]},"539":{"position":[[10,2]]},"542":{"position":[[135,2]]}}}],["模拟输出",{"_index":2275,"t":{"470":{"position":[[761,4]]}}}],["模板",{"_index":481,"t":{"53":{"position":[[15,2]]},"57":{"position":[[1068,2]]},"304":{"position":[[14,2],[115,2]]},"347":{"position":[[918,2]]},"874":{"position":[[380,2]]}}}],["横向",{"_index":2623,"t":{"564":{"position":[[18,2]]}}}],["次",{"_index":1178,"t":{"164":{"position":[[127,1]]},"250":{"position":[[127,1]]},"336":{"position":[[25,1]]},"340":{"position":[[866,1],[874,1]]},"434":{"position":[[128,1]]},"442":{"position":[[72,1]]},"523":{"position":[[344,1],[2699,1]]},"668":{"position":[[21,1]]},"689":{"position":[[99,1],[239,1]]},"792":{"position":[[216,1]]},"864":{"position":[[15,1]]},"866":{"position":[[71,1]]}}}],["次数",{"_index":1691,"t":{"338":{"position":[[57,2]]},"340":{"position":[[829,2],[835,2]]},"882":{"position":[[144,2]]}}}],["欢迎",{"_index":1496,"t":{"263":{"position":[[40,2]]}}}],["正",{"_index":620,"t":{"62":{"position":[[22,1]]},"71":{"position":[[22,1]]},"82":{"position":[[22,1]]},"134":{"position":[[38,1]]}}}],["正向",{"_index":1068,"t":{"144":{"position":[[2,2]]}}}],["正在",{"_index":3166,"t":{"822":{"position":[[11,2]]},"830":{"position":[[680,2]]}}}],["正在连接",{"_index":1399,"t":{"223":{"position":[[175,4]]},"225":{"position":[[932,4],[1486,4]]},"617":{"position":[[261,4]]}}}],["正好",{"_index":1783,"t":{"361":{"position":[[1570,2]]}}}],["正如",{"_index":1423,"t":{"231":{"position":[[0,2]]}}}],["正常",{"_index":1673,"t":{"334":{"position":[[12,2]]},"976":{"position":[[0,2]]}}}],["正是",{"_index":1309,"t":{"184":{"position":[[1024,2],[1803,2]]},"218":{"position":[[1024,2],[1803,2]]}}}],["正确",{"_index":621,"t":{"62":{"position":[[24,2]]},"71":{"position":[[24,2]]},"82":{"position":[[24,2]]},"91":{"position":[[483,2]]},"134":{"position":[[40,2]]},"166":{"position":[[132,2],[138,2]]},"252":{"position":[[132,2],[138,2]]},"347":{"position":[[974,2]]},"447":{"position":[[821,2]]},"882":{"position":[[352,2]]},"894":{"position":[[786,2]]}}}],["此处",{"_index":538,"t":{"57":{"position":[[615,2],[1617,2]]},"127":{"position":[[252,2],[528,2]]},"184":{"position":[[957,2],[1736,2]]},"218":{"position":[[957,2],[1736,2]]},"223":{"position":[[983,2]]},"225":{"position":[[218,2],[231,2],[554,2],[701,2],[1319,2],[1873,2]]},"272":{"position":[[1504,2]]},"290":{"position":[[1251,2]]},"301":{"position":[[2558,2]]},"308":{"position":[[2026,2]]},"340":{"position":[[568,2],[728,2],[762,2],[878,2]]},"347":{"position":[[909,2],[1478,2],[1506,2],[2189,2]]},"361":{"position":[[769,2]]},"365":{"position":[[1744,2]]},"393":{"position":[[202,2],[233,2]]},"431":{"position":[[537,2]]},"470":{"position":[[206,2],[222,2],[433,2],[449,2]]},"473":{"position":[[234,2]]},"493":{"position":[[441,2]]},"528":{"position":[[824,2],[1522,2]]},"530":{"position":[[984,2],[1111,2]]},"537":{"position":[[493,2]]},"539":{"position":[[8,2]]},"561":{"position":[[479,2]]},"574":{"position":[[282,2]]},"610":{"position":[[457,2],[557,2]]},"663":{"position":[[64,2]]},"672":{"position":[[1032,2]]},"674":{"position":[[939,2]]},"727":{"position":[[175,2],[923,2]]},"756":{"position":[[78,2]]},"774":{"position":[[308,2]]},"820":{"position":[[248,2]]},"830":{"position":[[86,2]]},"832":{"position":[[298,2],[2058,2]]},"859":{"position":[[1029,2]]},"878":{"position":[[443,2]]},"896":{"position":[[357,2]]},"906":{"position":[[51,2]]}}}],["此外",{"_index":2503,"t":{"530":{"position":[[139,2]]},"693":{"position":[[39,2]]},"836":{"position":[[39,2]]}}}],["此时",{"_index":296,"t":{"34":{"position":[[139,2],[178,2]]},"159":{"position":[[259,2]]},"184":{"position":[[313,2],[343,2]]},"218":{"position":[[313,2],[343,2]]},"220":{"position":[[66,2]]},"235":{"position":[[1181,2]]},"301":{"position":[[425,2]]},"357":{"position":[[43,2],[144,2]]},"447":{"position":[[973,2]]},"514":{"position":[[90,2]]},"628":{"position":[[99,2]]},"736":{"position":[[328,2]]},"806":{"position":[[135,2]]},"830":{"position":[[408,2]]}}}],["此次",{"_index":3201,"t":{"830":{"position":[[572,2]]}}}],["此类",{"_index":506,"t":{"57":{"position":[[77,2]]},"184":{"position":[[1028,2],[1807,2]]},"218":{"position":[[1028,2],[1807,2]]},"272":{"position":[[73,2]]},"301":{"position":[[53,2]]},"308":{"position":[[74,2]]},"347":{"position":[[74,2]]}}}],["步骤",{"_index":360,"t":{"42":{"position":[[14,2]]},"44":{"position":[[9,2]]},"57":{"position":[[21,2],[144,2],[230,2]]},"134":{"position":[[62,2]]},"194":{"position":[[45,2]]},"225":{"position":[[411,2]]},"233":{"position":[[45,2]]},"235":{"position":[[242,2]]},"272":{"position":[[21,2],[136,2],[222,2]]},"286":{"position":[[52,2]]},"301":{"position":[[11,2],[106,2],[192,2]]},"308":{"position":[[21,2],[138,2],[224,2]]},"347":{"position":[[21,2],[140,2],[226,2]]},"406":{"position":[[21,2]]},"422":{"position":[[21,2]]},"444":{"position":[[121,2]]},"641":{"position":[[0,2]]},"643":{"position":[[0,2]]},"745":{"position":[[21,2]]},"750":{"position":[[193,2],[470,2]]},"969":{"position":[[211,2]]},"980":{"position":[[0,2]]}}}],["殇",{"_index":1865,"t":{"370":{"position":[[235,1]]}}}],["殊途同归",{"_index":2083,"t":{"440":{"position":[[78,4]]}}}],["段",{"_index":540,"t":{"57":{"position":[[621,1]]},"376":{"position":[[25,1]]}}}],["每个",{"_index":480,"t":{"50":{"position":[[298,2]]},"127":{"position":[[705,2]]},"146":{"position":[[83,2]]},"237":{"position":[[6,2]]},"507":{"position":[[473,2],[654,2]]},"526":{"position":[[176,2]]},"570":{"position":[[96,2]]},"572":{"position":[[26,2]]},"613":{"position":[[0,2]]},"648":{"position":[[1189,2]]},"780":{"position":[[11,2]]},"790":{"position":[[25,2]]},"826":{"position":[[54,2]]},"828":{"position":[[5,2]]}}}],["每年",{"_index":3267,"t":{"866":{"position":[[157,2]]}}}],["每当",{"_index":2607,"t":{"559":{"position":[[65,2]]}}}],["每次",{"_index":472,"t":{"50":{"position":[[248,2]]},"359":{"position":[[140,2]]},"361":{"position":[[792,2]]},"365":{"position":[[1767,2]]},"411":{"position":[[61,2]]},"413":{"position":[[61,2]]},"418":{"position":[[32,2]]},"447":{"position":[[833,2]]},"554":{"position":[[92,2]]},"814":{"position":[[10,2]]}}}],["每种",{"_index":1448,"t":{"246":{"position":[[23,2]]}}}],["每秒",{"_index":1386,"t":{"212":{"position":[[38,2]]},"528":{"position":[[835,2],[1533,2]]},"539":{"position":[[253,2]]},"597":{"position":[[157,2]]},"832":{"position":[[2074,2]]}}}],["每秒钟",{"_index":3202,"t":{"830":{"position":[[583,3]]}}}],["比如",{"_index":73,"t":{"7":{"position":[[132,2]]},"451":{"position":[[76,2]]},"774":{"position":[[36,2]]}}}],["比较",{"_index":333,"t":{"38":{"position":[[22,2]]},"110":{"position":[[115,2]]},"357":{"position":[[83,2],[96,2],[191,2]]},"361":{"position":[[1079,2]]},"420":{"position":[[30,2]]},"526":{"position":[[206,2]]},"679":{"position":[[138,2]]},"741":{"position":[[116,2]]},"806":{"position":[[15,2],[72,2]]}}}],["比较复杂",{"_index":1777,"t":{"361":{"position":[[1163,4]]}}}],["比较简单",{"_index":586,"t":{"60":{"position":[[28,4]]},"69":{"position":[[28,4]]},"80":{"position":[[58,4]]},"132":{"position":[[36,4]]},"357":{"position":[[204,4]]},"361":{"position":[[539,4]]},"530":{"position":[[1009,4]]}}}],["毫无",{"_index":2129,"t":{"444":{"position":[[429,2]]}}}],["毫秒",{"_index":2649,"t":{"581":{"position":[[132,2]]},"659":{"position":[[34,2]]},"820":{"position":[[18,2]]}}}],["永久",{"_index":43,"t":{"7":{"position":[[0,2],[11,2]]},"961":{"position":[[45,2],[48,2],[51,2]]},"967":{"position":[[12,2],[47,2]]}}}],["永远",{"_index":477,"t":{"50":{"position":[[281,2]]},"420":{"position":[[15,2]]},"595":{"position":[[94,2]]}}}],["汝",{"_index":15,"t":{"5":{"position":[[16,1],[36,1]]},"16":{"position":[[66,1]]},"18":{"position":[[48,1]]},"94":{"position":[[29,1]]},"436":{"position":[[957,1]]},"507":{"position":[[1806,1]]},"699":{"position":[[9,1]]},"935":{"position":[[144,1]]},"973":{"position":[[20,1]]}}}],["江",{"_index":2414,"t":{"521":{"position":[[51,1]]}}}],["池",{"_index":313,"t":{"34":{"position":[[282,1]]},"149":{"position":[[2,1]]},"151":{"position":[[2,1]]},"180":{"position":[[17,1]]},"184":{"position":[[281,1],[1130,1],[1909,1]]},"201":{"position":[[13,1]]},"212":{"position":[[17,1]]},"218":{"position":[[281,1],[1130,1],[1909,1]]},"361":{"position":[[760,1],[787,1]]},"365":{"position":[[335,1],[594,1],[853,1],[1114,1],[1735,1],[1762,1]]},"911":{"position":[[13,1]]}}}],["没",{"_index":1240,"t":{"184":{"position":[[137,1]]},"218":{"position":[[137,1]]},"347":{"position":[[1540,1]]},"449":{"position":[[259,1]]},"465":{"position":[[21,1]]},"859":{"position":[[1166,1]]},"874":{"position":[[333,1]]}}}],["没什么",{"_index":2104,"t":{"444":{"position":[[14,3]]}}}],["没有",{"_index":59,"t":{"7":{"position":[[61,2],[122,2]]},"46":{"position":[[451,2]]},"50":{"position":[[33,2]]},"57":{"position":[[457,2]]},"120":{"position":[[475,2]]},"220":{"position":[[87,2]]},"272":{"position":[[1079,2]]},"340":{"position":[[791,2]]},"361":{"position":[[1489,2]]},"389":{"position":[[56,2]]},"415":{"position":[[5,2],[22,2]]},"444":{"position":[[369,2]]},"455":{"position":[[971,2],[977,2]]},"487":{"position":[[88,2]]},"503":{"position":[[63,2]]},"528":{"position":[[667,2],[1381,2]]},"548":{"position":[[17,2]]},"617":{"position":[[15,2]]},"623":{"position":[[102,2]]},"666":{"position":[[7,2]]},"720":{"position":[[37,2]]},"741":{"position":[[83,2]]},"778":{"position":[[132,2]]},"783":{"position":[[159,2]]},"787":{"position":[[87,2]]},"822":{"position":[[59,2]]},"872":{"position":[[733,2]]}}}],["泄露",{"_index":1102,"t":{"153":{"position":[[105,2]]},"444":{"position":[[305,2],[678,2]]}}}],["泛",{"_index":204,"t":{"25":{"position":[[370,1]]},"34":{"position":[[57,1],[77,1]]},"57":{"position":[[153,1],[1548,1]]},"132":{"position":[[350,1]]},"225":{"position":[[2,1],[42,1],[427,1]]},"229":{"position":[[15,1]]},"272":{"position":[[145,1],[1439,1]]},"301":{"position":[[115,1],[2503,1]]},"308":{"position":[[147,1],[1960,1]]},"347":{"position":[[149,1],[2121,1]]},"544":{"position":[[142,1]]},"574":{"position":[[285,1]]},"872":{"position":[[177,1],[1095,1]]},"882":{"position":[[285,1]]}}}],["注入",{"_index":1406,"t":{"223":{"position":[[921,2]]},"225":{"position":[[1257,2],[1811,2]]},"229":{"position":[[513,2]]},"235":{"position":[[72,2],[234,2],[248,2],[867,2]]},"376":{"position":[[97,2]]},"378":{"position":[[23,2]]},"542":{"position":[[4,2],[53,2],[105,2],[143,2]]},"544":{"position":[[14,2],[77,2],[116,2],[126,2],[136,2],[144,2],[156,2]]},"546":{"position":[[27,2],[53,2],[61,2],[110,2]]},"550":{"position":[[52,2]]},"552":{"position":[[28,2],[1409,2]]},"554":{"position":[[6,2],[54,2],[58,2],[89,2],[117,2]]},"859":{"position":[[967,2]]},"874":{"position":[[205,2]]},"882":{"position":[[171,2],[194,2]]},"884":{"position":[[239,2],[309,2]]},"891":{"position":[[29,2],[294,2]]},"969":{"position":[[203,2],[377,2],[407,2]]}}}],["注册",{"_index":165,"t":{"23":{"position":[[13,2]]},"25":{"position":[[206,2]]},"127":{"position":[[245,2],[521,2]]},"129":{"position":[[250,2]]},"235":{"position":[[1257,2]]},"286":{"position":[[86,2]]},"447":{"position":[[59,2],[516,2],[882,2],[1278,2]]},"451":{"position":[[3,2]]},"544":{"position":[[99,2]]},"548":{"position":[[19,2]]},"876":{"position":[[189,2]]},"878":{"position":[[68,2]]},"891":{"position":[[102,2]]},"896":{"position":[[212,2],[280,2]]},"932":{"position":[[30,2],[218,2]]}}}],["注册表",{"_index":2660,"t":{"586":{"position":[[57,3]]}}}],["注意",{"_index":394,"t":{"46":{"position":[[333,2]]},"57":{"position":[[721,2]]},"110":{"position":[[31,2]]},"146":{"position":[[68,2]]},"153":{"position":[[70,2]]},"184":{"position":[[668,2],[1426,2],[1507,2]]},"196":{"position":[[43,2]]},"207":{"position":[[341,2]]},"218":{"position":[[668,2],[1426,2],[1507,2]]},"223":{"position":[[924,2]]},"225":{"position":[[1260,2],[1814,2]]},"229":{"position":[[516,2]]},"239":{"position":[[105,2]]},"297":{"position":[[285,2]]},"319":{"position":[[677,2]]},"378":{"position":[[105,2]]},"406":{"position":[[525,2]]},"413":{"position":[[94,2]]},"422":{"position":[[94,2],[509,2]]},"473":{"position":[[253,2]]},"595":{"position":[[122,2]]},"597":{"position":[[166,2]]},"655":{"position":[[311,2]]},"668":{"position":[[80,2]]},"745":{"position":[[94,2],[580,2]]},"780":{"position":[[361,2],[511,2]]},"809":{"position":[[36,2]]},"816":{"position":[[391,2]]},"836":{"position":[[55,2]]},"851":{"position":[[331,2]]},"859":{"position":[[970,2]]},"980":{"position":[[62,2]]}}}],["注意事项",{"_index":3251,"t":{"859":{"position":[[1114,4]]}}}],["注明",{"_index":2867,"t":{"699":{"position":[[21,2]]}}}],["注释",{"_index":953,"t":{"127":{"position":[[218,2],[494,2]]},"455":{"position":[[747,2]]},"512":{"position":[[94,2]]},"648":{"position":[[1198,2]]},"894":{"position":[[93,2]]},"928":{"position":[[103,2]]}}}],["注销",{"_index":1381,"t":{"210":{"position":[[44,2]]}}}],["活",{"_index":2676,"t":{"595":{"position":[[239,1]]},"597":{"position":[[262,1]]},"752":{"position":[[50,1]]}}}],["活动",{"_index":87,"t":{"10":{"position":[[12,2]]},"12":{"position":[[12,2]]},"14":{"position":[[12,2]]}}}],["派生",{"_index":421,"t":{"46":{"position":[[499,2]]},"57":{"position":[[1505,2]]},"237":{"position":[[26,2]]},"272":{"position":[[1396,2]]},"301":{"position":[[2460,2]]},"308":{"position":[[1917,2]]},"347":{"position":[[2078,2]]}}}],["派生类",{"_index":803,"t":{"116":{"position":[[36,3]]},"140":{"position":[[39,3]]},"216":{"position":[[32,3]]},"641":{"position":[[75,3]]}}}],["流",{"_index":1200,"t":{"166":{"position":[[312,1],[478,1],[524,1],[555,1]]},"184":{"position":[[657,1]]},"218":{"position":[[657,1]]},"252":{"position":[[312,1],[478,1],[524,1],[555,1]]},"507":{"position":[[2129,1]]},"628":{"position":[[11,1]]},"630":{"position":[[88,1],[255,1],[278,1]]},"672":{"position":[[56,1],[195,1]]},"674":{"position":[[167,1]]},"727":{"position":[[254,1],[860,1],[1035,1],[1323,1]]},"743":{"position":[[50,1]]},"748":{"position":[[127,1]]},"798":{"position":[[23,1]]},"830":{"position":[[544,1]]},"878":{"position":[[173,1]]},"950":{"position":[[13,1]]}}}],["流水",{"_index":1857,"t":{"370":{"position":[[206,2]]}}}],["流程",{"_index":1631,"t":{"304":{"position":[[24,2]]},"830":{"position":[[66,2]]}}}],["流量",{"_index":1390,"t":{"212":{"position":[[59,2]]},"526":{"position":[[165,2]]},"729":{"position":[[18,2]]}}}],["测",{"_index":1690,"t":{"338":{"position":[[44,1]]}}}],["测试",{"_index":139,"t":{"18":{"position":[[8,2],[11,2]]},"20":{"position":[[39,2]]},"288":{"position":[[85,2]]},"334":{"position":[[3,2],[6,2],[25,2]]},"340":{"position":[[67,2],[777,2],[827,2],[896,2],[995,2],[1049,2]]},"434":{"position":[[1,2],[118,2]]},"436":{"position":[[1,2]]},"521":{"position":[[113,2]]},"542":{"position":[[137,2]]},"650":{"position":[[16,2]]},"663":{"position":[[163,2]]},"672":{"position":[[30,2],[169,2]]},"674":{"position":[[30,2],[141,2]]},"734":{"position":[[821,2]]},"736":{"position":[[591,2],[632,2],[667,2]]},"811":{"position":[[24,2]]},"896":{"position":[[434,2]]},"971":{"position":[[5,2],[30,2]]}}}],["测试表明",{"_index":2391,"t":{"509":{"position":[[2,4]]}}}],["测量",{"_index":2691,"t":{"602":{"position":[[16,2]]}}}],["浏览",{"_index":2939,"t":{"714":{"position":[[25,2]]}}}],["浏览器",{"_index":636,"t":{"69":{"position":[[33,3]]},"909":{"position":[[170,3]]}}}],["浪费",{"_index":1242,"t":{"184":{"position":[[143,2]]},"218":{"position":[[143,2]]}}}],["消息",{"_index":1501,"t":{"268":{"position":[[15,2]]},"292":{"position":[[124,2]]},"321":{"position":[[41,2]]},"630":{"position":[[115,2]]},"663":{"position":[[48,2]]},"748":{"position":[[279,2]]},"774":{"position":[[280,2],[304,2]]},"778":{"position":[[62,2]]},"857":{"position":[[578,2]]},"859":{"position":[[467,2]]},"917":{"position":[[36,2]]},"925":{"position":[[66,2]]}}}],["消耗",{"_index":316,"t":{"34":{"position":[[292,2]]},"184":{"position":[[954,2],[1733,2]]},"218":{"position":[[954,2],[1733,2]]},"365":{"position":[[1332,2]]}}}],["涉及",{"_index":1412,"t":{"225":{"position":[[396,2]]},"378":{"position":[[71,2]]},"906":{"position":[[55,2]]}}}],["涵盖",{"_index":3089,"t":{"783":{"position":[[219,2]]}}}],["淘宝",{"_index":733,"t":{"94":{"position":[[51,2]]},"973":{"position":[[52,2]]}}}],["深度",{"_index":2196,"t":{"451":{"position":[[71,2]]}}}],["混淆",{"_index":2301,"t":{"487":{"position":[[21,2]]}}}],["添加",{"_index":824,"t":{"120":{"position":[[335,2],[466,2],[477,2]]},"134":{"position":[[81,2],[3672,2]]},"194":{"position":[[78,2]]},"223":{"position":[[912,2],[987,2]]},"225":{"position":[[1248,2],[1323,2],[1802,2],[1877,2]]},"229":{"position":[[504,2]]},"233":{"position":[[78,2]]},"261":{"position":[[82,2],[231,2],[326,2]]},"284":{"position":[[43,2],[363,2]]},"286":{"position":[[99,2]]},"290":{"position":[[8,2]]},"340":{"position":[[754,2]]},"431":{"position":[[851,2],[957,2]]},"447":{"position":[[193,2],[748,2],[768,2],[795,2],[806,2],[823,2],[888,2]]},"451":{"position":[[47,2]]},"458":{"position":[[309,2]]},"514":{"position":[[63,2]]},"516":{"position":[[22,2]]},"750":{"position":[[208,2]]},"859":{"position":[[958,2],[1033,2]]},"878":{"position":[[266,2]]},"891":{"position":[[197,2]]},"896":{"position":[[343,2]]},"925":{"position":[[493,2],[540,2]]},"932":{"position":[[0,2],[6,2],[17,2],[116,2]]}}}],["清理",{"_index":3294,"t":{"872":{"position":[[700,2],[1119,2]]}}}],["清空",{"_index":445,"t":{"50":{"position":[[42,2]]}}}],["清除",{"_index":1607,"t":{"301":{"position":[[365,2]]}}}],["游戏",{"_index":3127,"t":{"806":{"position":[[96,2]]},"824":{"position":[[52,2]]}}}],["游标",{"_index":1119,"t":{"157":{"position":[[300,2]]},"301":{"position":[[1212,2],[1566,2]]},"347":{"position":[[967,2],[1429,2],[1603,2]]}}}],["游标位置",{"_index":1623,"t":{"301":{"position":[[1195,4]]}}}],["游鱼",{"_index":1858,"t":{"370":{"position":[[208,2]]}}}],["源",{"_index":107,"t":{"12":{"position":[[68,1]]},"290":{"position":[[718,1]]}}}],["源代码",{"_index":26,"t":{"5":{"position":[[45,3]]},"12":{"position":[[138,3]]},"18":{"position":[[71,3]]},"444":{"position":[[465,3],[572,3]]},"447":{"position":[[993,3]]},"455":{"position":[[477,3],[564,3],[935,3],[1073,3]]},"503":{"position":[[90,3]]},"509":{"position":[[17,3]]},"872":{"position":[[565,3],[993,3]]},"961":{"position":[[166,3]]}}}],["源文件",{"_index":2103,"t":{"444":{"position":[[0,3],[39,3]]}}}],["源码",{"_index":2143,"t":{"444":{"position":[[629,2]]},"447":{"position":[[1304,2]]},"961":{"position":[[123,2],[163,2]]}}}],["溢出",{"_index":2256,"t":{"465":{"position":[[386,2]]}}}],["滞后",{"_index":1154,"t":{"159":{"position":[[294,2]]}}}],["满",{"_index":2452,"t":{"526":{"position":[[126,1]]}}}],["满足",{"_index":1609,"t":{"301":{"position":[[381,2],[586,2]]},"574":{"position":[[58,2]]},"595":{"position":[[132,2]]},"597":{"position":[[192,2]]}}}],["满足要求",{"_index":2444,"t":{"523":{"position":[[2726,4]]}}}],["演示",{"_index":193,"t":{"25":{"position":[[212,2]]},"120":{"position":[[44,2]]},"225":{"position":[[35,2]]},"431":{"position":[[556,2]]},"552":{"position":[[38,2]]},"554":{"position":[[175,2]]},"822":{"position":[[0,2]]},"828":{"position":[[112,2]]}}}],["潮",{"_index":1850,"t":{"370":{"position":[[162,1]]}}}],["澜",{"_index":1864,"t":{"370":{"position":[[234,1]]}}}],["激活",{"_index":1380,"t":{"210":{"position":[[38,2]]},"961":{"position":[[103,2],[110,2],[115,2],[120,2]]}}}],["灵活",{"_index":286,"t":{"34":{"position":[[86,2]]},"225":{"position":[[1922,2]]},"286":{"position":[[14,2]]},"440":{"position":[[149,2],[179,2]]}}}],["灵活性",{"_index":2099,"t":{"440":{"position":[[315,3]]}}}],["点",{"_index":1647,"t":{"308":{"position":[[2404,1]]},"826":{"position":[[83,1],[90,1],[176,1]]},"828":{"position":[[48,1],[186,1],[216,1],[265,1]]},"830":{"position":[[83,1],[151,1],[354,1],[374,1],[415,1],[474,1]]},"906":{"position":[[134,1]]}}}],["点击",{"_index":2937,"t":{"714":{"position":[[6,2],[22,2],[62,2]]},"973":{"position":[[50,2]]}}}],["点函数",{"_index":3194,"t":{"830":{"position":[[175,3]]}}}],["烈日",{"_index":1866,"t":{"370":{"position":[[245,2]]}}}],["然后",{"_index":178,"t":{"25":{"position":[[20,2]]},"32":{"position":[[46,2]]},"48":{"position":[[29,2]]},"50":{"position":[[51,2]]},"57":{"position":[[239,2],[318,2],[361,2],[1014,2]]},"118":{"position":[[9,2]]},"127":{"position":[[724,2]]},"142":{"position":[[214,2]]},"146":{"position":[[29,2]]},"157":{"position":[[313,2]]},"159":{"position":[[297,2],[615,2]]},"166":{"position":[[9,2]]},"205":{"position":[[9,2]]},"220":{"position":[[94,2]]},"235":{"position":[[1162,2]]},"239":{"position":[[171,2],[229,2]]},"252":{"position":[[9,2]]},"272":{"position":[[231,2],[302,2],[732,2]]},"284":{"position":[[71,2]]},"290":{"position":[[53,2],[70,2],[757,2]]},"292":{"position":[[430,2]]},"301":{"position":[[201,2],[530,2]]},"308":{"position":[[233,2],[306,2],[346,2],[1375,2],[2482,2]]},"321":{"position":[[125,2]]},"336":{"position":[[54,2],[66,2],[71,2],[175,2],[191,2],[200,2]]},"340":{"position":[[151,2],[163,2],[168,2],[248,2],[262,2],[271,2],[609,2]]},"347":{"position":[[235,2],[310,2],[352,2],[1422,2],[1475,2]]},"359":{"position":[[8,2]]},"361":{"position":[[30,2],[1776,2],[1782,2],[1982,2]]},"365":{"position":[[1420,2]]},"415":{"position":[[156,2]]},"440":{"position":[[96,2]]},"444":{"position":[[566,2]]},"447":{"position":[[180,2],[727,2],[776,2],[924,2],[1004,2],[1246,2]]},"453":{"position":[[22,2]]},"455":{"position":[[69,2],[376,2]]},"465":{"position":[[359,2]]},"473":{"position":[[9,2]]},"477":{"position":[[31,2]]},"485":{"position":[[255,2]]},"507":{"position":[[468,2],[649,2]]},"512":{"position":[[41,2]]},"535":{"position":[[43,2]]},"542":{"position":[[77,2]]},"554":{"position":[[264,2]]},"559":{"position":[[95,2]]},"574":{"position":[[244,2]]},"617":{"position":[[141,2]]},"626":{"position":[[19,2]]},"630":{"position":[[244,2]]},"670":{"position":[[32,2]]},"686":{"position":[[134,2]]},"714":{"position":[[29,2],[49,2]]},"716":{"position":[[12,2]]},"718":{"position":[[16,2],[121,2],[186,2]]},"774":{"position":[[23,2]]},"778":{"position":[[151,2],[158,2]]},"798":{"position":[[32,2]]},"818":{"position":[[25,2],[32,2]]},"830":{"position":[[121,2],[131,2]]},"832":{"position":[[331,2],[339,2]]},"854":{"position":[[25,2],[50,2]]},"857":{"position":[[449,2]]},"859":{"position":[[343,2]]},"878":{"position":[[264,2]]},"891":{"position":[[107,2],[195,2],[225,2]]},"894":{"position":[[41,2]]},"928":{"position":[[51,2]]},"932":{"position":[[28,2]]},"935":{"position":[[78,2]]},"969":{"position":[[113,2]]}}}],["熟悉",{"_index":1085,"t":{"149":{"position":[[60,2]]},"554":{"position":[[154,2]]},"661":{"position":[[72,2]]}}}],["熟识",{"_index":642,"t":{"69":{"position":[[129,2]]}}}],["父",{"_index":1580,"t":{"290":{"position":[[1254,1]]}}}],["版",{"_index":133,"t":{"16":{"position":[[32,1]]},"389":{"position":[[13,1]]},"444":{"position":[[286,1]]},"539":{"position":[[166,1]]},"597":{"position":[[2,1]]},"806":{"position":[[181,1],[224,1],[275,1],[366,1],[396,1],[473,1]]},"866":{"position":[[18,1],[105,1],[139,1]]},"882":{"position":[[156,1],[178,1],[201,1]]},"884":{"position":[[143,1],[157,1]]},"938":{"position":[[10,1],[21,1]]},"940":{"position":[[10,1]]},"944":{"position":[[8,1]]},"950":{"position":[[9,1],[19,1],[38,1],[55,1],[70,1]]},"954":{"position":[[22,1]]},"965":{"position":[[162,1],[187,1],[210,1]]},"971":{"position":[[43,1],[96,1]]}}}],["版本",{"_index":1166,"t":{"162":{"position":[[24,2]]},"292":{"position":[[86,2]]},"391":{"position":[[49,2]]},"444":{"position":[[272,2]]},"705":{"position":[[44,2]]},"707":{"position":[[104,2]]},"716":{"position":[[132,2]]},"718":{"position":[[190,2]]},"806":{"position":[[164,2],[399,2],[419,2]]},"866":{"position":[[165,2]]},"882":{"position":[[392,2]]},"886":{"position":[[23,2]]},"935":{"position":[[30,2]]}}}],["版本升级",{"_index":3272,"t":{"870":{"position":[[21,4]]},"872":{"position":[[20,4],[44,4]]}}}],["版本号",{"_index":3262,"t":{"866":{"position":[[60,3],[67,3],[72,3],[78,3],[109,3],[143,3]]}}}],["版权",{"_index":22,"t":{"5":{"position":[[30,2]]},"16":{"position":[[60,2]]},"699":{"position":[[5,2]]},"906":{"position":[[59,2]]}}}],["版税",{"_index":61,"t":{"7":{"position":[[74,2]]}}}],["物",{"_index":1663,"t":{"319":{"position":[[27,1]]},"326":{"position":[[2,1]]}}}],["特定",{"_index":426,"t":{"48":{"position":[[35,2]]},"142":{"position":[[291,2]]},"155":{"position":[[25,2]]},"223":{"position":[[543,2]]},"485":{"position":[[20,2]]},"670":{"position":[[21,2]]}}}],["特征",{"_index":1901,"t":{"376":{"position":[[99,2]]}}}],["特性",{"_index":2046,"t":{"431":{"position":[[849,2]]},"646":{"position":[[34,2]]},"806":{"position":[[175,2]]}}}],["特殊",{"_index":236,"t":{"28":{"position":[[85,2]]},"284":{"position":[[15,2]]},"574":{"position":[[75,2]]}}}],["特殊字符",{"_index":3015,"t":{"741":{"position":[[14,4]]}}}],["特点",{"_index":970,"t":{"127":{"position":[[700,2]]},"679":{"position":[[64,2],[74,2],[111,2]]},"806":{"position":[[422,2]]}}}],["状态",{"_index":851,"t":{"120":{"position":[[1018,2],[2179,2]]},"340":{"position":[[1000,2]]},"409":{"position":[[17,2]]},"463":{"position":[[232,2]]},"526":{"position":[[329,2]]},"528":{"position":[[660,2],[1374,2]]},"639":{"position":[[7,2]]},"648":{"position":[[724,2]]},"653":{"position":[[11,2],[16,2],[125,2],[188,2]]},"672":{"position":[[1091,2]]},"674":{"position":[[996,2]]},"702":{"position":[[968,2]]},"727":{"position":[[803,2],[941,2],[1080,2]]},"787":{"position":[[128,2]]},"830":{"position":[[184,2],[268,2],[645,2],[649,2]]},"832":{"position":[[827,2],[922,2],[1773,2]]},"868":{"position":[[219,2]]},"878":{"position":[[676,2],[776,2]]},"882":{"position":[[349,2]]}}}],["狗",{"_index":1853,"t":{"370":{"position":[[185,1]]}}}],["独占",{"_index":1979,"t":{"409":{"position":[[15,2]]}}}],["独立",{"_index":3122,"t":{"800":{"position":[[2,2]]},"876":{"position":[[215,2]]},"882":{"position":[[360,2]]},"961":{"position":[[5,2]]}}}],["狮子",{"_index":1875,"t":{"370":{"position":[[300,2]]}}}],["猝死",{"_index":2096,"t":{"440":{"position":[[290,2]]}}}],["王二麻子",{"_index":887,"t":{"120":{"position":[[1704,4]]}}}],["玫瑰",{"_index":3431,"t":{"961":{"position":[[239,2],[246,2],[253,2]]}}}],["环境",{"_index":1676,"t":{"334":{"position":[[63,2]]},"336":{"position":[[126,2]]},"340":{"position":[[9,2],[203,2]]},"535":{"position":[[8,2]]},"689":{"position":[[122,2]]},"872":{"position":[[414,2],[581,2],[1009,2]]},"906":{"position":[[121,2]]}}}],["环节",{"_index":2797,"t":{"666":{"position":[[145,2]]},"677":{"position":[[31,2]]}}}],["现",{"_index":2720,"t":{"615":{"position":[[123,1]]}}}],["现在",{"_index":458,"t":{"50":{"position":[[128,2]]},"455":{"position":[[465,2]]}}}],["现成",{"_index":2303,"t":{"487":{"position":[[37,2]]}}}],["现有",{"_index":1723,"t":{"347":{"position":[[1005,2]]},"447":{"position":[[772,2]]},"778":{"position":[[10,2]]},"961":{"position":[[79,2]]},"967":{"position":[[64,2]]}}}],["理念",{"_index":1356,"t":{"194":{"position":[[16,2]]},"233":{"position":[[16,2]]}}}],["理解",{"_index":232,"t":{"28":{"position":[[72,2]]}}}],["理论",{"_index":497,"t":{"55":{"position":[[48,2]]},"505":{"position":[[40,2]]}}}],["琼",{"_index":1837,"t":{"370":{"position":[[57,1]]}}}],["瓶颈",{"_index":2347,"t":{"503":{"position":[[26,2]]}}}],["甚微",{"_index":1815,"t":{"365":{"position":[[1364,2]]}}}],["甚至",{"_index":1236,"t":{"184":{"position":[[105,2]]},"218":{"position":[[105,2]]},"523":{"position":[[366,2]]},"906":{"position":[[114,2]]}}}],["生产",{"_index":2512,"t":{"535":{"position":[[6,2]]}}}],["生命",{"_index":943,"t":{"127":{"position":[[66,2],[691,2]]}}}],["生命周期",{"_index":1444,"t":{"239":{"position":[[123,4]]},"544":{"position":[[62,4]]},"554":{"position":[[0,4],[36,4]]},"880":{"position":[[147,4],[180,4]]}}}],["生成",{"_index":629,"t":{"66":{"position":[[44,2]]},"75":{"position":[[44,2]]},"86":{"position":[[89,2],[335,2]]},"127":{"position":[[209,2],[485,2]]},"134":{"position":[[66,2],[74,2],[102,2],[113,2]]},"376":{"position":[[175,2]]},"440":{"position":[[173,2],[196,2],[267,2]]},"444":{"position":[[462,2]]},"447":{"position":[[45,2],[225,2],[783,2],[1209,2],[1295,2],[1334,2]]},"455":{"position":[[16,2],[480,2],[560,2],[745,2],[905,2],[938,2],[947,2],[1049,2],[1076,2]]},"477":{"position":[[36,2]]},"503":{"position":[[93,2]]},"509":{"position":[[20,2]]},"512":{"position":[[92,2]]},"608":{"position":[[6,2]]},"820":{"position":[[8,2]]},"894":{"position":[[91,2]]},"928":{"position":[[101,2]]}}}],["生效",{"_index":357,"t":{"40":{"position":[[315,2]]},"184":{"position":[[1470,2],[1523,2]]},"218":{"position":[[1470,2],[1523,2]]},"544":{"position":[[27,2]]},"570":{"position":[[147,2]]},"595":{"position":[[198,2],[230,2],[244,2]]},"597":{"position":[[253,2],[267,2]]},"870":{"position":[[182,2]]}}}],["用于",{"_index":737,"t":{"97":{"position":[[22,2]]},"268":{"position":[[8,2],[54,2],[81,2]]},"297":{"position":[[67,2]]},"449":{"position":[[221,2]]},"458":{"position":[[30,2]]},"630":{"position":[[108,2]]},"705":{"position":[[36,2]]},"727":{"position":[[353,2]]},"732":{"position":[[29,2]]},"830":{"position":[[256,2],[757,2]]},"832":{"position":[[1761,2]]},"868":{"position":[[207,2]]},"896":{"position":[[432,2]]},"925":{"position":[[28,2]]},"961":{"position":[[183,2]]}}}],["用作",{"_index":85,"t":{"10":{"position":[[6,2]]},"12":{"position":[[6,2]]},"14":{"position":[[6,2]]}}}],["用户",{"_index":125,"t":{"14":{"position":[[57,2]]},"25":{"position":[[239,2]]},"57":{"position":[[348,2],[706,2]]},"159":{"position":[[89,2]]},"166":{"position":[[154,2],[482,2],[530,2]]},"184":{"position":[[639,2]]},"218":{"position":[[639,2]]},"225":{"position":[[561,2]]},"252":{"position":[[154,2],[482,2],[530,2]]},"263":{"position":[[5,2]]},"295":{"position":[[9,2]]},"304":{"position":[[1,2]]},"308":{"position":[[333,2]]},"347":{"position":[[339,2]]},"357":{"position":[[130,2]]},"444":{"position":[[438,2]]},"473":{"position":[[32,2]]},"559":{"position":[[97,2]]},"572":{"position":[[0,2]]},"666":{"position":[[64,2],[90,2]]},"745":{"position":[[535,2]]}}}],["用法",{"_index":1048,"t":{"140":{"position":[[161,2],[228,2]]}}}],["由于",{"_index":1443,"t":{"239":{"position":[[108,2]]},"415":{"position":[[14,2]]},"707":{"position":[[0,2]]},"814":{"position":[[3,2]]},"874":{"position":[[105,2]]}}}],["由此",{"_index":806,"t":{"116":{"position":[[66,2]]},"216":{"position":[[64,2]]},"248":{"position":[[133,2]]}}}],["申请",{"_index":1276,"t":{"184":{"position":[[636,2]]},"218":{"position":[[636,2]]},"301":{"position":[[894,2]]},"361":{"position":[[761,2],[794,2]]},"365":{"position":[[1736,2],[1769,2]]}}}],["申请专利",{"_index":91,"t":{"10":{"position":[[29,4]]},"12":{"position":[[29,4]]},"14":{"position":[[29,4]]}}}],["电力",{"_index":1637,"t":{"306":{"position":[[25,2]]}}}],["电脑",{"_index":2148,"t":{"447":{"position":[[32,2]]}}}],["界面",{"_index":127,"t":{"14":{"position":[[61,2]]},"588":{"position":[[2,2],[12,2]]},"590":{"position":[[26,2]]},"906":{"position":[[44,2],[138,2]]}}}],["留空",{"_index":645,"t":{"69":{"position":[[200,2]]}}}],["疑惑",{"_index":3094,"t":{"783":{"position":[[348,2]]}}}],["疑问",{"_index":2230,"t":{"455":{"position":[[932,2]]}}}],["登录",{"_index":950,"t":{"127":{"position":[[196,2],[472,2]]},"134":{"position":[[258,2],[594,2],[1096,2],[1779,2],[2288,2],[2975,2]]},"385":{"position":[[35,2],[38,2],[43,2]]},"455":{"position":[[732,2]]},"641":{"position":[[155,2]]},"643":{"position":[[113,2]]}}}],["白",{"_index":1894,"t":{"370":{"position":[[475,1]]}}}],["白名单",{"_index":2995,"t":{"729":{"position":[[66,3]]}}}],["的话",{"_index":403,"t":{"46":{"position":[[382,2],[460,2]]},"120":{"position":[[479,2]]},"151":{"position":[[114,2]]},"225":{"position":[[403,2]]},"284":{"position":[[6,2]]},"340":{"position":[[795,2]]},"442":{"position":[[133,2]]},"444":{"position":[[180,2],[244,2]]},"447":{"position":[[25,2]]},"595":{"position":[[193,2],[223,2]]},"597":{"position":[[246,2]]},"628":{"position":[[39,2]]},"655":{"position":[[345,2]]},"756":{"position":[[33,2]]},"878":{"position":[[320,2]]}}}],["盈利",{"_index":3424,"t":{"961":{"position":[[185,2]]},"963":{"position":[[48,2]]}}}],["监听",{"_index":796,"t":{"112":{"position":[[21,2],[29,2]]},"184":{"position":[[461,2],[1215,2],[1223,2],[1568,2]]},"207":{"position":[[347,2]]},"212":{"position":[[76,2],[84,2]]},"218":{"position":[[461,2],[1215,2],[1223,2],[1568,2]]},"223":{"position":[[840,2]]},"225":{"position":[[1176,2],[1730,2]]},"229":{"position":[[432,2]]},"495":{"position":[[421,2]]},"561":{"position":[[637,2]]},"736":{"position":[[170,2]]},"859":{"position":[[886,2]]},"911":{"position":[[49,2],[57,2]]}}}],["监测",{"_index":2658,"t":{"586":{"position":[[31,2]]},"702":{"position":[[970,2]]}}}],["目前",{"_index":1955,"t":{"395":{"position":[[29,2]]},"465":{"position":[[3,2]]},"498":{"position":[[89,2]]},"503":{"position":[[74,2]]},"862":{"position":[[78,2]]},"874":{"position":[[303,2]]},"957":{"position":[[38,2]]}}}],["目录",{"_index":2285,"t":{"477":{"position":[[17,2],[28,2]]},"718":{"position":[[115,2]]}}}],["目标",{"_index":1207,"t":{"173":{"position":[[155,2]]},"444":{"position":[[212,2]]},"530":{"position":[[31,2],[99,2],[428,2]]},"533":{"position":[[44,2],[55,2]]},"693":{"position":[[31,2]]},"836":{"position":[[31,2]]}}}],["目的",{"_index":239,"t":{"28":{"position":[[110,2]]},"393":{"position":[[213,2]]},"444":{"position":[[391,2]]},"530":{"position":[[86,2],[1007,2],[1073,2]]},"610":{"position":[[280,2]]},"668":{"position":[[43,2]]},"741":{"position":[[36,2]]},"778":{"position":[[33,2]]}}}],["直到",{"_index":1682,"t":{"336":{"position":[[82,2],[211,2]]},"340":{"position":[[179,2],[282,2]]},"561":{"position":[[356,2]]},"725":{"position":[[33,2]]},"727":{"position":[[1902,2]]},"832":{"position":[[2355,2]]}}}],["直接",{"_index":199,"t":{"25":{"position":[[243,2]]},"34":{"position":[[55,2],[63,2]]},"40":{"position":[[302,2]]},"57":{"position":[[749,2]]},"60":{"position":[[0,2],[15,2],[102,2],[201,2],[467,2]]},"66":{"position":[[89,2]]},"69":{"position":[[0,2],[15,2],[38,2]]},"75":{"position":[[89,2]]},"78":{"position":[[21,2],[74,2],[188,2],[301,2],[327,2]]},"80":{"position":[[28,2],[45,2]]},"86":{"position":[[134,2]]},"120":{"position":[[813,2],[870,2],[973,2]]},"127":{"position":[[746,2]]},"132":{"position":[[0,2],[23,2],[250,2]]},"134":{"position":[[3436,2]]},"153":{"position":[[18,2],[51,2]]},"159":{"position":[[164,2]]},"166":{"position":[[141,2]]},"184":{"position":[[205,2],[1099,2],[1878,2]]},"188":{"position":[[42,2]]},"192":{"position":[[49,2]]},"196":{"position":[[30,2],[70,2],[290,2]]},"207":{"position":[[427,2]]},"218":{"position":[[205,2],[1099,2],[1878,2]]},"223":{"position":[[0,2],[78,2],[499,2]]},"225":{"position":[[429,2]]},"229":{"position":[[55,2]]},"231":{"position":[[10,2],[49,2]]},"235":{"position":[[67,2]]},"239":{"position":[[3,2],[143,2]]},"241":{"position":[[33,2],[243,2],[468,2]]},"252":{"position":[[141,2]]},"290":{"position":[[1260,2]]},"292":{"position":[[7,2],[76,2],[88,2]]},"301":{"position":[[1158,2]]},"357":{"position":[[18,2]]},"361":{"position":[[1496,2],[1586,2]]},"365":{"position":[[341,2],[600,2],[859,2],[1120,2]]},"431":{"position":[[541,2],[955,2]]},"442":{"position":[[54,2]]},"444":{"position":[[336,2],[445,2]]},"447":{"position":[[964,2],[984,2],[1026,2],[1222,2],[1332,2]]},"455":{"position":[[71,2],[791,2]]},"463":{"position":[[292,2]]},"465":{"position":[[269,2]]},"485":{"position":[[274,2]]},"493":{"position":[[40,2]]},"507":{"position":[[289,2],[814,2]]},"512":{"position":[[246,2]]},"561":{"position":[[293,2],[472,2],[481,2]]},"577":{"position":[[2,2]]},"579":{"position":[[107,2]]},"595":{"position":[[218,2]]},"597":{"position":[[241,2]]},"610":{"position":[[339,2]]},"626":{"position":[[30,2]]},"628":{"position":[[109,2]]},"632":{"position":[[23,2]]},"636":{"position":[[5,2]]},"655":{"position":[[20,2]]},"659":{"position":[[0,2]]},"686":{"position":[[498,2]]},"691":{"position":[[7,2],[210,2]]},"723":{"position":[[7,2]]},"752":{"position":[[84,2],[100,2]]},"756":{"position":[[101,2]]},"758":{"position":[[7,2]]},"778":{"position":[[79,2],[160,2]]},"780":{"position":[[142,2]]},"798":{"position":[[34,2]]},"828":{"position":[[266,2]]},"830":{"position":[[399,2]]},"872":{"position":[[1045,2]]},"878":{"position":[[232,2]]},"880":{"position":[[191,2]]},"884":{"position":[[287,2]]},"891":{"position":[[71,2],[100,2],[210,2],[257,2]]},"909":{"position":[[192,2]]},"932":{"position":[[336,2]]}}}],["直接参与",{"_index":1212,"t":{"178":{"position":[[21,4]]}}}],["直白",{"_index":933,"t":{"125":{"position":[[187,2]]}}}],["直至",{"_index":1606,"t":{"301":{"position":[[355,2]]}}}],["直观",{"_index":1677,"t":{"334":{"position":[[71,2]]},"705":{"position":[[138,2]]}}}],["相互",{"_index":936,"t":{"125":{"position":[[247,2]]},"723":{"position":[[44,2]]}}}],["相似",{"_index":2024,"t":{"427":{"position":[[45,2]]},"809":{"position":[[29,2]]}}}],["相信",{"_index":2587,"t":{"554":{"position":[[163,2]]},"707":{"position":[[157,2]]}}}],["相关",{"_index":145,"t":{"18":{"position":[[36,2]]},"50":{"position":[[166,2]]},"57":{"position":[[821,2],[1651,2]]},"94":{"position":[[14,2]]},"110":{"position":[[20,2]]},"120":{"position":[[65,2]]},"255":{"position":[[56,2]]},"261":{"position":[[101,2],[251,2]]},"272":{"position":[[1538,2]]},"286":{"position":[[29,2]]},"301":{"position":[[2578,2]]},"308":{"position":[[2057,2]]},"347":{"position":[[2222,2]]},"411":{"position":[[52,2]]},"413":{"position":[[52,2]]},"447":{"position":[[1328,2]]},"512":{"position":[[479,2]]},"646":{"position":[[50,2]]},"681":{"position":[[77,2]]},"702":{"position":[[1093,2],[1180,2]]},"774":{"position":[[20,2]]},"816":{"position":[[86,2]]},"828":{"position":[[257,2]]},"872":{"position":[[1150,2]]},"878":{"position":[[286,2]]},"882":{"position":[[249,2]]},"925":{"position":[[72,2]]}}}],["相同",{"_index":1967,"t":{"400":{"position":[[75,2]]},"409":{"position":[[43,2]]},"427":{"position":[[29,2]]},"444":{"position":[[499,2]]},"449":{"position":[[66,2],[102,2],[122,2]]},"783":{"position":[[284,2]]},"816":{"position":[[425,2],[433,2]]},"891":{"position":[[286,2]]},"961":{"position":[[270,2]]}}}],["相对路径",{"_index":3195,"t":{"830":{"position":[[363,4]]}}}],["相应",{"_index":812,"t":{"118":{"position":[[62,2]]},"166":{"position":[[71,2]]},"186":{"position":[[37,2]]},"205":{"position":[[74,2]]},"220":{"position":[[37,2]]},"252":{"position":[[71,2]]},"514":{"position":[[509,2]]},"572":{"position":[[20,2]]}}}],["相当于",{"_index":330,"t":{"38":{"position":[[13,3]]},"225":{"position":[[240,3]]},"288":{"position":[[304,3],[323,3]]},"365":{"position":[[1319,3],[1385,3]]},"507":{"position":[[2101,3],[2206,3]]},"528":{"position":[[826,3],[1524,3]]},"750":{"position":[[236,3],[527,3]]},"830":{"position":[[47,3]]},"832":{"position":[[305,3],[2063,3]]},"978":{"position":[[22,3]]}}}],["相比",{"_index":1513,"t":{"268":{"position":[[153,2]]},"295":{"position":[[6,2]]},"304":{"position":[[9,2]]},"444":{"position":[[5,2]]},"526":{"position":[[51,2]]},"689":{"position":[[59,2]]}}}],["相等",{"_index":1708,"t":{"340":{"position":[[845,2]]}}}],["省",{"_index":2381,"t":{"507":{"position":[[1264,1]]}}}],["省略",{"_index":1413,"t":{"225":{"position":[[408,2]]},"736":{"position":[[320,2]]},"750":{"position":[[196,2],[473,2]]}}}],["看做",{"_index":1652,"t":{"308":{"position":[[2475,2]]}}}],["看出",{"_index":1419,"t":{"225":{"position":[[1910,2]]},"677":{"position":[[13,2]]}}}],["看到",{"_index":242,"t":{"28":{"position":[[120,2]]},"822":{"position":[[6,2]]}}}],["真实",{"_index":3081,"t":{"780":{"position":[[366,2],[550,2]]}}}],["瞬时",{"_index":942,"t":{"127":{"position":[[64,2],[689,2]]},"554":{"position":[[87,2]]},"876":{"position":[[202,2]]},"880":{"position":[[145,2],[178,2]]}}}],["知道",{"_index":987,"t":{"134":{"position":[[16,2]]},"146":{"position":[[16,2]]},"207":{"position":[[416,2]]},"376":{"position":[[2,2]]},"485":{"position":[[31,2]]},"546":{"position":[[38,2]]},"554":{"position":[[166,2]]},"639":{"position":[[13,2]]},"661":{"position":[[83,2]]}}}],["短线",{"_index":3339,"t":{"884":{"position":[[292,2]]}}}],["码",{"_index":3469,"t":{"973":{"position":[[46,1]]}}}],["破坏性",{"_index":2097,"t":{"440":{"position":[[298,3]]},"866":{"position":[[34,3]]}}}],["确保",{"_index":1595,"t":{"297":{"position":[[146,2],[238,2],[310,2]]},"485":{"position":[[40,2]]},"969":{"position":[[3,2]]}}}],["确定性",{"_index":1702,"t":{"340":{"position":[[616,3]]}}}],["确认",{"_index":2164,"t":{"447":{"position":[[816,2]]},"866":{"position":[[85,2]]}}}],["碎片",{"_index":1770,"t":{"361":{"position":[[788,2]]},"365":{"position":[[1763,2]]}}}],["示例",{"_index":531,"t":{"57":{"position":[[454,2]]},"78":{"position":[[43,2]]},"91":{"position":[[238,2],[311,2],[370,2]]},"104":{"position":[[27,2]]},"129":{"position":[[3,2]]},"132":{"position":[[299,2]]},"134":{"position":[[98,2]]},"138":{"position":[[195,2]]},"140":{"position":[[173,2]]},"308":{"position":[[1136,2],[2370,2]]},"361":{"position":[[544,2],[1085,2]]},"365":{"position":[[1288,2]]},"376":{"position":[[123,2],[139,2],[146,2],[561,2]]},"447":{"position":[[160,2]]},"455":{"position":[[1080,2]]},"470":{"position":[[816,2]]},"479":{"position":[[26,2]]},"495":{"position":[[18,2]]},"516":{"position":[[113,2]]},"550":{"position":[[56,2]]},"552":{"position":[[35,2]]},"561":{"position":[[2,2]]},"615":{"position":[[138,2]]},"630":{"position":[[259,2]]},"636":{"position":[[2,2]]},"684":{"position":[[90,2]]},"686":{"position":[[510,2]]},"707":{"position":[[126,2]]},"718":{"position":[[209,2]]},"828":{"position":[[109,2]]},"872":{"position":[[1029,2]]},"878":{"position":[[274,2]]},"921":{"position":[[6,2]]},"969":{"position":[[415,2]]}}}],["祝你好运",{"_index":2966,"t":{"720":{"position":[[101,4]]}}}],["神奇",{"_index":2227,"t":{"455":{"position":[[857,2]]}}}],["禁止",{"_index":82,"t":{"7":{"position":[[162,2]]},"839":{"position":[[48,2]]}}}],["禁用",{"_index":3419,"t":{"959":{"position":[[71,2]]}}}],["离职",{"_index":3440,"t":{"965":{"position":[[75,2],[130,2]]}}}],["秉承",{"_index":1145,"t":{"159":{"position":[[78,2]]}}}],["秋",{"_index":1877,"t":{"370":{"position":[[310,1]]}}}],["秒",{"_index":2615,"t":{"561":{"position":[[229,1]]},"659":{"position":[[123,1]]},"727":{"position":[[467,1]]}}}],["租",{"_index":2458,"t":{"526":{"position":[[218,1]]}}}],["移动",{"_index":1120,"t":{"157":{"position":[[302,2]]},"301":{"position":[[495,2]]},"347":{"position":[[962,2]]},"579":{"position":[[134,2]]},"796":{"position":[[17,2]]}}}],["移动网",{"_index":451,"t":{"50":{"position":[[94,3]]}}}],["移至",{"_index":1613,"t":{"301":{"position":[[661,2]]},"347":{"position":[[1431,2]]}}}],["移除",{"_index":3261,"t":{"866":{"position":[[53,2]]},"870":{"position":[[210,2]]},"872":{"position":[[974,2]]}}}],["程序",{"_index":24,"t":{"5":{"position":[[42,2]]},"10":{"position":[[3,2],[19,2],[40,2]]},"12":{"position":[[3,2],[19,2],[40,2]]},"14":{"position":[[3,2],[19,2],[40,2]]},"18":{"position":[[68,2]]},"20":{"position":[[50,2],[74,2]]},"23":{"position":[[33,2]]},"125":{"position":[[97,2],[150,2],[194,2]]},"319":{"position":[[22,2]]},"444":{"position":[[300,2],[673,2]]},"447":{"position":[[1252,2]]},"449":{"position":[[124,2],[141,2],[172,2],[192,2],[217,2],[250,2]]},"521":{"position":[[190,2],[454,2]]},"542":{"position":[[122,2]]},"590":{"position":[[28,2]]},"686":{"position":[[479,2]]},"705":{"position":[[26,2],[128,2]]},"707":{"position":[[83,2]]},"822":{"position":[[81,2]]},"932":{"position":[[222,2]]},"969":{"position":[[116,2]]}}}],["程序包",{"_index":2938,"t":{"714":{"position":[[16,3]]}}}],["程序库",{"_index":2965,"t":{"720":{"position":[[74,3]]},"959":{"position":[[0,3]]}}}],["程序运行",{"_index":2532,"t":{"542":{"position":[[9,4]]}}}],["程度",{"_index":1297,"t":{"184":{"position":[[880,2],[1052,2],[1068,2],[1235,2],[1659,2],[1831,2],[1847,2]]},"218":{"position":[[880,2],[1052,2],[1068,2],[1235,2],[1659,2],[1831,2],[1847,2]]},"503":{"position":[[108,2]]},"617":{"position":[[86,2]]},"668":{"position":[[61,2]]},"677":{"position":[[48,2]]}}}],["稍",{"_index":2438,"t":{"523":{"position":[[369,1],[2719,1]]}}}],["稍微",{"_index":3172,"t":{"822":{"position":[[74,2]]}}}],["稳健性",{"_index":3276,"t":{"872":{"position":[[90,3]]}}}],["稳妥",{"_index":3125,"t":{"806":{"position":[[74,2]]}}}],["稳定",{"_index":1965,"t":{"400":{"position":[[35,2]]},"870":{"position":[[139,2]]},"872":{"position":[[101,2]]}}}],["稳定性",{"_index":1679,"t":{"334":{"position":[[81,3]]},"741":{"position":[[99,3]]}}}],["空",{"_index":412,"t":{"46":{"position":[[420,1]]},"134":{"position":[[1481,1],[1979,1]]}}}],["空格",{"_index":3388,"t":{"925":{"position":[[743,2]]}}}],["空白",{"_index":2943,"t":{"716":{"position":[[15,2]]}}}],["空闲",{"_index":1379,"t":{"207":{"position":[[444,2]]}}}],["空间",{"_index":1024,"t":{"134":{"position":[[3676,2]]},"481":{"position":[[4,2]]},"872":{"position":[[476,2],[487,2]]}}}],["穿透",{"_index":2516,"t":{"535":{"position":[[65,2],[85,2]]}}}],["突然",{"_index":3100,"t":{"787":{"position":[[32,2]]}}}],["窗体",{"_index":3362,"t":{"906":{"position":[[143,2],[146,2]]}}}],["立即",{"_index":356,"t":{"40":{"position":[[313,2]]},"159":{"position":[[266,2]]},"196":{"position":[[99,2]]},"241":{"position":[[52,2]]},"413":{"position":[[130,2]]},"595":{"position":[[228,2]]},"597":{"position":[[251,2]]},"857":{"position":[[394,2]]},"859":{"position":[[288,2]]}}}],["站",{"_index":2020,"t":{"424":{"position":[[1,1]]}}}],["童",{"_index":1847,"t":{"370":{"position":[[135,1]]}}}],["端",{"_index":937,"t":{"127":{"position":[[4,1]]},"134":{"position":[[86,1]]},"235":{"position":[[211,1]]},"404":{"position":[[66,1],[70,1],[132,1],[136,1]]},"455":{"position":[[1011,1],[1016,1]]},"498":{"position":[[74,1]]},"505":{"position":[[68,1],[74,1]]},"528":{"position":[[86,1]]},"590":{"position":[[9,1],[40,1]]},"630":{"position":[[10,1],[20,1],[34,1],[40,1],[213,1],[218,1]]},"672":{"position":[[8,1],[677,1]]},"674":{"position":[[8,1],[549,1]]},"681":{"position":[[34,1]]},"748":{"position":[[216,1],[433,1],[443,1],[458,1]]},"752":{"position":[[157,1]]},"761":{"position":[[2,1],[33,1],[122,1]]},"767":{"position":[[19,1],[51,1]]},"783":{"position":[[84,1],[88,1]]},"816":{"position":[[401,1]]},"851":{"position":[[345,1]]},"868":{"position":[[182,1]]},"901":{"position":[[14,1],[25,1]]},"917":{"position":[[121,1]]}}}],["端口",{"_index":799,"t":{"112":{"position":[[36,2]]},"184":{"position":[[1196,2],[1217,2],[1228,2],[1239,2],[1544,2]]},"207":{"position":[[422,2],[432,2],[449,2]]},"212":{"position":[[91,2]]},"218":{"position":[[1196,2],[1217,2],[1228,2],[1239,2],[1544,2]]},"261":{"position":[[110,2],[122,2]]},"537":{"position":[[249,2]]},"617":{"position":[[107,2]]},"729":{"position":[[82,2]]},"806":{"position":[[441,2]]},"884":{"position":[[132,2]]},"911":{"position":[[64,2]]}}}],["端口号",{"_index":1261,"t":{"184":{"position":[[466,3],[1591,3]]},"218":{"position":[[466,3],[1591,3]]}}}],["符",{"_index":2403,"t":{"514":{"position":[[516,1]]}}}],["符号",{"_index":2894,"t":{"702":{"position":[[1261,2],[1557,2],[1650,2]]},"748":{"position":[[219,2],[446,2],[461,2]]},"783":{"position":[[96,2]]}}}],["符合",{"_index":100,"t":{"10":{"position":[[62,2]]},"12":{"position":[[182,2]]},"14":{"position":[[81,2]]}}}],["第一",{"_index":287,"t":{"34":{"position":[[93,2]]},"574":{"position":[[177,2]]}}}],["第一个",{"_index":984,"t":{"132":{"position":[[256,3]]},"184":{"position":[[1109,3],[1888,3]]},"218":{"position":[[1109,3],[1888,3]]},"301":{"position":[[1373,3]]},"304":{"position":[[62,3]]},"308":{"position":[[1140,3]]},"359":{"position":[[27,3]]},"391":{"position":[[298,3]]},"395":{"position":[[0,3]]},"404":{"position":[[10,3]]},"615":{"position":[[37,3]]},"641":{"position":[[53,3]]},"780":{"position":[[52,3]]}}}],["第一次",{"_index":2670,"t":{"595":{"position":[[146,3]]}}}],["第三",{"_index":1753,"t":{"359":{"position":[[65,2]]}}}],["第二",{"_index":301,"t":{"34":{"position":[[199,2]]},"359":{"position":[[54,2]]},"574":{"position":[[193,2]]}}}],["第二个",{"_index":985,"t":{"132":{"position":[[268,3]]},"184":{"position":[[1115,3],[1894,3]]},"218":{"position":[[1115,3],[1894,3]]},"391":{"position":[[308,3]]},"395":{"position":[[10,3]]}}}],["等",{"_index":92,"t":{"10":{"position":[[33,1]]},"12":{"position":[[33,1],[103,1]]},"14":{"position":[[33,1]]},"120":{"position":[[546,1]]},"125":{"position":[[92,1]]},"132":{"position":[[295,1]]},"178":{"position":[[43,1]]},"180":{"position":[[59,1],[78,1]]},"184":{"position":[[97,1]]},"188":{"position":[[39,1]]},"212":{"position":[[129,1],[148,1]]},"218":{"position":[[97,1]]},"223":{"position":[[75,1]]},"235":{"position":[[236,1]]},"306":{"position":[[31,1]]},"319":{"position":[[32,1]]},"361":{"position":[[1984,1]]},"385":{"position":[[18,1]]},"397":{"position":[[103,1]]},"406":{"position":[[63,1]]},"418":{"position":[[78,1]]},"427":{"position":[[79,1]]},"442":{"position":[[98,1]]},"463":{"position":[[24,1]]},"487":{"position":[[36,1]]},"500":{"position":[[42,1]]},"503":{"position":[[44,1]]},"512":{"position":[[478,1]]},"526":{"position":[[346,1]]},"542":{"position":[[139,1]]},"561":{"position":[[352,1]]},"572":{"position":[[85,1]]},"579":{"position":[[64,1],[95,1]]},"595":{"position":[[186,1],[234,1]]},"597":{"position":[[257,1]]},"626":{"position":[[37,1]]},"639":{"position":[[49,1],[104,1]]},"653":{"position":[[139,1],[237,1],[276,1]]},"705":{"position":[[59,1]]},"707":{"position":[[145,1]]},"718":{"position":[[78,1]]},"725":{"position":[[9,1]]},"727":{"position":[[364,1]]},"738":{"position":[[32,1]]},"743":{"position":[[17,1]]},"774":{"position":[[47,1]]},"796":{"position":[[23,1]]},"802":{"position":[[16,1]]},"806":{"position":[[115,1],[346,1]]},"816":{"position":[[104,1]]},"824":{"position":[[35,1]]},"830":{"position":[[129,1],[276,1]]},"832":{"position":[[1775,1]]},"864":{"position":[[58,1]]},"868":{"position":[[166,1]]},"874":{"position":[[98,1],[259,1]]},"878":{"position":[[317,1]]},"884":{"position":[[129,1]]},"906":{"position":[[161,1],[212,1]]},"919":{"position":[[29,1]]},"957":{"position":[[133,1]]}}}],["等于",{"_index":1784,"t":{"361":{"position":[[1572,2]]},"702":{"position":[[1569,2],[1662,2]]}}}],["等到",{"_index":2618,"t":{"561":{"position":[[358,2]]}}}],["等待",{"_index":784,"t":{"106":{"position":[[27,2]]},"207":{"position":[[333,2]]},"653":{"position":[[184,2]]},"657":{"position":[[11,2]]},"672":{"position":[[1062,2]]},"674":{"position":[[967,2]]},"854":{"position":[[27,2],[52,2],[116,2]]},"859":{"position":[[1126,2]]},"880":{"position":[[110,2]]}}}],["等等",{"_index":2116,"t":{"444":{"position":[[288,2]]},"586":{"position":[[84,2]]}}}],["策略",{"_index":1260,"t":{"184":{"position":[[440,2]]},"218":{"position":[[440,2]]},"615":{"position":[[70,2]]},"814":{"position":[[51,2]]}}}],["筛查",{"_index":3283,"t":{"872":{"position":[[320,2]]}}}],["筛选",{"_index":1058,"t":{"142":{"position":[[209,2]]},"301":{"position":[[330,2]]},"780":{"position":[[146,2]]},"880":{"position":[[122,2]]}}}],["简介",{"_index":783,"t":{"106":{"position":[[6,2]]}}}],["简单",{"_index":231,"t":{"28":{"position":[[70,2]]},"89":{"position":[[5,2]]},"110":{"position":[[49,2]]},"120":{"position":[[47,2]]},"138":{"position":[[192,2]]},"180":{"position":[[0,2],[63,2]]},"184":{"position":[[1074,2],[1853,2]]},"188":{"position":[[0,2]]},"199":{"position":[[23,2]]},"201":{"position":[[0,2]]},"212":{"position":[[0,2],[133,2]]},"218":{"position":[[1074,2],[1853,2]]},"223":{"position":[[36,2]]},"295":{"position":[[44,2]]},"299":{"position":[[14,2]]},"304":{"position":[[22,2]]},"334":{"position":[[68,2]]},"420":{"position":[[25,2]]},"455":{"position":[[492,2]]},"487":{"position":[[107,2]]},"505":{"position":[[5,2]]},"523":{"position":[[1,2]]},"530":{"position":[[75,2]]},"566":{"position":[[0,2]]},"668":{"position":[[50,2]]},"705":{"position":[[119,2]]},"743":{"position":[[28,2]]},"748":{"position":[[12,2]]},"783":{"position":[[11,2]]},"814":{"position":[[71,2]]},"872":{"position":[[127,2]]},"884":{"position":[[108,2]]},"909":{"position":[[135,2]]},"911":{"position":[[0,2]]},"925":{"position":[[61,2]]}}}],["简称",{"_index":2547,"t":{"542":{"position":[[171,2]]},"748":{"position":[[23,2]]}}}],["算是",{"_index":2205,"t":{"455":{"position":[[7,2]]}}}],["算法",{"_index":1296,"t":{"184":{"position":[[866,2],[1645,2]]},"218":{"position":[[866,2],[1645,2]]},"334":{"position":[[43,2]]},"357":{"position":[[81,2]]},"400":{"position":[[77,2]]},"402":{"position":[[116,2]]},"404":{"position":[[6,2],[53,2],[113,2]]},"420":{"position":[[23,2]]},"526":{"position":[[169,2]]},"743":{"position":[[26,2]]},"783":{"position":[[302,2],[338,2]]},"816":{"position":[[427,2]]},"820":{"position":[[6,2]]}}}],["管理",{"_index":364,"t":{"42":{"position":[[35,2]]},"210":{"position":[[41,2]]},"409":{"position":[[95,2]]},"440":{"position":[[281,2]]},"590":{"position":[[38,2]]},"714":{"position":[[9,2]]},"891":{"position":[[229,2]]}}}],["管道",{"_index":2604,"t":{"559":{"position":[[20,2]]}}}],["篡改",{"_index":2172,"t":{"447":{"position":[[1207,2]]}}}],["类",{"_index":501,"t":{"57":{"position":[[28,1],[97,1],[150,1],[316,1]]},"66":{"position":[[86,1],[94,1]]},"75":{"position":[[86,1],[94,1]]},"86":{"position":[[131,1],[139,1],[340,1]]},"97":{"position":[[18,1]]},"118":{"position":[[7,1],[58,1]]},"127":{"position":[[10,1],[38,1],[273,1],[549,1],[720,1]]},"140":{"position":[[20,1]]},"142":{"position":[[552,1]]},"151":{"position":[[48,1]]},"153":{"position":[[11,1]]},"166":{"position":[[7,1],[67,1]]},"186":{"position":[[33,1]]},"194":{"position":[[76,1]]},"205":{"position":[[7,1],[70,1]]},"210":{"position":[[61,1],[115,1]]},"220":{"position":[[33,1]]},"225":{"position":[[76,1],[386,1]]},"233":{"position":[[76,1]]},"248":{"position":[[95,1]]},"252":{"position":[[7,1],[67,1]]},"268":{"position":[[13,1]]},"272":{"position":[[28,1],[93,1],[142,1],[300,1]]},"290":{"position":[[1092,1],[1255,1]]},"301":{"position":[[18,1],[73,1],[112,1]]},"308":{"position":[[28,1],[94,1],[144,1],[304,1]]},"347":{"position":[[28,1],[94,1],[146,1],[308,1]]},"361":{"position":[[5,1]]},"376":{"position":[[119,1]]},"378":{"position":[[10,1]]},"436":{"position":[[3,1]]},"440":{"position":[[147,1],[168,1],[191,1],[229,1],[266,1]]},"447":{"position":[[1326,1]]},"453":{"position":[[6,1],[33,1]]},"455":{"position":[[374,1],[625,1]]},"503":{"position":[[100,1]]},"512":{"position":[[10,1],[24,1]]},"542":{"position":[[70,1],[86,1],[98,1],[115,1]]},"546":{"position":[[4,1]]},"600":{"position":[[38,1]]},"679":{"position":[[253,1]]},"732":{"position":[[59,1]]},"743":{"position":[[7,1]]},"859":{"position":[[1106,1]]},"870":{"position":[[193,1]]},"872":{"position":[[142,1],[159,1],[228,1],[427,1]]},"876":{"position":[[143,1]]},"882":{"position":[[59,1]]},"884":{"position":[[104,1]]},"894":{"position":[[10,1],[24,1]]},"925":{"position":[[97,1]]},"928":{"position":[[10,1],[29,1]]},"969":{"position":[[296,1]]}}}],["类似",{"_index":1455,"t":{"255":{"position":[[307,2]]},"268":{"position":[[18,2]]},"304":{"position":[[77,2]]},"383":{"position":[[43,2]]},"389":{"position":[[22,2],[37,2]]},"554":{"position":[[236,2]]},"559":{"position":[[32,2]]},"761":{"position":[[84,2]]},"783":{"position":[[377,2]]},"872":{"position":[[164,2]]},"906":{"position":[[46,2]]},"969":{"position":[[67,2]]}}}],["类型",{"_index":206,"t":{"25":{"position":[[372,2],[380,2]]},"34":{"position":[[70,2]]},"57":{"position":[[236,2]]},"62":{"position":[[20,2]]},"71":{"position":[[20,2]]},"78":{"position":[[324,2]]},"82":{"position":[[20,2]]},"110":{"position":[[27,2]]},"132":{"position":[[356,2]]},"134":{"position":[[36,2]]},"164":{"position":[[198,2]]},"184":{"position":[[607,2],[1288,2],[1340,2]]},"186":{"position":[[260,2]]},"194":{"position":[[322,2]]},"218":{"position":[[607,2],[1288,2],[1340,2]]},"220":{"position":[[267,2]]},"233":{"position":[[328,2]]},"235":{"position":[[733,2]]},"250":{"position":[[198,2]]},"272":{"position":[[228,2]]},"297":{"position":[[4,2]]},"301":{"position":[[198,2]]},"308":{"position":[[230,2],[778,2]]},"347":{"position":[[232,2]]},"359":{"position":[[50,2],[73,2],[108,2]]},"363":{"position":[[53,2]]},"365":{"position":[[23,2],[116,2],[146,2]]},"376":{"position":[[632,2]]},"378":{"position":[[68,2]]},"395":{"position":[[24,2]]},"402":{"position":[[54,2]]},"413":{"position":[[116,2]]},"427":{"position":[[27,2],[52,2]]},"431":{"position":[[16,2],[838,2]]},"434":{"position":[[3,2]]},"447":{"position":[[912,2]]},"449":{"position":[[55,2],[92,2],[105,2]]},"451":{"position":[[51,2],[113,2]]},"473":{"position":[[274,2]]},"500":{"position":[[18,2],[24,2]]},"505":{"position":[[20,2]]},"507":{"position":[[287,2],[383,2],[564,2],[874,2]]},"514":{"position":[[102,2]]},"530":{"position":[[71,2]]},"544":{"position":[[86,2],[92,2]]},"546":{"position":[[41,2],[63,2]]},"608":{"position":[[12,2]]},"679":{"position":[[148,2]]},"686":{"position":[[163,2]]},"702":{"position":[[1082,2],[1169,2]]},"748":{"position":[[37,2],[206,2],[481,2],[501,2]]},"750":{"position":[[26,2]]},"756":{"position":[[73,2]]},"770":{"position":[[36,2]]},"780":{"position":[[63,2]]},"783":{"position":[[98,2]]},"792":{"position":[[26,2]]},"798":{"position":[[6,2]]},"804":{"position":[[13,2]]},"806":{"position":[[172,2]]},"816":{"position":[[32,2]]},"820":{"position":[[97,2]]},"830":{"position":[[717,2],[750,2]]},"832":{"position":[[645,2],[879,2]]},"836":{"position":[[99,2]]},"866":{"position":[[41,2]]},"872":{"position":[[677,2]]},"878":{"position":[[560,2],[728,2]]},"880":{"position":[[129,2]]},"884":{"position":[[110,2]]},"889":{"position":[[1,2],[7,2]]},"919":{"position":[[12,2],[18,2]]},"961":{"position":[[0,2]]}}}],["类型转换",{"_index":2836,"t":{"686":{"position":[[172,4]]}}}],["粗暴",{"_index":2800,"t":{"668":{"position":[[52,2]]}}}],["粘",{"_index":1218,"t":{"180":{"position":[[40,1]]},"212":{"position":[[110,1]]},"400":{"position":[[14,1]]},"402":{"position":[[6,1]]},"418":{"position":[[52,1]]},"736":{"position":[[341,1]]},"738":{"position":[[105,1]]},"741":{"position":[[30,1]]},"976":{"position":[[46,1]]}}}],["精简",{"_index":3287,"t":{"872":{"position":[[470,2],[521,2],[895,2]]}}}],["系",{"_index":3,"t":{"3":{"position":[[10,1]]},"36":{"position":[[4,1]]},"178":{"position":[[13,1]]},"210":{"position":[[14,1]]},"767":{"position":[[11,1]]},"870":{"position":[[55,1]]},"872":{"position":[[61,1],[81,1],[192,1],[280,1],[335,1],[381,1],[445,1],[658,1],[752,1],[893,1],[920,1]]},"874":{"position":[[91,1]]},"878":{"position":[[145,1],[223,1]]},"935":{"position":[[26,1]]}}}],["系列",{"_index":3278,"t":{"872":{"position":[[195,2]]}}}],["系统",{"_index":1334,"t":{"184":{"position":[[1464,2]]},"207":{"position":[[442,2]]},"218":{"position":[[1464,2]]},"485":{"position":[[152,2]]},"748":{"position":[[230,2]]},"822":{"position":[[24,2]]},"880":{"position":[[118,2],[135,2],[159,2],[222,2]]}}}],["索引",{"_index":1727,"t":{"347":{"position":[[1186,2],[1541,2]]}}}],["索要",{"_index":3423,"t":{"961":{"position":[[159,2]]}}}],["紧接着",{"_index":3031,"t":{"748":{"position":[[162,3]]}}}],["纠结",{"_index":619,"t":{"62":{"position":[[13,2]]},"71":{"position":[[13,2]]},"82":{"position":[[13,2]]},"134":{"position":[[29,2]]}}}],["约",{"_index":3140,"t":{"814":{"position":[[20,1]]}}}],["约定",{"_index":2802,"t":{"670":{"position":[[19,2]]},"756":{"position":[[13,2]]},"780":{"position":[[71,2]]}}}],["约束",{"_index":282,"t":{"34":{"position":[[79,2]]},"872":{"position":[[1097,2]]}}}],["级别",{"_index":1923,"t":{"378":{"position":[[119,2]]},"473":{"position":[[281,2]]}}}],["线程",{"_index":1147,"t":{"159":{"position":[[110,2],[263,2],[291,2]]},"184":{"position":[[279,2],[285,2],[292,2],[315,2],[324,2],[401,2],[925,2],[1128,2],[1131,2],[1704,2],[1907,2],[1910,2]]},"218":{"position":[[279,2],[285,2],[292,2],[315,2],[324,2],[401,2],[925,2],[1128,2],[1131,2],[1704,2],[1907,2],[1910,2]]},"411":{"position":[[30,2]]},"413":{"position":[[37,2]]},"876":{"position":[[217,2]]},"882":{"position":[[362,2]]}}}],["组",{"_index":1262,"t":{"184":{"position":[[469,1]]},"218":{"position":[[469,1]]},"479":{"position":[[4,1]]},"630":{"position":[[106,1]]},"809":{"position":[[12,1]]},"839":{"position":[[110,1],[120,1]]},"841":{"position":[[0,1],[71,1],[97,1]]},"843":{"position":[[335,1],[337,1]]},"845":{"position":[[287,1]]},"849":{"position":[[12,1],[14,1]]}}}],["组件",{"_index":167,"t":{"23":{"position":[[21,2]]},"110":{"position":[[76,2]]},"199":{"position":[[3,2],[17,2]]},"402":{"position":[[86,2]]},"572":{"position":[[28,2]]},"806":{"position":[[354,2]]},"872":{"position":[[451,2]]}}}],["组合",{"_index":260,"t":{"32":{"position":[[92,2]]},"190":{"position":[[30,2]]},"227":{"position":[[31,2]]},"361":{"position":[[1579,2],[1772,2],[1978,2]]},"365":{"position":[[152,2]]},"830":{"position":[[384,2]]}}}],["组合成",{"_index":1305,"t":{"184":{"position":[[991,3],[1770,3]]},"218":{"position":[[991,3],[1770,3]]}}}],["组成部分",{"_index":1083,"t":{"149":{"position":[[24,4]]}}}],["细心",{"_index":3086,"t":{"783":{"position":[[142,2]]}}}],["织",{"_index":2081,"t":{"440":{"position":[[66,1],[132,1]]}}}],["终止",{"_index":1509,"t":{"268":{"position":[[108,2],[135,2]]},"738":{"position":[[78,2]]},"741":{"position":[[0,2]]},"743":{"position":[[65,2],[76,2]]},"745":{"position":[[483,2],[522,2],[574,2]]},"957":{"position":[[72,2]]}}}],["终端",{"_index":1050,"t":{"142":{"position":[[6,2],[553,2]]},"581":{"position":[[28,2]]},"630":{"position":[[53,2]]},"806":{"position":[[85,2]]}}}],["终结",{"_index":2775,"t":{"661":{"position":[[37,2]]},"820":{"position":[[243,2],[260,2]]}}}],["经典",{"_index":1644,"t":{"308":{"position":[[2376,2]]}}}],["经常出现",{"_index":1148,"t":{"159":{"position":[[124,4]]}}}],["经过",{"_index":254,"t":{"32":{"position":[[48,2]]},"166":{"position":[[444,2]]},"196":{"position":[[60,2]]},"241":{"position":[[458,2]]},"252":{"position":[[444,2]]},"619":{"position":[[39,2]]},"857":{"position":[[356,2]]},"859":{"position":[[250,2]]},"872":{"position":[[308,2]]}}}],["绑定",{"_index":1337,"t":{"184":{"position":[[1542,2]]},"207":{"position":[[418,2],[429,2]]},"218":{"position":[[1542,2]]}}}],["结合",{"_index":2603,"t":{"559":{"position":[[13,2],[24,2]]},"761":{"position":[[183,2]]}}}],["结尾",{"_index":668,"t":{"78":{"position":[[105,2]]},"268":{"position":[[41,2]]},"514":{"position":[[126,2]]},"732":{"position":[[81,2]]},"734":{"position":[[37,2]]},"736":{"position":[[273,2]]},"745":{"position":[[496,2]]},"925":{"position":[[119,2],[726,2]]}}}],["结束",{"_index":524,"t":{"57":{"position":[[383,2]]},"166":{"position":[[254,2],[560,2]]},"252":{"position":[[254,2],[560,2]]},"272":{"position":[[766,2]]},"290":{"position":[[501,2]]},"297":{"position":[[55,2],[217,2]]},"308":{"position":[[368,2]]},"336":{"position":[[215,2]]},"340":{"position":[[286,2],[997,2],[1051,2]]},"347":{"position":[[374,2],[1440,2]]},"514":{"position":[[114,2],[512,2]]},"561":{"position":[[16,2]]},"725":{"position":[[39,2]]},"727":{"position":[[800,2],[1077,2],[1904,2]]},"820":{"position":[[208,2]]},"832":{"position":[[803,2],[859,2],[2359,2]]},"859":{"position":[[1167,2]]},"878":{"position":[[652,2],[708,2]]},"971":{"position":[[38,2]]}}}],["结构",{"_index":1899,"t":{"374":{"position":[[36,2]]},"427":{"position":[[62,2]]},"449":{"position":[[64,2],[100,2]]},"655":{"position":[[373,2]]},"681":{"position":[[147,2]]},"718":{"position":[[117,2]]}}}],["结果",{"_index":599,"t":{"60":{"position":[[208,2]]},"66":{"position":[[264,2]]},"69":{"position":[[553,2],[694,2]]},"75":{"position":[[190,2]]},"80":{"position":[[426,2],[561,2],[723,2],[968,2],[1387,2],[1615,2],[2038,2],[2129,2],[2222,2],[2404,2]]},"434":{"position":[[113,2],[137,2]]},"436":{"position":[[1997,2]]},"530":{"position":[[1116,2]]},"670":{"position":[[58,2]]},"714":{"position":[[54,2]]},"763":{"position":[[63,2]]},"765":{"position":[[66,2]]},"828":{"position":[[325,2]]},"859":{"position":[[1148,2]]},"917":{"position":[[79,2]]}}}],["绝不",{"_index":1768,"t":{"361":{"position":[[773,2]]},"365":{"position":[[1748,2]]}}}],["绝大多数",{"_index":2212,"t":{"455":{"position":[[356,4]]}}}],["绝对",{"_index":2300,"t":{"487":{"position":[[17,2]]}}}],["绝对路径",{"_index":3197,"t":{"830":{"position":[[391,4]]}}}],["统一",{"_index":2094,"t":{"440":{"position":[[284,2]]},"891":{"position":[[227,2]]}}}],["统统",{"_index":2926,"t":{"705":{"position":[[105,2]]}}}],["继承",{"_index":267,"t":{"32":{"position":[[169,2]]},"48":{"position":[[316,2]]},"57":{"position":[[99,2],[972,2]]},"99":{"position":[[0,2]]},"118":{"position":[[41,2]]},"120":{"position":[[36,2]]},"127":{"position":[[26,2],[72,2]]},"151":{"position":[[38,2]]},"166":{"position":[[46,2]]},"186":{"position":[[17,2]]},"205":{"position":[[47,2]]},"220":{"position":[[17,2]]},"225":{"position":[[74,2],[384,2],[1915,2]]},"252":{"position":[[46,2]]},"272":{"position":[[95,2],[694,2]]},"277":{"position":[[0,2]]},"284":{"position":[[498,2]]},"290":{"position":[[716,2],[753,2],[1084,2]]},"301":{"position":[[75,2]]},"308":{"position":[[96,2],[1336,2]]},"313":{"position":[[0,2]]},"347":{"position":[[96,2],[1669,2]]},"357":{"position":[[40,2],[141,2]]},"361":{"position":[[7,2]]},"376":{"position":[[151,2]]},"431":{"position":[[70,2]]},"473":{"position":[[0,2]]},"512":{"position":[[12,2]]},"561":{"position":[[171,2]]},"574":{"position":[[144,2],[199,2]]},"632":{"position":[[50,2]]},"643":{"position":[[4,2]]},"732":{"position":[[53,2],[57,2]]},"894":{"position":[[12,2]]},"925":{"position":[[91,2],[95,2]]},"928":{"position":[[12,2]]}}}],["继续",{"_index":1749,"t":{"357":{"position":[[69,2]]},"561":{"position":[[364,2],[464,2]]}}}],["续",{"_index":1686,"t":{"336":{"position":[[208,1]]},"340":{"position":[[279,1]]},"385":{"position":[[31,1]]},"830":{"position":[[127,1]]},"952":{"position":[[12,1]]}}}],["综上",{"_index":1776,"t":{"361":{"position":[[1158,2]]}}}],["缓存",{"_index":460,"t":{"50":{"position":[[132,2],[197,2],[216,2],[255,2],[279,2],[300,2]]},"184":{"position":[[27,2]]},"218":{"position":[[27,2]]},"297":{"position":[[64,2]]},"299":{"position":[[17,2]]},"301":{"position":[[876,2],[888,2],[1079,2],[1160,2]]},"336":{"position":[[68,2],[193,2]]},"340":{"position":[[95,2],[165,2],[264,2]]},"347":{"position":[[1210,2],[1425,2],[1564,2]]},"361":{"position":[[1181,2]]},"874":{"position":[[218,2]]},"876":{"position":[[172,2]]}}}],["缓存数据",{"_index":446,"t":{"50":{"position":[[46,4]]}}}],["缓解",{"_index":1298,"t":{"184":{"position":[[883,2],[1237,2],[1662,2]]},"218":{"position":[[883,2],[1237,2],[1662,2]]}}}],["编写",{"_index":2031,"t":{"431":{"position":[[30,2]]},"505":{"position":[[27,2]]}}}],["编号",{"_index":2900,"t":{"702":{"position":[[1349,2]]},"818":{"position":[[29,2]]}}}],["编码",{"_index":1498,"t":{"265":{"position":[[8,2]]},"702":{"position":[[980,2]]},"748":{"position":[[20,2],[28,2],[92,2],[112,2]]},"917":{"position":[[87,2]]}}}],["编码方式",{"_index":3016,"t":{"741":{"position":[[53,4]]}}}],["编程",{"_index":1672,"t":{"330":{"position":[[2,2]]},"903":{"position":[[2,2]]}}}],["编程语言",{"_index":2339,"t":{"498":{"position":[[18,4]]},"862":{"position":[[17,4]]},"917":{"position":[[95,4]]}}}],["编译",{"_index":993,"t":{"134":{"position":[[89,2]]},"440":{"position":[[71,2],[137,2]]},"444":{"position":[[105,2],[210,2],[219,2],[561,2],[612,2]]},"447":{"position":[[966,2],[1249,2]]},"707":{"position":[[149,2]]},"868":{"position":[[136,2]]}}}],["编译成",{"_index":2175,"t":{"447":{"position":[[1239,3]]}}}],["编辑",{"_index":2942,"t":{"716":{"position":[[9,2]]}}}],["缜密",{"_index":153,"t":{"20":{"position":[[36,2]]}}}],["缺",{"_index":2085,"t":{"440":{"position":[[111,1]]}}}],["缺点",{"_index":1917,"t":{"378":{"position":[[61,2]]},"440":{"position":[[216,2]]},"444":{"position":[[17,2]]},"505":{"position":[[59,2]]}}}],["缺省",{"_index":833,"t":{"120":{"position":[[488,2]]}}}],["网",{"_index":1931,"t":{"385":{"position":[[30,1]]},"526":{"position":[[343,1]]},"535":{"position":[[64,1],[84,1]]},"702":{"position":[[100,1]]},"716":{"position":[[144,1]]},"718":{"position":[[7,1]]},"787":{"position":[[35,1]]},"906":{"position":[[112,1]]}}}],["网上",{"_index":2683,"t":{"600":{"position":[[12,2]]}}}],["网友",{"_index":1924,"t":{"381":{"position":[[0,2]]},"383":{"position":[[2,2]]},"584":{"position":[[0,2]]},"586":{"position":[[2,2]]},"882":{"position":[[259,2]]},"899":{"position":[[0,2]]},"901":{"position":[[2,2]]}}}],["网址",{"_index":1661,"t":{"319":{"position":[[15,2]]}}}],["网线",{"_index":2674,"t":{"595":{"position":[[221,2]]},"597":{"position":[[244,2]]}}}],["网络",{"_index":908,"t":{"125":{"position":[[39,2],[61,2],[112,2],[144,2]]},"330":{"position":[[0,2]]},"336":{"position":[[121,2]]},"340":{"position":[[198,2]]},"374":{"position":[[45,2]]},"485":{"position":[[53,2]]},"526":{"position":[[172,2]]},"542":{"position":[[182,2]]},"677":{"position":[[8,2]]},"839":{"position":[[34,2]]},"903":{"position":[[0,2]]},"906":{"position":[[119,2]]}}}],["网络通信",{"_index":729,"t":{"94":{"position":[[10,4]]}}}],["网页",{"_index":2239,"t":{"458":{"position":[[22,2]]},"952":{"position":[[17,2]]}}}],["置",{"_index":411,"t":{"46":{"position":[[419,1]]}}}],["美国",{"_index":55,"t":{"7":{"position":[[47,2]]}}}],["美少女",{"_index":1855,"t":{"370":{"position":[[196,3]]}}}],["群",{"_index":8,"t":{"3":{"position":[[21,1],[35,1]]}}}],["群友",{"_index":1741,"t":{"353":{"position":[[2,2]]},"521":{"position":[[48,2]]}}}],["老",{"_index":2357,"t":{"503":{"position":[[118,1]]},"521":{"position":[[50,1]]}}}],["考虑",{"_index":1254,"t":{"184":{"position":[[347,2]]},"218":{"position":[[347,2]]},"295":{"position":[[55,2]]},"301":{"position":[[1077,2]]},"340":{"position":[[14,2]]},"343":{"position":[[120,2]]},"357":{"position":[[91,2],[186,2]]},"361":{"position":[[1074,2],[1091,2]]},"444":{"position":[[203,2],[481,2],[587,2],[610,2]]},"447":{"position":[[1232,2]]},"570":{"position":[[47,2]]},"718":{"position":[[72,2]]}}}],["而且",{"_index":319,"t":{"36":{"position":[[26,2]]},"151":{"position":[[81,2]]},"444":{"position":[[197,2],[691,2]]},"485":{"position":[[218,2]]}}}],["而已",{"_index":2767,"t":{"653":{"position":[[170,2]]},"976":{"position":[[69,2]]}}}],["而是",{"_index":2536,"t":{"542":{"position":[[45,2]]},"720":{"position":[[67,2]]},"857":{"position":[[647,2]]},"859":{"position":[[536,2]]}}}],["而言",{"_index":2582,"t":{"554":{"position":[[17,2]]}}}],["耗时",{"_index":1256,"t":{"184":{"position":[[360,2]]},"218":{"position":[[360,2]]}}}],["耦",{"_index":1360,"t":{"194":{"position":[[40,1]]},"233":{"position":[[40,1]]},"542":{"position":[[118,1]]}}}],["职员",{"_index":3447,"t":{"967":{"position":[[28,2]]}}}],["职能",{"_index":1926,"t":{"383":{"position":[[27,2]]},"389":{"position":[[20,2]]},"533":{"position":[[27,2]]}}}],["联",{"_index":1667,"t":{"326":{"position":[[3,1]]}}}],["联系",{"_index":3445,"t":{"965":{"position":[[197,2]]},"973":{"position":[[15,2],[24,2]]}}}],["联系方式",{"_index":3410,"t":{"935":{"position":[[148,4]]}}}],["联网",{"_index":1664,"t":{"319":{"position":[[28,2]]}}}],["聪明",{"_index":3109,"t":{"787":{"position":[[110,2]]}}}],["背道而驰",{"_index":3418,"t":{"959":{"position":[[49,4]]}}}],["能",{"_index":302,"t":{"34":{"position":[[206,1]]},"69":{"position":[[37,1]]},"80":{"position":[[1791,1]]},"138":{"position":[[174,1]]},"159":{"position":[[46,1]]},"180":{"position":[[98,1]]},"199":{"position":[[31,1]]},"212":{"position":[[168,1]]},"225":{"position":[[21,1],[1945,1]]},"235":{"position":[[1243,1]]},"268":{"position":[[53,1]]},"286":{"position":[[18,1],[35,1]]},"290":{"position":[[1026,1]]},"334":{"position":[[49,1]]},"336":{"position":[[115,1]]},"340":{"position":[[192,1]]},"359":{"position":[[142,1]]},"409":{"position":[[72,1],[88,1]]},"444":{"position":[[543,1]]},"533":{"position":[[51,1]]},"544":{"position":[[103,1]]},"552":{"position":[[86,1]]},"574":{"position":[[57,1]]},"617":{"position":[[83,1]]},"653":{"position":[[107,1],[193,1]]},"661":{"position":[[34,1],[61,1]]},"663":{"position":[[14,1]]},"666":{"position":[[171,1]]},"785":{"position":[[57,1]]},"872":{"position":[[134,1],[197,1],[454,1]]},"959":{"position":[[6,1]]}}}],["能力",{"_index":1041,"t":{"138":{"position":[[416,2]]},"151":{"position":[[89,2]]}}}],["能够",{"_index":786,"t":{"110":{"position":[[12,2]]},"199":{"position":[[39,2]]},"299":{"position":[[12,2]]},"328":{"position":[[11,2]]},"334":{"position":[[30,2],[66,2]]},"521":{"position":[[74,2]]},"530":{"position":[[501,2]]},"668":{"position":[[55,2]]},"854":{"position":[[107,2]]},"976":{"position":[[57,2]]},"978":{"position":[[0,2]]}}}],["臂",{"_index":2013,"t":{"418":{"position":[[71,1]]}}}],["自制",{"_index":1558,"t":{"288":{"position":[[60,2]]}}}],["自动",{"_index":1274,"t":{"184":{"position":[[616,2]]},"218":{"position":[[616,2]]},"340":{"position":[[752,2]]},"440":{"position":[[171,2],[194,2]]},"447":{"position":[[860,2]]},"493":{"position":[[21,2]]},"542":{"position":[[91,2]]},"561":{"position":[[418,2]]},"750":{"position":[[239,2],[530,2]]},"754":{"position":[[26,2]]},"967":{"position":[[68,2]]}}}],["自动化",{"_index":2543,"t":{"542":{"position":[[132,3]]}}}],["自定义",{"_index":425,"t":{"48":{"position":[[10,3]]},"57":{"position":[[350,3]]},"118":{"position":[[2,3]]},"166":{"position":[[2,3]]},"182":{"position":[[24,3]]},"205":{"position":[[2,3]]},"214":{"position":[[24,3]]},"252":{"position":[[2,3]]},"295":{"position":[[11,3]]},"301":{"position":[[1979,3],[2065,3],[2155,3],[2247,3]]},"304":{"position":[[3,3]]},"308":{"position":[[335,3],[648,3],[768,3],[887,3]]},"319":{"position":[[76,3]]},"340":{"position":[[578,3],[781,3]]},"347":{"position":[[341,3],[656,3]]},"357":{"position":[[0,3],[134,3]]},"363":{"position":[[0,3]]},"402":{"position":[[16,3]]},"427":{"position":[[55,3]]},"431":{"position":[[0,3]]},"440":{"position":[[165,3],[188,3],[226,3]]},"444":{"position":[[167,3]]},"449":{"position":[[89,3]]},"500":{"position":[[15,3]]},"568":{"position":[[11,3]]},"574":{"position":[[79,3]]},"615":{"position":[[108,3]]},"630":{"position":[[112,3]]},"679":{"position":[[151,3]]},"684":{"position":[[4,3]]},"738":{"position":[[120,3]]},"778":{"position":[[23,3],[145,3],[168,3],[180,3]]},"783":{"position":[[27,3]]},"792":{"position":[[23,3],[183,3]]},"872":{"position":[[254,3]]},"874":{"position":[[74,3]]},"913":{"position":[[28,3]]},"919":{"position":[[9,3]]},"944":{"position":[[0,3]]},"961":{"position":[[259,3]]},"969":{"position":[[198,3]]}}}],["自己",{"_index":157,"t":{"20":{"position":[[67,2]]},"48":{"position":[[19,2]]},"104":{"position":[[194,2]]},"120":{"position":[[484,2]]},"184":{"position":[[661,2]]},"218":{"position":[[661,2]]},"223":{"position":[[662,2]]},"347":{"position":[[960,2]]},"359":{"position":[[0,2]]},"361":{"position":[[1173,2]]},"365":{"position":[[67,2]]},"431":{"position":[[28,2]]},"447":{"position":[[21,2]]},"455":{"position":[[38,2],[62,2]]},"485":{"position":[[33,2],[247,2]]},"505":{"position":[[25,2]]},"526":{"position":[[216,2]]},"574":{"position":[[20,2]]},"691":{"position":[[372,2]]},"758":{"position":[[94,2]]}}}],["自带",{"_index":2074,"t":{"436":{"position":[[2014,2]]}}}],["自由",{"_index":493,"t":{"55":{"position":[[2,2]]},"270":{"position":[[2,2]]},"306":{"position":[[2,2]]},"345":{"position":[[2,2]]},"455":{"position":[[1025,2]]},"610":{"position":[[350,2]]},"615":{"position":[[63,2]]},"826":{"position":[[180,2]]}}}],["自由度",{"_index":1603,"t":{"299":{"position":[[2,3]]}}}],["自行",{"_index":11,"t":{"3":{"position":[[38,2]]},"57":{"position":[[708,2]]},"132":{"position":[[313,2]]},"263":{"position":[[20,2]]},"340":{"position":[[801,2]]},"359":{"position":[[126,2]]},"440":{"position":[[233,2]]},"473":{"position":[[34,2],[43,2]]},"530":{"position":[[542,2]]},"691":{"position":[[77,2]]},"748":{"position":[[248,2]]},"774":{"position":[[27,2]]},"780":{"position":[[144,2]]}}}],["自身",{"_index":3092,"t":{"783":{"position":[[333,2]]},"790":{"position":[[38,2]]},"814":{"position":[[5,2]]}}}],["至于",{"_index":3106,"t":{"787":{"position":[[79,2]]}}}],["至关重要",{"_index":2816,"t":{"677":{"position":[[24,4]]}}}],["至少",{"_index":1600,"t":{"297":{"position":[[260,2],[332,2]]}}}],["舔",{"_index":1852,"t":{"370":{"position":[[184,1]]}}}],["节",{"_index":1632,"t":{"304":{"position":[[31,1]]}}}],["节约",{"_index":1233,"t":{"184":{"position":[[77,2]]},"218":{"position":[[77,2]]},"546":{"position":[[68,2]]}}}],["英文",{"_index":2544,"t":{"542":{"position":[[146,2]]}}}],["范围",{"_index":49,"t":{"7":{"position":[[19,2]]},"184":{"position":[[375,2]]},"218":{"position":[[375,2]]},"702":{"position":[[1564,2],[1657,2]]},"830":{"position":[[619,2]]}}}],["茗",{"_index":17,"t":{"5":{"position":[[18,1],[38,1]]},"16":{"position":[[68,1]]},"18":{"position":[[50,1]]},"94":{"position":[[31,1]]},"436":{"position":[[959,1]]},"507":{"position":[[1808,1]]},"699":{"position":[[11,1]]},"935":{"position":[[146,1]]},"973":{"position":[[22,1]]}}}],["获取",{"_index":12,"t":{"3":{"position":[[40,2]]},"64":{"position":[[0,2]]},"66":{"position":[[7,2]]},"73":{"position":[[0,2]]},"75":{"position":[[7,2]]},"84":{"position":[[0,2]]},"86":{"position":[[7,2],[50,2]]},"91":{"position":[[348,2]]},"142":{"position":[[2,2],[517,2]]},"184":{"position":[[654,2]]},"218":{"position":[[654,2]]},"225":{"position":[[569,2]]},"239":{"position":[[5,2],[38,2],[190,2],[213,2],[262,2]]},"292":{"position":[[21,2]]},"308":{"position":[[1634,2]]},"361":{"position":[[660,2]]},"376":{"position":[[1248,2]]},"411":{"position":[[26,2]]},"413":{"position":[[26,2]]},"512":{"position":[[449,2]]},"521":{"position":[[278,2]]},"528":{"position":[[837,2],[1535,2]]},"530":{"position":[[38,2],[97,2],[426,2],[503,2],[1016,2]]},"544":{"position":[[84,2]]},"554":{"position":[[94,2]]},"579":{"position":[[50,2],[70,2]]},"581":{"position":[[1,2]]},"639":{"position":[[78,2]]},"691":{"position":[[45,2]]},"702":{"position":[[2305,2]]},"727":{"position":[[289,2],[346,2],[360,2]]},"734":{"position":[[507,2]]},"822":{"position":[[84,2]]},"828":{"position":[[255,2],[279,2]]},"830":{"position":[[258,2],[569,2],[590,2],[641,2]]},"832":{"position":[[1763,2]]},"857":{"position":[[210,2]]},"859":{"position":[[109,2]]},"874":{"position":[[185,2]]},"878":{"position":[[46,2],[102,2]]},"880":{"position":[[193,2]]},"882":{"position":[[283,2]]},"891":{"position":[[125,2]]},"932":{"position":[[287,2]]}}}],["获取信息",{"_index":2642,"t":{"579":{"position":[[42,4]]}}}],["获取数据",{"_index":1156,"t":{"159":{"position":[[316,4]]},"530":{"position":[[119,4]]}}}],["获得",{"_index":52,"t":{"7":{"position":[[30,2],[103,2],[117,2]]},"34":{"position":[[283,2]]},"91":{"position":[[499,2]]},"235":{"position":[[1172,2],[1244,2]]},"284":{"position":[[26,2]]},"286":{"position":[[23,2]]},"447":{"position":[[917,2]]},"512":{"position":[[469,2]]},"554":{"position":[[287,2]]},"639":{"position":[[88,2]]},"641":{"position":[[82,2]]},"830":{"position":[[310,2],[574,2]]},"882":{"position":[[140,2]]},"969":{"position":[[65,2]]}}}],["蒋",{"_index":1876,"t":{"370":{"position":[[308,1]]}}}],["薄弱",{"_index":794,"t":{"110":{"position":[[117,2]]}}}],["虽然",{"_index":1101,"t":{"153":{"position":[[99,2]]},"184":{"position":[[115,2]]},"218":{"position":[[115,2]]},"290":{"position":[[1012,2]]},"548":{"position":[[15,2]]}}}],["蚕食",{"_index":3014,"t":{"738":{"position":[[129,2]]}}}],["行为",{"_index":2176,"t":{"447":{"position":[[1268,2]]},"617":{"position":[[271,2]]},"859":{"position":[[1064,2]]}}}],["行使",{"_index":164,"t":{"23":{"position":[[11,2]]}}}],["衍生",{"_index":77,"t":{"7":{"position":[[146,2]]}}}],["补充",{"_index":482,"t":{"53":{"position":[[18,2]]},"909":{"position":[[78,2]]}}}],["表明",{"_index":565,"t":{"57":{"position":[[1036,2]]},"272":{"position":[[759,2]]},"308":{"position":[[1397,2]]},"451":{"position":[[67,2]]},"455":{"position":[[551,2]]}}}],["表格",{"_index":3408,"t":{"935":{"position":[[93,2]]}}}],["表示",{"_index":1339,"t":{"184":{"position":[[1564,2],[1584,2]]},"194":{"position":[[187,2],[470,2]]},"218":{"position":[[1564,2],[1584,2]]},"233":{"position":[[190,2],[476,2]]},"272":{"position":[[951,2]]},"281":{"position":[[14,2],[39,2]]},"301":{"position":[[1378,2]]},"308":{"position":[[1145,2]]},"359":{"position":[[32,2],[58,2],[69,2],[80,2]]},"473":{"position":[[264,2]]},"570":{"position":[[115,2]]},"691":{"position":[[253,2]]},"697":{"position":[[30,2]]},"702":{"position":[[1338,2]]},"734":{"position":[[224,2]]},"748":{"position":[[155,2],[172,2],[261,2],[290,2],[326,2],[388,2]]},"761":{"position":[[16,2]]},"774":{"position":[[301,2]]},"857":{"position":[[344,2],[384,2],[427,2]]},"859":{"position":[[238,2],[278,2],[321,2]]}}}],["表象",{"_index":2463,"t":{"526":{"position":[[258,2]]}}}],["表达式",{"_index":2349,"t":{"503":{"position":[[35,3]]}}}],["表面",{"_index":2226,"t":{"455":{"position":[[772,2]]}}}],["被动",{"_index":2671,"t":{"595":{"position":[[155,2]]}}}],["装",{"_index":2901,"t":{"702":{"position":[[1356,1]]}}}],["装箱",{"_index":1919,"t":{"378":{"position":[[74,2]]}}}],["装置",{"_index":2885,"t":{"702":{"position":[[972,2],[1342,2]]}}}],["要",{"_index":273,"t":{"34":{"position":[[25,1],[126,1]]},"120":{"position":[[1016,1],[2177,1]]},"184":{"position":[[973,1],[985,1],[1752,1],[1764,1]]},"207":{"position":[[367,1]]},"218":{"position":[[973,1],[985,1],[1752,1],[1764,1]]},"365":{"position":[[1279,1]]},"463":{"position":[[230,1]]},"470":{"position":[[640,1]]},"487":{"position":[[9,1]]},"530":{"position":[[531,1]]},"657":{"position":[[16,1]]},"689":{"position":[[43,1]]}}}],["要么",{"_index":2513,"t":{"535":{"position":[[20,2],[28,2]]}}}],["要命",{"_index":2117,"t":{"444":{"position":[[294,2]]}}}],["要求",{"_index":1670,"t":{"328":{"position":[[4,2]]},"383":{"position":[[4,2]]},"427":{"position":[[17,2]]},"440":{"position":[[252,2]]},"449":{"position":[[50,2]]},"505":{"position":[[63,2]]},"574":{"position":[[182,2]]},"586":{"position":[[4,2]]},"588":{"position":[[9,2]]},"595":{"position":[[138,2]]},"597":{"position":[[198,2]]},"615":{"position":[[119,2]]},"679":{"position":[[251,2]]},"778":{"position":[[47,2]]},"901":{"position":[[4,2]]},"906":{"position":[[19,2]]}}}],["覆盖",{"_index":1577,"t":{"290":{"position":[[788,2],[1262,2]]}}}],["见",{"_index":2418,"t":{"521":{"position":[[111,1]]},"872":{"position":[[590,1],[1018,1]]}}}],["规则",{"_index":1671,"t":{"328":{"position":[[26,2],[33,2]]},"864":{"position":[[42,2]]},"866":{"position":[[19,2],[63,2]]}}}],["规定",{"_index":2308,"t":{"487":{"position":[[90,2]]},"748":{"position":[[137,2]]},"963":{"position":[[13,2]]},"965":{"position":[[13,2]]}}}],["规范",{"_index":278,"t":{"34":{"position":[[59,2]]},"265":{"position":[[13,2]]},"498":{"position":[[14,2]]},"617":{"position":[[6,2]]},"909":{"position":[[80,2]]}}}],["视为",{"_index":1179,"t":{"164":{"position":[[132,2]]},"250":{"position":[[132,2]]},"697":{"position":[[86,2]]}}}],["视图",{"_index":3365,"t":{"906":{"position":[[167,2],[188,2]]}}}],["觉得",{"_index":2106,"t":{"444":{"position":[[23,2]]}}}],["解",{"_index":1359,"t":{"194":{"position":[[39,1]]},"233":{"position":[[39,1]]},"542":{"position":[[117,1]]}}}],["解决",{"_index":1161,"t":{"159":{"position":[[595,2]]},"180":{"position":[[35,2]]},"184":{"position":[[974,2],[1753,2]]},"212":{"position":[[105,2]]},"218":{"position":[[974,2],[1753,2]]},"334":{"position":[[36,2]]},"336":{"position":[[99,2]]},"402":{"position":[[4,2]]},"431":{"position":[[12,2]]},"503":{"position":[[9,2],[111,2]]},"666":{"position":[[174,2]]},"668":{"position":[[57,2]]},"743":{"position":[[81,2]]},"906":{"position":[[90,2],[106,2]]},"976":{"position":[[44,2]]}}}],["解决方案",{"_index":2161,"t":{"447":{"position":[[739,4]]},"503":{"position":[[69,4]]}}}],["解包",{"_index":2267,"t":{"468":{"position":[[68,2],[103,2]]},"507":{"position":[[2203,2]]}}}],["解压",{"_index":2711,"t":{"610":{"position":[[241,2]]},"718":{"position":[[108,2]]}}}],["解密",{"_index":1738,"t":{"350":{"position":[[104,2],[172,2]]}}}],["解封",{"_index":1774,"t":{"361":{"position":[[1067,2]]},"468":{"position":[[12,2]]}}}],["解析",{"_index":230,"t":{"28":{"position":[[60,2],[89,2],[105,2],[142,2]]},"34":{"position":[[127,2],[166,2]]},"57":{"position":[[894,2],[1070,2]]},"180":{"position":[[45,2]]},"182":{"position":[[29,2],[35,2]]},"212":{"position":[[115,2]]},"214":{"position":[[29,2],[35,2]]},"272":{"position":[[982,2],[986,2]]},"297":{"position":[[108,2]]},"299":{"position":[[21,2]]},"301":{"position":[[332,2],[357,2],[383,2],[588,2],[1065,2],[1073,2],[1154,2],[1206,2]]},"304":{"position":[[16,2],[113,2]]},"308":{"position":[[2491,2]]},"336":{"position":[[63,2],[86,2],[184,2],[213,2]]},"340":{"position":[[160,2],[183,2],[255,2],[284,2]]},"343":{"position":[[8,2],[162,2]]},"347":{"position":[[998,2],[1461,2]]},"361":{"position":[[1053,2]]},"470":{"position":[[460,2]]},"487":{"position":[[74,2]]},"489":{"position":[[16,2]]},"542":{"position":[[93,2]]},"568":{"position":[[16,2]]},"729":{"position":[[88,2]]},"780":{"position":[[536,2]]},"809":{"position":[[15,2],[55,2]]},"872":{"position":[[260,2]]},"913":{"position":[[33,2],[39,2]]},"944":{"position":[[3,2]]},"957":{"position":[[35,2],[84,2],[93,2],[145,2]]}}}],["解析器",{"_index":1458,"t":{"257":{"position":[[15,3]]},"259":{"position":[[9,3],[15,3]]},"447":{"position":[[885,3]]},"514":{"position":[[2,3]]},"686":{"position":[[22,3]]},"891":{"position":[[63,3],[94,3],[149,3],[166,3],[201,3],[231,3],[283,3]]},"930":{"position":[[2,3]]},"932":{"position":[[2,3],[118,3],[122,3]]}}}],["解码",{"_index":1729,"t":{"347":{"position":[[1380,2]]}}}],["解释",{"_index":533,"t":{"57":{"position":[[465,2]]}}}],["触发",{"_index":166,"t":{"23":{"position":[[16,2]]},"25":{"position":[[362,2],[366,2]]},"57":{"position":[[786,2],[812,2]]},"118":{"position":[[36,2]]},"120":{"position":[[75,2]]},"159":{"position":[[250,2],[261,2]]},"166":{"position":[[40,2],[228,2],[314,2]]},"186":{"position":[[86,2],[118,2],[151,2],[178,2],[205,2],[252,2]]},"188":{"position":[[211,2]]},"196":{"position":[[314,2]]},"205":{"position":[[42,2],[111,2]]},"220":{"position":[[96,2],[125,2],[158,2],[185,2],[212,2],[259,2],[381,2]]},"241":{"position":[[267,2]]},"252":{"position":[[40,2],[228,2],[314,2]]},"284":{"position":[[444,2]]},"290":{"position":[[86,2],[91,2],[804,2],[1027,2]]},"393":{"position":[[221,2]]},"397":{"position":[[101,2]]},"470":{"position":[[443,2]]},"493":{"position":[[23,2]]},"514":{"position":[[14,2]]},"559":{"position":[[76,2]]},"570":{"position":[[13,2],[39,2],[72,2],[203,2]]},"572":{"position":[[23,2]]},"574":{"position":[[97,2],[188,2]]},"666":{"position":[[107,2]]},"802":{"position":[[14,2],[21,2]]},"828":{"position":[[311,2]]},"830":{"position":[[93,2],[152,2]]},"857":{"position":[[396,2],[438,2]]},"859":{"position":[[290,2],[332,2]]},"930":{"position":[[14,2]]}}}],["警告",{"_index":3304,"t":{"872":{"position":[[1121,2]]}}}],["计数器",{"_index":2316,"t":{"491":{"position":[[58,3]]}}}],["计时器",{"_index":2772,"t":{"657":{"position":[[18,3]]},"661":{"position":[[8,3],[50,3]]}}}],["计算",{"_index":931,"t":{"125":{"position":[[181,2]]},"304":{"position":[[67,2]]},"832":{"position":[[2032,2]]}}}],["计算方法",{"_index":2687,"t":{"600":{"position":[[25,4]]}}}],["计算机",{"_index":909,"t":{"125":{"position":[[44,3]]},"761":{"position":[[4,3]]}}}],["订阅",{"_index":713,"t":{"91":{"position":[[126,2]]},"235":{"position":[[215,2]]},"323":{"position":[[0,2]]},"389":{"position":[[31,2]]},"393":{"position":[[3,2]]},"397":{"position":[[93,2],[98,2]]},"617":{"position":[[128,2]]},"802":{"position":[[8,2]]},"828":{"position":[[219,2]]}}}],["认为",{"_index":3096,"t":{"785":{"position":[[82,2]]}}}],["认定",{"_index":2406,"t":{"516":{"position":[[187,2]]}}}],["记录",{"_index":1622,"t":{"301":{"position":[[1191,2]]},"473":{"position":[[27,2]]},"479":{"position":[[14,2],[38,2]]},"481":{"position":[[10,2]]},"639":{"position":[[41,2]]},"874":{"position":[[287,2]]}}}],["记录器",{"_index":2284,"t":{"475":{"position":[[8,3]]},"477":{"position":[[7,3]]},"479":{"position":[[5,3]]}}}],["许可",{"_index":56,"t":{"7":{"position":[[50,2]]}}}],["设",{"_index":1692,"t":{"338":{"position":[[62,1]]},"521":{"position":[[518,1]]},"745":{"position":[[564,1]]},"872":{"position":[[934,1]]}}}],["设定",{"_index":1454,"t":{"255":{"position":[[298,2]]},"516":{"position":[[102,2]]},"552":{"position":[[45,2]]},"689":{"position":[[15,2]]},"874":{"position":[[222,2]]},"882":{"position":[[75,2]]}}}],["设定值",{"_index":2017,"t":{"420":{"position":[[18,3]]},"741":{"position":[[75,3]]}}}],["设想",{"_index":2119,"t":{"444":{"position":[[308,2]]}}}],["设立",{"_index":2840,"t":{"689":{"position":[[44,2]]}}}],["设置",{"_index":402,"t":{"46":{"position":[[377,2],[394,2],[455,2]]},"50":{"position":[[17,2],[136,2],[170,2],[307,2]]},"57":{"position":[[187,2]]},"91":{"position":[[62,2]]},"132":{"position":[[282,2]]},"142":{"position":[[526,2]]},"164":{"position":[[23,2],[76,2],[107,2],[164,2],[191,2],[214,2]]},"173":{"position":[[153,2]]},"184":{"position":[[51,2],[298,2],[319,2],[381,2],[396,2],[476,2],[789,2],[873,2],[922,2],[1500,2],[1652,2],[1701,2],[1968,2]]},"207":{"position":[[391,2]]},"218":{"position":[[51,2],[298,2],[319,2],[381,2],[396,2],[476,2],[789,2],[873,2],[922,2],[1500,2],[1652,2],[1701,2],[1968,2]]},"225":{"position":[[740,2]]},"250":{"position":[[23,2],[76,2],[107,2],[164,2],[191,2],[214,2]]},"257":{"position":[[22,2]]},"259":{"position":[[22,2]]},"261":{"position":[[207,2],[431,2]]},"268":{"position":[[90,2],[158,2]]},"272":{"position":[[179,2]]},"290":{"position":[[55,2]]},"292":{"position":[[393,2]]},"301":{"position":[[149,2]]},"308":{"position":[[181,2],[1165,2]]},"319":{"position":[[39,2]]},"321":{"position":[[88,2]]},"338":{"position":[[16,2]]},"347":{"position":[[183,2]]},"376":{"position":[[904,2]]},"385":{"position":[[5,2]]},"406":{"position":[[44,2]]},"422":{"position":[[44,2]]},"455":{"position":[[503,2],[793,2]]},"546":{"position":[[59,2]]},"561":{"position":[[218,2]]},"570":{"position":[[178,2]]},"595":{"position":[[109,2]]},"617":{"position":[[162,2]]},"619":{"position":[[48,2]]},"655":{"position":[[366,2]]},"668":{"position":[[90,2]]},"686":{"position":[[20,2]]},"702":{"position":[[1455,2]]},"727":{"position":[[388,2],[469,2]]},"741":{"position":[[42,2],[69,2]]},"743":{"position":[[72,2]]},"745":{"position":[[44,2]]},"750":{"position":[[8,2],[241,2],[532,2],[588,2]]},"772":{"position":[[13,2]]},"814":{"position":[[73,2]]},"816":{"position":[[8,2],[435,2]]},"830":{"position":[[416,2],[434,2]]},"832":{"position":[[2048,2]]},"872":{"position":[[946,2]]},"882":{"position":[[149,2]]},"891":{"position":[[13,2]]},"906":{"position":[[199,2]]},"980":{"position":[[23,2]]}}}],["设计",{"_index":274,"t":{"34":{"position":[[26,2]]},"50":{"position":[[61,2]]},"159":{"position":[[8,2],[83,2]]},"194":{"position":[[14,2]]},"233":{"position":[[14,2]]},"328":{"position":[[29,2]]},"400":{"position":[[73,2]]},"455":{"position":[[985,2]]},"468":{"position":[[29,2]]},"485":{"position":[[249,2]]},"487":{"position":[[103,2]]},"505":{"position":[[54,2]]},"697":{"position":[[73,2]]},"729":{"position":[[58,2]]}}}],["访问",{"_index":972,"t":{"127":{"position":[[748,2]]},"166":{"position":[[371,2],[399,2]]},"252":{"position":[[371,2],[399,2]]},"376":{"position":[[20,2]]},"391":{"position":[[312,2]]},"411":{"position":[[39,2],[44,2]]},"413":{"position":[[34,2],[43,2],[123,2]]},"415":{"position":[[89,2]]},"577":{"position":[[4,2]]},"628":{"position":[[32,2]]},"729":{"position":[[16,2],[60,2]]},"830":{"position":[[401,2]]},"878":{"position":[[174,2]]},"925":{"position":[[651,2]]},"950":{"position":[[14,2]]}}}],["证书",{"_index":759,"t":{"104":{"position":[[38,2],[42,2],[190,2],[205,2]]},"288":{"position":[[65,2]]},"319":{"position":[[8,2],[79,2]]}}}],["试图",{"_index":1155,"t":{"159":{"position":[[299,2]]}}}],["试用",{"_index":1936,"t":{"389":{"position":[[65,2]]},"971":{"position":[[57,2]]}}}],["话",{"_index":245,"t":{"28":{"position":[[137,1]]},"34":{"position":[[47,1]]}}}],["该类",{"_index":946,"t":{"127":{"position":[[116,2]]},"512":{"position":[[44,2]]},"732":{"position":[[42,2]]},"894":{"position":[[44,2]]},"925":{"position":[[80,2]]},"928":{"position":[[54,2]]}}}],["该项",{"_index":2125,"t":{"444":{"position":[[389,2]]}}}],["详情",{"_index":146,"t":{"18":{"position":[[43,2]]},"64":{"position":[[6,2]]},"73":{"position":[[6,2]]},"84":{"position":[[6,2]]},"86":{"position":[[56,2]]},"94":{"position":[[24,2]]},"830":{"position":[[436,2]]},"872":{"position":[[588,2],[1016,2],[1102,2]]},"874":{"position":[[54,2]]},"876":{"position":[[48,2]]},"878":{"position":[[34,2]]},"880":{"position":[[35,2]]},"882":{"position":[[35,2]]},"884":{"position":[[29,2]]},"965":{"position":[[153,2]]}}}],["详细",{"_index":990,"t":{"134":{"position":[[60,2]]},"498":{"position":[[32,2]]},"528":{"position":[[107,2]]},"572":{"position":[[32,2]]},"648":{"position":[[1195,2]]},"787":{"position":[[183,2]]},"872":{"position":[[26,2]]},"935":{"position":[[87,2]]}}}],["语言",{"_index":495,"t":{"55":{"position":[[33,2]]},"114":{"position":[[17,2]]},"182":{"position":[[18,2]]},"203":{"position":[[16,2]]},"214":{"position":[[18,2]]},"270":{"position":[[35,2]]},"306":{"position":[[52,2]]},"345":{"position":[[32,2]]},"400":{"position":[[58,2],[70,2]]},"420":{"position":[[38,2]]},"705":{"position":[[60,2]]},"743":{"position":[[38,2]]},"756":{"position":[[7,2]]},"806":{"position":[[50,2],[82,2]]},"913":{"position":[[22,2]]},"978":{"position":[[13,2]]}}}],["误报",{"_index":2295,"t":{"485":{"position":[[223,2]]}}}],["说",{"_index":246,"t":{"28":{"position":[[138,1]]},"125":{"position":[[190,1]]},"184":{"position":[[932,1],[1711,1]]},"218":{"position":[[932,1],[1711,1]]},"677":{"position":[[36,1]]}}}],["说明",{"_index":371,"t":{"44":{"position":[[35,2]]},"57":{"position":[[793,2]]},"498":{"position":[[34,2]]},"542":{"position":[[178,2]]},"572":{"position":[[39,2]]},"707":{"position":[[130,2]]},"820":{"position":[[54,2]]},"906":{"position":[[12,2]]}}}],["请",{"_index":151,"t":{"20":{"position":[[33,1]]},"57":{"position":[[617,1]]},"91":{"position":[[486,1]]},"129":{"position":[[29,1]]},"134":{"position":[[1483,1],[1981,1]]},"166":{"position":[[269,1],[575,1]]},"196":{"position":[[75,1]]},"241":{"position":[[473,1]]},"252":{"position":[[269,1],[575,1]]},"297":{"position":[[143,1],[235,1],[307,1]]},"301":{"position":[[389,1],[494,1],[594,1]]},"461":{"position":[[39,1]]},"473":{"position":[[297,1]]},"528":{"position":[[106,1]]},"699":{"position":[[18,1]]},"716":{"position":[[135,1]]},"756":{"position":[[10,1]]},"830":{"position":[[582,1]]},"870":{"position":[[34,1],[199,1]]},"872":{"position":[[25,1]]},"878":{"position":[[301,1]]},"969":{"position":[[2,1]]},"973":{"position":[[13,1]]}}}],["请参阅",{"_index":2340,"t":{"498":{"position":[[36,3]]}}}],["请求",{"_index":308,"t":{"34":{"position":[[251,2]]},"69":{"position":[[50,2],[165,2],[171,2]]},"97":{"position":[[24,2]]},"106":{"position":[[17,2]]},"118":{"position":[[96,2],[114,2],[134,2],[152,2],[212,2]]},"120":{"position":[[384,2],[556,2]]},"125":{"position":[[48,2]]},"127":{"position":[[707,2]]},"146":{"position":[[85,2]]},"166":{"position":[[308,2]]},"252":{"position":[[308,2]]},"284":{"position":[[36,2]]},"290":{"position":[[600,2]]},"343":{"position":[[62,2]]},"512":{"position":[[788,2],[915,2],[998,2],[1171,2]]},"528":{"position":[[783,2]]},"593":{"position":[[31,2]]},"630":{"position":[[8,2],[32,2],[38,2]]},"634":{"position":[[8,2]]},"641":{"position":[[387,2]]},"643":{"position":[[271,2]]},"653":{"position":[[94,2],[166,2],[179,2],[199,2],[246,2]]},"663":{"position":[[23,2]]},"794":{"position":[[40,2],[58,2]]},"820":{"position":[[14,2]]},"830":{"position":[[43,2],[76,2],[192,2],[196,2],[206,2],[248,2],[346,2]]},"832":{"position":[[621,2],[643,2],[665,2],[877,2],[920,2],[1920,2]]},"859":{"position":[[1173,2]]},"878":{"position":[[194,2],[536,2],[558,2],[726,2],[774,2]]},"917":{"position":[[42,2],[59,2]]}}}],["请求者",{"_index":1715,"t":{"343":{"position":[[58,3]]}}}],["读",{"_index":1721,"t":{"347":{"position":[[965,1]]},"411":{"position":[[49,1]]},"561":{"position":[[10,1]]},"626":{"position":[[34,1]]}}}],["读写",{"_index":3315,"t":{"876":{"position":[[116,2]]}}}],["读取",{"_index":519,"t":{"57":{"position":[[241,2]]},"157":{"position":[[294,2],[323,2]]},"272":{"position":[[233,2]]},"301":{"position":[[203,2],[1428,2]]},"308":{"position":[[235,2]]},"347":{"position":[[237,2],[1014,2]]},"409":{"position":[[79,2]]},"411":{"position":[[37,2],[63,2]]},"507":{"position":[[878,2]]},"561":{"position":[[220,2]]},"628":{"position":[[113,2]]},"636":{"position":[[7,2]]},"868":{"position":[[173,2]]}}}],["读取数据",{"_index":1976,"t":{"406":{"position":[[99,4]]},"422":{"position":[[89,4]]},"745":{"position":[[89,4]]},"980":{"position":[[57,4]]}}}],["读数据",{"_index":1724,"t":{"347":{"position":[[1009,3]]}}}],["调度",{"_index":1318,"t":{"184":{"position":[[1133,2],[1912,2]]},"218":{"position":[[1133,2],[1912,2]]}}}],["调整",{"_index":3260,"t":{"866":{"position":[[49,2]]},"868":{"position":[[223,2],[238,2]]},"870":{"position":[[186,2]]},"872":{"position":[[465,2],[542,2],[585,2],[598,2],[649,2],[685,2],[746,2],[765,2],[793,2],[818,2],[847,2],[882,2],[907,2],[1013,2]]}}}],["调用",{"_index":343,"t":{"40":{"position":[[46,2]]},"60":{"position":[[2,2],[104,2],[203,2],[474,2]]},"62":{"position":[[2,2],[15,2]]},"66":{"position":[[97,2],[259,2]]},"69":{"position":[[2,2],[40,2],[111,2],[548,2],[689,2]]},"71":{"position":[[2,2],[15,2]]},"75":{"position":[[97,2],[185,2]]},"78":{"position":[[12,2],[32,2],[76,2],[190,2],[303,2]]},"80":{"position":[[30,2]]},"82":{"position":[[2,2],[15,2]]},"86":{"position":[[142,2],[381,2]]},"125":{"position":[[30,2],[200,2],[208,2],[236,2],[249,2]]},"127":{"position":[[2,2],[753,2]]},"132":{"position":[[2,2],[252,2],[262,2],[274,2],[284,2],[293,2],[342,2]]},"134":{"position":[[2,2],[31,2],[84,2],[321,2],[398,2],[657,2],[734,2],[1159,2],[1236,2],[2351,2],[2428,2],[3438,2]]},"136":{"position":[[35,2]]},"138":{"position":[[182,2],[211,2]]},"140":{"position":[[156,2],[223,2]]},"142":{"position":[[217,2],[512,2],[528,2]]},"146":{"position":[[4,2],[58,2]]},"159":{"position":[[631,2],[940,2]]},"184":{"position":[[935,2],[1714,2]]},"186":{"position":[[143,2],[318,2]]},"196":{"position":[[32,2],[292,2]]},"218":{"position":[[935,2],[1714,2]]},"220":{"position":[[150,2],[325,2]]},"239":{"position":[[194,2]]},"241":{"position":[[35,2],[245,2]]},"261":{"position":[[185,2]]},"290":{"position":[[37,2]]},"413":{"position":[[98,2]]},"415":{"position":[[30,2],[121,2]]},"440":{"position":[[182,2],[209,2],[219,2],[247,2]]},"442":{"position":[[44,2],[59,2],[73,2],[76,2],[90,2],[139,2]]},"444":{"position":[[417,2]]},"447":{"position":[[49,2],[893,2]]},"449":{"position":[[162,2],[255,2]]},"451":{"position":[[14,2]]},"455":{"position":[[73,2],[604,2],[795,2],[1035,2]]},"470":{"position":[[216,2]]},"491":{"position":[[32,2]]},"498":{"position":[[115,2]]},"500":{"position":[[43,2]]},"512":{"position":[[432,2],[451,2]]},"514":{"position":[[17,2],[93,2],[112,2],[499,2],[514,2]]},"516":{"position":[[75,2],[90,2],[142,2],[190,2],[195,2]]},"537":{"position":[[530,2]]},"539":{"position":[[45,2]]},"542":{"position":[[21,2]]},"561":{"position":[[483,2]]},"574":{"position":[[272,2]]},"595":{"position":[[168,2]]},"630":{"position":[[66,2]]},"634":{"position":[[13,2]]},"639":{"position":[[20,2],[31,2],[73,2]]},"641":{"position":[[221,2]]},"646":{"position":[[7,2]]},"653":{"position":[[4,2],[9,2],[263,2]]},"657":{"position":[[0,2]]},"661":{"position":[[4,2],[41,2],[351,2]]},"663":{"position":[[57,2],[169,2]]},"672":{"position":[[619,2]]},"674":{"position":[[834,2]]},"677":{"position":[[56,2]]},"681":{"position":[[32,2],[43,2]]},"691":{"position":[[9,2],[212,2]]},"736":{"position":[[330,2],[337,2]]},"738":{"position":[[35,2],[39,2],[101,2],[112,2]]},"752":{"position":[[86,2]]},"776":{"position":[[81,2]]},"792":{"position":[[78,2],[98,2],[104,2],[109,2],[124,2],[140,2],[196,2],[217,2]]},"830":{"position":[[586,2]]},"834":{"position":[[20,2]]},"841":{"position":[[47,2],[74,2]]},"857":{"position":[[192,2]]},"859":{"position":[[91,2]]},"862":{"position":[[13,2]]},"864":{"position":[[16,2],[59,2]]},"868":{"position":[[57,2],[100,2]]},"880":{"position":[[195,2],[210,2],[230,2]]},"882":{"position":[[61,2]]},"884":{"position":[[289,2]]},"894":{"position":[[384,2]]},"917":{"position":[[63,2]]},"919":{"position":[[30,2]]},"925":{"position":[[159,2],[163,2]]},"930":{"position":[[17,2]]},"932":{"position":[[141,2]]},"971":{"position":[[69,2]]}}}],["调用者",{"_index":2535,"t":{"542":{"position":[[41,3]]},"639":{"position":[[90,3]]},"641":{"position":[[97,3]]},"663":{"position":[[74,3],[87,3]]},"734":{"position":[[509,3]]}}}],["调试",{"_index":2511,"t":{"535":{"position":[[0,2],[14,2],[59,2]]}}}],["谢幕",{"_index":1860,"t":{"370":{"position":[[220,2]]}}}],["负责",{"_index":807,"t":{"116":{"position":[[70,2]]},"184":{"position":[[1026,2],[1805,2]]},"216":{"position":[[68,2]]},"218":{"position":[[1026,2],[1805,2]]},"248":{"position":[[137,2]]},"787":{"position":[[68,2]]}}}],["贡献者",{"_index":19,"t":{"5":{"position":[[22,3]]}}}],["账号密码",{"_index":1456,"t":{"255":{"position":[[309,4]]}}}],["购买",{"_index":143,"t":{"18":{"position":[[29,2],[84,2]]},"935":{"position":[[73,2]]},"969":{"position":[[57,2]]},"973":{"position":[[0,2],[10,2]]}}}],["购买者",{"_index":3437,"t":{"963":{"position":[[5,3],[15,3]]},"965":{"position":[[5,3],[15,3],[27,3],[56,3],[72,3],[105,3]]}}}],["贯穿",{"_index":216,"t":{"28":{"position":[[17,2]]},"149":{"position":[[53,2]]}}}],["费用",{"_index":66,"t":{"7":{"position":[[86,2]]}}}],["资源",{"_index":2004,"t":{"415":{"position":[[65,2]]},"528":{"position":[[785,2]]},"878":{"position":[[43,2]]},"880":{"position":[[336,2]]}}}],["资源管理",{"_index":2659,"t":{"586":{"position":[[43,4]]}}}],["赋值",{"_index":332,"t":{"38":{"position":[[19,2]]},"40":{"position":[[72,2],[310,2]]},"44":{"position":[[28,2],[60,2]]},"46":{"position":[[348,2]]},"48":{"position":[[47,2],[222,2],[320,2]]},"57":{"position":[[405,2],[899,2],[1031,2]]},"134":{"position":[[1492,2],[1990,2]]},"272":{"position":[[754,2]]},"288":{"position":[[317,2]]},"301":{"position":[[1868,2]]},"308":{"position":[[390,2],[1392,2]]},"347":{"position":[[396,2],[941,2],[1480,2]]},"378":{"position":[[32,2]]},"436":{"position":[[889,2]]},"655":{"position":[[22,2]]},"659":{"position":[[26,2]]},"661":{"position":[[151,2]]},"686":{"position":[[139,2]]}}}],["赠品",{"_index":3428,"t":{"961":{"position":[[232,2]]}}}],["起始",{"_index":1525,"t":{"272":{"position":[[761,2],[1081,2]]}}}],["起来",{"_index":3065,"t":{"761":{"position":[[185,2]]},"780":{"position":[[2,2]]}}}],["超",{"_index":1219,"t":{"180":{"position":[[62,1]]},"212":{"position":[[132,1]]}}}],["超出",{"_index":2795,"t":{"666":{"position":[[94,2]]}}}],["超大",{"_index":2732,"t":{"628":{"position":[[9,2]]},"794":{"position":[[80,2]]},"872":{"position":[[382,2]]},"952":{"position":[[0,2]]}}}],["超时",{"_index":461,"t":{"50":{"position":[[134,2],[199,2],[218,2]]},"132":{"position":[[286,2]]},"134":{"position":[[323,2],[659,2],[1161,2],[2353,2]]},"164":{"position":[[27,2]]},"250":{"position":[[27,2]]},"340":{"position":[[901,2]]},"442":{"position":[[83,2]]},"561":{"position":[[222,2]]},"581":{"position":[[125,2]]},"792":{"position":[[106,2]]},"832":{"position":[[2050,2]]},"868":{"position":[[105,2]]},"874":{"position":[[220,2]]}}}],["超过",{"_index":484,"t":{"53":{"position":[[39,2]]},"184":{"position":[[127,2]]},"218":{"position":[[127,2]]},"361":{"position":[[775,2]]},"365":{"position":[[1750,2]]},"465":{"position":[[261,2]]}}}],["超长",{"_index":1765,"t":{"361":{"position":[[704,2]]},"365":{"position":[[1679,2]]}}}],["超高",{"_index":3279,"t":{"872":{"position":[[199,2]]}}}],["越",{"_index":1363,"t":{"194":{"position":[[208,1],[211,1]]},"233":{"position":[[211,1],[214,1]]},"570":{"position":[[130,1]]}}}],["跨",{"_index":801,"t":{"114":{"position":[[16,1]]},"120":{"position":[[382,1],[493,1]]},"182":{"position":[[17,1]]},"203":{"position":[[15,1]]},"214":{"position":[[17,1]]},"400":{"position":[[57,1]]},"420":{"position":[[37,1],[41,1]]},"743":{"position":[[37,1],[41,1]]},"806":{"position":[[49,1],[81,1]]},"913":{"position":[[21,1]]}}}],["跨平台",{"_index":800,"t":{"114":{"position":[[12,3]]},"182":{"position":[[13,3]]},"203":{"position":[[11,3]]},"214":{"position":[[13,3]]},"913":{"position":[[17,3]]}}}],["跨越",{"_index":170,"t":{"23":{"position":[[31,2]]},"125":{"position":[[123,2]]}}}],["路径",{"_index":690,"t":{"80":{"position":[[1805,2]]},"164":{"position":[[217,2]]},"250":{"position":[[217,2]]},"447":{"position":[[221,2]]},"514":{"position":[[365,2]]},"528":{"position":[[787,2],[816,2]]},"830":{"position":[[356,2],[386,2],[403,2],[480,2]]},"832":{"position":[[1875,2],[1922,2]]}}}],["路由",{"_index":663,"t":{"78":{"position":[[64,2]]},"120":{"position":[[352,2],[490,2]]},"146":{"position":[[95,2]]},"166":{"position":[[420,2]]},"252":{"position":[[420,2]]},"284":{"position":[[20,2]]},"286":{"position":[[46,2]]},"516":{"position":[[99,2],[104,2],[518,2]]},"530":{"position":[[150,2]]},"693":{"position":[[50,2]]},"836":{"position":[[50,2],[77,2],[88,2]]},"862":{"position":[[33,2],[55,2]]},"864":{"position":[[40,2]]},"882":{"position":[[327,2]]},"894":{"position":[[165,2]]}}}],["转",{"_index":1066,"t":{"142":{"position":[[559,1]]}}}],["转为",{"_index":518,"t":{"57":{"position":[[228,2]]},"272":{"position":[[220,2]]},"292":{"position":[[40,2]]},"301":{"position":[[190,2]]},"308":{"position":[[222,2]]},"321":{"position":[[9,2]]},"347":{"position":[[224,2]]}}}],["转写",{"_index":2141,"t":{"444":{"position":[[603,2],[687,2],[694,2]]}}}],["转化",{"_index":2030,"t":{"431":{"position":[[3,2]]}}}],["转发",{"_index":1073,"t":{"146":{"position":[[102,2]]},"166":{"position":[[418,2]]},"252":{"position":[[418,2]]},"328":{"position":[[13,2],[31,2]]},"533":{"position":[[13,2],[39,2],[63,2]]},"535":{"position":[[36,2],[79,2]]},"537":{"position":[[234,2],[251,2],[320,2],[512,2],[980,2]]},"539":{"position":[[27,2],[181,2]]},"884":{"position":[[169,2]]},"901":{"position":[[26,2]]},"940":{"position":[[0,2]]}}}],["转换",{"_index":1701,"t":{"340":{"position":[[601,2]]},"393":{"position":[[207,2]]},"447":{"position":[[959,2]]},"606":{"position":[[9,2],[113,2]]}}}],["转换器",{"_index":2033,"t":{"431":{"position":[[47,3],[700,3],[853,3]]}}}],["轮询",{"_index":2681,"t":{"597":{"position":[[37,2]]},"884":{"position":[[145,2]]},"938":{"position":[[0,2]]}}}],["软件",{"_index":1743,"t":{"353":{"position":[[28,2]]},"806":{"position":[[116,2]]},"963":{"position":[[36,2]]},"965":{"position":[[42,2]]}}}],["软件开发",{"_index":3355,"t":{"899":{"position":[[3,4]]}}}],["轻松",{"_index":2018,"t":{"420":{"position":[[32,2]]}}}],["轻量",{"_index":2360,"t":{"505":{"position":[[51,2]]}}}],["轻量级",{"_index":2243,"t":{"461":{"position":[[16,3]]}}}],["载体",{"_index":2399,"t":{"514":{"position":[[25,2]]},"930":{"position":[[25,2]]}}}],["载入",{"_index":576,"t":{"57":{"position":[[1791,2]]},"188":{"position":[[526,2]]},"192":{"position":[[407,2]]},"223":{"position":[[743,2]]},"225":{"position":[[1079,2],[1633,2]]},"229":{"position":[[335,2]]},"272":{"position":[[1589,2]]},"301":{"position":[[2718,2]]},"308":{"position":[[2197,2]]},"347":{"position":[[2362,2]]},"406":{"position":[[329,2]]},"422":{"position":[[342,2]]},"495":{"position":[[330,2]]},"561":{"position":[[728,2]]},"630":{"position":[[110,2],[250,2]]},"736":{"position":[[473,2]]},"745":{"position":[[342,2]]},"857":{"position":[[135,2]]},"859":{"position":[[789,2]]},"980":{"position":[[310,2]]}}}],["载荷",{"_index":2309,"t":{"487":{"position":[[132,2]]},"748":{"position":[[269,2],[298,2],[334,2],[491,2]]},"783":{"position":[[136,2]]},"820":{"position":[[253,2]]}}}],["较",{"_index":1230,"t":{"184":{"position":[[62,1]]},"218":{"position":[[62,1]]},"268":{"position":[[92,1]]},"440":{"position":[[178,1],[223,1]]},"718":{"position":[[200,1]]}}}],["较大",{"_index":1234,"t":{"184":{"position":[[88,2]]},"218":{"position":[[88,2]]}}}],["较慢",{"_index":2953,"t":{"718":{"position":[[67,2]]}}}],["辅助",{"_index":1045,"t":{"140":{"position":[[18,2],[67,2]]},"142":{"position":[[550,2]]},"528":{"position":[[426,2]]},"530":{"position":[[824,2]]},"623":{"position":[[61,2]]},"776":{"position":[[18,2]]}}}],["输入",{"_index":726,"t":{"91":{"position":[[487,2]]},"447":{"position":[[908,2]]},"470":{"position":[[618,2]]},"714":{"position":[[35,2]]}}}],["输出",{"_index":714,"t":{"91":{"position":[[132,2]]},"470":{"position":[[636,2],[785,2]]},"473":{"position":[[36,2],[242,2],[272,2],[279,2],[289,2]]},"475":{"position":[[20,2]]},"832":{"position":[[2076,2]]},"872":{"position":[[640,2]]},"880":{"position":[[127,2]]}}}],["输电",{"_index":2870,"t":{"702":{"position":[[101,2]]}}}],["达",{"_index":1391,"t":{"212":{"position":[[62,1]]}}}],["达到",{"_index":229,"t":{"28":{"position":[[58,2],[103,2]]},"418":{"position":[[30,2]]},"741":{"position":[[26,2],[73,2]]},"822":{"position":[[44,2]]},"884":{"position":[[78,2]]}}}],["迁移",{"_index":3340,"t":{"886":{"position":[[39,2],[45,2]]}}}],["迅雷",{"_index":2248,"t":{"463":{"position":[[20,2]]},"718":{"position":[[76,2]]}}}],["过",{"_index":1895,"t":{"374":{"position":[[1,1]]},"455":{"position":[[998,1]]},"465":{"position":[[319,1],[378,1]]}}}],["过度",{"_index":3090,"t":{"783":{"position":[[232,2]]}}}],["过期",{"_index":479,"t":{"50":{"position":[[285,2]]}}}],["过程",{"_index":318,"t":{"36":{"position":[[23,2]]},"125":{"position":[[28,2],[165,2],[172,2],[213,2]]},"447":{"position":[[3,2]]},"473":{"position":[[47,2]]},"542":{"position":[[13,2]]}}}],["运营商",{"_index":452,"t":{"50":{"position":[[100,3]]}}}],["运行",{"_index":1203,"t":{"166":{"position":[[450,2]]},"184":{"position":[[1221,2]]},"218":{"position":[[1221,2]]},"252":{"position":[[450,2]]},"447":{"position":[[219,2]]},"503":{"position":[[56,2]]},"570":{"position":[[29,2]]},"602":{"position":[[18,2]]},"783":{"position":[[204,2]]},"832":{"position":[[574,2]]},"874":{"position":[[319,2]]},"915":{"position":[[3,2]]}}}],["近",{"_index":2076,"t":{"436":{"position":[[2020,1],[2064,1]]},"509":{"position":[[66,1]]}}}],["返回",{"_index":558,"t":{"57":{"position":[[803,2]]},"60":{"position":[[206,2]]},"66":{"position":[[262,2]]},"80":{"position":[[424,2],[559,2],[721,2],[966,2],[1385,2],[1613,2],[2036,2],[2127,2],[2220,2],[2402,2]]},"106":{"position":[[29,2]]},"120":{"position":[[354,2]]},"159":{"position":[[268,2]]},"223":{"position":[[501,2],[540,2],[617,2]]},"297":{"position":[[0,2],[138,2],[230,2],[288,2]]},"301":{"position":[[390,2],[532,2],[595,2],[1904,2]]},"347":{"position":[[972,2],[1588,2]]},"431":{"position":[[678,2]]},"485":{"position":[[276,2]]},"653":{"position":[[190,2],[250,2]]},"670":{"position":[[56,2]]},"734":{"position":[[236,2]]},"748":{"position":[[311,2]]},"774":{"position":[[278,2]]},"792":{"position":[[206,2],[227,2]]},"830":{"position":[[114,2],[178,2]]},"854":{"position":[[118,2]]},"857":{"position":[[638,2]]},"859":{"position":[[527,2],[1136,2]]},"880":{"position":[[112,2]]},"917":{"position":[[90,2]]}}}],["返回值",{"_index":208,"t":{"25":{"position":[[377,3]]},"132":{"position":[[353,3]]},"272":{"position":[[567,3]]},"521":{"position":[[422,3]]},"653":{"position":[[133,3],[231,3],[270,3]]},"691":{"position":[[249,3]]},"752":{"position":[[146,3]]},"828":{"position":[[276,3]]}}}],["还是",{"_index":1304,"t":{"184":{"position":[[983,2],[1762,2]]},"218":{"position":[[983,2],[1762,2]]},"301":{"position":[[0,2]]},"720":{"position":[[32,2]]}}}],["还有",{"_index":2200,"t":{"451":{"position":[[109,2]]},"561":{"position":[[449,2]]},"741":{"position":[[63,2]]},"935":{"position":[[59,2]]}}}],["还要",{"_index":3193,"t":{"828":{"position":[[327,2]]}}}],["这个",{"_index":1319,"t":{"184":{"position":[[1139,2],[1918,2]]},"218":{"position":[[1139,2],[1918,2]]},"235":{"position":[[58,2]]},"409":{"position":[[20,2]]},"444":{"position":[[356,2],[409,2]]},"447":{"position":[[1010,2]]},"449":{"position":[[248,2]]},"455":{"position":[[553,2],[987,2]]},"485":{"position":[[131,2],[146,2],[289,2]]},"537":{"position":[[522,2]]},"539":{"position":[[37,2]]},"574":{"position":[[41,2]]},"639":{"position":[[34,2]]},"661":{"position":[[106,2]]},"783":{"position":[[153,2]]}}}],["这么",{"_index":2264,"t":{"468":{"position":[[19,2]]},"668":{"position":[[75,2]]},"720":{"position":[[28,2]]}}}],["这些",{"_index":622,"t":{"62":{"position":[[29,2]]},"71":{"position":[[29,2]]},"82":{"position":[[29,2]]},"134":{"position":[[45,2]]},"444":{"position":[[232,2],[427,2]]},"542":{"position":[[84,2],[96,2]]},"689":{"position":[[187,2]]},"854":{"position":[[64,2]]},"957":{"position":[[105,2]]}}}],["这时",{"_index":2108,"t":{"444":{"position":[[74,2],[517,2]]}}}],["这时候",{"_index":1651,"t":{"308":{"position":[[2458,3]]},"455":{"position":[[853,3]]},"487":{"position":[[55,3]]},"503":{"position":[[155,3]]},"526":{"position":[[134,3],[197,3],[300,3]]},"617":{"position":[[119,3]]},"661":{"position":[[46,3]]},"778":{"position":[[139,3]]},"787":{"position":[[107,3]]}}}],["这样",{"_index":311,"t":{"34":{"position":[[272,2]]},"159":{"position":[[43,2],[80,2]]},"184":{"position":[[998,2],[1777,2]]},"207":{"position":[[435,2]]},"218":{"position":[[998,2],[1777,2]]},"235":{"position":[[169,2]]},"304":{"position":[[79,2]]},"338":{"position":[[35,2]]},"447":{"position":[[830,2]]},"530":{"position":[[1051,2]]},"686":{"position":[[484,2]]},"761":{"position":[[74,2]]},"891":{"position":[[292,2]]},"969":{"position":[[107,2]]}}}],["这种",{"_index":447,"t":{"50":{"position":[[59,2]]},"184":{"position":[[871,2],[1650,2]]},"218":{"position":[[871,2],[1650,2]]},"418":{"position":[[60,2]]},"455":{"position":[[351,2]]},"617":{"position":[[2,2],[30,2]]},"761":{"position":[[163,2]]},"787":{"position":[[38,2],[49,2]]}}}],["这部分",{"_index":491,"t":{"53":{"position":[[70,3]]}}}],["这里",{"_index":546,"t":{"57":{"position":[[695,2]]},"86":{"position":[[40,2]]},"194":{"position":[[306,2]]},"233":{"position":[[312,2]]},"235":{"position":[[717,2]]},"272":{"position":[[486,2]]},"528":{"position":[[30,2]]},"672":{"position":[[816,2]]},"674":{"position":[[715,2]]},"720":{"position":[[5,2]]}}}],["进入",{"_index":834,"t":{"120":{"position":[[517,2]]},"718":{"position":[[123,2]]}}}],["进制",{"_index":2698,"t":{"606":{"position":[[4,2],[108,2]]}}}],["进度",{"_index":2487,"t":{"528":{"position":[[845,2],[1012,2],[1543,2],[1710,2]]},"725":{"position":[[7,2]]},"727":{"position":[[362,2],[717,2],[1735,2]]},"830":{"position":[[262,2],[616,2]]},"832":{"position":[[1767,2],[2083,2],[2263,2]]}}}],["进程",{"_index":162,"t":{"23":{"position":[[6,2]]},"409":{"position":[[27,2],[45,2]]},"971":{"position":[[51,2]]}}}],["进行",{"_index":152,"t":{"20":{"position":[[34,2]]},"28":{"position":[[46,2]]},"40":{"position":[[70,2]]},"134":{"position":[[1490,2],[1988,2]]},"142":{"position":[[556,2]]},"166":{"position":[[169,2],[225,2],[283,2],[589,2]]},"225":{"position":[[728,2]]},"252":{"position":[[169,2],[225,2],[283,2],[589,2]]},"261":{"position":[[99,2]]},"292":{"position":[[68,2]]},"297":{"position":[[62,2]]},"321":{"position":[[31,2]]},"365":{"position":[[1308,2]]},"427":{"position":[[10,2]]},"449":{"position":[[36,2]]},"473":{"position":[[298,2]]},"485":{"position":[[82,2]]},"535":{"position":[[57,2]]},"626":{"position":[[32,2]]},"628":{"position":[[111,2]]},"646":{"position":[[48,2]]},"655":{"position":[[364,2]]},"691":{"position":[[197,2]]},"723":{"position":[[24,2]]},"752":{"position":[[47,2]]},"778":{"position":[[21,2],[81,2]]},"792":{"position":[[85,2]]},"800":{"position":[[10,2]]},"826":{"position":[[29,2]]},"828":{"position":[[340,2]]},"830":{"position":[[682,2]]},"872":{"position":[[204,2],[1148,2]]},"909":{"position":[[21,2],[206,2]]},"957":{"position":[[27,2]]},"976":{"position":[[25,2],[62,2]]}}}],["远程",{"_index":804,"t":{"116":{"position":[[43,2]]},"125":{"position":[[26,2],[42,2],[210,2]]},"166":{"position":[[306,2],[367,2],[395,2]]},"184":{"position":[[1272,2]]},"218":{"position":[[1272,2]]},"252":{"position":[[306,2],[367,2],[395,2]]},"290":{"position":[[598,2]]},"440":{"position":[[99,2]]},"577":{"position":[[6,2]]},"586":{"position":[[22,2],[27,2],[39,2],[49,2],[55,2],[63,2]]},"588":{"position":[[24,2]]},"628":{"position":[[1,2]]},"776":{"position":[[39,2],[98,2]]},"798":{"position":[[20,2]]},"878":{"position":[[148,2],[171,2]]},"932":{"position":[[285,2]]},"935":{"position":[[128,2]]},"950":{"position":[[0,2],[11,2]]}}}],["远非",{"_index":3112,"t":{"787":{"position":[[173,2]]}}}],["违法犯罪",{"_index":86,"t":{"10":{"position":[[8,4]]},"12":{"position":[[8,4]]},"14":{"position":[[8,4]]}}}],["连",{"_index":405,"t":{"46":{"position":[[387,1]]},"526":{"position":[[340,1],[345,1]]},"539":{"position":[[190,1]]},"593":{"position":[[5,1]]},"595":{"position":[[5,1],[128,1]]},"597":{"position":[[8,1],[188,1]]},"882":{"position":[[143,1],[368,1]]},"884":{"position":[[151,1],[175,1],[295,1]]},"891":{"position":[[36,1]]},"938":{"position":[[6,1]]},"940":{"position":[[6,1]]}}}],["连接",{"_index":341,"t":{"40":{"position":[[36,2]]},"60":{"position":[[431,2]]},"66":{"position":[[487,2]]},"69":{"position":[[161,2],[386,2]]},"80":{"position":[[267,2],[1245,2],[1792,2],[1948,2]]},"102":{"position":[[158,2]]},"104":{"position":[[4,2]]},"116":{"position":[[10,2]]},"138":{"position":[[146,2]]},"166":{"position":[[107,2],[123,2],[195,2]]},"178":{"position":[[29,2]]},"184":{"position":[[540,2],[544,2]]},"186":{"position":[[83,2],[111,2]]},"188":{"position":[[139,2],[203,2]]},"210":{"position":[[96,2]]},"216":{"position":[[10,2]]},"218":{"position":[[540,2],[544,2]]},"220":{"position":[[81,2],[114,2]]},"223":{"position":[[227,2]]},"225":{"position":[[722,2],[984,2],[1538,2]]},"235":{"position":[[591,2]]},"237":{"position":[[13,2]]},"248":{"position":[[62,2]]},"252":{"position":[[107,2],[123,2],[195,2]]},"255":{"position":[[300,2]]},"259":{"position":[[45,2]]},"281":{"position":[[21,2]]},"284":{"position":[[28,2]]},"286":{"position":[[44,2],[491,2],[996,2]]},"317":{"position":[[404,2]]},"319":{"position":[[4,2],[74,2],[609,2],[685,2],[705,2]]},"444":{"position":[[332,2]]},"447":{"position":[[809,2]]},"485":{"position":[[42,2]]},"495":{"position":[[1054,2]]},"516":{"position":[[520,2]]},"526":{"position":[[17,2],[77,2],[88,2],[121,2],[178,2],[233,2],[268,2],[286,2]]},"528":{"position":[[23,2],[658,2],[669,2],[1372,2],[1383,2]]},"533":{"position":[[66,2]]},"537":{"position":[[501,2],[1439,2]]},"539":{"position":[[16,2]]},"581":{"position":[[79,2]]},"593":{"position":[[29,2]]},"595":{"position":[[98,2],[149,2]]},"597":{"position":[[31,2],[40,2]]},"613":{"position":[[6,2],[16,2]]},"615":{"position":[[14,2],[20,2],[40,2],[124,2]]},"617":{"position":[[11,2],[146,2]]},"619":{"position":[[33,2]]},"702":{"position":[[1357,2]]},"723":{"position":[[17,2]]},"729":{"position":[[40,2]]},"770":{"position":[[0,2],[10,2]]},"774":{"position":[[251,2]]},"787":{"position":[[21,2]]},"790":{"position":[[2,2],[30,2]]},"806":{"position":[[191,2],[243,2],[285,2],[300,2]]},"824":{"position":[[21,2]]},"828":{"position":[[60,2]]},"832":{"position":[[257,2],[1597,2]]},"857":{"position":[[387,2],[430,2]]},"859":{"position":[[281,2],[324,2]]},"872":{"position":[[661,2]]},"884":{"position":[[215,2],[276,2]]},"896":{"position":[[430,2]]},"909":{"position":[[18,2],[202,2]]}}}],["连接数",{"_index":1271,"t":{"184":{"position":[[576,3]]},"218":{"position":[[576,3]]}}}],["连接端",{"_index":1278,"t":{"184":{"position":[[671,3]]},"218":{"position":[[671,3]]},"826":{"position":[[56,3]]}}}],["连线",{"_index":3369,"t":{"906":{"position":[[190,2]]}}}],["连续",{"_index":1177,"t":{"164":{"position":[[124,2]]},"250":{"position":[[124,2]]},"336":{"position":[[19,2]]},"738":{"position":[[99,2]]}}}],["迷惑",{"_index":271,"t":{"34":{"position":[[8,2]]}}}],["追加",{"_index":548,"t":{"57":{"position":[[700,2]]},"514":{"position":[[507,2]]},"756":{"position":[[194,2]]}}}],["退出",{"_index":2609,"t":{"559":{"position":[[131,2]]},"561":{"position":[[407,2]]},"841":{"position":[[95,2]]}}}],["送",{"_index":3429,"t":{"961":{"position":[[235,1],[242,1],[249,1]]}}}],["送达",{"_index":3116,"t":{"792":{"position":[[202,2]]}}}],["适应性",{"_index":2087,"t":{"440":{"position":[[152,3]]}}}],["适当",{"_index":1245,"t":{"184":{"position":[[200,2]]},"218":{"position":[[200,2]]}}}],["适用",{"_index":53,"t":{"7":{"position":[[35,2]]},"57":{"position":[[8,2],[1981,2]]},"272":{"position":[[8,2],[1775,2]]},"290":{"position":[[1034,2]]},"301":{"position":[[2894,2]]},"308":{"position":[[8,2],[2579,2]]},"347":{"position":[[8,2],[2551,2]]},"374":{"position":[[42,2]]},"400":{"position":[[47,2]]},"406":{"position":[[8,2],[594,2]]},"418":{"position":[[66,2]]},"420":{"position":[[48,2]]},"422":{"position":[[8,2],[578,2]]},"561":{"position":[[797,2]]},"697":{"position":[[4,2]]},"743":{"position":[[1,2]]},"745":{"position":[[8,2],[649,2]]},"758":{"position":[[147,2]]},"806":{"position":[[403,2]]},"980":{"position":[[480,2]]}}}],["适配",{"_index":291,"t":{"34":{"position":[[108,2],[153,2]]},"55":{"position":[[4,2]]},"270":{"position":[[4,2]]},"306":{"position":[[4,2]]},"345":{"position":[[4,2]]},"402":{"position":[[112,2]]},"487":{"position":[[31,2]]},"876":{"position":[[42,2]]}}}],["适配器",{"_index":215,"t":{"28":{"position":[[14,3],[128,3]]},"32":{"position":[[12,3],[50,3]]},"34":{"position":[[52,3],[102,3],[184,3],[194,3],[222,3]]},"36":{"position":[[12,3],[53,3]]},"44":{"position":[[19,3],[38,3]]},"46":{"position":[[339,3],[379,3],[396,3],[421,3],[445,3],[457,3],[468,3],[486,3],[508,3]]},"48":{"position":[[31,3]]},"50":{"position":[[1,3]]},"53":{"position":[[30,3]]},"57":{"position":[[1083,3],[1508,3],[1542,3],[1944,3],[1970,3]]},"78":{"position":[[90,3]]},"180":{"position":[[25,3]]},"186":{"position":[[246,3],[257,3],[324,3]]},"194":{"position":[[319,3],[365,3]]},"196":{"position":[[62,3]]},"212":{"position":[[95,3]]},"220":{"position":[[253,3],[264,3],[331,3]]},"233":{"position":[[325,3],[371,3]]},"235":{"position":[[730,3],[776,3]]},"241":{"position":[[460,3]]},"263":{"position":[[25,3]]},"268":{"position":[[2,3],[49,3],[103,3],[114,3],[129,3],[145,3]]},"272":{"position":[[1399,3],[1433,3],[1738,3],[1764,3]]},"295":{"position":[[3,3],[14,3]]},"301":{"position":[[219,3],[2463,3],[2497,3],[2857,3],[2883,3]]},"304":{"position":[[6,3]]},"308":{"position":[[1920,3],[1954,3],[2347,3],[2568,3]]},"334":{"position":[[0,3],[8,3],[77,3]]},"336":{"position":[[56,3],[177,3]]},"340":{"position":[[3,3],[29,3],[52,3],[64,3],[153,3],[250,3],[581,3],[738,3],[748,3],[784,3]]},"347":{"position":[[2081,3],[2115,3],[2514,3],[2540,3]]},"357":{"position":[[3,3],[137,3]]},"359":{"position":[[4,3],[123,3]]},"361":{"position":[[1064,3]]},"363":{"position":[[3,3],[13,3]]},"365":{"position":[[1423,3],[1475,3]]},"400":{"position":[[8,3]]},"406":{"position":[[507,3],[582,3]]},"418":{"position":[[8,3]]},"422":{"position":[[478,3],[566,3]]},"468":{"position":[[0,3],[43,3],[65,3],[100,3]]},"470":{"position":[[813,3],[830,3]]},"487":{"position":[[67,3]]},"514":{"position":[[99,3],[494,3]]},"537":{"position":[[309,3],[322,3]]},"559":{"position":[[8,3]]},"561":{"position":[[713,3],[786,3]]},"666":{"position":[[35,3],[102,3]]},"668":{"position":[[10,3]]},"738":{"position":[[73,3],[84,3]]},"741":{"position":[[8,3]]},"745":{"position":[[487,3],[637,3]]},"748":{"position":[[3,3]]},"750":{"position":[[1,3],[243,3],[534,3]]},"758":{"position":[[136,3]]},"809":{"position":[[4,3],[44,3]]},"816":{"position":[[11,3]]},"857":{"position":[[358,3],[629,3]]},"859":{"position":[[252,3],[518,3]]},"872":{"position":[[257,3],[753,3],[1037,3]]},"874":{"position":[[213,3]]},"880":{"position":[[81,3],[88,3]]},"882":{"position":[[70,3],[304,3],[307,3]]},"938":{"position":[[15,3]]},"957":{"position":[[21,3],[57,3],[97,3],[107,3]]},"961":{"position":[[262,3]]},"976":{"position":[[6,3]]},"980":{"position":[[446,3],[468,3]]}}}],["选",{"_index":2315,"t":{"491":{"position":[[5,1]]},"653":{"position":[[19,1]]},"691":{"position":[[367,1]]},"738":{"position":[[76,1]]},"870":{"position":[[101,1],[123,1]]}}}],["选择",{"_index":256,"t":{"32":{"position":[[59,2]]},"34":{"position":[[143,2]]},"46":{"position":[[464,2],[482,2],[502,2]]},"239":{"position":[[231,2]]},"402":{"position":[[24,2]]},"447":{"position":[[744,2],[778,2],[792,2],[803,2]]},"455":{"position":[[1066,2]]},"544":{"position":[[21,2]]},"661":{"position":[[16,2]]},"681":{"position":[[11,2]]},"707":{"position":[[136,2]]},"714":{"position":[[57,2]]},"718":{"position":[[10,2],[18,2],[135,2],[194,2],[213,2]]}}}],["选择器",{"_index":1183,"t":{"164":{"position":[[169,3]]},"250":{"position":[[169,3]]},"684":{"position":[[20,3]]},"686":{"position":[[507,3]]}}}],["选择性",{"_index":665,"t":{"78":{"position":[[94,3]]}}}],["选项",{"_index":3295,"t":{"872":{"position":[[708,2]]}}}],["递增",{"_index":1601,"t":{"297":{"position":[[264,2],[336,2]]},"301":{"position":[[1313,2],[1649,2]]},"411":{"position":[[76,2]]},"413":{"position":[[76,2]]},"415":{"position":[[95,2]]},"872":{"position":[[681,2]]}}}],["通俗",{"_index":2400,"t":{"514":{"position":[[28,2]]},"542":{"position":[[56,2]]},"930":{"position":[[28,2]]}}}],["通信",{"_index":916,"t":{"125":{"position":[[95,2]]},"210":{"position":[[122,2]]},"440":{"position":[[101,2]]},"468":{"position":[[58,2]]},"514":{"position":[[34,2]]},"528":{"position":[[84,2],[313,2],[428,2],[655,2],[1369,2]]},"530":{"position":[[680,2],[826,2]]},"588":{"position":[[38,2]]},"626":{"position":[[3,2]]},"689":{"position":[[94,2]]},"872":{"position":[[302,2]]},"906":{"position":[[85,2]]},"909":{"position":[[26,2]]},"930":{"position":[[34,2]]}}}],["通信协议",{"_index":3371,"t":{"909":{"position":[[41,4]]}}}],["通信模型",{"_index":2468,"t":{"528":{"position":[[40,4],[73,4]]}}}],["通用",{"_index":655,"t":{"78":{"position":[[10,2]]},"498":{"position":[[8,2]]},"862":{"position":[[7,2]]},"917":{"position":[[7,2]]}}}],["通知",{"_index":1953,"t":{"393":{"position":[[351,2]]},"559":{"position":[[149,2]]},"868":{"position":[[211,2]]},"872":{"position":[[290,2],[926,2]]}}}],["通讯",{"_index":3216,"t":{"839":{"position":[[23,2],[96,2]]}}}],["通过",{"_index":514,"t":{"57":{"position":[[191,2]]},"94":{"position":[[49,2]]},"120":{"position":[[34,2],[71,2],[504,2]]},"125":{"position":[[37,2]]},"127":{"position":[[728,2]]},"140":{"position":[[13,2]]},"142":{"position":[[510,2]]},"153":{"position":[[35,2]]},"166":{"position":[[270,2],[576,2]]},"184":{"position":[[642,2]]},"188":{"position":[[8,2]]},"192":{"position":[[44,2]]},"196":{"position":[[48,2]]},"210":{"position":[[128,2]]},"218":{"position":[[642,2]]},"223":{"position":[[44,2]]},"225":{"position":[[0,2],[40,2],[1913,2],[1946,2]]},"229":{"position":[[50,2]]},"235":{"position":[[229,2]]},"237":{"position":[[45,2]]},"239":{"position":[[15,2],[174,2],[186,2],[239,2]]},"241":{"position":[[444,2]]},"243":{"position":[[0,2]]},"252":{"position":[[270,2],[576,2]]},"263":{"position":[[7,2]]},"265":{"position":[[0,2]]},"272":{"position":[[183,2]]},"284":{"position":[[0,2]]},"286":{"position":[[0,2],[988,2]]},"301":{"position":[[153,2]]},"308":{"position":[[185,2]]},"347":{"position":[[187,2],[984,2],[1451,2]]},"357":{"position":[[153,2]]},"406":{"position":[[68,2]]},"418":{"position":[[18,2]]},"422":{"position":[[58,2]]},"431":{"position":[[847,2],[860,2]]},"447":{"position":[[182,2],[927,2],[1309,2]]},"449":{"position":[[0,2]]},"455":{"position":[[786,2]]},"521":{"position":[[226,2]]},"530":{"position":[[491,2]]},"572":{"position":[[2,2]]},"617":{"position":[[273,2]]},"619":{"position":[[61,2]]},"670":{"position":[[38,2]]},"681":{"position":[[47,2]]},"684":{"position":[[13,2]]},"691":{"position":[[57,2]]},"718":{"position":[[102,2]]},"727":{"position":[[943,2]]},"732":{"position":[[51,2]]},"741":{"position":[[12,2]]},"745":{"position":[[58,2],[538,2]]},"767":{"position":[[25,2]]},"814":{"position":[[69,2]]},"828":{"position":[[268,2],[329,2]]},"830":{"position":[[499,2]]},"891":{"position":[[111,2]]},"925":{"position":[[89,2]]},"932":{"position":[[275,2]]},"957":{"position":[[19,2]]},"973":{"position":[[3,2]]},"980":{"position":[[26,2]]}}}],["通道",{"_index":2805,"t":{"672":{"position":[[49,2],[188,2],[785,2]]},"674":{"position":[[160,2],[684,2]]},"689":{"position":[[80,2]]},"702":{"position":[[1334,2]]},"800":{"position":[[4,2]]},"836":{"position":[[75,2],[97,2]]}}}],["速度",{"_index":2486,"t":{"528":{"position":[[842,2],[986,2],[1540,2],[1684,2]]},"679":{"position":[[119,2],[239,2]]},"725":{"position":[[4,2]]},"727":{"position":[[689,2],[1707,2]]},"830":{"position":[[265,2],[577,2],[592,2]]},"832":{"position":[[1770,2],[2086,2],[2290,2]]}}}],["速率",{"_index":2457,"t":{"526":{"position":[[183,2],[192,2],[235,2]]}}}],["造成",{"_index":154,"t":{"20":{"position":[[53,2],[58,2]]},"866":{"position":[[31,2]]}}}],["逻辑",{"_index":532,"t":{"57":{"position":[[461,2]]},"69":{"position":[[168,2]]},"188":{"position":[[5,2]]},"223":{"position":[[41,2]]},"225":{"position":[[220,2],[703,2]]},"347":{"position":[[911,2],[987,2]]},"444":{"position":[[348,2],[545,2]]},"581":{"position":[[34,2],[44,2]]},"761":{"position":[[210,2]]},"809":{"position":[[23,2]]},"872":{"position":[[1076,2]]},"878":{"position":[[48,2],[446,2]]},"880":{"position":[[55,2]]},"882":{"position":[[49,2],[63,2],[222,2]]},"891":{"position":[[37,2]]}}}],["遍历",{"_index":2370,"t":{"507":{"position":[[470,2],[651,2]]}}}],["遗留",{"_index":1616,"t":{"301":{"position":[[763,2]]}}}],["遥不可及",{"_index":1880,"t":{"370":{"position":[[334,4]]}}}],["遵守",{"_index":1141,"t":{"159":{"position":[[14,2]]},"963":{"position":[[54,2]]}}}],["遵循",{"_index":27,"t":{"5":{"position":[[49,2]]},"18":{"position":[[34,2]]},"78":{"position":[[60,2]]}}}],["避免",{"_index":1142,"t":{"159":{"position":[[50,2]]},"338":{"position":[[37,2]]},"361":{"position":[[783,2]]},"365":{"position":[[1758,2]]},"783":{"position":[[230,2]]}}}],["邑",{"_index":1666,"t":{"326":{"position":[[0,1]]}}}],["那个",{"_index":1378,"t":{"207":{"position":[[420,2]]}}}],["那么",{"_index":373,"t":{"44":{"position":[[51,2]]},"48":{"position":[[50,2]]},"304":{"position":[[98,2]]},"376":{"position":[[656,2]]},"409":{"position":[[98,2]]},"455":{"position":[[483,2]]},"468":{"position":[[93,2]]},"485":{"position":[[285,2]]},"526":{"position":[[195,2],[298,2]]},"530":{"position":[[73,2]]},"574":{"position":[[39,2]]},"619":{"position":[[55,2]]},"689":{"position":[[141,2]]},"707":{"position":[[154,2],[166,2]]},"778":{"position":[[137,2]]},"787":{"position":[[105,2]]},"891":{"position":[[67,2],[153,2]]},"957":{"position":[[135,2]]},"959":{"position":[[54,2]]}}}],["那样",{"_index":276,"t":{"34":{"position":[[41,2]]}}}],["邮箱",{"_index":122,"t":{"12":{"position":[[153,2]]},"263":{"position":[[49,2]]}}}],["部",{"_index":2902,"t":{"702":{"position":[[1360,1]]}}}],["部分",{"_index":115,"t":{"12":{"position":[[127,2]]},"194":{"position":[[368,2]]},"233":{"position":[[374,2]]},"235":{"position":[[779,2]]},"301":{"position":[[488,2]]},"444":{"position":[[703,2]]},"544":{"position":[[25,2]]},"546":{"position":[[49,2]]},"628":{"position":[[35,2]]},"761":{"position":[[191,2],[200,2]]},"872":{"position":[[759,2]]},"882":{"position":[[310,2]]},"969":{"position":[[411,2]]}}}],["都",{"_index":69,"t":{"7":{"position":[[100,1]]},"62":{"position":[[36,1]]},"71":{"position":[[36,1]]},"82":{"position":[[36,1]]},"127":{"position":[[710,1]]},"134":{"position":[[52,1]]},"136":{"position":[[8,1]]},"146":{"position":[[88,1]]},"159":{"position":[[104,1]]},"166":{"position":[[441,1]]},"180":{"position":[[97,1]]},"184":{"position":[[947,1],[1726,1]]},"207":{"position":[[363,1]]},"210":{"position":[[126,1]]},"212":{"position":[[167,1]]},"218":{"position":[[947,1],[1726,1]]},"237":{"position":[[20,1]]},"241":{"position":[[456,1]]},"246":{"position":[[31,1]]},"252":{"position":[[441,1]]},"301":{"position":[[1151,1]]},"409":{"position":[[13,1]]},"418":{"position":[[42,1]]},"440":{"position":[[85,1]]},"447":{"position":[[17,1]]},"455":{"position":[[887,1]]},"485":{"position":[[64,1]]},"503":{"position":[[62,1]]},"535":{"position":[[75,1]]},"554":{"position":[[99,1],[165,1]]},"570":{"position":[[35,1],[100,1]]},"572":{"position":[[30,1]]},"613":{"position":[[13,1]]},"615":{"position":[[8,1]]},"648":{"position":[[1193,1]]},"661":{"position":[[82,1]]},"686":{"position":[[495,1]]},"702":{"position":[[2304,1]]},"705":{"position":[[107,1]]},"718":{"position":[[173,1]]},"720":{"position":[[36,1]]},"727":{"position":[[934,1]]},"776":{"position":[[92,1]]},"778":{"position":[[70,1],[115,1]]},"780":{"position":[[38,1]]},"787":{"position":[[99,1]]},"792":{"position":[[135,1]]},"828":{"position":[[9,1]]},"857":{"position":[[354,1]]},"859":{"position":[[248,1]]},"872":{"position":[[305,1],[933,1]]}}}],["配合",{"_index":791,"t":{"110":{"position":[[78,2]]}}}],["配备",{"_index":2714,"t":{"610":{"position":[[313,2]]}}}],["配置",{"_index":329,"t":{"38":{"position":[[7,2]]},"46":{"position":[[18,2]]},"57":{"position":[[184,2],[1793,2],[1942,2]]},"104":{"position":[[21,2]]},"120":{"position":[[153,2],[495,2]]},"122":{"position":[[34,2]]},"129":{"position":[[135,2]]},"132":{"position":[[276,2]]},"164":{"position":[[1,2]]},"169":{"position":[[23,2]]},"171":{"position":[[23,2]]},"173":{"position":[[13,2]]},"184":{"position":[[1,2],[431,2],[762,2],[1202,2],[1411,2],[1459,2],[1468,2],[1511,2]]},"188":{"position":[[402,2],[528,2]]},"192":{"position":[[283,2],[409,2]]},"194":{"position":[[54,2]]},"210":{"position":[[35,2]]},"218":{"position":[[1,2],[431,2],[762,2],[1202,2],[1411,2],[1459,2],[1468,2],[1511,2]]},"223":{"position":[[745,2],[876,2]]},"225":{"position":[[401,2],[558,2],[566,2],[571,2],[1081,2],[1212,2],[1635,2],[1766,2]]},"229":{"position":[[337,2],[468,2]]},"233":{"position":[[54,2]]},"235":{"position":[[264,2],[273,2]]},"250":{"position":[[1,2]]},"255":{"position":[[20,2],[39,2],[53,2],[59,2],[141,2]]},"257":{"position":[[20,2],[132,2]]},"259":{"position":[[20,2],[155,2]]},"261":{"position":[[103,2],[108,2],[249,2]]},"272":{"position":[[176,2],[1591,2],[1736,2]]},"284":{"position":[[168,2]]},"286":{"position":[[65,2],[194,2]]},"288":{"position":[[12,2],[28,2],[90,2],[291,2]]},"301":{"position":[[146,2],[2720,2],[2855,2]]},"308":{"position":[[178,2],[2199,2],[2345,2]]},"334":{"position":[[53,2]]},"347":{"position":[[180,2],[2364,2],[2512,2]]},"385":{"position":[[7,2]]},"404":{"position":[[118,2]]},"406":{"position":[[41,2],[331,2],[505,2]]},"422":{"position":[[41,2],[344,2],[476,2]]},"442":{"position":[[78,2]]},"447":{"position":[[329,2]]},"495":{"position":[[332,2]]},"514":{"position":[[282,2]]},"516":{"position":[[375,2]]},"528":{"position":[[103,2],[310,2],[424,2]]},"530":{"position":[[677,2],[822,2]]},"561":{"position":[[504,2],[711,2],[730,2]]},"574":{"position":[[235,2]]},"615":{"position":[[83,2],[87,2]]},"668":{"position":[[146,2]]},"686":{"position":[[17,2],[65,2]]},"736":{"position":[[475,2]]},"745":{"position":[[41,2],[344,2],[481,2]]},"772":{"position":[[9,2],[81,2]]},"816":{"position":[[4,2],[364,2]]},"832":{"position":[[45,2]]},"841":{"position":[[10,2]]},"847":{"position":[[10,2]]},"851":{"position":[[99,2],[346,2]]},"857":{"position":[[137,2]]},"859":{"position":[[791,2],[922,2]]},"872":{"position":[[1125,2],[1152,2]]},"874":{"position":[[264,2]]},"884":{"position":[[136,2],[237,2]]},"906":{"position":[[201,2]]},"980":{"position":[[20,2],[312,2],[444,2]]}}}],["酱",{"_index":1856,"t":{"370":{"position":[[199,1]]}}}],["采取",{"_index":2007,"t":{"415":{"position":[[185,2]]}}}],["采用",{"_index":2666,"t":{"588":{"position":[[30,2]]},"767":{"position":[[13,2]]},"859":{"position":[[1154,2]]},"880":{"position":[[236,2]]}}}],["采集",{"_index":2898,"t":{"702":{"position":[[1340,2]]}}}],["释放",{"_index":1092,"t":{"151":{"position":[[85,2]]},"153":{"position":[[87,2]]},"159":{"position":[[40,2],[53,2],[114,2],[272,2],[303,2]]},"166":{"position":[[550,2]]},"184":{"position":[[1244,2]]},"218":{"position":[[1244,2]]},"252":{"position":[[550,2]]},"361":{"position":[[2948,2]]},"411":{"position":[[90,2]]},"413":{"position":[[90,2],[132,2]]},"415":{"position":[[9,2],[24,2],[63,2],[114,2],[166,2],[175,2]]},"561":{"position":[[420,2]]},"727":{"position":[[1033,2]]},"822":{"position":[[61,2]]},"880":{"position":[[339,2]]},"884":{"position":[[256,2]]}}}],["里",{"_index":1982,"t":{"409":{"position":[[47,1]]},"444":{"position":[[343,1]]}}}],["里面",{"_index":277,"t":{"34":{"position":[[48,2]]},"186":{"position":[[224,2],[291,2]]},"216":{"position":[[92,2]]},"220":{"position":[[231,2],[298,2]]},"235":{"position":[[60,2]]},"301":{"position":[[1416,2]]},"361":{"position":[[2942,2]]},"561":{"position":[[447,2]]},"872":{"position":[[132,2]]}}}],["重",{"_index":404,"t":{"46":{"position":[[386,1]]},"526":{"position":[[339,1],[344,1]]},"539":{"position":[[189,1]]},"593":{"position":[[4,1]]},"595":{"position":[[4,1],[127,1]]},"597":{"position":[[7,1],[187,1]]},"872":{"position":[[232,1]]},"882":{"position":[[142,1],[367,1]]},"884":{"position":[[150,1],[174,1],[294,1]]},"891":{"position":[[35,1]]},"938":{"position":[[5,1]]},"940":{"position":[[5,1]]}}}],["重任",{"_index":2777,"t":{"661":{"position":[[56,2]]}}}],["重写",{"_index":811,"t":{"118":{"position":[[60,2]]},"120":{"position":[[506,2]]},"166":{"position":[[69,2]]},"186":{"position":[[35,2]]},"205":{"position":[[72,2]]},"220":{"position":[[35,2]]},"225":{"position":[[22,2]]},"231":{"position":[[28,2]]},"252":{"position":[[69,2]]},"290":{"position":[[759,2]]},"570":{"position":[[79,2],[214,2]]},"630":{"position":[[226,2]]},"684":{"position":[[15,2]]},"774":{"position":[[5,2]]},"874":{"position":[[384,2]]}}}],["重启",{"_index":3461,"t":{"971":{"position":[[49,2]]}}}],["重命名",{"_index":2661,"t":{"586":{"position":[[76,3]]},"796":{"position":[[20,3]]}}}],["重复",{"_index":1507,"t":{"268":{"position":[[72,2]]},"608":{"position":[[16,2]]},"615":{"position":[[132,2]]},"820":{"position":[[36,2]]},"878":{"position":[[196,2]]}}}],["重建",{"_index":1382,"t":{"210":{"position":[[47,2]]}}}],["重新",{"_index":407,"t":{"46":{"position":[[392,2]]},"50":{"position":[[53,2]]},"297":{"position":[[222,2]]},"365":{"position":[[2080,2]]},"440":{"position":[[307,2]]},"453":{"position":[[27,2]]},"507":{"position":[[1266,2]]},"512":{"position":[[79,2]]},"679":{"position":[[263,2]]},"894":{"position":[[78,2]]},"928":{"position":[[88,2]]}}}],["重点",{"_index":3258,"t":{"866":{"position":[[25,2]]}}}],["重组",{"_index":3145,"t":{"818":{"position":[[43,2]]}}}],["重置",{"_index":2388,"t":{"507":{"position":[[2132,2]]},"776":{"position":[[122,2]]},"790":{"position":[[55,2]]}}}],["重要",{"_index":702,"t":{"89":{"position":[[15,2]]},"149":{"position":[[21,2],[77,2]]},"526":{"position":[[314,2]]},"666":{"position":[[140,2]]},"828":{"position":[[29,2]]},"841":{"position":[[29,2]]},"847":{"position":[[29,2]]}}}],["重载",{"_index":1795,"t":{"365":{"position":[[56,2]]},"512":{"position":[[74,2]]},"882":{"position":[[147,2]]},"894":{"position":[[73,2]]},"928":{"position":[[83,2]]}}}],["针对",{"_index":3234,"t":{"854":{"position":[[62,2]]}}}],["链接",{"_index":695,"t":{"86":{"position":[[59,2]]},"184":{"position":[[1268,2]]},"218":{"position":[[1268,2]]},"225":{"position":[[782,2]]},"447":{"position":[[184,2],[826,2]]},"830":{"position":[[438,2]]},"973":{"position":[[54,2]]}}}],["链路",{"_index":2446,"t":{"526":{"position":[[19,2],[79,2]]},"528":{"position":[[4,2]]},"794":{"position":[[85,2]]},"872":{"position":[[387,2]]}}}],["锁",{"_index":3254,"t":{"859":{"position":[[1160,1]]}}}],["锁定",{"_index":1163,"t":{"159":{"position":[[612,2],[624,2],[803,2],[933,2]]}}}],["错综复杂",{"_index":3256,"t":{"862":{"position":[[71,4]]}}}],["错误",{"_index":3252,"t":{"859":{"position":[[1146,2]]}}}],["键",{"_index":955,"t":{"127":{"position":[[250,1],[526,1]]},"132":{"position":[[264,1]]},"216":{"position":[[103,1]]},"455":{"position":[[797,1]]},"512":{"position":[[85,1]]},"804":{"position":[[9,1]]},"894":{"position":[[84,1]]},"928":{"position":[[94,1]]}}}],["键值",{"_index":2991,"t":{"727":{"position":[[1832,2]]},"830":{"position":[[753,2]]}}}],["镜像文件",{"_index":3167,"t":{"822":{"position":[[26,4]]}}}],["长",{"_index":1767,"t":{"361":{"position":[[747,1]]},"365":{"position":[[1722,1]]}}}],["长度",{"_index":566,"t":{"57":{"position":[[1043,2]]},"184":{"position":[[551,2]]},"218":{"position":[[551,2]]},"272":{"position":[[1071,2]]},"290":{"position":[[247,2],[434,2],[510,2]]},"301":{"position":[[1317,2],[1382,2],[1442,2],[1662,2]]},"304":{"position":[[48,2],[58,2]]},"308":{"position":[[536,2],[1154,2],[1189,2],[1404,2],[1559,2],[2512,2]]},"338":{"position":[[32,2]]},"343":{"position":[[84,2]]},"347":{"position":[[546,2],[1472,2]]},"350":{"position":[[97,2]]},"359":{"position":[[38,2],[119,2]]},"361":{"position":[[527,2],[671,2],[949,2],[1288,2],[1568,2],[1576,2],[1762,2],[1768,2],[1958,2],[1964,2]]},"365":{"position":[[1924,2]]},"402":{"position":[[34,2]]},"404":{"position":[[24,2],[31,2],[85,2],[92,2],[150,2],[157,2]]},"406":{"position":[[533,2]]},"418":{"position":[[2,2],[47,2]]},"420":{"position":[[13,2]]},"422":{"position":[[54,2],[99,2],[486,2],[517,2]]},"431":{"position":[[691,2]]},"465":{"position":[[628,2]]},"487":{"position":[[124,2]]},"507":{"position":[[463,2],[644,2]]},"697":{"position":[[39,2]]},"702":{"position":[[861,2]]},"727":{"position":[[1327,2],[1447,2]]},"745":{"position":[[54,2],[99,2],[588,2]]},"748":{"position":[[49,2],[176,2],[355,2],[390,2]]},"818":{"position":[[19,2]]},"830":{"position":[[545,2]]},"957":{"position":[[69,2]]},"980":{"position":[[67,2]]}}}],["闭环",{"_index":1987,"t":{"409":{"position":[[92,2]]}}}],["问",{"_index":3087,"t":{"783":{"position":[[151,1]]}}}],["问题",{"_index":60,"t":{"7":{"position":[[63,2]]},"50":{"position":[[124,2]]},"184":{"position":[[894,2],[977,2],[1247,2],[1673,2],[1756,2]]},"218":{"position":[[894,2],[977,2],[1247,2],[1673,2],[1756,2]]},"334":{"position":[[45,2]]},"338":{"position":[[49,2]]},"400":{"position":[[19,2]]},"402":{"position":[[11,2]]},"409":{"position":[[22,2]]},"418":{"position":[[57,2]]},"442":{"position":[[109,2]]},"444":{"position":[[277,2],[475,2],[595,2],[616,2]]},"465":{"position":[[22,2]]},"485":{"position":[[121,2]]},"503":{"position":[[17,2],[53,2],[101,2]]},"570":{"position":[[51,2]]},"639":{"position":[[36,2]]},"668":{"position":[[67,2]]},"809":{"position":[[69,2]]},"874":{"position":[[334,2]]},"884":{"position":[[278,2]]},"976":{"position":[[51,2]]}}}],["间接",{"_index":155,"t":{"20":{"position":[[56,2]]}}}],["间隔",{"_index":1175,"t":{"164":{"position":[[115,2]]},"184":{"position":[[1122,2],[1901,2]]},"218":{"position":[[1122,2],[1901,2]]},"250":{"position":[[115,2]]}}}],["阁主",{"_index":1862,"t":{"370":{"position":[[231,2]]}}}],["阅读",{"_index":3275,"t":{"872":{"position":[[28,2]]}}}],["阈值",{"_index":2796,"t":{"666":{"position":[[96,2]]}}}],["队列",{"_index":457,"t":{"50":{"position":[[117,2]]},"184":{"position":[[546,2]]},"218":{"position":[[546,2]]}}}],["防止",{"_index":1624,"t":{"301":{"position":[[1200,2]]},"447":{"position":[[1205,2]]}}}],["阳",{"_index":1890,"t":{"370":{"position":[[436,1]]}}}],["阴影",{"_index":3363,"t":{"906":{"position":[[148,2]]}}}],["阶段",{"_index":249,"t":{"32":{"position":[[19,2]]},"34":{"position":[[123,2]]},"503":{"position":[[59,2]]}}}],["阻塞",{"_index":1710,"t":{"340":{"position":[[883,2]]},"672":{"position":[[1035,2]]},"674":{"position":[[942,2]]},"727":{"position":[[1899,2]]},"832":{"position":[[2352,2]]}}}],["附加",{"_index":35,"t":{"5":{"position":[[78,2]]},"323":{"position":[[273,2]]},"431":{"position":[[698,2]]},"935":{"position":[[63,2]]}}}],["附带",{"_index":106,"t":{"12":{"position":[[66,2]]}}}],["附表",{"_index":2888,"t":{"702":{"position":[[1087,2],[1174,2]]}}}],["陌生",{"_index":1897,"t":{"374":{"position":[[17,2]]}}}],["降",{"_index":3450,"t":{"967":{"position":[[70,1]]}}}],["降低",{"_index":1310,"t":{"184":{"position":[[1055,2],[1066,2],[1834,2],[1845,2]]},"218":{"position":[[1055,2],[1066,2],[1834,2],[1845,2]]}}}],["限于",{"_index":109,"t":{"12":{"position":[[82,2]]}}}],["限制",{"_index":424,"t":{"48":{"position":[[0,2]]},"559":{"position":[[105,2]]},"657":{"position":[[9,2]]},"666":{"position":[[16,2]]},"668":{"position":[[17,2]]},"729":{"position":[[8,2],[32,2]]},"814":{"position":[[7,2]]}}}],["限时",{"_index":137,"t":{"18":{"position":[[0,2]]},"971":{"position":[[24,2]]}}}],["限速",{"_index":3120,"t":{"794":{"position":[[25,2]]},"950":{"position":[[50,2]]},"952":{"position":[[26,2]]}}}],["除",{"_index":1938,"t":{"391":{"position":[[20,1]]},"455":{"position":[[612,1]]},"630":{"position":[[56,1]]},"878":{"position":[[164,1]]}}}],["除了",{"_index":1067,"t":{"144":{"position":[[0,2]]},"530":{"position":[[80,2]]}}}],["除外",{"_index":2648,"t":{"581":{"position":[[88,2]]}}}],["除此之外",{"_index":3407,"t":{"935":{"position":[[54,4]]}}}],["陶",{"_index":1925,"t":{"381":{"position":[[3,1]]}}}],["随后",{"_index":1706,"t":{"340":{"position":[[813,2]]}}}],["随意",{"_index":370,"t":{"44":{"position":[[26,2]]},"48":{"position":[[45,2],[220,2]]},"55":{"position":[[18,2]]},"270":{"position":[[20,2]]},"306":{"position":[[37,2]]},"345":{"position":[[17,2]]},"741":{"position":[[40,2]]}}}],["随时",{"_index":289,"t":{"34":{"position":[[98,2]]},"44":{"position":[[44,2],[58,2]]},"411":{"position":[[88,2]]},"413":{"position":[[88,2]]},"537":{"position":[[528,2]]},"539":{"position":[[43,2]]},"727":{"position":[[1532,2]]},"828":{"position":[[75,2]]},"961":{"position":[[157,2]]}}}],["隔开",{"_index":1714,"t":{"343":{"position":[[48,2]]},"925":{"position":[[745,2]]}}}],["隔离",{"_index":3123,"t":{"800":{"position":[[14,2]]}}}],["难",{"_index":2093,"t":{"440":{"position":[[283,1]]}}}],["难受",{"_index":2110,"t":{"444":{"position":[[225,2]]}}}],["雅",{"_index":885,"t":{"120":{"position":[[1686,1]]}}}],["集",{"_index":25,"t":{"5":{"position":[[44,1]]},"10":{"position":[[5,1],[21,1],[42,1]]},"12":{"position":[[5,1],[21,1],[42,1]]},"14":{"position":[[5,1],[21,1],[42,1]]},"18":{"position":[[70,1]]},"20":{"position":[[52,1],[76,1]]},"23":{"position":[[35,1]]},"444":{"position":[[302,1],[675,1]]},"447":{"position":[[1254,1]]},"449":{"position":[[126,1],[143,1],[174,1],[194,1],[219,1],[252,1]]},"521":{"position":[[192,1],[456,1]]},"705":{"position":[[28,1]]},"932":{"position":[[224,1]]}}}],["集中",{"_index":2839,"t":{"686":{"position":[[481,2]]}}}],["集合",{"_index":2368,"t":{"507":{"position":[[381,2],[461,2]]},"530":{"position":[[45,2],[113,2],[438,2],[519,2],[1045,2]]}}}],["集成",{"_index":3175,"t":{"824":{"position":[[43,2]]}}}],["集群",{"_index":3128,"t":{"806":{"position":[[125,2]]}}}],["雪花",{"_index":2704,"t":{"608":{"position":[[0,2]]},"820":{"position":[[4,2]]}}}],["需",{"_index":762,"t":{"104":{"position":[[51,1]]},"301":{"position":[[1425,1]]},"340":{"position":[[13,1]]},"357":{"position":[[185,1]]},"449":{"position":[[43,1]]},"595":{"position":[[93,1]]}}}],["需求",{"_index":490,"t":{"53":{"position":[[65,2]]},"151":{"position":[[112,2]]},"455":{"position":[[999,2],[1064,2]]},"574":{"position":[[43,2]]},"776":{"position":[[128,2]]},"778":{"position":[[50,2]]},"854":{"position":[[11,2],[66,2]]},"959":{"position":[[47,2]]}}}],["需要",{"_index":149,"t":{"18":{"position":[[80,2]]},"40":{"position":[[1,2]]},"66":{"position":[[53,2]]},"75":{"position":[[53,2]]},"86":{"position":[[42,2],[63,2],[72,2],[98,2]]},"104":{"position":[[2,2],[201,2]]},"125":{"position":[[55,2]]},"134":{"position":[[3668,2]]},"136":{"position":[[28,2],[43,2]]},"146":{"position":[[14,2],[89,2],[110,2]]},"159":{"position":[[606,2]]},"166":{"position":[[416,2],[442,2],[484,2],[532,2]]},"196":{"position":[[41,2]]},"239":{"position":[[233,2]]},"252":{"position":[[416,2],[442,2],[484,2],[532,2]]},"259":{"position":[[52,2]]},"288":{"position":[[18,2]]},"295":{"position":[[53,2]]},"301":{"position":[[886,2]]},"319":{"position":[[2,2],[37,2]]},"340":{"position":[[799,2]]},"343":{"position":[[6,2]]},"347":{"position":[[926,2],[958,2],[1599,2]]},"361":{"position":[[662,2],[1072,2],[1089,2]]},"365":{"position":[[63,2],[83,2],[1371,2],[1428,2],[1473,2]]},"378":{"position":[[28,2],[51,2]]},"383":{"position":[[7,2]]},"400":{"position":[[65,2]]},"402":{"position":[[95,2]]},"415":{"position":[[171,2]]},"431":{"position":[[26,2]]},"442":{"position":[[37,2],[145,2]]},"444":{"position":[[62,2],[78,2],[139,2],[187,2],[201,2],[505,2],[521,2],[585,2],[608,2],[634,2],[650,2],[670,2]]},"447":{"position":[[731,2],[746,2],[846,2],[1285,2]]},"449":{"position":[[166,2]]},"453":{"position":[[1,2]]},"455":{"position":[[501,2]]},"473":{"position":[[287,2]]},"485":{"position":[[149,2]]},"487":{"position":[[100,2]]},"503":{"position":[[169,2]]},"505":{"position":[[23,2]]},"512":{"position":[[77,2]]},"514":{"position":[[109,2]]},"516":{"position":[[79,2],[146,2]]},"521":{"position":[[337,2]]},"530":{"position":[[25,2],[82,2],[93,2],[146,2],[995,2]]},"542":{"position":[[19,2],[82,2],[213,2]]},"574":{"position":[[30,2]]},"615":{"position":[[74,2]]},"628":{"position":[[75,2]]},"630":{"position":[[248,2]]},"641":{"position":[[9,2]]},"661":{"position":[[59,2],[117,2]]},"679":{"position":[[261,2]]},"681":{"position":[[73,2]]},"689":{"position":[[85,2],[153,2],[185,2]]},"693":{"position":[[25,2],[46,2]]},"707":{"position":[[170,2]]},"718":{"position":[[12,2]]},"720":{"position":[[94,2]]},"750":{"position":[[206,2]]},"758":{"position":[[103,2]]},"778":{"position":[[58,2],[103,2]]},"780":{"position":[[359,2]]},"806":{"position":[[79,2]]},"809":{"position":[[34,2]]},"816":{"position":[[1,2]]},"828":{"position":[[10,2]]},"832":{"position":[[814,2],[2046,2]]},"834":{"position":[[15,2]]},"836":{"position":[[25,2],[46,2],[53,2],[83,2]]},"849":{"position":[[8,2]]},"872":{"position":[[738,2],[942,2]]},"874":{"position":[[37,2]]},"878":{"position":[[313,2],[663,2]]},"894":{"position":[[76,2]]},"896":{"position":[[361,2]]},"901":{"position":[[7,2]]},"909":{"position":[[178,2]]},"928":{"position":[[86,2]]},"932":{"position":[[9,2]]},"935":{"position":[[69,2]]},"969":{"position":[[31,2]]}}}],["静态",{"_index":1096,"t":{"153":{"position":[[9,2]]},"411":{"position":[[20,2]]},"413":{"position":[[20,2]]},"440":{"position":[[64,2],[69,2],[130,2],[135,2],[158,2]]},"447":{"position":[[1324,2]]},"458":{"position":[[20,2],[311,2]]},"521":{"position":[[274,2],[514,2]]},"868":{"position":[[236,2]]},"952":{"position":[[15,2]]},"969":{"position":[[294,2]]}}}],["静态方法",{"_index":2195,"t":{"451":{"position":[[42,4]]},"610":{"position":[[15,4]]}}}],["非",{"_index":1146,"t":{"159":{"position":[[88,1]]},"229":{"position":[[14,1]]},"402":{"position":[[97,1]]},"738":{"position":[[66,1]]},"876":{"position":[[147,1]]}}}],["非常",{"_index":1086,"t":{"149":{"position":[[75,2]]},"288":{"position":[[92,2]]},"409":{"position":[[115,2]]},"468":{"position":[[8,2]]},"503":{"position":[[167,2]]},"778":{"position":[[130,2],[189,2]]},"822":{"position":[[66,2]]},"824":{"position":[[16,2]]},"828":{"position":[[27,2]]}}}],["非常容易",{"_index":3020,"t":{"743":{"position":[[31,4]]}}}],["非常简单",{"_index":317,"t":{"36":{"position":[[16,4]]},"159":{"position":[[211,4],[600,4]]},"194":{"position":[[31,4]]},"233":{"position":[[31,4]]},"595":{"position":[[6,4]]},"597":{"position":[[46,4]]},"681":{"position":[[17,4]]},"756":{"position":[[40,4]]},"780":{"position":[[5,4]]},"783":{"position":[[70,4]]},"841":{"position":[[4,4]]},"847":{"position":[[4,4]]}}}],["面对",{"_index":1802,"t":{"365":{"position":[[166,2]]}}}],["页面",{"_index":1492,"t":{"263":{"position":[[1,2]]},"458":{"position":[[313,2]]}}}],["项",{"_index":1167,"t":{"164":{"position":[[3,1]]},"184":{"position":[[3,1]]},"218":{"position":[[3,1]]},"225":{"position":[[573,1]]},"235":{"position":[[74,1]]},"250":{"position":[[3,1]]},"255":{"position":[[55,1]]},"261":{"position":[[253,1]]},"376":{"position":[[179,1],[251,1],[404,1],[651,1],[732,1]]},"447":{"position":[[774,1]]},"507":{"position":[[475,1],[656,1]]},"906":{"position":[[183,1]]}}}],["项目",{"_index":626,"t":{"66":{"position":[[15,2],[61,2]]},"75":{"position":[[15,2],[61,2]]},"86":{"position":[[15,2],[106,2]]},"138":{"position":[[227,2]]},"385":{"position":[[12,2]]},"440":{"position":[[277,2]]},"442":{"position":[[126,2],[141,2],[150,2]]},"444":{"position":[[92,2],[102,2],[109,2],[132,2],[137,2],[164,2],[193,2],[207,2],[327,2],[358,2],[411,2],[557,2],[563,2]]},"447":{"position":[[199,2],[753,2],[764,2]]},"449":{"position":[[204,2]]},"503":{"position":[[119,2],[142,2]]},"686":{"position":[[493,2]]},"705":{"position":[[62,2],[71,2]]},"707":{"position":[[108,2]]},"714":{"position":[[2,2]]},"716":{"position":[[2,2],[7,2]]},"718":{"position":[[170,2],[240,2]]},"906":{"position":[[92,2],[164,2],[206,2]]},"969":{"position":[[8,2],[34,2],[219,2],[399,2]]}}}],["项目管理",{"_index":3358,"t":{"906":{"position":[[36,4]]}}}],["顺利",{"_index":2768,"t":{"653":{"position":[[201,2]]}}}],["顺序",{"_index":1124,"t":{"157":{"position":[[318,2]]},"194":{"position":[[194,2]]},"223":{"position":[[878,2]]},"225":{"position":[[1214,2],[1768,2]]},"229":{"position":[[470,2]]},"233":{"position":[[197,2]]},"570":{"position":[[92,2],[123,2]]},"761":{"position":[[28,2],[95,2]]},"859":{"position":[[924,2]]}}}],["须",{"_index":144,"t":{"18":{"position":[[33,1]]},"440":{"position":[[232,1],[240,1]]}}}],["顾名思义",{"_index":2445,"t":{"526":{"position":[[8,4]]}}}],["颁发",{"_index":761,"t":{"104":{"position":[[46,2]]},"319":{"position":[[12,2]]}}}],["预先",{"_index":225,"t":{"28":{"position":[[48,2]]}}}],["预处理",{"_index":1216,"t":{"180":{"position":[[28,3]]},"212":{"position":[[98,3]]},"957":{"position":[[29,3]]}}}],["预定",{"_index":2656,"t":{"586":{"position":[[12,2]]}}}],["预留",{"_index":2297,"t":{"485":{"position":[[257,2]]}}}],["预置",{"_index":2905,"t":{"702":{"position":[[1444,2],[1458,2],[1471,2]]}}}],["预设",{"_index":986,"t":{"132":{"position":[[305,2]]},"363":{"position":[[10,2]]},"572":{"position":[[8,2]]},"684":{"position":[[98,2]]}}}],["频繁",{"_index":1922,"t":{"378":{"position":[[114,2]]}}}],["额外",{"_index":1022,"t":{"134":{"position":[[3670,2]]},"530":{"position":[[27,2]]},"693":{"position":[[27,2]]},"836":{"position":[[27,2],[93,2]]}}}],["风暴",{"_index":3221,"t":{"839":{"position":[[68,2]]}}}],["首个",{"_index":3030,"t":{"748":{"position":[[145,2]]}}}],["首先",{"_index":522,"t":{"57":{"position":[[284,2]]},"166":{"position":[[119,2]]},"235":{"position":[[0,2]]},"252":{"position":[[119,2]]},"261":{"position":[[584,2]]},"272":{"position":[[272,2]]},"308":{"position":[[275,2]]},"347":{"position":[[279,2]]},"361":{"position":[[0,2]]},"415":{"position":[[148,2]]},"526":{"position":[[63,2]]},"787":{"position":[[0,2]]},"806":{"position":[[20,2]]},"891":{"position":[[156,2]]},"969":{"position":[[0,2]]}}}],["首页",{"_index":2021,"t":{"424":{"position":[[2,2]]}}}],["驱动",{"_index":1222,"t":{"180":{"position":[[90,2]]},"212":{"position":[[160,2]]}}}],["验证",{"_index":772,"t":{"104":{"position":[[214,2]]},"164":{"position":[[25,2],[78,2]]},"166":{"position":[[105,2],[121,2],[173,2],[197,2]]},"250":{"position":[[25,2],[78,2]]},"252":{"position":[[105,2],[121,2],[173,2],[197,2]]},"385":{"position":[[45,2]]},"397":{"position":[[108,2]]},"619":{"position":[[43,2]]},"770":{"position":[[2,2],[46,2],[63,2]]},"772":{"position":[[39,2]]},"790":{"position":[[4,2],[14,2]]},"824":{"position":[[23,2]]},"832":{"position":[[259,2],[1064,2],[1837,2]]},"878":{"position":[[130,2]]}}}],["高",{"_index":1312,"t":{"184":{"position":[[1072,1],[1851,1]]},"218":{"position":[[1072,1],[1851,1]]},"440":{"position":[[207,1]]},"442":{"position":[[28,1]]},"523":{"position":[[370,1]]},"761":{"position":[[69,1],[140,1],[188,1],[195,1]]},"778":{"position":[[46,1],[191,1]]},"806":{"position":[[369,1]]}}}],["高位",{"_index":3058,"t":{"761":{"position":[[113,2]]}}}],["高低",{"_index":3061,"t":{"761":{"position":[[173,2]]}}}],["高字节",{"_index":3054,"t":{"761":{"position":[[42,3],[131,3]]}}}],["高度",{"_index":1358,"t":{"194":{"position":[[37,2]]},"233":{"position":[[37,2]]}}}],["高性能",{"_index":305,"t":{"34":{"position":[[227,3]]},"180":{"position":[[21,3]]},"201":{"position":[[15,3]]},"212":{"position":[[21,3]]},"792":{"position":[[193,3]]},"864":{"position":[[0,3]]},"911":{"position":[[15,3]]}}}],["高效",{"_index":1964,"t":{"400":{"position":[[31,2]]},"487":{"position":[[109,2]]},"498":{"position":[[85,2]]},"505":{"position":[[11,2]]},"689":{"position":[[260,2]]},"748":{"position":[[14,2]]},"783":{"position":[[18,2]]},"917":{"position":[[132,2]]}}}],["高效率",{"_index":1307,"t":{"184":{"position":[[1003,3],[1782,3]]},"218":{"position":[[1003,3],[1782,3]]}}}],["高级",{"_index":3098,"t":{"785":{"position":[[95,2]]}}}],["高速",{"_index":3009,"t":{"736":{"position":[[335,2]]}}}],["高频",{"_index":1693,"t":{"338":{"position":[[66,2]]}}}],["麻烦",{"_index":2102,"t":{"442":{"position":[[154,2]]},"666":{"position":[[179,2]]}}}],["麻烦事",{"_index":2744,"t":{"639":{"position":[[55,3]]}}}],["黄",{"_index":1870,"t":{"370":{"position":[[277,1]]}}}],["黏",{"_index":234,"t":{"28":{"position":[[77,1]]}}}],["黑",{"_index":886,"t":{"120":{"position":[[1687,1]]},"444":{"position":[[437,1]]}}}],["黑名单",{"_index":2994,"t":{"729":{"position":[[62,3]]}}}],["默认",{"_index":201,"t":{"25":{"position":[[267,2]]},"46":{"position":[[466,2]]},"50":{"position":[[24,2],[260,2]]},"127":{"position":[[260,2],[536,2]]},"164":{"position":[[32,2],[112,2]]},"166":{"position":[[110,2]]},"184":{"position":[[41,2],[181,2],[554,2],[580,2],[808,2],[860,2],[1466,2],[1639,2],[1987,2]]},"218":{"position":[[41,2],[181,2],[554,2],[580,2],[808,2],[860,2],[1466,2],[1639,2],[1987,2]]},"223":{"position":[[19,2]]},"250":{"position":[[32,2],[112,2]]},"252":{"position":[[110,2]]},"404":{"position":[[64,2],[116,2],[130,2]]},"413":{"position":[[96,2]]},"493":{"position":[[16,2]]},"521":{"position":[[0,2]]},"528":{"position":[[663,2],[1377,2]]},"544":{"position":[[112,2]]},"546":{"position":[[6,2]]},"552":{"position":[[41,2],[117,2]]},"610":{"position":[[311,2]]},"615":{"position":[[0,2]]},"666":{"position":[[26,2]]},"668":{"position":[[15,2]]},"689":{"position":[[20,2]]},"745":{"position":[[517,2]]},"748":{"position":[[467,2]]},"750":{"position":[[61,2]]},"767":{"position":[[15,2]]},"770":{"position":[[24,2]]},"783":{"position":[[82,2]]},"816":{"position":[[37,2]]},"868":{"position":[[258,2]]},"872":{"position":[[605,2],[731,2],[931,2]]},"874":{"position":[[350,2]]}}}],["默认设置",{"_index":2791,"t":{"666":{"position":[[40,4]]}}}]],"pipeline":["stemmer"]}}] \ No newline at end of file diff --git a/handbook/build/search/index.html b/handbook/build/search/index.html new file mode 100644 index 000000000..0294ab2df --- /dev/null +++ b/handbook/build/search/index.html @@ -0,0 +1,16 @@ + + + + + +Search the documentation + + + + +
+

Search the documentation

+ + + + \ No newline at end of file diff --git a/handbook/build/sitemap.xml b/handbook/build/sitemap.xml new file mode 100644 index 000000000..15b12109a --- /dev/null +++ b/handbook/build/sitemap.xml @@ -0,0 +1 @@ +https://rrqm_home.gitee.io/touchsocket/searchweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/weekly0.5https://rrqm_home.gitee.io/touchsocket/docs/adapterdemodescriptionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/adapterdescriptionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/appmessengerweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/bigfixedheadercustomdatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/bytepoolweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/calljsonrpcweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/callwebapiweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/callxmlrpcweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/consoleactionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/cooperationweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createandcallrpcweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createhttpclientweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createhttpserviceweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createtcpclientweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createtcpserviceweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createtouchrpcclientweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createtouchrpcserviceweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createudpsessionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createwebsocketclientweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/createwebsocketserviceweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/custombetweenanddatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/customdatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/customfixedheaderdatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/customunfixedheaderdatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/dataadaptertesterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/dataforwardingweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/datahandleadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/datasecurityweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/dependencypropertyweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/donateweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/engineertoolboxweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/enterpriseweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/eventbusweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/fastbinaryformatterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/filepoolweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/filesynchronizationweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/fixedheaderpackageadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/fixedsizepackageadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/fpsgameweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/generateproxyweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/heartbeatweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/httpfiletransferweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/httpstaticpagepluginweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/ilogweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/independentusedatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/iocweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/ipackageweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/jsonrpcdescriptionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/jsonrpcserviceweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/jsonserializeweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/multithreadingfiletransferweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/natserviceweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/normaldatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/othercoreweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/pipelinedatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/pluginsmanagerweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/reconnectionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/remotefilecontrolweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/remotemonitoringweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/remotestreamaccessweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/resetidweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/rpcactionfilterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/rpcallcontextweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/rpcoptionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/rpcstreamweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/serializationselectorweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/smallfiletransferweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/startguideweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/stategridtransmissionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/streamtransferweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/tcpcommandlinepluginweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/tcpotherweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/terminatorpackageadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/tlvdatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/touchrpcbaseweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/touchrpcdescriptionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/touchsocketbitconverterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/transferfileweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/udpbroadcastweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/udpdatahandlingadapterweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/udptransmitbigdataweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/upgradeweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/waitingclientweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/webapidescriptionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/webapiserviceweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/webdataforwardingweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/websocketdescriptionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/wpfuifiletransferweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/wscommandlinepluginweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/wsjsonrpcweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/xmlrpcdescriptionweekly0.5https://rrqm_home.gitee.io/touchsocket/docs/xmlrpcserviceweekly0.5https://rrqm_home.gitee.io/touchsocket/weekly0.5 \ No newline at end of file diff --git a/handbook/docs/adapterdemodescription.mdx b/handbook/docs/adapterdemodescription.mdx new file mode 100644 index 000000000..6ff33d79d --- /dev/null +++ b/handbook/docs/adapterdemodescription.mdx @@ -0,0 +1,16 @@ +--- +id: adapterdemodescription +title: 说明 +--- + + +## 说明 + +此页面展示用户通过TouchSocket自行实现的适配器案例。更好的共享资源。 + +欢迎大家提交更多。邮箱:505554090@qq.com + +## 提交要求 + +1. 通过单元测试。 +2. 编码尽可能规范。 \ No newline at end of file diff --git a/handbook/docs/adapterdescription.mdx b/handbook/docs/adapterdescription.mdx new file mode 100644 index 000000000..9039c4e0d --- /dev/null +++ b/handbook/docs/adapterdescription.mdx @@ -0,0 +1,105 @@ +--- +id: adapterdescription +title: 介绍及使用 +--- + +## 说明 +在TouchSocket中,适配器贯穿始终,其作用实际上有两个,分别为: + +- 对发送和接收的数据进行预先的封装和解封,以达到解析数据的作用(可以简单理解为处理黏、分包)。 +- 将特殊数据解析为可以传递的数据结构,以达到解析数据的目的。 + +**很明显,大家看到了,数据处理适配器的作用用一句话说,就是解析数据用的。** +## 设计架构 +### 工作逻辑 +![](https://images.gitee.com/uploads/images/2022/0125/192152_18f6c642_8553710.png#crop=0&crop=0&crop=1&crop=1&id=y6Ob5&originHeight=1487&originWidth=3450&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=) +### 数据逻辑 +TouchSocket的适配器,在初始阶段(原始TCP),会收到一个ByteBlock数据,然后经过适配器处理以后,可选择两个参数(ByteBlock和IRequestInfo)的**任意组合**投递数据。 + +例如:**FixedHeaderPackageAdapter**,仅投递ByteBlock数据,届时IRequestInfo将为null。而如果是继承的**CustomDataHandlingAdapter**,则仅投递IRequestInfo,ByteBlock将为null。 +### 设计解释 +大家有时候可能会迷惑,为什么TouchSocket要设计两个参数投递,而不像其他的那样的,在会话里面,把适配器直接泛型规范了,直接抛出对应的类型。这是因为泛型约束太大,不够灵活。例如: + +- 第一,不能随时切换适配器,例如适配webSocket,在握手阶段,要解析http数据,所以,此时应该选择http数据处理适配,而完成握手以后,就要解析ws数据格式了,所以此时应该切换适配器为ws数据处理适配器。 +- 第二,两个参数能提高性能。例如HTTP数据处理适配器,在高性能工作模式下,由IRequestInfo投递请求头,由ByteBlock投递Body,这样Body是从内存池获得,就不存在内存消耗了。 +## 三、TCP使用 +在TCP系中使用数据处理适配器是非常简单的一个过程。而且为了不同场景,TouchSocket支持多种方式的适配器使用。服务器和客户端使用一致 + +### 3.1 在Config配置中使用 +在Config配置使用时,相当于初始化赋值。比较单一,但是很可靠。 +```csharp +.SetDataHandlingAdapter(()=> { return new MyCustomBetweenAndDataHandlingAdapter(); }) +``` +### 3.2 订阅Connecting相关事件 +只需要在`OnConnecting`方法(或`Connecting`事件)中对新连接的Client,调用SetDataHandlingAdapter进行赋值即可。 +```csharp +public class MyTcpService : TcpService +{ + protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e) + { + socketClient.SetDataHandlingAdapter(new NormalDataHandlingAdapter());//直接对数据处理器赋值,立即生效 + base.OnConnecting(socketClient, e); + } +} +``` + +### 3.3 使用插件,代替Connecting相关事件实现 +使用插件实现该功能,实际上和步骤2一样,但是因为是基于插件,所以更好于管理。 +```csharp +class MyPlugin : TcpPluginBase +{ + protected override void OnConnecting(ITcpClientBase client, ClientOperationEventArgs e) + { + client.SetDataHandlingAdapter(new NormalDataHandlingAdapter()); + base.OnConnecting(client, e); + } +} +``` + +### 3.4 任意时刻设置 +实际上,大家可以从步骤2、3中看出来,适配器是可以被随意赋值的,这也就说明,适配器是可以随时被替换的。那么也就可以被随时赋值了。 + +## 四、UDP使用插件 +Udp使用的插件,只能从Config配置。 +【**UdpSession**】 +```csharp + m_udpSession.Setup(new TouchSocketConfig() + .SetBindIPHost(new IPHost(this.textBox2.Text)) + .SetUdpDataHandlingAdapter(()=> + { + return new NormalUdpDataHandlingAdapter(); + }) + .ConfigureContainer(a => + { + a.SetSingletonLogger(new LoggerGroup(new EasyLogger(this.ShowMsg), new FileLogger())); + })) + .Start(); +``` +**_注意:_同一个适配器实例,只可被赋值一次,不然会异常。_如果在构造函数(或其他一次性函数)中设置适配器的话,在重连时,最好重新设置适配器,因为框架在Disconnected时会置空适配器,同时在Connecting执行完后会检测适配器,如果没有再次设置适配器的话,会选择默认适配器(TcpClient会选择普通适配器,Protocol及派生会选择固定包头适配器)。_** +## 五、限制使用 +限制使用的场景应用于自定义封装。例如:自己封装一个服务器,然后适配器仅**特定使用**,不允许外部随意赋值,那么可以如下实现: +```csharp +public class MySocketClient : SocketClient +{ + /// + /// + /// + public override sealed bool CanSetDataHandlingAdapter => false;//不允许随意赋值 + + private void InternalSetAdapter(DataHandlingAdapter adapter) + { + this.SetAdapter(adapter);//仅继承内部赋值 + } +} +``` + +## 六、缓存超时(仅Tcp适配器) +当适配器在工作时,如果一个数据包在设置的周期内(默认1000ms)没有完成接收,则会清空所有缓存数据,然后重新接收。 +这种设计是为了应对,当接收数据时,如果发送方发送了异常数据(也有可能在移动网时,由运营商发送的无效包)而导致整个接收队列数据无效的问题。 +现在加入缓存超时设置,则如果发送上述情况,也会在一个周期后,快速恢复接收。 + +相关属性设置: + +- CacheTimeoutEnable:是否启用缓存超时。 +- CacheTimeout:缓存超时时间 +- UpdateCacheTimeWhenRev:是否每次接收就更新缓存时间。默认true,意味着只要有数据接收,则缓存永远不会过期。当为false时,则每个缓存包,必须在设置的周期内完成接收。 diff --git a/handbook/docs/appmessenger.mdx b/handbook/docs/appmessenger.mdx new file mode 100644 index 000000000..60acfe582 --- /dev/null +++ b/handbook/docs/appmessenger.mdx @@ -0,0 +1,46 @@ +--- +id: appmessenger +title: 应用信使 +--- + +## 一、说明 +应用信使是在进程内的,行使注册和触发功能的组件。可**代替事件**,可**跨越程序集**,可**依赖倒置**。 + +## 二、使用 + + +【声明主体】 +实现IMessage接口,然后增加AppMessage标记的公共方法。 +```csharp +public class MessageObject : IMessage +{ + + [AppMessage] + public int Add(int a, int b) + { + return a + b; + } + + [AppMessage] + public int Sub(int a, int b) + { + return a - b; + } +} + +``` +【注册】 +下列演示时,是新实例化的AppMessenger,实际上,用户可以直接使用AppMessenger.Default默认实例。 +```csharp +AppMessenger appMessenger = new AppMessenger(); +appMessenger.Register(); +``` +【触发】 +触发时,泛型类型,即时返回值类型。 +```csharp +int add = appMessenger.Send("Add", 20, 10); +Assert.Equal(30,add); + +int sub = appMessenger.Send("Sub", 20, 10); +Assert.Equal(10, sub); +``` diff --git a/handbook/docs/bigfixedheadercustomdatahandlingadapter.mdx b/handbook/docs/bigfixedheadercustomdatahandlingadapter.mdx new file mode 100644 index 000000000..9bd03c9bf --- /dev/null +++ b/handbook/docs/bigfixedheadercustomdatahandlingadapter.mdx @@ -0,0 +1,106 @@ +--- +id: bigfixedheadercustomdatahandlingadapter +title: 模板解析“大数据固定包头”数据适配器 +--- + +## 一、说明 + +大数据固定包头,是对固定的包头模板的补充,一般来是,固定包头适配器,不能工作于超过2G的数据,但是在少数情况下,会有大量的数据传输需求。所以这部分的业务,可以用大数据固定包头实现。 + + +## 二、特点 + +1. 可以自由适配**99%**的数据协议。 +2. 可以随意定制数据协议。 +3. 可以与**任意语言、框架**对接数据。 +4. 可以接收**理论无限大**的数据。 + + +## 三、使用 + +客户端与服务器均适用。下列以服务器为例。 + +步骤 + +1. 声明新建类,实现IBigFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 +2. 声明新建类,继承BigFixedHeaderCustomDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 +3. TouchSocketConfig配置中设置。 +4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 + +【MyBigFixedHeaderRequestInfo】 +首先,新建MyBigFixedHeaderRequestInfo类,然后实现IBigFixedHeaderRequestInfo用户自定义固定包头接口。 +然后在**OnParsingHeader**函数执行结束时,对实现的`BodyLength`属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。 + +```csharp +/// +/// 下列示例,没有实现逻辑,仅解释思路。 +/// +class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo +{ + public long BodyLength => throw new NotImplementedException();//此处请使用字段实现。 + + public void OnAppendBody(byte[] buffer, int offset, int length) + { + //在这里会一直追加数据体,用户自行实现数据的保存。 + //注意,buffer可能为内存块的成员,所以,一定一定不要直接引用。 + } + + public bool OnFinished() + { + //触发该方法时,说明数据体接收完毕,返回true时,会触发Receive相关事件,否则不会。 + return true; + } + + public bool OnParsingHeader(byte[] header) + { + //解析头部。赋值BodyLength + return true; + } +} + +``` + +新建MyBigFixedHeaderCustomDataHandlingAdapter继承**CustomBigFixedHeaderDataHandlingAdapter**,然后对HeaderLength作出赋值,以此表明固定包头的长度是多少。 + +```csharp +/// +/// 模板解析“大数据固定包头”数据适配器 +/// +class MyBigFixedHeaderCustomDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter +{ + public override int HeaderLength =>8; + + protected override MyBigFixedHeaderRequestInfo GetInstance() + { + return new MyBigFixedHeaderRequestInfo(); + } +} +``` + +【接收】 + +```csharp +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 + if (requestInfo is MyBigFixedHeaderRequestInfo myRequestInfo) + { + //此处可以处理MyBigFixedHeaderRequestInfo的相关信息了。 + string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); + } + +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(() => { return new MyBigFixedHeaderCustomDataHandlingAdapter(); }))//配置适配器 + .Start();//启动 +``` + + +:::tip 提示 + +上述创建的适配器客户端与服务器均适用。 + +::: \ No newline at end of file diff --git a/handbook/docs/bytepool.mdx b/handbook/docs/bytepool.mdx new file mode 100644 index 000000000..2edd91f4e --- /dev/null +++ b/handbook/docs/bytepool.mdx @@ -0,0 +1,77 @@ +--- +id: bytepool +title: 内存池 +--- + +## 一、说明 +内存池是TouchSocketCore的最重要的组成部分,在TouchSocket产品中,BytePool贯穿始终。所以熟悉使用BytePool,也是非常重要的。 + +**Nuget Package:**[TouchSocket](https://www.nuget.org/packages/TouchSocket/) +## 二、功能 +内存池(BytePool)的最小实现单体是内存块(ByteBlock),它是继承自Stream的类,拥有和MemoryStream一样的功能和RRQM的增强功能。而且拥有释放回收能力,所以如果有MemoryStream的使用需求的话,就可以完全让ByteBlock替代。 +## 三、创建 +BytePool是静态类,无需创建,直接使用即可。ByteBlock可通过BytePool创建,也可以直接new对象,这两者实际操作一致。 +**_注意:创建的ByteBlock必须释放(Dispose),虽然不会内存泄露,但是会影响性能。_** +```csharp +ByteBlock byteBlock1 = new ByteBlock(byteSize:1024*1024,equalSize:false); +byteBlock1.Dispose(); +ByteBlock byteBlock2 = BytePool.GetByteBlock(byteSize:1024*1024,equalSize:false); +byteBlock2.Dispose(); +using (ByteBlock byteBlock3=new ByteBlock()) +{ +} +``` +## 四、使用 +基础使用和MemoryStream一致,下面仅介绍特定使用。 +### 4.1 写入、读取数据对象 +```csharp +using (ByteBlock byteBlock = new ByteBlock()) +{ + byteBlock.Write(byte.MaxValue); + byteBlock.Write(int.MaxValue); + byteBlock.Write(long.MaxValue); + byteBlock.Write("RRQM"); + byteBlock.WriteObject(new Person(), SerializationType.Json); + byteBlock.WriteBytesPackage(new byte[1024]); + byteBlock.Pos = 0;//读取时,先将游标移动到初始写入的位置,然后按写入顺序,依次读取 + byte ByteValue = byteBlock.ReadByte(); + int IntValue = byteBlock.ReadInt32(); + long LongValue = byteBlock.ReadInt64(); + string StringValue = byteBlock.ReadString(); + Person ObjectValue = byteBlock.ReadObject(SerializationType.Json); + byte[] BytesValue = byteBlock.ReadBytesPackage(); +} +``` +### 4.2 多线程同步协作(Hold) +在多线程异步时,设计架构应当遵守谁(Thread)创建的ByteBlock,由谁释放,这样就能很好的避免未释放的情况发生。实际上RRQMSocket中,就是秉承这样的设计,任何非用户创建的ByteBlock,都会由创建的线程最后释放。但是在使用中,经常出现异步多线程的操作。 +以RRQMSocket的TcpClient为例。如果直接在收到数据时,使用Task异步,则必定会发生关于ByteBlock的各种各样的异常。 +**原因非常简单,byteBlock对象在到达HandleReceivedData时,触发Task异步,此时触发线程会立即返回,并释放byteBlock,而Task异步线程会滞后,然后试图从已释放的byteBlock中获取数据,所以,必定发生异常。** +```csharp +public class MyTClient : TcpClient +{ + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + Task.Run(()=> + { + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + Console.WriteLine($"已接收到信息:{mes}"); + }); + } +} +``` +解决方法也非常简单,只需要在异步前锁定,然后使用完成后取消锁定,且不用再调用Dispose。 +```csharp +public class MyTClient : TcpClient +{ + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + byteBlock.SetHolding(true);//异步前锁定 + Task.Run(()=> + { + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + byteBlock.SetHolding(false);//使用完成后取消锁定,且不用再调用Dispose + Console.WriteLine($"已接收到信息:{mes}"); + }); + } +} +``` diff --git a/handbook/docs/calljsonrpc.mdx b/handbook/docs/calljsonrpc.mdx new file mode 100644 index 000000000..7573427a9 --- /dev/null +++ b/handbook/docs/calljsonrpc.mdx @@ -0,0 +1,139 @@ +--- +id: calljsonrpc +title: 发现、调用服务 +--- + + +## 一、直接调用 + +因为JsonRpc是通用调用协议,所以可以直接使用Json字符串调用。 + +以下字符串只是示例,具体的method参数,应当遵循当前路由。 + +【Tcp协议直接调用】 +在TCP协议时,按照适配器,选择性的是否以\r\n结尾。 + +```csharp +{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1} +``` + +【Http协议直接调用】 +在Http协议时,以Url+Post方式即可 + +```csharp +{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1} +``` + +【Websocket协议直接调用】 +在Websocket协议时,以文本类型,直接发送到服务器即可。 + +```csharp +{"jsonrpc": "2.0", "method": "testjsonrpc", "params":["RRQM"], "id": 1} +``` + + + +## 二、客户端直接调用 + +TouchSocket提供了JsonRpc的专属客户端,直接调用,则会则是不使用**任何代理**,直接Call RPC,使用比较简单。 + +【TCP协议】 + +```csharp +JsonRpcClient jsonRpcClient = new JsonRpcClient(); +jsonRpcClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7705") + .SetJRPT(JRPT.Tcp)); +jsonRpcClient.Connect(); + +Console.WriteLine("连接成功"); +string result = jsonRpcClient.Invoke("jsonrpcconsoleapp.server.testjsonrpc", InvokeOption.WaitInvoke, "TouchSocket"); +Console.WriteLine($"Tcp返回结果:{result}"); + +result = jsonRpcClient.Invoke("TestJsonRpc1", InvokeOption.WaitInvoke, "TouchSocket"); +Console.WriteLine($"Tcp返回结果:{result}"); + +result = jsonRpcClient.Invoke("jsonrpcconsoleapp.server.testgetcontext", InvokeOption.WaitInvoke, "TouchSocket"); +Console.WriteLine($"Tcp返回结果:{result}"); + +JObject obj = new JObject(); +obj.Add("A", "A"); +obj.Add("B", 10); +obj.Add("C", 100.1); +JObject newObj = jsonRpcClient.Invoke("jsonrpcconsoleapp.server.testjobject", InvokeOption.WaitInvoke, obj); +Console.WriteLine($"Tcp返回结果:{newObj}"); +``` + +【Http协议】 + +```csharp +static void JsonRpcClientInvokeByHttp() +{ + JsonRpcClient jsonRpcClient = new JsonRpcClient(); + jsonRpcClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost("http://127.0.0.1:7706/jsonrpc") + .SetJRPT(JRPT.Http)); + jsonRpcClient.Connect(); + Console.WriteLine("连接成功"); + string result = jsonRpcClient.Invoke("server/testjsonrpc", InvokeOption.WaitInvoke, "TouchSocket"); + Console.WriteLine($"Http返回结果:{result}"); + + JObject obj = new JObject(); + obj.Add("A", "A"); + obj.Add("B", 10); + obj.Add("C", 100.1); + JObject newObj = jsonRpcClient.Invoke("server/testjobject", InvokeOption.WaitInvoke, obj); + Console.WriteLine($"Http返回结果:{newObj}"); +} +``` + +【Websocket协议】 + +```csharp +JsonRpcClient jsonRpcClient = new JsonRpcClient(); +jsonRpcClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost("ws://127.0.0.1:7706/ws")//此url就是能连接到websocket的路径。 + .SetDataHandlingAdapter(() => new TerminatorPackageAdapter("\r\n")) + .SetJRPT(JRPT.Websocket)); +jsonRpcClient.Connect(); + +Console.WriteLine("连接成功"); +string result = jsonRpcClient.TestJsonRpc("RRQM"); +Console.WriteLine($"Websocket返回结果:{result}"); + +result = jsonRpcClient.TestJsonRpc1("RRQM"); +Console.WriteLine($"Websocket返回结果:{result}"); + +result = jsonRpcClient.TestGetContext("RRQM"); +Console.WriteLine($"Websocket返回结果:{result}"); + +JObject obj = new JObject(); +obj.Add("A", "A"); +obj.Add("B", 10); +obj.Add("C", 100.1); +JObject newObj = jsonRpcClient.TestJObject(obj); +Console.WriteLine($"Websocket返回结果:{newObj}"); +``` + + + +## 代理调用RPC + +代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。 + +### 如何生成获取代理文件? + +[获取代理文件详情](https://www.yuque.com/eo2w71/rrqm/a13509bfc3581f4576861b690b4a809a) + +### 调用 + +当代理被客户端获取以后,客户端项目中会多出一个**RRQMProxy(//TODO:这里需要修改,上面的获取代理文件详情的链接失效需要修改,下面截图需要修改)**的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的**代理方法**和**代理类**,可直接由代理类发起调用。 + + +```csharp +JsonRpcClient jsonRpcClient = new JsonRpcClient(JRPT.Http); +jsonRpcClient.Setup("http://127.0.0.1:7706/jsonrpc"); +jsonRpcClient.Connect(); +Server server= new Server(jsonRpcClient);//Server是生成的代理类。 +server.TestJsonRpc("TouchSocket");//代理调用 +``` diff --git a/handbook/docs/callwebapi.mdx b/handbook/docs/callwebapi.mdx new file mode 100644 index 000000000..076c01af1 --- /dev/null +++ b/handbook/docs/callwebapi.mdx @@ -0,0 +1,58 @@ +--- +id: callwebapi +title: 发现、调用服务 +--- + +## 直接调用 + +直接调用,则是不使用**任何代理**,直接Call RPC,使用比较简单,**浏览器**也能直接调用实现。 + +【Url请求】 + +```scheme +http://127.0.0.1:7789/ApiServer/Sum?a=10&b=20 +``` + +【HttpClient调用】 +WebApi的客户端和大家所**熟识**的有一些差距,TouchSocket的WebApi使用的是**先连接**,**后请求**的逻辑。请求时,先标记**GET/POST**的函数。如果是**GET**,则必须**留空URL**,如果是**POST**,则只写URL即可。 + +```csharp +private static WebApiClient CreateWebApiClient() +{ + WebApiClient client = new WebApiClient(); + client.Setup("127.0.0.1:7789"); + client.Connect(); + Console.WriteLine("连接成功"); + return client; +} +``` + +```scheme +var client = CreateWebApiClient(); + +int sum1 = client.Invoke("GET:/ApiServer/Sum?a={0}&b={1}", null, 10, 20); +Console.WriteLine($"Get调用成功,结果:{sum1}"); + +int sum2 = client.Invoke("POST:/ApiServer/TestPost", null, new MyClass() { A = 10, B = 20 }); +Console.WriteLine($"Post调用成功,结果:{sum2}"); +``` + + + +## 代理调用RPC + +代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。 + +### 如何生成获取代理文件? + +[获取代理文件详情](https://www.yuque.com/eo2w71/rrqm/a13509bfc3581f4576861b690b4a809a) + +### 调用 + +当代理被客户端获取以后,客户端项目中会多出一个**RRQMProxy**的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的**代理方法**和**代理类**,可直接由代理类发起调用。 + + +```csharp +int sum3 = client.TestPost(new MyClass() { A = 10, B = 20 }); +Console.WriteLine($"代理调用成功,结果:{sum3}"); +``` diff --git a/handbook/docs/callxmlrpc.mdx b/handbook/docs/callxmlrpc.mdx new file mode 100644 index 000000000..d41ed9c9c --- /dev/null +++ b/handbook/docs/callxmlrpc.mdx @@ -0,0 +1,90 @@ +--- +id: callxmlrpc +title: 发现、调用服务 +--- + + +## 直接调用 + +直接调用,则是不使用**任何代理**,直接Call RPC,使用比较简单。 + +```csharp +static void Main(string[] args) +{ + var client = GetXmlRpcClient(); + + //直接调用 + int result1 = client.Invoke("Sum", InvokeOption.WaitInvoke, 10, 20); + Console.WriteLine($"直接调用,返回结果:{result1}"); + + Console.ReadKey(); +} +static XmlRpcClient GetXmlRpcClient() +{ + XmlRpcClient jsonRpcClient = new XmlRpcClient(); + jsonRpcClient.Setup("http://127.0.0.1:7706/xmlRpc"); + jsonRpcClient.Connect(); + Console.WriteLine("连接成功"); + return jsonRpcClient; +} +``` + +【亦或者直接使用字符串调用】 +在Http-Post方式即可。 + +```xml + + + Sum + + + + 10 + + + + + 20 + + + + +``` + + + +## 代理调用RPC + +代理调用的便捷在于,不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。 + +### 如何生成获取代理文件? + +[获取代理文件详情](https://www.yuque.com/eo2w71/rrqm/a13509bfc3581f4576861b690b4a809a) + +### 调用 + +当代理被客户端获取以后,客户端项目中会多出一个**RRQMProxy**的文件(或者如果是服务器生成的本地代理,则需要复制到客户端项目中),在该文件中,则包含了所有的**代理方法**和**代理类**,可直接由代理类发起调用。 + + +```csharp +static void Main(string[] args) +{ + var client = GetXmlRpcClient(); + + Server server = new Server(client); + int result2 = server.Sum(10, 20); + Console.WriteLine($"代理调用,返回结果:{result2}"); + + Console.ReadKey(); +} + +static XmlRpcClient GetXmlRpcClient() +{ + XmlRpcClient jsonRpcClient = new XmlRpcClient(); + jsonRpcClient.Setup("http://127.0.0.1:7706/xmlRpc"); + jsonRpcClient.Connect(); + Console.WriteLine("连接成功"); + return jsonRpcClient; +} + +``` diff --git a/handbook/docs/consoleaction.mdx b/handbook/docs/consoleaction.mdx new file mode 100644 index 000000000..7c0ea9b8d --- /dev/null +++ b/handbook/docs/consoleaction.mdx @@ -0,0 +1,29 @@ +--- +id: consoleaction +title: 控制台行为 +--- + +## 一、说明 +这是一个很简单的控制台命令器,重要作用就是很方便的实现控制台控制。 + +**Nuget Package:**[TouchSocket](https://www.nuget.org/packages/TouchSocket/) +## 二、使用 +```csharp +ConsoleAction consoleAction = new ConsoleAction("h|help|?");//设置帮助命令 +consoleAction.OnException += ConsoleAction_OnException;//订阅执行异常输出 + +//下列的ShareProxy,StopShareProxy,GetAll均为无参数的方法 +consoleAction.Add("sp|shareProxy", "分享代理", ShareProxy);//示例命令 +consoleAction.Add("ssp|stopShareProxy", "停止分享代理", StopShareProxy);//示例命令 +consoleAction.Add("ga|getAll", "获取所有客户端信息", GetAll);//示例命令 +consoleAction.ShowAll(); +while (true) +{ + if (!consoleAction.Run(Console.ReadLine())) + { + Console.WriteLine("命令不正确,请输入“h|help|?”获得帮助。"); + } +} +``` +## 三、效果图 +![](../static/img/docs/consoleaction-1.gif) diff --git a/handbook/docs/cooperation.mdx b/handbook/docs/cooperation.mdx new file mode 100644 index 000000000..7092c913d --- /dev/null +++ b/handbook/docs/cooperation.mdx @@ -0,0 +1,8 @@ +--- +id: cooperation +title: 商业合作 +--- + +RRQM承接WPF及网络通信相关的开发任务。价格详情咨询若汝棋茗。QQ:505554090 + +支付可通过淘宝。安全有保障。 \ No newline at end of file diff --git a/handbook/docs/createandcallrpc.mdx b/handbook/docs/createandcallrpc.mdx new file mode 100644 index 000000000..913b4cfc3 --- /dev/null +++ b/handbook/docs/createandcallrpc.mdx @@ -0,0 +1,361 @@ +--- +id: createandcallrpc +title: 创建rpc服务 +--- + +## 一、说明 + +RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。RPC它假定某些协议的存在,例如TPC/UDP等,为通信程序之间携带信息数据。在OSI网络七层模型中,RPC跨越了传输层和应用层,RPC使得开发,包括网络分布式多程序在内的应用程序更加容易。 + +过程是什么? 过程就是业务处理、计算任务,更直白的说,就是程序,就是想调用本地方法一样调用远程的过程。 + +TouchRpc支持服务器与客户端互相调用,也支持客户端之间相互调用。 + +## 二、定义服务 + +1. 在**被调用**端中新建一个类名为**MyRpcServer**。 +2. 继承于RpcServer类、或实现IRpcServer。亦或者将服务器声明为**瞬时生命**的服务,继承TransientRpcServer、或ITransientRpcServer。 +3. 在该类中写**公共方法**,并用**TouchRpc**属性标签标记。 + +```csharp +public class MyRpcServer : RpcServer +{ + [Description("登录")]//服务描述,在生成代理时,会变成注释。 + [TouchRpc("Login")]//服务注册的函数键,此处为显式指定。默认不传参的时候,为该函数类全名+方法名的全小写。 + public bool Login(string account,string password) + { + if (account=="123"&&password=="abc") + { + return true; + } + + return false; + } +} +``` + + +```csharp +public class MyRpcServer : TransientRpcServer +{ + [Description("登录")]//服务描述,在生成代理时,会变成注释。 + [TouchRpc("Login")]//服务注册的函数键,此处为显式指定。默认不传参的时候,为该函数类全名+方法名的全小写。 + public bool Login(string account,string password) + { + if (account=="123"&&password=="abc") + { + return true; + } + + return false; + } +} +``` + +:::tip 提示 + +**瞬时生命**的服务,最大的特点就是,每个请求,都会创建一个新的服务类对象。然后可以通过**this.CallContext**直接访问当前的调用上下文。 + +::: + + +## 三、启动Rpc服务器 + +以下仅示例基于Tcp协议TouchRpc。其他协议的服务器请看[创建TouchRpc服务器](./createtouchrpcservice.mdx) + +```csharp +var service =new TcpTouchRpcService(); +TouchSocketConfig config= new TouchSocketConfig()//配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureRpcStore(a=> + { + a.RegisterServer();//注册服务 + }) + .SetVerifyToken("TouchRpc"); + +service.Setup(config) + .Start(); + +service.Logger.Info($"{service.GetType().Name}已启动"); +``` + +## 四、调用Rpc + + +### 4.1 直接调用 + +直接调用,则是不使用**任何代理**,使用**字符串**和**参数**直接Call Rpc,使用比较简单。 + +下列以TcpTouchRpcClient为例,其他客户端一模一样。 + +```csharp +TcpTouchRpcClient client = new TcpTouchRpcClient(); +client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("TouchRpc")); +client.Connect(); + +//直接调用时,第一个参数为调用键 +//第二个参数为调用配置参数,可设置调用超时时间,取消调用等功能。示例中使用的预设,实际上可以自行new InvokeOption(); +//后续参数为调用参数。 +//泛型为返回值类型。 +bool result = client.Invoke("Login", InvokeOption.WaitInvoke, 123, "abc"); +``` + +## 4.2、代理调用 + +代理调用的便捷在于,客户端不用再知道哪些服务可调,也不用再纠结调用的参数类型正不正确,因为这些,代理工具都会替你做好。 + +详细步骤: + +1. [生成代理文件](./generateproxy.mdx) +2. 将生成的cs文件添加到调用端一起编译。 + +:::info 备注 + +以上示例,会生成下列代理代码。 + +::: +【生成的代理】 + +```csharp +using TouchSocket.Rpc; +using System.Threading.Tasks; +namespace RpcProxy +{ + public interface IMyRpcServer : IRemoteServer + { + /// + ///登录 + /// + /// 调用超时 + /// Rpc调用异常 + /// 其他异常 + System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default); + /// + ///登录 + /// + /// 调用超时 + /// Rpc调用异常 + /// 其他异常 + Task LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default); + + } + public class MyRpcServer : IMyRpcServer + { + public MyRpcServer(IRpcClient client) + { + this.Client = client; + } + public IRpcClient Client { get; private set; } + /// + ///登录 + /// + /// 调用超时 + /// Rpc调用异常 + /// 其他异常 + public System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default) + { + if (Client == null) + { + throw new RpcException("IRpcClient为空,请先初始化或者进行赋值"); + } + if (Client.TryCanInvoke?.Invoke(Client) == false) + { + throw new RpcException("Rpc无法执行。"); + } + object[] parameters = new object[] { account, password }; + System.Boolean returnData = Client.Invoke("Login", invokeOption, parameters); + return returnData; + } + /// + ///登录 + /// + public Task LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default) + { + if (Client == null) + { + throw new RpcException("IRpcClient为空,请先初始化或者进行赋值"); + } + if (Client.TryCanInvoke?.Invoke(Client) == false) + { + throw new RpcException("Rpc无法执行。"); + } + object[] parameters = new object[] { account, password }; + return Client.InvokeAsync("Login", invokeOption, parameters); + } + } + public static class MyRpcServerExtensions + { + /// + ///登录 + /// + /// 调用超时 + /// Rpc调用异常 + /// 其他异常 + public static System.Boolean Login(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient : + TouchSocket.Rpc.IRpcClient + { + if (client.TryCanInvoke?.Invoke(client) == false) + { + throw new RpcException("Rpc无法执行。"); + } + object[] parameters = new object[] { account, password }; + System.Boolean returnData = client.Invoke("Login", invokeOption, parameters); + return returnData; + } + /// + ///登录 + /// + public static Task LoginAsync(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient : + TouchSocket.Rpc.IRpcClient + { + if (client.TryCanInvoke?.Invoke(client) == false) + { + throw new RpcException("Rpc无法执行。"); + } + object[] parameters = new object[] { account, password }; + return client.InvokeAsync("Login", invokeOption, parameters); + } + } +} + +``` + +使用代理扩展直接调用。 + +```csharp +TcpTouchRpcClient client = new TcpTouchRpcClient(); +client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("TouchRpc")); +client.Connect(); + +bool result = client.Login(123, "abc");//Login是扩展方法。可能需要额外添加命名空间。 +``` + + +## 五、反向Rpc + +一般的rpc服务都是客户端发起,服务器响应。但是有时候也需要服务器主动调用客户端,所以需要反向rpc。 + +### 5.1 定义、发布反向RPC服务 + +实际上,所有的Rpc客户端(**TcpTouchRpcClient**、**UdpTouchRpc**(不区分客户端)、**HttpTouchRpcClient**、**WSTouchRpcClient**)也实现了**IRpcParser**接口,这意味着反向RPC其实**也是RPC**,所以,所有操作一模一样。因为当客户端和服务器建立连接以后,就不再区分谁是客户端,谁是服务器了。只关心,**谁能提供服务,谁在调用服务**。 + +下列就以简单的示例下,由客户端声明服务,服务器调用服务。 + +具体步骤: + +1. 在**客户端项目**中定义服务 +2. 用**TouchRpc**标记 + +```csharp +public class ReverseCallbackServer : RpcServer +{ + [TouchRpc] + public string SayHello(string name) + { + return $"{name},hi"; + } +} +``` + +**【客户端发布服务】** +发布服务,实际上是让TcpTouchRpcClient也拥有提供RPC的能力。 + +```csharp +TcpTouchRpcClient client = new TcpTouchRpcClient(); +client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }) + .ConfigureRpcStore(a => + { + a.RegisterServer(); + }) + .SetVerifyToken("TouchRpc")); +client.Connect(); +``` + +### 5.2 调用反向RPC + +服务器回调客户端,最终必须通过**服务器辅助类客户端**(ISocketClient的派生类),以TcpTouchRpcService为例,其辅助客户端为TcpTouchRpcSocketClient。 + +因为,TcpTouchRpcSocketClient已实现IRpcClient接口,意味着,反向RPC也可以使用代理调用。所有用法和RPC一致。 + +下列示例以TcpTouchRpcSocketClient为例,其余一致。 + +:::tip 提示 + +反向RPC也可以使用代理调用。所有用法和RPC一致。 + +::: + +### 5.2.1 通过服务器直接获取 + +可以获取所有终端。 + +```csharp +foreach (var item in tcpTouchRpcService.GetClients()) +{ + client.Logger.Info(item.Invoke("ReverseRpcConsoleApp.ReverseCallbackServer.SayHello".ToLower(), InvokeOption.WaitInvoke, "张三")); +} +``` + +也可以先筛选ID,然后再调用。 + +```csharp +string id = tcpTouchRpcService.GetIDs().FirstOrDefault(a => a.Equals("特定id")); +if (tcpTouchRpcService.TryGetSocketClient(id, out var rpcSocketClient)) +{ + rpcSocketClient.Invoke("ReverseRpcConsoleApp.ReverseCallbackServer.SayHello".ToLower(), InvokeOption.WaitInvoke, "张三"); +} +``` + +#### 5.2.2 通过调用上下文获取 + +具体步骤 + +1. 设置调用上下文 +2. 上下文的Caller,即为服务器辅助类终端,进行强转即可。 + + +## 六、客户端互Call RPC + +除了正向RPC,反向RPC,TouchRpc还支持**客户端**之间互Call RPC。服务的定义与Rpc一样。 + +### 6.1 互Call RPC + +客户端A调用客户端B的方法,需要知道对方的**ID**。和**方法名**。然后使用下列函数调用即可。 + +:::tip 提示 + +互Call RPC也支持调用上下文。 + +::: + +:::caution 服务器注意 + +客户端互Call的时候,每个请求,都需要服务同意路由,才可以被转发。所以服务器需要做一些允许操作。 + +::: + + +```csharp +internal class MyTouchRpcPlugin : TouchRpcPluginBase +{ + protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e) + { + if (e.RouterType== RouteType.Rpc) + { + e.IsPermitOperation = true; + } + base.OnRouting(client, e); + } +} +``` + diff --git a/handbook/docs/createhttpclient.mdx b/handbook/docs/createhttpclient.mdx new file mode 100644 index 000000000..1b3e17dc0 --- /dev/null +++ b/handbook/docs/createhttpclient.mdx @@ -0,0 +1,78 @@ +--- +id: createhttpclient +title: 创建HttpClient +--- + +## 说明 + +HttpClient是Http客户端类。主要用于请求Http报文。 + + +## 可配置项 + +继承TcpClient + + + +## 支持插件接口 + +支持**ITcpPlugin**接口。 + + + +## 创建HttpClient + +```csharp +HttpClient client = new HttpClient(); + +client.Setup(new TouchSocketConfig() + .UsePlugin() + .SetRemoteIPHost(new IPHost("http://localhost:7219"))) + .Connect();//先做连接 + +HttpRequest request = new HttpRequest(); +request + .InitHeaders() + .SetUrl("/WeatherForecast") + .SetHost(client.RemoteIPHost.Host) + .AsGet(); + +var respose = client.Request(request, timeout: 1000*10); +Console.WriteLine(respose.GetBody()); +``` + + + +## 创建HttpsClient + +如果需要连接到Https服务器。则必须手动配置Ssl。示例如下: + +如果服务器证书是由**证书机构颁发**,则只需填充**TargetHost**和**SslProtocols**。 + +```csharp +SetClientSslOption(new ClientSslOption() { TargetHost = "localhost", SslProtocols = SslProtocols.Tls12 }) +``` + +如果服务器证书是由**自己制作的**,则需要加载证书文件,和必要的**验证**。 + +```csharp +.SetClientSslOption(new ClientSslOption() +{ + ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") }, + SslProtocols = SslProtocols.Tls12, + TargetHost = "127.0.0.1", + CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; } +})); +``` + + + +## 主要方法简介 + +| **方法名** | **功能简介** | +| --- | --- | +| Request | 请求Http数据,并等待返回 | + + + +## diff --git a/handbook/docs/createhttpservice.mdx b/handbook/docs/createhttpservice.mdx new file mode 100644 index 000000000..ff4a47fe3 --- /dev/null +++ b/handbook/docs/createhttpservice.mdx @@ -0,0 +1,150 @@ +--- +id: createhttpservice +title: 创建HttpService +--- + + +## 一、说明 + +**HttpService**是能够提供Http相关服务的基础类型。 + +:::caution 注意 + +**HttpService**仅仅支持简单的web服务,如果是和TouchSocket的其他组件配合,则可以使用,如果想单独作为web服务器,则**最好不要**使用。因为其兼容性比较薄弱。 + +::: + +## 二、产品特点 + +- 支持HTTPS。 +- **多种数据接收模式** +- **多地址监听**(可以一次性监听多个IP及端口) + +## 三、产品应用场景 + +- HTTP基础使用场景:可跨平台、跨语言使用。 + + +## 四、服务器架构 + +服务器在收到新客户端连接时,会创建一个HttpSocketClient的派生类实例,与远程HttpClient对应,后续的数据通信均由此实例负责。 + + + + +## 五、支持插件接口 + +声明自定义实例类,然后实现**IHttpPlugin**接口,即可实现下列事务的触发。或者继承自**HttpPluginBase**类,重写相应方法即可。 + +| 插件方法| 功能 | +| --- | --- | +| OnDelete | 当收到Delete请求时 | +| OnGet | 当收到OnGet请求时 | +| OnPost | 当收到OnPost请求时 | +| OnPut | 当收到OnPut请求时 | +| OnReceivedOtherHttpRequest | 当收到OnReceivedOtherHttpRequest请求时 | + + +## 六、创建HttpService + +HttpService的创建,基本和TcpService一致,也可以通过继承实现,下列仅演示最简单实现。 + +HttpService的相关事务,会通过**插件**触发。 + +```csharp +var service = new HttpService(); +service.Setup(new TouchSocketConfig()//加载配置 + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + + //default插件应该最后添加,其作用是 + //1、为找不到的路由返回404 + //2、处理header为Option的探视跨域请求。 + a.UseDefaultHttpServicePlugin(); + + })) + .Start(); +``` + +:::tip 提示 + +DefaultHttpServicePlugin插件最好添加在插件中,如果没有添加的话,最好自己做好缺省路由和跨域配置。 + +::: + +在插件中,通过**重写**(或实现)的方式,进入**OnGet**、**OnPost**、**OnDelete**、**OnPut**等函数,即可处理对应请求。 + +```csharp +/// +/// 支持GET、Post、Put,Delete,或者其他 +/// +internal class MyHttpPlug : HttpPluginBase +{ + protected override void OnGet(HttpSocketClient client, HttpContextEventArgs e) + { + if (e.Context.Request.UrlEquals("/success")) + { + //直接响应文字 + e.Context.Response.FromText("Success").Answer();//直接回应 + Console.WriteLine("处理完毕"); + e.Handled = true; + } + else if (e.Context.Request.UrlEquals("/file")) + { + //直接回应文件。 + e.Context.Response + .SetStatus()//必须要有状态 + .FromFile(@"D:\System\Windows.iso", e.Context.Request); + } + else if (e.Context.Request.UrlEquals("/html")) + { + //回应html + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine("TouchSocket"); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine("
"); + stringBuilder.AppendLine("王二麻子"); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine("
"); + stringBuilder.AppendLine(""); + stringBuilder.AppendLine(""); + + e.Context.Response + .SetStatus()//必须要有状态 + .SetContentTypeByExtension(".html") + .SetContent(stringBuilder.ToString()); + e.Context.Response.Answer(); + } + } + + protected override void OnPost(HttpSocketClient client, HttpContextEventArgs e) + { + + } +} +``` + +## 七、创建加密Ssl的HttpsService + +Https服务器,和http服务器几乎一样,只不过增加了一个Ssl的配置。 + +```csharp +.SetServiceSslOption(new ServiceSslOption() +{ + Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"), + SslProtocols = SslProtocols.Tls12 +})) +``` diff --git a/handbook/docs/createtcpclient.mdx b/handbook/docs/createtcpclient.mdx new file mode 100644 index 000000000..d4df957ae --- /dev/null +++ b/handbook/docs/createtcpclient.mdx @@ -0,0 +1,270 @@ +--- +id: createtcpclient +title: 创建TcpClient +--- + + +## 一、说明 + +TcpClient是Tcp系客户端基类,他直接参与tcp的连接、发送、接收、处理、断开等,他的业务与服务器的**SocketClient**是一一对应的。 + +## 二、特点 + +- 简单易用。 +- IOCP多线程。 +- 内存池支持 +- 高性能 +- 适配器预处理,一键式解决**分包**、**粘包**、对象解析(如HTTP,Json)等。 +- 超简单的同步发送、异步发送、接收等操作。 +- 基于委托、插件驱动,让每一步都能执行AOP。 + +## 三、产品应用场景 + +- 所有Tcp基础使用场景:可跨平台、跨语言使用。 +- 自定义协议解析场景:可解析任意数据格式的TCP数据报文。 + +## 四、可配置项 + +
+可配置项 +
+ +#### SetBufferLength + +发送、接收缓存容量(单位:byte),默认1024×64。设置建议: + +1. 如果数据包较小,建议10k左右的值。更加节约内存。 +2. 如果数据包较大,例如文件传输等,建议64k,甚至更大的值。 +3. 该值虽然无上限,但是一般不要超过1Mb,不然不仅没意义,还很浪费 + +#### SetMaxPackageSize + +数据包最大值(单位:byte),默认1024×1024×10。该值会在适当时间,直接作用DataHandlingAdapter.MaxPackageSize。 + +#### SetThreadCount + +多线程数量。该值在Auto模式下指示线程池的最少线程数量和IO线程数量。 + +设置建议: + +1. 异步处理接收数据,此时线程数量设置为内核线程左右的值即可。 +2. 同步处理接收数据,此时应当考虑两个因素。该操作是否为耗时操作,如果是,则该值在允许范围内,应当设置更可能大的值。如果不是,则设置为内核线程左右的值即可。 + +#### SetGetDefaultNewID + +配置初始ID的分配策略 + +#### SetListenIPHosts + +监听IP和端口号组,可以一次性设置多个地址。 + +#### SetServerName +服务器标识名称,无实际使用意义。 + +#### SetBacklogProperty +Tcp半连接挂起连接队列的最大长度。默认为30 + +#### SetMaxCount +最大可连接数,默认为10000 + +#### SetReceiveType +接收类型。 +- AUTO:自动接收模式。 +- None:不投递IO接收申请,用户可通过GetStream,获取到流以后,自己处理接收。注意:连接端不会感知主动断开。 + +#### UsePlugin +是否启用插件。在启用时或许会带来一点点性能损耗,基本上不是千万数据交互根本不值一提。 + +#### SetServiceSslOption +Ssl配置,为Null时则不启用。 + +#### UseNoDelay +设置Socket的NoDelay属性,默认false。 + +#### UseDelaySender +使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用**延迟算法**。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。 + +使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: +1. 如果一个包大于512kb,则不会延迟,直接发送。 +2. 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10**微秒**左右),则会将这两个包压缩为一个包发送。 + +#### UseReuseAddress +启用端口复用。该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题。 + +#### SetRemoteIPHost + +链接到的远程IPHost,支持域名。支持类型: +1. 使用IP&Port,传入形如:127.0.0.1:7789的字符串即可。 +2. 使用域名,必须包含协议类型,形如:http://baidu.com或者https://baidu.com:80 + +#### SetClientSslOption +客户端Ssl配置,为Null时则不启用。 +注意,当RemoteIPHost使用https、wss的域名时,该配置会使用系统默认配置生效。 + +#### SetKeepAliveValue +为Socket设置的属性。 +注意:该配置仅在window平台生效。 + +#### SetBindIPHost +绑定端口。 +- 在UdpSessionBase中表示本地监听地址 +- 在TcpClient中表示固定客户端端口号。 + +#### UseDelaySender +使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。 + +使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: + +如果一个包大于512kb,则不会延迟,直接发送。 +如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。 + +#### UseNoDelay +设置Socket的NoDelay属性,默认false。 + +#### UseBroadcast +该值指定可以发送或接收广播数据包。 + +
+
+ +## 五、支持插件 + +支持**ITcpPlugin**接口,或者继承自**TcpPluginBase**类,重写相应方法即可。 + +| 插件方法| 功能 | +| --- | --- | +| OnConnecting | 在Socket完成初始化,但是并未连接时触发。 | +| OnConnected | 在Socket完成连接,且成功后触发 | +| OnDisconnecting | 当客户端主动调用Close时触发 | +| OnDisconnected | 当客户端断开连接后触发 | +| OnReceivingData | 在收到原始数据时触发,所有的数据均在ByteBlock里面。 | +| OnReceivedData | 在收到适配器数据时触发,根据适配器类型,数据可能在ByteBlock或者IRequestInfo里面。 | +| OnSendingData | 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 | + +## 六、创建TcpClient + +简单的处理逻辑可通过**Connecting**、**Connected**、**Received**等委托直接实现。 + +代码如下: + +```csharp +TcpClient tcpClient = new TcpClient(); +tcpClient.Connected += (client, e) => { };//成功连接到服务器 +tcpClient.Disconnected += (client, e) => { };//从服务器断开连接,当连接不成功时不会触发。 +tcpClient.Received += (client, byteBlock, requestInfo) => +{ + //从服务器收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + Console.WriteLine($"接收到信息:{mes}"); +}; + +//声明配置 +TouchSocketConfig config = new TouchSocketConfig(); +config.SetRemoteIPHost(new IPHost("127.0.0.1:7789")) + .UsePlugin(); + +//载入配置 +tcpClient.Setup(config); +tcpClient.Connect(); +tcpClient.Send("RRQM"); +``` + +## 七、接收数据 + +在TcpClient中,接收数据的方式有很多种。多种方式可以组合使用。 + +### 7.1 Received委托处理 + +当使用TcpClient创建客户端时,内部已经定义好了一个外置委托Received,可以通过该委托直接接收数据。 + +```csharp +TcpClient tcpClient = new TcpClient(); +tcpClient.Received += (client, byteBlock, requestInfo) => +{ + //从服务器收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + Console.WriteLine($"接收到信息:{mes}"); +}; + +//声明配置 +TouchSocketConfig config = new TouchSocketConfig(); +config.SetRemoteIPHost(new IPHost("127.0.0.1:7789")) + .UsePlugin(); + +//载入配置 +tcpClient.Setup(config); +tcpClient.Connect(); +``` + +### 7.2 插件处理推荐 + +按照TouchSocket的设计理念,使用插件处理数据,是一项非常简单,且高度解耦的方式。步骤如下: + +1. 服务器配置启用插件(UsePlugin) +2. 新建插件类 +3. 添加插件 + +代码如下: + +(1)声明插件 + +```csharp +public class MyPlugin : TcpPluginBase +{ + public MyPlugin() + { + this.Order = 0;//此值表示插件的执行顺序,当多个插件并存时,该值越大,越在前执行。 + } + + protected override void OnReceivedData(TcpClient client, ReceivedDataEventArgs e) + { + //这里处理数据接收 + //根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。 + ByteBlock byteBlock = e.ByteBlock; + IRequestInfo requestInfo = e.RequestInfo; + + //e.Handled = true;//表示该数据已经被本插件处理,无需再投递到其他插件。 + base.OnReceivedData(client, e); + } +} +``` + +(2)创建使用插件处理的客户端 + +```csharp +TcpClient client = new TcpClient(); +client.Setup(new TouchSocketConfig() + .SetRemoteIPHost(new IPHost("127.0.0.1:7789")) + .UsePlugin() + .ConfigureContainer(a=> + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + })) + .Connect(); +``` + +## 八、发送数据 + +【同步发送】 + +TcpClient已经内置了三种同步发送方法,直接调用就可以发送,但需要注意的是,通过该方法发送的数据,会经过**适配器**,如果想要直接发送,请使用**DefaultSend**。如果发送失败,则会立即抛出异常。 + +```csharp +public virtual void Send(byte[] buffer); +public virtual void Send(ByteBlock byteBlock); +public virtual void Send(byte[] buffer, int offset, int length); +``` + +【异步发送】 + +TcpClient已经内置了三种异步发送方法,直接调用就可以发送。如果发送失败,await就会触发异常。 + +```csharp +public virtual Task SendAsync(byte[] buffer); +public virtual Task SendAsync(byte[] buffer, int offset, int length); +``` + diff --git a/handbook/docs/createtcpservice.mdx b/handbook/docs/createtcpservice.mdx new file mode 100644 index 000000000..d92d5b5e3 --- /dev/null +++ b/handbook/docs/createtcpservice.mdx @@ -0,0 +1,521 @@ +--- +id: createtcpservice +title: 创建TcpService +--- + +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 +TcpService是Tcp系服务器基类,它不参与实际的数据交互,只是配置、激活、管理、注销、重建**SocketClient**类实例。而**SocketClient**是当**TcpClient(客户端)**成功连接服务器以后,由服务器新建的一个实例类,后续的所有通信,也都是通过该实例完成的。 + +## 二、特点 + +- 简单易用。 +- IOCP多线程。 +- 内存池支持 +- 高性能(实测服务器单客户端单线程,每秒可接收200w条8字节的信息,接收数据流量可达2.5GB/s)。 +- **多地址监听**(可以一次性监听多个IP及端口) +- 适配器预处理,一键式解决**分包**、**粘包**、对象解析(如HTTP,Json)等。 +- 超简单的同步发送、异步发送、接收等操作。 +- 基于委托、插件驱动,让每一步都能执行AOP。 + +## 三、产品应用场景 + +- 所有Tcp基础使用场景:可跨平台、跨语言使用。 +- 自定义协议解析场景:可解析任意数据格式的TCP数据报文。 + +## 四、服务器架构 + +服务器在收到**新客户端连接**时,会创建一个SocketClient的派生类实例,与客户端TcpClient一一对应,后续的数据通信均由此实例负责。 + +SocketClient在Service里面以字典映射。ID为键,SocketClient本身为值。 + + + +## 五、可配置项 + +
+可配置项 +
+ +#### SetBufferLength + +发送、接收缓存容量(单位:byte),默认1024×64。设置建议: + +1. 如果数据包较小,建议10k左右的值。更加节约内存。 +2. 如果数据包较大,例如文件传输等,建议64k,甚至更大的值。 +3. 该值虽然无上限,但是一般不要超过1Mb,不然不仅没意义,还很浪费 + +#### SetMaxPackageSize + +数据包最大值(单位:byte),默认1024×1024×10。该值会在适当时间,直接作用DataHandlingAdapter.MaxPackageSize。 + +#### SetThreadCount + +多线程数量。该值在Auto模式下指示线程池的最少线程数量和IO线程数量。 + +设置建议: + +1. 异步处理接收数据,此时线程数量设置为内核线程左右的值即可。 +2. 同步处理接收数据,此时应当考虑两个因素。该操作是否为耗时操作,如果是,则该值在允许范围内,应当设置更可能大的值。如果不是,则设置为内核线程左右的值即可。 + +#### SetGetDefaultNewID + +配置初始ID的分配策略 + +#### SetListenIPHosts + +监听IP和端口号组,可以一次性设置多个地址。 + +#### SetServerName +服务器标识名称,无实际使用意义。 + +#### SetBacklogProperty +Tcp半连接挂起连接队列的最大长度。默认为30 + +#### SetMaxCount +最大可连接数,默认为10000 + +#### SetReceiveType +接收类型。 +- AUTO:自动接收模式。 +- None:不投递IO接收申请,用户可通过GetStream,获取到流以后,自己处理接收。注意:连接端不会感知主动断开。 + +#### UsePlugin +是否启用插件。在启用时或许会带来一点点性能损耗,基本上不是千万数据交互根本不值一提。 + +#### SetServiceSslOption +Ssl配置,为Null时则不启用。 + +#### UseNoDelay +设置Socket的NoDelay属性,默认false。 + +#### UseDelaySender +使用延迟发送。众所周知,tcp数据报文为了发送效率,会默认启用**延迟算法**。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。 + +使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: +1. 如果一个包大于512kb,则不会延迟,直接发送。 +2. 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10**微秒**左右),则会将这两个包压缩为一个包发送。 + +#### UseReuseAddress +启用端口复用。该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题。 + +#### SetRemoteIPHost + +链接到的远程IPHost,支持域名。支持类型: +1. 使用IP&Port,传入形如:127.0.0.1:7789的字符串即可。 +2. 使用域名,必须包含协议类型,形如:http://baidu.com或者https://baidu.com:80 + +#### SetClientSslOption +客户端Ssl配置,为Null时则不启用。 +注意,当RemoteIPHost使用https、wss的域名时,该配置会使用系统默认配置生效。 + +#### SetKeepAliveValue +为Socket设置的属性。 +注意:该配置仅在window平台生效。 + +#### SetBindIPHost +绑定端口。 +- 在UdpSessionBase中表示本地监听地址 +- 在TcpClient中表示固定客户端端口号。 + +使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说: + +如果一个包大于512kb,则不会延迟,直接发送。 +如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。 + +#### UseNoDelay +设置Socket的NoDelay属性,默认false。 + +#### UseBroadcast +该值指定可以发送或接收广播数据包。 + +
+
+ + +## 六、支持插件 + +支持**ITcpPlugin**接口,或者继承自**TcpPluginBase**类,重写相应方法即可。 + +| 插件方法| 功能 | +| --- | --- | +| OnConnecting | 此时Socket实际上已经完成连接,但是并没有启动接收,然后触发。 | +| OnConnected | 同意连接,且成功启动接收后触发 | +| OnDisconnecting | 当客户端主动调用Close时触发 | +| OnDisconnected | 当客户端断开连接后触发 | +| OnReceivingData | 在收到原始数据时触发,所有的数据均在ByteBlock里面。 | +| OnReceivedData | 在收到适配器数据时触发,根据适配器类型,数据可能在ByteBlock或者IRequestInfo里面。 | +| OnSendingData | 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 | +| OnIDChanged | 当SocketClient的ID发生改变时触发。 | + +## 七、创建TcpService + +### 7.1 简单创建 + +直接初始化TcpService,会使用默认的**SocketClient**。 +简单的处理逻辑可通过**Connecting**、**Connected**、**Received**等委托直接实现。 + +代码如下: + +```csharp +TcpService service = new TcpService(); +service.Connecting = (client, e) => { };//有客户端正在连接 +service.Connected = (client, e) => { };//有客户端成功连接 +service.Disconnected = (client, e) => { };//有客户端断开连接 +service.Received = (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + client.Logger.Info($"已从{client.ID}接收到信息:{mes}"); + + client.Send(mes);//将收到的信息直接返回给发送方 + + //client.Send("id",mes);//将收到的信息返回给特定ID的客户端 + + var ids = service.GetIDs(); + foreach (var clientId in ids)//将收到的信息返回给在线的所有客户端。 + { + if (clientId != client.ID)//不给自己发 + { + service.Send(clientId, mes); + } + } +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + }) + .ConfigurePlugins(a => + { + //a.Add();//此处可以添加插件 + })) + .Start();//启动 +``` + +### 7.2 泛型创建 + +通过泛型创建服务器,可以实现很多有意思,且能**重写**一些有用的功能。下面就演示,如何通过泛型创建服务器。 + +代码如下: + +(1)建立SocketClient继承类。 + +```csharp +public class MySocketClient : SocketClient +{ + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + //此处逻辑单线程处理。 + + //此处处理数据,功能相当于Received委托。 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + Console.WriteLine($"已接收到信息:{mes}"); + } +} +``` + +(2)建立TcpService继承类。实际上如果业务不涉及服务器配置的话,可以省略该步骤,使用**TcpService的泛型**直接创建。 + +```csharp +public class MyService : TcpService +{ + protected override void LoadConfig(TouchSocketConfig config) + { + //此处加载配置,用户可以从配置中获取配置项。 + base.LoadConfig(config); + } + + protected override void OnConnecting(MySocketClient socketClient, ClientOperationEventArgs e) + { + //此处逻辑会多线程处理。 + + + //e.ID:对新连接的客户端进行ID初始化,例如可以设置为其IP地址。 + //e.IsPermitOperation:指示是否允许该客户端链接。 + base.OnConnecting(socketClient, e); + } +} + +``` + +(3)创建服务器(包含MyService)。 + +```csharp +MyService service = new MyService(); +service.Connecting = (client, e) => { };//有客户端正在连接 +service.Connected = (client, e) => { };//有客户端成功连接 +service.Disconnected = (client, e) => { };//有客户端断开连接 + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + }) + .ConfigurePlugins(a => + { + //a.Add();//此处可以添加插件 + })) + .Start();//启动 +``` + +(4)创建服务器(不含MyService)。 + +```csharp +TcpService service = new TcpService(); +service.Connecting = (client, e) => { };//有客户端正在连接 +service.Connected = (client, e) => { };//有客户端成功连接 +service.Disconnected = (client, e) => { };//有客户端断开连接 + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + }) + .ConfigurePlugins(a => + { + //a.Add();//此处可以添加插件 + })) + .Start();//启动 +``` + +:::tip 建议 + +由上述代码可以看出,通过继承,可以更加灵活的实现扩展。但实际上,很多业务我们希望大家能通过插件完成。 + +::: + + +## 八、接收数据 + +在TcpService中,接收数据的方式有很多种。多种方式可以组合使用。 + +### 8.1 Received委托处理 + +当使用TcpService(非泛型)创建服务器时,内部已经定义好了一个外置委托Received,可以通过该委托直接接收数据。 + +```csharp +TcpService service = new TcpService(); +service.Received = (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + client.Logger.Info($"已从{client.ID}接收到信息:{mes}"); +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.UseConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + })) + .Start();//启动 +``` + +### 8.2 重写SocketClient处理 + +正如6.2所示,可以直接在MySocketClient的重写**HandleReceivedData**中直接处理数据。 + +### 8.3 插件处理 推荐 + +按照TouchSocket的设计理念,使用插件处理数据,是一项非常简单,且高度解耦的方式。步骤如下: + +1. 服务器配置启用插件(UsePlugin) +2. 新建插件类 +3. 添加插件 + +代码如下: + +(1)声明插件 + +```csharp +public class MyPlugin : TcpPluginBase +{ + public MyPlugin() + { + this.Order = 0;//此值表示插件的执行顺序,当多个插件并存时,该值越大,越在前执行。 + } + + protected override void OnReceivedData(SocketClient client, ReceivedDataEventArgs e) + { + //这里处理数据接收 + //根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。 + ByteBlock byteBlock = e.ByteBlock; + IRequestInfo requestInfo = e.RequestInfo; + + //e.Handled = true;//表示该数据已经被本插件处理,无需再投递到其他插件。 + base.OnReceivedData(client, e); + } +} +``` + +(2)创建使用插件处理的服务器 + +```csharp +TcpService service = new TcpService(); +service.Setup(new TouchSocketConfig() + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) }) + .UsePlugin() + .ConfigureContainer(a=> + { + a.UseConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + })) + .Start(); +``` + +## 九、AspNetCore中创建 + +首先建议安装`TouchSocket.AspNetCore`或者`TouchSocketPro.AspNetCore`,因为这个里面有很多可以直接使用的注入项。 + +:::tip 建议 + +在安装`TouchSocket.AspNetCore`或者`TouchSocketPro.AspNetCore`的同时,最好也安装`TouchSocket`或者`TouchSocketPro`。这样更新也即时一些。 + +::: + +在AspNetCore中使用TcpService,**不应该**像普通端一样,订阅Received。应该是通过**插件**,**注入**等方式实现。步骤如下: + +1. 注入TcpService,并做好配置(和常规服务器配置一样)。 +2. 新建插件,处理收到的数据。 + +代码如下: + +(1)声明插件 + +```csharp +public class MyTcpPlugin : TcpPluginBase +{ + private ILogger m_logger; + + public MyTcpPlugin(ILogger logger) + { + this.m_logger = logger; + } + + protected override void OnConnected(SocketClient client, TouchSocketEventArgs e) + { + m_logger.LogInformation("客户端连接"); + base.OnConnected(client, e); + } + + protected override void OnReceivedData(SocketClient client, ReceivedDataEventArgs e) + { + //这里处理数据接收 + //根据适配器类型,e.ByteBlock与e.RequestInfo会呈现不同的值,具体看文档=》适配器部分。 + ByteBlock byteBlock = e.ByteBlock; + IRequestInfo requestInfo = e.RequestInfo; + } +} +``` + +(2)注入服务 + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + var tcpService = services.AddTcpService(config => + { + config.SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .UsePlugin() + .UseAspNetCoreContainer(services) + .ConfigurePlugins(a => + { + a.Add();//此插件就可以处理接收数据 + }); + }); +} + +``` + +然后在任意地方,也可获得服务。 + +![image.png](../static/img/docs/createtcpservice-1.png) + +:::tip 提示 + +此时,TcpService与整个AspNetCore是共享IOC容器的。即:TcpService中的任何地方(例如:插件)也能获得AspNetCore已注册的服务。 + +::: + + +## 十、发送数据 + +按照架构图,每个客户端成功连接后,**服务器**都会创建一个派生自**SocketClient**的实例,通过**该实例**即可将数据发送至**客户端**。 + +### 10.1 如何获取SocketClient? + +(1)直接获取所有在线客户端 + +通过`service.GetClients`方法,获取当前在线的所有客户端。 + +```csharp +SocketClient[] socketClients = service.GetClients(); +``` + +:::caution 注意 + +由于SocketClient的生命周期是由框架控制的,所以最好尽量不要直接引用该实例,可以引用SocketClient.ID,然后再通过服务器查找。 + +::: + +(2)通过ID获取 + +先调用`service.GetIDs`方法,获取当前在线的所有客户端的ID,然后选择需要的ID,通过TryGetSocketClient方法,获取到想要的客户端。 + +```csharp +string[] ids = service.GetIDs(); +if (service.TryGetSocketClient(ids[0], out SocketClient socketClient)) +{ +} +``` + +### 10.2 发送 + +【同步发送】 + +SocketClient已经内置了三种同步发送方法,直接调用就可以发送,如果发送失败,则会立即抛出异常。 +```csharp +public virtual void Send(byte[] buffer); +public virtual void Send(ByteBlock byteBlock); +public virtual void Send(byte[] buffer, int offset, int length); +``` + +【异步发送】 + +TcpClient已经内置了三种异步发送方法,直接调用就可以发送。如果发送失败,await就会触发异常。 + +```csharp +public virtual Task SendAsync(byte[] buffer); +public virtual Task SendAsync(ByteBlock byteBlock); +public virtual Task SendAsync(byte[] buffer, int offset, int length); +``` + +:::tip 提示 + +通过上述方法发送的数据,都会经过**适配器**,如果想要直接发送,请使用**DefaultSend**。 + +::: + +### 10.3 通过TcpService发送 + +通过ID发送数据。 + +```csharp +public virtual void Send(string id, ByteBlock byteBlock); +public virtual void Send(string id, byte[] buffer, int offset, int length); +public virtual void Send(string id, byte[] buffer); +public virtual Task SendAsync(string id, ByteBlock byteBlock); +public virtual Task SendAsync(string id, byte[] buffer, int offset, int length); +public virtual Task SendAsync(string id, byte[] buffer); +``` + + diff --git a/handbook/docs/createtouchrpcclient.mdx b/handbook/docs/createtouchrpcclient.mdx new file mode 100644 index 000000000..b717388f8 --- /dev/null +++ b/handbook/docs/createtouchrpcclient.mdx @@ -0,0 +1,103 @@ +--- +id: createtouchrpcclient +title: 创建TouchRpc客户端 +--- + + +## 一、说明 + +TouchRpc客户端对应的,也有四种不同协议的版本。 + +## 二、可配置项 + +
+可配置项 +
+ +#### SetVerifyTimeout +设置验证超时时间,默认3000ms。(仅TcpTouchRpc可用) 。 + +#### SetVerifyToken +设置验证口令。 + +#### SetHeartbeatFrequency +设置心跳。默认为间隔2000ms,连续3次无响应即视为断开。 + +#### SetSerializationSelector +设置序列化选择器。 + +#### SetResponseType +设置允许的响应类型 + +#### SetRootPath +设置根路径 +
+
+ +## 三、支持插件接口 + +声明自定义实例类,然后实现**ITouchRpcPlugin**接口,即可实现下列事务的触发。 +或者继承自**TouchRpcPluginBase**类,重写相应方法即可。 + +| 插件方法 | 功能 | +| --- | --- | +| OnHandshaking | 客户端在验证连接。默认情况下,框架会首先验证连接Token是否正确,如果不正确则直接拒绝。不会有任何投递。用户也可以使用Metadata进行动态验证。 | +| OnHandshaked | 客户端完成连接验证 | +| OnFileTransfering | 在文件传输即将进行时触发。 | +| OnFileTransfered | 当文件传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。 | +| OnLoadingStream | 在远程请求加载流时触发。 | +| OnReceivedProtocolData | 收到协议数据 | +| OnRemoteAccessing | 在远程操作访问之前。 | +| OnRemoteAccessed | 在远程操作访问之后。 | +| OnRouting | 当需要转发路由包时。一般所有的**客户端之间**的数据传输,都需要经过该函数的运行。 | +| OnStreamTransfering | 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 | +| OnStreamTransfered | 流数据处理,用户需要在此事件中对e.Bucket手动释放。 当流数据传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。 | + + +## 四、创建 + +### 4.1 TcpTouchRpcClient + +基本创建如下,支持[创建TcpClient](./createtcpclient.mdx)的所有配置。 + +```csharp +TcpTouchRpcClient client = new TcpTouchRpcClient(); +client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("TouchRpc")); +client.Connect(); +``` + +### 4.2 HttpTouchRpcClient + +基本创建如下,支持[创建TcpClient](./createtcpclient.mdx)的所有配置。 + +```csharp +HttpTouchRpcClient client = new HttpTouchRpcClient(); +client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("TouchRpc")); +client.Connect(); +``` + +### 4.3 UdpTouchRpc + +基本创建如下,支持@的所有配置。 + +```csharp +UdpTouchRpc client = new UdpTouchRpc(); +client.Setup(new TouchSocketConfig() + .SetBindIPHost(7794) + .SetRemoteIPHost("127.0.0.1:7789"));//设置目标地址。 +client.Start(); +``` + + +### 4.4 WSTouchRpcClient + +```csharp + WSTouchRpcClient client = new WSTouchRpcClient(); + client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("ws://127.0.0.1:5000/wstouchrpc")); + client.ConnectAsync(); +``` diff --git a/handbook/docs/createtouchrpcservice.mdx b/handbook/docs/createtouchrpcservice.mdx new file mode 100644 index 000000000..1ef25e9e4 --- /dev/null +++ b/handbook/docs/createtouchrpcservice.mdx @@ -0,0 +1,188 @@ +--- +id: createtouchrpcservice +title: 创建TouchRpc服务器 +--- + + +## 一、说明 + +TouchRpc的服务器有多种形式的host,每种服务器的创建都大同小异,且功能基本一致。 + + +## 二、服务器架构 + +TouchRpc服务器的架构与其所属的基础协议架构一致,例如,在基于tcp协议时,其架构就和tcp服务器一致。在收到**新客户端连接**时,会创建一个**TcpTouchRpcSocketClient**的类实例,与**客户端TcpTouchRpcClient**一一对应,后续的数据通信均由此实例负责。 + + +## 三、可配置项 + +
+可配置项 +
+ +#### SetVerifyTimeout +设置验证超时时间,默认3000ms。(仅TcpTouchRpc可用) 。 + +#### SetVerifyToken +设置验证口令。 + +#### SetHeartbeatFrequency +设置心跳。默认为间隔2000ms,连续3次无响应即视为断开。 + +#### SetSerializationSelector +设置序列化选择器。 + +#### SetResponseType +设置允许的响应类型 + +#### SetRootPath +设置根路径 +
+
+ +## 四、支持插件接口 + +声明自定义实例类,然后实现**ITouchRpcPlugin**接口,即可实现下列事务的触发。 +或者继承自**TouchRpcPluginBase**类,重写相应方法即可。 + +| 插件方法 | 功能 | +| --- | --- | +| OnHandshaking | 客户端在验证连接。默认情况下,框架会首先验证连接Token是否正确,如果不正确则直接拒绝。不会有任何投递。用户也可以使用Metadata进行动态验证。 | +| OnHandshaked | 客户端完成连接验证 | +| OnFileTransfering | 在文件传输即将进行时触发。 | +| OnFileTransfered | 当文件传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。 | +| OnLoadingStream | 在远程请求加载流时触发。 | +| OnReceivedProtocolData | 收到协议数据 | +| OnRemoteAccessing | 在远程操作访问之前。 | +| OnRemoteAccessed | 在远程操作访问之后。 | +| OnRouting | 当需要转发路由包时。一般所有的**客户端之间**的数据传输,都需要经过该函数的运行。 | +| OnStreamTransfering | 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 | +| OnStreamTransfered | 流数据处理,用户需要在此事件中对e.Bucket手动释放。 当流数据传输结束之后。并不意味着完成传输,请通过e.Result属性值进行判断。 | + + +## 五、创建服务器 + + +### 5.1 基于Tcp协议 + +这是基于Tcp协议TouchRpc。在可配置TouchRpc的基础之上,还可以配置与[TcpService可配置项](./createtcpservice.mdx#可配置项)相关的配置。 + +```csharp +var service = new TcpTouchRpcService(); +var config = new TouchSocketConfig()//配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }) + .SetVerifyToken("TouchRpc");//设定连接口令,作用类似账号密码 + +service.Setup(config) + .Start(); + +service.Logger.Info($"{service.GetType().Name}已启动"); +``` + +### 5.2 基于Http协议 + +这是基于Http升级协议。在该解析器中,配置设置[HttpService](./createhttpservice.mdx)一致。 + +```csharp +var service = new HttpTouchRpcService(); +TouchSocketConfig config = new TouchSocketConfig()//配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }) + .SetVerifyToken("TouchRpc"); + +service.Setup(config) + .Start(); + +service.Logger.Info($"{service.GetType().Name}已启动"); +``` + +### 5.3 基于Udp协议 + +这是基于UDP协议解析器。在该解析器中,配置设置与[UdpSession](./createudpsession.mdx)一致。因为udp是无连接的,所以不需要SetVerifyToken。 + +```csharp +var service = new UdpTouchRpc(); +TouchSocketConfig config = new TouchSocketConfig()//配置 + .SetBindIPHost(new IPHost(7789)) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }); + +service.Setup(config) + .Start(); + +service.Logger.Info($"{service.GetType().Name}已启动"); +``` + +### 5.4 基于AspNetCore的Websocket协议 + +具体步骤 + +1. nuget 安装`TouchSocket.AspNetCore`或者`TouchSocketPro.AspNetCore`。 +2. IServiceCollection添加AddWSTouchRpc,并进行相关配置(不用配置端口,会和asp使用同一端口)。 +3. IApplicationBuilder必须先使用UseWebSockets。 +4. IApplicationBuilder调用UseWSTouchRpc,并传入url设置。 + +在ConfigureServices时,添加AddWSTouchRpc,并且配置相关项。 + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + //向Asp服务中添加IWSTouchRpcService + services.AddWSTouchRpc(new TouchSocketConfig() + .UseAspNetCoreContainer(services));//设置IOC容器 + + services.AddControllers(); + + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "API Demo", Version = "v1" }); + }); +} +``` + +启用中间件 + +首先必须启用WebSocket。其次使用UseWSTouchRpc即可。 + +```csharp + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + // Swagger + app.UseSwagger(); + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "API Demo v1"); + }); + + + app.UseWebSockets();//必须先使用WebSocket + app.UseWSTouchRpc("/wstouchrpc");//该操作不会影响原有的WebSocket,只要url不同即可。 + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } +``` \ No newline at end of file diff --git a/handbook/docs/createudpsession.mdx b/handbook/docs/createudpsession.mdx new file mode 100644 index 000000000..d18693923 --- /dev/null +++ b/handbook/docs/createudpsession.mdx @@ -0,0 +1,48 @@ +--- +id: createudpsession +title: 创建UdpSession +--- + +## 一、说明 +UDP组件是基于UDP协议的最基础组件,其功能简单,易用。它既能充当服务器,又能够作为客户端。 + +## 二、产品特点 + +- 简单易用。 +- 多线程。 +- 内存池 +- 高性能 + +## 三、产品应用场景 + +- UDP基础使用场景:可跨平台、跨语言使用。 + +## 四、支持插件接口 + +声明自定义实例类,然后实现**IUdpSessionPlugin**接口,即可实现下列事务的触发。或者继承自**UdpSessionPluginBase**类,重写相应方法即可。 + +| 插件方法| 功能 | +| --- | --- | +| OnReceivedData | 在收到数据时触发 | + +## 四、使用UdpSession + +```csharp +UdpSession udpSession = new UdpSession(); +udpSession.Received += (remote, byteBlock,requestInfo) => +{ + udpSession.Send(remote, byteBlock); + Console.WriteLine($"收到:{Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len)}"); +}; +udpSession.Setup(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7789))) + .Start(); +Console.WriteLine("等待接收"); + +``` +:::caution 注意 + +1. 即使不监听地址,Setup和Start都是必须要的。 +2. 当udp作为客户端时,Config如果不设置SetBindIPHost,将不会接收,如果不知道绑定那个端口,可以直接绑定0端口,这样,就会使用系统空闲的一个端口了。 + +::: \ No newline at end of file diff --git a/handbook/docs/createwebsocketclient.mdx b/handbook/docs/createwebsocketclient.mdx new file mode 100644 index 000000000..f6077d875 --- /dev/null +++ b/handbook/docs/createwebsocketclient.mdx @@ -0,0 +1,117 @@ +--- +id: createwebsocketclient +title: 创建WebSocket客户端 +--- + + +## 说明 + +支持Ssl的WebSocket客户端。 + + +## 可配置项 + +继承HttpClient。 + + +## 支持插件接口 + +支持**ITcpPlugin、IWebSocketPlugin** + + +## 创建WS客户端 + +```csharp +WebSocketClient myWSClient = new WebSocketClient(); +//myWSClient.Received += this.MyWSClient_Received; +//myWSClient.Handshaked += this.MyWSClient_Handshaked; + +myWSClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost(this.textBox3.Text) + .ConfigureContainer(a => + { + a.SetSingletonLogger(new LoggerGroup(new EasyLogger(this.ShowMsg), new FileLogger())); + })); +myWSClient.Connect(); + +myWSClient.Logger.Message("连接成功"); +``` + + + +## 创建WSs客户端 + +***当需要连接到由证书机构颁发的网址(例如:**小程序**、\_\_物联网\_\_等)时,仅需要设置url即可。*** + +```csharp +wss://127.0.0.1:7789/ws +``` + +**当连接自定义证书的Ssl:wss://127.0.0.1:7789/ws** + +```csharp +WebSocketClient myWSClient = new WebSocketClient(); + +myWSClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost(new IPHost("wss://127.0.0.1:7789/ws")) + .SetClientSslOption( + new ClientSslOption() + { + ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") }, + SslProtocols = SslProtocols.Tls12, + TargetHost = "127.0.0.1", + CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; } + })) + .Connect(); + +Console.WriteLine("连接成功"); +while (true) +{ + myWSClient.SendWithWS(Console.ReadLine()); +} +``` + +***注意:当使用域名连接时,TargetHost为域名,例如连接到IPHost("ws://baidu.com")时,TargetHost应当填写:baidu.com*** + +## 发送数据 + +将client对象转为**HttpClient**,即可使用**扩展方法**,进行发送。 + +**作为一条消息发送** + + +**将一个数据分包发送** +例如:发送的数据为{0,1,2,3,4,5,6,7,8,9},当设置packageSize为5时,会先发送{0,1,2,3,4}作为头包,然后发送{5,6,7,8,9}的后继包。 + + + + +## 接收数据 + +**订阅Received事件实现,或使用插件实现。** + +```csharp +client.Received += (c, e) => + { + switch (e.Opcode) + { + case WSDataType.Cont: + break; + case WSDataType.Text: + break; + case WSDataType.Binary: + break; + case WSDataType.Close: + break; + case WSDataType.Ping: + break; + case WSDataType.Pong: + break; + default: + break; + } + }; +``` + +**附加插件实现** +该操作和服务器一致。 diff --git a/handbook/docs/createwebsocketservice.mdx b/handbook/docs/createwebsocketservice.mdx new file mode 100644 index 000000000..8daf36c34 --- /dev/null +++ b/handbook/docs/createwebsocketservice.mdx @@ -0,0 +1,236 @@ +--- +id: createwebsocketservice +title: 创建WebSocket服务器 +--- + + +## 一、说明 + +WebSocket是基于Http协议的升级协议,所以应当挂载在http服务器执行。 + + +## 二、可配置项 + +继承HttpService + + +## 三、支持插件接口 + +支持**ITcpPlugin、IHttpPlugin、IWebSocketPlugin** + + +### IWebSocketPlugin + +| | +| --- | --- | +| OnHandshaking | 表示在即将握手连接时。 | +| OnHandshaked | 表示完成握手后。 | +| OnHandleWSDataFrame | 当收到WS数据时。 | + +## 四、创建WebSocket服务 + + +### 4.1 简单通过插件创建 + +通过插件创建的话,只能指定一个特殊url路由。如果想获得连接前的Http请求,也必须再添加一个实现IWebSocketPlugin接口的插件,然后从OnHandshaking方法中捕获。 + +```csharp +var service = new HttpService(); +service.Setup(new TouchSocketConfig()//加载配置 + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a => + { + a.SetSingletonLogger(); + }) + .ConfigurePlugins(a => + { + a.Add()//添加WebSocket功能 + .SetWSUrl("/ws") + .SetCallback(WSCallback);//WSCallback回调函数是在WS收到数据时触发回调的。 + a.Add();//MyWebSocketPlugin是继承自WebSocketPluginBase的插件。 + })) + .Start(); + +Console.WriteLine("Http服务器已启动"); +Console.WriteLine("ws://127.0.0.1:7789/ws"); + +``` + + +### 4.2 通过WebApi创建 + +通过WebApi的方式会更加灵活,也能很方便的获得Http相关参数。还能实现多个Url的连接路由。 +实现步骤: + +1. 必须启用插件 +2. 必须配置ConfigureRpcStore,和注册MyServer +3. 必须添加WebApiParserPlugin + +```csharp +var service = new HttpService(); +service.Setup(new TouchSocketConfig()//加载配置 + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a => + { + a.SetSingletonLogger(); + }) + .ConfigureRpcStore(a=> + { + a.RegisterServer(); + }) + .ConfigurePlugins(a => + { + a.Add(); + })) + .Start(); + +Console.WriteLine("服务器已启动,可使用下列地址连接"); +Console.WriteLine("ws://127.0.0.1:7789/MyServer/ConnectWS"); +``` + +```csharp +public class MyServer : RpcServer +{ + private readonly ILog m_logger; + + public MyServer(ILog logger) + { + this.m_logger = logger; + } + + [Router("/[api]/[action]")] + [WebApi(HttpMethodType.GET, MethodFlags = MethodFlags.IncludeCallContext)] + public void ConnectWS(IWebApiCallContext callContext) + { + if (callContext.Caller is HttpSocketClient socketClient) + { + if (socketClient.SwitchProtocolToWebSocket(callContext.Context)) + { + m_logger.Message("WS通过WebApi连接"); + } + } + } +} +``` + + + +## 创建基于Ssl的WebSocket服务 + +创建WSs服务器时,其他配置不变,只需要在config中配置SslOption代码即可。 +在[RRQMBox](https://gitee.com/RRQM_Home/RRQMBox/tree/master/Ssl%E8%AF%81%E4%B9%A6%E7%9B%B8%E5%85%B3)中,放置了一个自制Ssl证书,密码为“RRQMSocket”以供测试。使用配置非常方便。 + +```csharp +var config = new TouchSocketConfig(); +config.UsePlugin() + .SetReceiveType(ReceiveType.Auto) + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .SetServiceSslOption(new ServiceSslOption() //Ssl配置,当为null的时候,相当于创建了ws服务器,当赋值的时候,相当于wss服务器。 + { + Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"), + SslProtocols = SslProtocols.Tls12 + }); +``` + + + +## 接收消息 + +**【回调接收】** +在添加**WebSocketServerPlugin**插件后,可以调用**SetCallback**函数,然后设置一个回调函数(如下所示),然后该函数在服务器收到信息时,会触发(并发触发)。 + +```csharp +static void WSCallback(ITcpClientBase client, WSDataFrameEventArgs e) +{ + switch (e.DataFrame.Opcode) + { + case WSDataType.Cont: + Console.WriteLine($"收到中间数据,长度为:{e.DataFrame.PayloadLength}"); + break; + case WSDataType.Text: + Console.WriteLine(e.DataFrame.ToText()); + break; + case WSDataType.Binary: + if (e.DataFrame.FIN) + { + Console.WriteLine($"收到二进制数据,长度为:{e.DataFrame.PayloadLength}"); + } + else + { + Console.WriteLine($"收到未结束的二进制数据,长度为:{e.DataFrame.PayloadLength}"); + } + break; + case WSDataType.Close: + { + Console.WriteLine("远程请求断开"); + client.Close("断开"); + } + + break; + case WSDataType.Ping: + break; + case WSDataType.Pong: + break; + default: + break; + } +} +``` + +**【继承源插件接收】** +实际上**WebSocketServerPlugin**是可以被继承的,然后重写**OnHandleWSDataFrame**函数,但尽量**不要覆盖**基类方法,不然插件其他将不会触发。 + +```csharp +class MyWebSocketServerPlugin: WebSocketServerPlugin +{ + protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + base.OnHandleWSDataFrame(client, e); + } +} +``` + +【插件接口接收】 +WS服务器,虽然是Http的插件,但是也能触发插件接口。适用于WS的插件接口是**IWebSocketPlugin**(或者从**WebSocketPluginBase**继承),声明任意类,实现该接口即可。 + +```csharp +class MyWebSocketServerPlugin: WebSocketPluginBase +{ + protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + //此处的父类方法可以直接覆盖。 + base.OnHandleWSDataFrame(client, e); + } +} +``` + + + +## 回复、响应数据 + +在以上接收、或直接从HttpService获取Clients,将client对象转为**HttpSocketClient**,即可使用**扩展方法**,进行发送。 + +**不要直接Send,7.x版本直接Send可以,但8.0以后,Send只会以TCP数据回应。** + +**作为一条消息发送** + + +**服务器广播发送** + +```csharp +//广播给所有人 +if (client is HttpSocketClient socketClient && socketClient.Service is HttpService service) +{ + var clients = service.GetClients(); + foreach (var item in clients) + { + item.SendWithWS(e.DataFrame.ToText()); + } +} +``` + +**将一个数据分包发送** +例如:发送的数据为{0,1,2,3,4,5,6,7,8,9},当设置packageSize为5时,会先发送{0,1,2,3,4}作为头包,然后发送{5,6,7,8,9}的后继包。 + diff --git a/handbook/docs/custombetweenanddatahandlingadapter.mdx b/handbook/docs/custombetweenanddatahandlingadapter.mdx new file mode 100644 index 000000000..045255ae3 --- /dev/null +++ b/handbook/docs/custombetweenanddatahandlingadapter.mdx @@ -0,0 +1,104 @@ +--- +id: custombetweenanddatahandlingadapter +title: 模板解析“区间数据”数据适配器 +--- + + +## 一、说明 + +区间适配器,一般用于字符串类的消息,类似“**Hello##”,该数据,以**开头,以##结尾。当然,区间适配器也能用于二进制数据,但是会有概率发生标识重复的情况。所以,用于二进制时,应当设置较复杂的区间标识。 + +该适配器与[终止因子分割适配器](../8.2 Tcp适配器/d.终止因子分割数据处理适配器.mdx)相比,可以设置开头的字符区间。 + + +## 二、特点 + +1. 可以自由适配**很多**的字符串数据协议。 +2. 可以随意定制数据协议。 +3. 可以与**任意语言、框架**对接数据。 + + +## 三、使用 + +客户端与服务器均适用。下列以服务器为例。 + +步骤 + +1. 声明新建类,实现**IBetweenAndRequestInfo**接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 +2. 声明新建类,继承**CustomBetweenAndDataHandlingAdapter**,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 +3. TouchSocketConfig配置中设置。 +4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 + +【MyBetweenAndRequestInfo】 +首先,新建MyBetweenAndRequestInfo类,然后实现**IBetweenAndRequestInfo**接口。 + +```csharp +/// +/// 以**12##12##,Min=5为例。 +/// +class MyBetweenAndRequestInfo : IBetweenAndRequestInfo +{ + public void OnParsingBody(byte[] body) + { + //这里的Body应该为12##12 + } + + public bool OnParsingEndCode(byte[] endCode) + { + return true;//该返回值决定,是否执行Receive + } + + public bool OnParsingStartCode(byte[] startCode) + { + return true; + } +} + +``` + +新建MyCustomBetweenAndDataHandlingAdapter继承**CustomBetweenAndDataHandlingAdapter**,然后对StartCode、EndCode作出赋值,以此表明起始字符与结束字符的值。 + +```csharp +class MyCustomBetweenAndDataHandlingAdapter : CustomBetweenAndDataHandlingAdapter +{ + public MyCustomBetweenAndDataHandlingAdapter() + { + this.MinSize = 5;//表示,实际数据体不会小于5,例如“**12##12##”数据,解析后会解析成“12##12” + } + + public override byte[] StartCode => Encoding.UTF8.GetBytes("**");//可以为0长度字节,意味着没有起始标识。 + + public override byte[] EndCode => Encoding.UTF8.GetBytes("##");//必须为有效值。 + + protected override MyBetweenAndRequestInfo GetInstance() + { + return new MyBetweenAndRequestInfo(); + } +} +``` + +【接收】 + +```csharp +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 + if (requestInfo is MyBetweenAndRequestInfo myRequestInfo) + { + //此处可以处理MyBigFixedHeaderRequestInfo的相关信息了。 + } + +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(() => { return new MyCustomBetweenAndDataHandlingAdapter(); }))//配置适配器 + .Start();//启动 +``` + +:::tip 提示 + +上述创建的适配器客户端与服务器均适用。 + +::: diff --git a/handbook/docs/customdatahandlingadapter.mdx b/handbook/docs/customdatahandlingadapter.mdx new file mode 100644 index 000000000..2b7beb019 --- /dev/null +++ b/handbook/docs/customdatahandlingadapter.mdx @@ -0,0 +1,156 @@ +--- +id: customdatahandlingadapter +title: 用户自定义适配器 +--- + +## 一、说明 + +和原始适配器相比,用户自定义适配器(**CustomDataHandlingAdapter**)简单很多。因为他只需要考虑接下来如何处理即可。 + +## 二、运行逻辑 + + + +返回指令类型: + +- FilterResult.Cache:将ByteBlock中的,从ByteBlock.Pos到结束的所有数据进行缓存,用于和下次接收数据做拼接。 +- FilterResult.Success:完成本次数据解析,向Received投递IRequestInfo对象。在返回之前,请一定确保已经修改ByteBlock.Pos属性。不然会发生无限循环的危险情况。 +- FilterResult.GoOn:将ByteBlock.Pos至结束的数据重新投递,所以在返回之前,请一定确保已经修改ByteBlock.Pos属性,至少已经递增一位。不然会发生无限循环的危险情况。 + +:::danger 注意 + +返回Success或者GoOn指令时,请一定确保已经修改ByteBlock.Pos属性,至少已经递增一位。不然会发生无限循环的危险情况。 + +::: + +## 三、特点 + +1. 更加自由度的操作数据。 +2. 能够简单的缓存不能解析的数据。 + + +## 四、使用 + +还是以下列数据为例: + + + +步骤 + +1. 声明新建类,实现IRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 +2. 声明新建类,继承CustomDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 +3. TouchSocketConfig配置中设置。 +4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 + +【定义适配器】 + +```csharp +internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter +{ + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量指导,指示当需要缓存时,应该申请多大的内存。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref MyRequestInfo request, ref int tempCapacity) + { + //以下解析思路为一次性解析,不考虑缓存的临时对象。 + + if (byteBlock.CanReadLen < 3) + { + return FilterResult.Cache;//当头部都无法解析时,直接缓存 + } + + int pos = byteBlock.Pos;//记录初始游标位置,防止本次无法解析时,回退游标。 + + MyRequestInfo myRequestInfo = new MyRequestInfo(); + + //此操作实际上有两个作用, + //1.填充header + //2.将byteBlock.Pos递增3的长度。 + byteBlock.Read(out byte[] header, 3);//填充header + + //因为第一个字节表示所有长度,而DataType、OrderType已经包含在了header里面。 + //所有只需呀再读取header[0]-2个长度即可。 + byte bodyLength = (byte)(header[0] - 2); + + if (bodyLength > byteBlock.CanReadLen) + { + //body数据不足。 + byteBlock.Pos = pos;//回退游标 + return FilterResult.Cache; + } + else + { + //此操作实际上有两个作用, + //1.填充body + //2.将byteBlock.Pos递增bodyLength的长度。 + byteBlock.Read(out byte[] body, bodyLength); + + myRequestInfo.Header = header; + myRequestInfo.DataType = header[1]; + myRequestInfo.OrderType = header[2]; + myRequestInfo.Body = body; + request = myRequestInfo;//赋值ref + return FilterResult.Success;//返回成功 + } + } +} + +internal class MyRequestInfo : IRequestInfo +{ + /// + /// 自定义属性,Body + /// + public byte[] Body { get; internal set; } + + /// + /// 自定义属性,Header + /// + public byte[] Header { get; internal set; } + + /// + /// 自定义属性,DataType + /// + public byte DataType { get; internal set; } + + /// + /// 自定义属性,OrderType + /// + public byte OrderType { get; internal set; } +} +``` + +【接收】 + +```csharp +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 + if (requestInfo is MyRequestInfo myRequestInfo) + { + //此处可以处理MyRequestInfo的相关信息了。 + string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); + } + +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(() => { return new MyCustomDataHandlingAdapter(); }))//配置适配器 + .Start();//启动 +``` + +:::tip 提示 + +上述创建的适配器客户端与服务器均适用。 + +::: \ No newline at end of file diff --git a/handbook/docs/customfixedheaderdatahandlingadapter.mdx b/handbook/docs/customfixedheaderdatahandlingadapter.mdx new file mode 100644 index 000000000..1a081744d --- /dev/null +++ b/handbook/docs/customfixedheaderdatahandlingadapter.mdx @@ -0,0 +1,153 @@ +--- +id: customfixedheaderdatahandlingadapter +title: 模板解析“固定包头”数据适配器 +--- + + +## 一、说明 + +和用户自定义适配器相比,使用模板解析将会更加简单流程。例如在上节所说的数据格式,前三个字节是**固定长度**的,为3,而后续长度则由第一个字节计算可得,所以我们把类似这样的数据格式,叫做“**固定包头**”数据,那么,他就可以使用固定包头数据解析模板。 + + + +## 二、特点 + +1. 可以自由适配**99%**的数据协议(例如:modbus,电力控制协议等)。 +2. 可以随意定制数据协议。 +3. 可以与**任意语言、框架**对接数据。 + + +## 三、使用 + +客户端与服务器均适用。下列以服务器为例。 + +步骤 + +1. 声明新建类,实现IFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 +2. 声明新建类,继承CustomFixedHeaderDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 +3. TouchSocketConfig配置中设置。 +4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 + +【MyFixedHeaderRequestInfo】 + +首先,新建MyFixedHeaderRequestInfo类,然后实现**IFixedHeaderRequestInfo**用户自定义固定包头接口。 + +然后在**OnParsingHeader**函数执行结束时,对实现的`BodyLength`属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。 + +```csharp +public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo +{ + private int bodyLength; + /// + /// 接口实现,标识数据长度 + /// + public int BodyLength + { + get { return bodyLength; } + } + + private byte dataType; + /// + /// 自定义属性,标识数据类型 + /// + public byte DataType + { + get { return dataType; } + } + + private byte orderType; + /// + /// 自定义属性,标识指令类型 + /// + public byte OrderType + { + get { return orderType; } + } + + private byte[] body; + /// + /// 自定义属性,标识实际数据 + /// + public byte[] Body + { + get { return body; } + } + + + public bool OnParsingBody(byte[] body) + { + if (body.Length == this.bodyLength) + { + this.body = body; + return true; + } + return false; + } + + + public bool OnParsingHeader(byte[] header) + { + //在该示例中,第一个字节表示后续的所有数据长度,但是header设置的是3,所以后续还应当接收length-2个长度。 + this.bodyLength = header[0]-2; + this.dataType = header[1]; + this.orderType = header[2]; + return true; + } +} + +``` + +新建MyFixedHeaderCustomDataHandlingAdapter继承**CustomFixedHeaderDataHandlingAdapter**,然后对HeaderLength作出赋值,以此表明固定包头的长度是多少。 + +```csharp +public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter +{ + /// + /// 接口实现,指示固定包头长度 + /// + public override int HeaderLength => 3; + + /// + /// 获取新实例 + /// + /// + protected override MyFixedHeaderRequestInfo GetInstance() + { + return new MyFixedHeaderRequestInfo(); + } +} +``` + +【接收】 + +```csharp {15} +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 + if (requestInfo is MyFixedHeaderRequestInfo myRequestInfo) + { + //此处可以处理MyFixedHeaderRequestInfo的相关信息了。 + string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); + } + +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(() => { return new MyFixedHeaderCustomDataHandlingAdapter(); }))//配置适配器 + .Start();//启动 +``` + +:::tip 提示 + +上述示例的数据是经典的固定包头格式,具有Header+Body的明显分割点。但有时候,也有一些数据有好几段,例如:具有Crc校验的数据,也就是Header+Body+Crc的格式,这时候,我们可以把Body+Crc看做一段数据,然后从Header解析BodyLength以后,加上Crc的长度。最后会在OnParsingBody时,将Body和Crc一起投递,届时做好数据分割即可。 + +::: + + +:::tip 提示 + +上述创建的适配器客户端与服务器均适用。 + +::: \ No newline at end of file diff --git a/handbook/docs/customunfixedheaderdatahandlingadapter.mdx b/handbook/docs/customunfixedheaderdatahandlingadapter.mdx new file mode 100644 index 000000000..5e9849989 --- /dev/null +++ b/handbook/docs/customunfixedheaderdatahandlingadapter.mdx @@ -0,0 +1,137 @@ +--- +id: customunfixedheaderdatahandlingadapter +title: 模板解析“非固定包头”数据适配器 +--- + + +## 一、说明 + +有时候,我们需要解析的数据的包头是不定的,例如:HTTP数据格式,其数据头和数据体由“\r\n”隔开,而数据头又因为请求者的请求信息的不同,头部数据量不固定,而数据体的长度,也是由数据头的ContentLength的值显式指定的,所以,可以考虑使用**CustomUnfixedHeaderDataHandlingAdapter**解析。 + + +## 二、特点 + +1. 可以自由适配**所有**的数据协议。 +2. 可以随意定制数据协议。 +3. 可以与**任意语言、框架**对接数据。 + + +## 三、使用 + +客户端与服务器均适用。下列以服务器为例。 + +步骤 + +1. 声明新建类,实现IFixedHeaderRequestInfo接口,此对象即为存储数据的实体类,可在此类中声明一些属性,以备使用。 +2. 声明新建类,继承CustomUnfixedHeaderDataHandlingAdapter,并且以步骤1声明的类作为泛型。并实现对应抽象方法。 +3. TouchSocketConfig配置中设置。 +4. 通过Received(事件、方法、插件)中的RequestInfo对象,强转为步骤1声明的类型,然后读取其属性值,以备使用。 + +【MyUnfixedHeaderRequestInfo】 +首先,新建MyFixedHeaderRequestInfo类,然后实现**IUnfixedHeaderRequestInfo**用户自定义固定包头接口。 +然后在**OnParsingHeader**函数执行结束时,对实现的`BodyLength`属性作出赋值,以此来决定,后续还应该接收多少数据作为Body 。 + +```csharp +public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo +{ + private int bodyLength; + /// + /// 接口实现,标识数据长度 + /// + public int BodyLength + { + get { return bodyLength; } + } + + + private byte[] body; + /// + /// 自定义属性,标识实际数据 + /// + public byte[] Body + { + get { return body; } + } + + + public bool OnParsingBody(byte[] body) + { + if (body.Length == this.bodyLength) + { + this.body = body; + return true; + } + return false; + } + + + public bool OnParsingHeader(ByteBlock byteBlock) + { + //此处逻辑和固定包头模板基本一致。也需要对BodyLength作出赋值。 + //但是不同固定包头的是,需要自己移动已读的游标。并且返回正确的值。 + + //下列通过假逻辑实现Http协议的解析。 + + //从现有的可读数据中,读取“\r\n\r\n”,以此来分割http的headers和body。 + int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, Encoding.UTF8.GetBytes("\r\n\r\n")); + if (index > 0) + { + //索引到了“\r\n\r\n”,以此推断出,在当前缓存区中,由byteBlock.Pos至index的数据即为headers。 + int headerLength = index - byteBlock.Pos; + string headers = Encoding.UTF8.GetString(byteBlock.Buffer, byteBlock.Pos,headerLength);//解码headers + byteBlock.Pos += headerLength;//然后将缓存区的游标移至headers结束的位置。 + + //最后通过headers,解析出后续的body的长度,然后在此处赋值。 + this.bodyLength = 0;//此处的0是占位值。 + return true; + } + else + { + //没索引到“\r\n\r\n”,以此推断出,在当前缓存区中,header的接收尚未完成, + //所以返回false,并且不需要修改游标。 + return false; + } + } +} + + +``` + +新建MyCustomUnfixedHeaderDataHandlingAdapter继承**CustomUnfixedHeaderDataHandlingAdapter**。 + +```csharp +public class MyCustomUnfixedHeaderDataHandlingAdapter : CustomUnfixedHeaderDataHandlingAdapter +{ + protected override MyUnfixedHeaderRequestInfo GetInstance() + { + return new MyUnfixedHeaderRequestInfo(); + } +} +``` + +【接收】 + +```csharp +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //接收信息,在CustomDataHandlingAdapter派生的适配器中,byteBlock将为null,requestInfo将为适配器定义的泛型 + if (requestInfo is MyUnfixedHeaderRequestInfo myRequestInfo) + { + //此处可以处理MyUnfixedHeaderRequestInfo的相关信息了。 + string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); + } + +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(() => { return new MyCustomUnfixedHeaderDataHandlingAdapter(); }))//配置适配器 + .Start();//启动 +``` + +:::tip 提示 + +上述创建的适配器客户端与服务器均适用。 + +::: \ No newline at end of file diff --git a/handbook/docs/dataadaptertester.mdx b/handbook/docs/dataadaptertester.mdx new file mode 100644 index 000000000..762e5203d --- /dev/null +++ b/handbook/docs/dataadaptertester.mdx @@ -0,0 +1,68 @@ +--- +id: dataadaptertester +sidebar_position: 5 +title: 适配器完整性、性能测试 +sidebar_label: 8.5 适配器完整性、性能测试 +--- + +## 一、说明 + +适配器测试是测试适配器在正常情况下,极端工作的一种测试方式。能够在前期,解决100%的算法问题。也能在极端配置下,模拟极端工作环境,能够简单,直观的展示出适配器的稳定性和工作性能。 + + +### 1.1 测试原理 + +假设发送数据为{0,1,2,3,4},连续发送10次。 +当bufferLength=1时,会先接收一个字节,然后适配器判断无法解析,然后缓存,然后再接收下一个字节,直到成功解析一个完整数据包。该模式解决的就是大家所说的分包,也就是能很好的模拟**网络很差**的环境。 +当bufferLength>5时,假如为8,则会先接收{0,1,2,3,4,0,1,2},然后适配器成功判断解析前五字节,然后缓存后三字节,然后再接收下一个续包,直到解析结束。 + + +### 1.2 测试事项 + +1. bufferLength应该多次设置,且最好不要整除于发送数据的长度,这样避免巧合发生,测不出极端问题。 +2. Run的次数应该多设,模拟高频情况。 + + +## 二、Tcp适配器 + +Tcp适配器的工作环境,只需考虑单线程即可。因为是客户端与适配器是一一对应的。 + +下列以 [固定包头数据处理适配器](./fixedheaderpackageadapter.mdx) 为例 + +```csharp +//Tcp适配器测试 +//bufferLength的作用是模拟tcp接收缓存区,例如: + +//发送数据为{0,1,2,3,4}时 +//当bufferLength=1时,会先接收一个字节,然后适配器判断无法解析,然后缓存,然后再接收下一个字节,直到成功解析。 +//该模式能很好的模拟网络很差的环境。 +//当bufferLength=8时,会先接收{0,1,2,3,4,0,1,2},然后适配器判断解析前五字节,然后缓存后三字节,然后再接收下一个续包,直到解析结束 + +for (int bufferLength = 1; bufferLength < 1024 * 10; bufferLength += 1024) +{ + bool isSuccess = true; + var data = new byte[] { 0, 1, 2, 3, 4 }; + DataAdapterTester tester = DataAdapterTester.CreateTester(new FixedHeaderPackageAdapter() + , bufferLength, (byteBlock, requestInfo) => + { + //此处就是接收,如果是自定义适配器,可以将requestInfo强制转换为实际对象,然后判断数据的确定性 + if (byteBlock.Len!=5||(!byteBlock.ToArray().SequenceEqual(data))) + { + isSuccess = false; + } + }); + + //data是发送的数据,因为此处使用的是固定包头适配器, + //发送前适配器会自动添加包头,所以,此处只发送数据即可。 + //如果测试的是自定义适配器,发送前没有封装的话,就需要自行构建发送数据。 + //随后的两个参数,10,10是测试次数,和期望次数,一般这两个值是相等的。 + //意为:本次数据将循环发送10次,且会接收10次。不然此处会一直阻塞。 + //最后一个参数是测试的最大超时时间。 + + var time = tester.Run(data, 10, 10, 1000 * 10); + Thread.Sleep(1000); + Console.WriteLine($"测试结束,状态:{isSuccess},用时:{time}"); +} +Console.WriteLine("测试结束"); + +``` diff --git a/handbook/docs/dataforwarding.mdx b/handbook/docs/dataforwarding.mdx new file mode 100644 index 000000000..19b2086de --- /dev/null +++ b/handbook/docs/dataforwarding.mdx @@ -0,0 +1,15 @@ +--- +id: dataforwarding +title: 数据转发项目 +--- + +## 定制方 +邑*物联有限公司 +## 说明 +应该公司要求,开发一个能够转发数据的服务器。按照一定规则,设计转发规则。 + +## 技术点 + +- 网络编程 +## 效果 +![image.png](../static/img/docs/dataforwarding-1.png) diff --git a/handbook/docs/datahandleadapter.mdx b/handbook/docs/datahandleadapter.mdx new file mode 100644 index 000000000..0efe2be1b --- /dev/null +++ b/handbook/docs/datahandleadapter.mdx @@ -0,0 +1,329 @@ +--- +id: datahandleadapter +title: 原始自定义适配器 +--- + + +## 说明 + +**自定义适配器可从两个方面入手。** + +1. 则是直接从DataHandlingAdapter继承,此时可以接触到最原始的TCP数据,可以自定实现数据的继续投递方式。但一般实现算法比较困难,因为所考虑的情况比较多。 +2. 则是从CustomDataHandlingAdapter(用户快捷自定义适配器)继承,此时数据的投递必须通过IRequestInfo,ByteBlock将为null。所需考虑的情况比较单一,对于数据的处理也比较简单。 + +## 原始DataHandlingAdapter + +自己实现适配器,然后使其工作。例如:假设如下数据格式,第一个字节表示整个数据长度(包括数据类型和指令类型),第二字节表示数据类型,第三字节表示指令类型,后续字节表示其他数据。 + +> 其次,希望在发送时,只传入数据类型,指令类型和其他数据,而数据长度则由适配器自行封装。最后,希望在接收端每次能接收到一个完整的数据。 + + + +## 实现 + +首先,创建类,继承自`DataHandlingAdapter`,然后实现对应属性,及方法。 + +```csharp +class MyDataHandleAdapter : DataHandlingAdapter +{ + public override bool CanSplicingSend => false; + + public override bool CanSendRequestInfo => false; + + protected override void PreviewReceived(ByteBlock byteBlock) + { + + } + + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + + } + + protected override void PreviewSend(IList> transferBytes) + { + + } + + protected override void Reset() + { + + } +} +``` + +【封装发送数据长度】 +封装发送数据时,比较简单,示例如下: + +```csharp +protected override void PreviewSend(byte[] buffer, int offset, int length) +{ + int dataLen = length - offset;//先获取需要发送的实际数据长度 + if (dataLen > byte.MaxValue)//超长判断 + { + throw new OverlengthException("发送数据太长。"); + } + + //从内存池申请内存块,因为此处数据绝不超过255,所以避免内存池碎片化,每次申请64K + //ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。 + using (ByteBlock byteBlock = new ByteBlock(64 * 1024)) + { + byteBlock.Write((byte)dataLen);//先写长度 + byteBlock.Write(buffer, offset, length);//再写数据 + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } +} +``` + +【解析接收数据】 +从原生适配器解封数据,需要考虑的情况比较多。在本示例中,需要考虑以下情况: + +1. 一次刚好接收一个数据。 +2. 一次刚好接收了多个数据。 +3. 一次接收了多个数据,但最后一个数据不完整。 +4. 一次未接收完一个数据。 + +综上,情况比较复杂,所以就必须自己做接收数据的缓存容器。 + +```csharp +/// +/// 临时包,此包仅当前实例储存 +/// +private ByteBlock tempByteBlock; + +/// +/// 包剩余长度 +/// +private byte surPlusLength; +protected override void PreviewReceived(ByteBlock byteBlock) +{ + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + if (this.tempByteBlock == null)//如果没有临时包,则直接分包。 + { + SplitPackage(buffer, 0, r); + } + else + { + if (surPlusLength == r)//接收长度正好等于剩余长度,组合完数据以后直接处理数据。 + { + this.tempByteBlock.Write(buffer, 0, surPlusLength); + PreviewHandle(this.tempByteBlock); + this.tempByteBlock = null; + surPlusLength = 0; + } + else if (surPlusLength < r)//接收长度大于剩余长度,先组合包,然后处理包,然后将剩下的分包。 + { + this.tempByteBlock.Write(buffer, 0, surPlusLength); + PreviewHandle(this.tempByteBlock); + this.tempByteBlock = null; + SplitPackage(buffer, surPlusLength, r); + } + else//接收长度小于剩余长度,无法处理包,所以必须先组合包,然后等下次接收。 + { + this.tempByteBlock.Write(buffer, 0, r); + surPlusLength -= (byte)r; + } + } +} +/// +/// 分解包 +/// +/// +/// +/// +private void SplitPackage(byte[] dataBuffer, int index, int r) +{ + while (index < r) + { + byte length = dataBuffer[index]; + int recedSurPlusLength = r - index - 1; + if (recedSurPlusLength >= length) + { + ByteBlock byteBlock = new ByteBlock(length); + byteBlock.Write(dataBuffer, index + 1, length); + PreviewHandle(byteBlock); + surPlusLength = 0; + } + else//半包 + { + this.tempByteBlock = new ByteBlock(length); + surPlusLength = (byte)(length - recedSurPlusLength); + this.tempByteBlock.Write(dataBuffer, index + 1, recedSurPlusLength); + } + index += length + 1; + } +} +/// +/// 处理数据 +/// +/// +private void PreviewHandle(ByteBlock byteBlock) +{ + try + { + this.GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose();//在框架里面将内存块释放 + } +} +``` + +## 使用自定义适配器 + +自定义适配器的使用和预设的适配器一样。不过在该案例中,发送数据时,应当传入三个有效值,分别为**数据类型**,**指令类型**,**其他数据**。 + + +## 封装函数及分片发送意义 + +在上述案例中,发送数据时应当传入**数据类型**,**指令类型**,**其他数据**三个有效值,而在RRQM中,发送函数仅有Send(和重载),这无疑需要我们自己封装`其他方法`。 +***假设以下情况需要实现:*** + +> 数据类型有两种,分别为Up(1),Down(0)。指令类型有两种,分别为Go(1)、Hold(0)。数据类型和指令类型可以任意组合,且均可携带其他数据。 + +面对上述情况,我们可以封装以下函数使用: + +```csharp +public class MySocketClient : SimpleSocketClient +{ + public void Up_Go_Send(byte[] data) + { + ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[]. + byteBlock.Write((byte)1); + byteBlock.Write((byte)1); + byteBlock.Write(data); + try + { + this.Send(byteBlock); + } + finally + { + byteBlock.Dispose(); + } + } + public void Down_Go_Send(byte[] data) + { + ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[]. + byteBlock.Write((byte)0); + byteBlock.Write((byte)1); + byteBlock.Write(data); + try + { + this.Send(byteBlock); + } + finally + { + byteBlock.Dispose(); + } + } + public void Up_Hold_Send(byte[] data) + { + ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[]. + byteBlock.Write((byte)1); + byteBlock.Write((byte)0); + byteBlock.Write(data); + try + { + this.Send(byteBlock); + } + finally + { + byteBlock.Dispose(); + } + } + public void Down_Hold_Send(byte[] data) + { + ByteBlock byteBlock = new ByteBlock(this.BufferLength);//内存池实现,可以直接new byte[]. + byteBlock.Write((byte)0); + byteBlock.Write((byte)0); + byteBlock.Write(data); + try + { + this.Send(byteBlock); + } + finally + { + byteBlock.Dispose(); + } + } +} +``` + +***为什么要分片发送??*** + +> 在示例代码中不难看出,封装的函数将**发送数据**进行了**Write**操作(相当于Copy),这无疑是消耗性能的。只是在该案例中,复制的数据最大为255,感觉优化效果甚微,倘若我们需要发送的数据是1Mb,那就相当于在封装数据时,因为**前两个字节**的存在而复制1Mb的数据(冤死了),然后在适配器中还需要因为**数据包头**,再复制一次。 + +***优化。。。*** +所以我们在封装时,可以使用分片发送,但是同时也需要适配器支持。不然内部会出错。 + +```csharp +protected override void PreviewSend(IList> transferBytes) +{ + int dataLen = 0; + foreach (var item in transferBytes) + { + dataLen += item.Count; + } + if (dataLen > byte.MaxValue)//超长判断 + { + throw new OverlengthException("发送数据太长。"); + } + + //从内存池申请内存块,因为此处数据绝不超过255,所以避免内存池碎片化,每次申请64K + //ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。 + + using (ByteBlock byteBlock = new ByteBlock(64 * 1024)) + { + byteBlock.Write((byte)dataLen);//先写长度 + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count);//依次写入 + } + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } +} +``` + +***重新封装函数。。。*** + +```csharp +public void Up_Go_SplicingSend(byte[] data) +{ + List transferBytes = new List(); + transferBytes.Add(new TransferByte(new byte[] { 1})); + transferBytes.Add(new TransferByte(new byte[] { 1})); + transferBytes.Add(new TransferByte(data)); + this.Send(transferBytes); +} +public void Down_Go_SplicingSend(byte[] data) +{ + List transferBytes = new List(); + transferBytes.Add(new TransferByte(new byte[] { 0 })); + transferBytes.Add(new TransferByte(new byte[] { 1 })); + transferBytes.Add(new TransferByte(data)); + this.Send(transferBytes); +} +public void Up_Hold_SplicingSend(byte[] data) +{ + List transferBytes = new List(); + transferBytes.Add(new TransferByte(new byte[] { 1 })); + transferBytes.Add(new TransferByte(new byte[] { 0 })); + transferBytes.Add(new TransferByte(data)); + this.Send(transferBytes); +} +public void Down_Hold_SplicingSend(byte[] data) +{ + List transferBytes = new List(); + transferBytes.Add(new TransferByte(new byte[] { 0 })); + transferBytes.Add(new TransferByte(new byte[] { 0 })); + transferBytes.Add(new TransferByte(data)); + this.Send(transferBytes); +} +``` diff --git a/handbook/docs/datasecurity.mdx b/handbook/docs/datasecurity.mdx new file mode 100644 index 000000000..34fece851 --- /dev/null +++ b/handbook/docs/datasecurity.mdx @@ -0,0 +1,15 @@ +--- +id: datasecurity +title: 数据加密 +--- + +## 一、3DES +**Nuget Package:**[TouchSocket](https://www.nuget.org/packages/TouchSocket/) +【加密】 +```csharp +var dataLocked = DataSecurity.EncryptDES(data, "12345678");//加密口令,长度为8。 +``` +【解密】 +```csharp +var newData = DataSecurity.DecryptDES(dataLocked, "12345678");//解密口令,和加密一致。 +``` diff --git a/handbook/docs/dependencyproperty.mdx b/handbook/docs/dependencyproperty.mdx new file mode 100644 index 000000000..8ddd9bc7d --- /dev/null +++ b/handbook/docs/dependencyproperty.mdx @@ -0,0 +1,110 @@ +--- +id: dependencyproperty +title: 依赖属性 +--- + + +## 一、说明 +用过WPF的小伙伴一定对依赖属性不陌生。所以TouchSocket模仿其结构,创建了适用于网络框架的依赖属性。 + + +## 二、什么是依赖属性? + +我们知道常规属性,就是拥有get,set访问器的字段,叫做属性。 +```csharp +class MyClass +{ + public int MyProperty { get; set; } +} +``` +而依赖属性,则是具有注入特征的属性。它可以像普通属性一样,声明在类内部(示例1)。也可以声明在任何地方(示例2)。 + +【示例1】 + +1. 继承**DependencyObject** +2. 按如下格式生成属性项(propdp代码块可快速实现) +```csharp +class MyClass: DependencyObject +{ + /// + /// 属性项 + /// + public int MyProperty + { + get { return GetValue(MyPropertyProperty); } + set { SetValue(MyPropertyProperty, value); } + } + + /// + /// 依赖项 + /// + public static readonly DependencyProperty MyPropertyProperty = + DependencyProperty.Register("MyProperty", typeof(MyClass), 10); + +} +``` + +【示例2】 +假设以下情况: +对于TouchSocket的**IClient**接口对象(已经实现IDependencyObject),希望创建一个int类型的,名为MyProperty的依赖项属性。 + +那么,可以用下列代码实现 +```csharp +public static class DependencyExtensions +{ + /// + /// 依赖项 + /// + public static readonly DependencyProperty MyPropertyProperty = + DependencyProperty.Register("MyProperty", typeof(MyClass), 10); + + /// + /// 设置MyProperty + /// + /// + /// + /// + /// + public static TClient SetMyProperty(this TClient client, int value) where TClient : IClient + { + client.SetValue(MyPropertyProperty, value); + return client; + } + + /// + /// 获取MyProperty + /// + /// + /// + /// + public static int GetMyProperty(this TClient client) where TClient : IClient + { + return client.GetValue(MyPropertyProperty); + } +} +``` + +```csharp +TcpClient tcpClient = new TcpClient(); +tcpClient.SetMyProperty(100); +int MyProperty = tcpClient.GetMyProperty(); +``` +## 三、优缺点 + +**优点:** + +1. 可以不声明在类内部。这意味着可以从外部注入。 +2. 不需要初始赋值,也就意味着创建大量对象时,可以不需要占用太多内存。 + +**缺点:** + +1. 对于值类型,涉及拆装箱操作,对性能有一定性能影响(不是几百万操作,可以忽略)。 + + + +:::caution 注意 + +当一个属性被频繁(千万级别)使用时,不建议使用依赖属性。 + +::: + diff --git a/handbook/docs/description.mdx b/handbook/docs/description.mdx new file mode 100644 index 000000000..659a5cb99 --- /dev/null +++ b/handbook/docs/description.mdx @@ -0,0 +1,81 @@ +--- +id: description +title: 说明 +slug: / +--- + +## 当前版本 + +![](https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket#crop=0&crop=0&crop=1&crop=1&height=25&id=nWQ9P&originHeight=20&originWidth=126&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=160) ![](https://img.shields.io/nuget/v/TouchSocket.AspNetCore.svg?label=TouchSocket.AspNetCore#crop=0&crop=0&crop=1&crop=1&height=25&id=FWXGC&originHeight=20&originWidth=194&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=245) +![](https://img.shields.io/nuget/v/TouchSocketPro.svg?label=TouchSocketPro#crop=0&crop=0&crop=1&crop=1&height=25&id=oHu5g&originHeight=20&originWidth=144&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=179) ![](https://img.shields.io/nuget/v/TouchSocketPro.AspNetCore.svg?label=TouchSocketPro.AspNetCore#crop=0&crop=0&crop=1&crop=1&height=25&id=K0VEy&originHeight=20&originWidth=212&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=261) + +--- + +:::tip 公告 + +1. **原 RRQM 系文档,可以加 qq 群(234762506),在群文件自行获取。** + +::: + + +## 使用前必要阅读 + +TouchSocket 由作者若汝棋茗及其他贡献者开发,所有版权归作者若汝棋茗所有,程序集源代码在遵循 Apache License 2.0 的开源协议以及**附加协议**下,可**免费**供其他开发者二次开发或(商业)使用。 + +# Apache License 2.0 开源协议简述 + +- 永久权利 +- 一旦被授权,永久拥有。 +- 全球范围的权利 +- 在一个国家获得授权,适用于所有国家。假如你在美国,许可是从印度授权的,也没有问题。 +- 授权免费,且无版税 +- 前期,后期均无任何费用。 +- 授权无排他性 +- 任何人都可以获得授权 +- 授权不可撤消 +- 一旦获得授权,没有任何人可以取消。比如,你基于该产品代码开发了衍生产品,你不用担心会在某一天被禁止使用该代码。 + +# 附加协议 + + + +### 个人使用须知: + +- 不得将程序集用作违法犯罪活动。 +- 不得将程序集单独包装售卖,申请专利等。 +- 不得擦除程序集所有有关作者的信息。 + +**以上内容必须全部符合,个人使用授权才成立。** + +### 二次开发须知: + +- 不得将程序集用作违法犯罪活动。 +- 不得将程序集单独包装售卖,申请专利等。 +- 不得擦除程序集所有有关作者的信息。 +- 二次开发完成后的作品必须附带源作品所有作者信息,包括但不限于作者名、Gitee、Github 地址等。 +- **完成后**的作品(仅 TouchSocket 部分)必须将发布时最新源代码提交一份给本作者,QQ 邮箱:505554090@qq.com。 + +**以上内容必须全部符合,二次开发授权才成立。** + +### 盈利性(商业)用途使用须知: + +- 不得将程序集用作违法犯罪活动。 +- 不得将程序集单独包装售卖,申请专利等。 +- **不得擦除程序集所有有关作者的信息,并必须于用户可见界面(如关于)中提名。** + +**以上内容必须全部符合,使用授权才成立。** + +## TouchSocketPro 商用许可 + +TouchSocketPro 是 TouchSocket 的企业版,其 99%功能与 TouchSocket 一致。所有版权归作者若汝棋茗所有。 + +### TouchSocketPro 功能部分遵循: + +- 限时(1h)免费测试,测试期间可参与商业使用。 +- 付费使用,购买后还须遵循相关使用协议,详情咨询若汝棋茗。 + +**TouchSocketPro 程序集源代码不公开开源,需要付费购买。** + +# 免责申明 + +**在使用 TouchSocket**或**TouchSocketPro 之前请进行缜密的测试。在使用期间,由本程序集造成或间接造成的所有损失,均自己承担,与本程序集无关。** diff --git a/handbook/docs/donate.mdx b/handbook/docs/donate.mdx new file mode 100644 index 000000000..0d4937cce --- /dev/null +++ b/handbook/docs/donate.mdx @@ -0,0 +1,60 @@ +--- +id: donate +title: 支持作者 +--- + + +## 赞助TouchSocket项目 +> 您的支持就是我不懈努力的动力。 + + +### 爱心赞助名单(以下排名只按照打赏时间顺序) + +1. Bobo Joker(200¥) +2. UnitySir(66¥) +3. Coffee(100¥) +4. Ninety(50¥) +5. *琼(100¥) +6. **安(5¥) +7. **文(200+200¥) +8. tonychen899(50¥) +9. *平(50¥) +10. 杜(400+100¥) +11. 施*双(666¥) +12. *童(20¥) +13. Tom (88¥) +14. *强(200¥) +15. *潮(10+20+1+2¥) +16. *星(20¥) +17. 舔狗反咬事件(66¥) +18. 美少女酱(30¥) +19. 流水游鱼(9.99¥) +20. 华丽谢幕(33+20¥) +21. 阁主悦澜殇(50+50¥) +22. 烈日(20+20¥) +23. Silent(50¥) +24. 月华散(50¥) +25. 黄*德(PayPal:1000NT$) +26. 一头大狮子(20¥) +27. 蒋*秋(188¥) +28. **发(100+100¥) +29. 梦想遥不可及(128+98¥) +30. 可爱又善良的我(100¥) +31. *君(6.6¥) +32. *于(30¥) +33. J*n(100¥) +34. D*Y(20¥) +35. *人(50¥) +36. *光(66¥) +37. Estel(100¥) +38. 1(200¥) +39. **阳(100¥) +40. chenqiang(6.6¥) +41. Azure(50¥) +42. 广东-小白(1.5¥) + +### 一起喝酒? + +![打赏支付.png](../static/img/docs/donate-1.png) + + diff --git a/handbook/docs/engineertoolbox.mdx b/handbook/docs/engineertoolbox.mdx new file mode 100644 index 000000000..6f9c66bb6 --- /dev/null +++ b/handbook/docs/engineertoolbox.mdx @@ -0,0 +1,12 @@ +--- +id: engineertoolbox +title: 工程师软件工具箱 +--- + +## 说明 +这是群友开发者,使用**TouchRpc**开发的一个内部工程师软件工具箱 。 + +## 界面展示 +![1](../static/img/docs/engineertoolbox-1.jpg) +![2](../static/img/docs/engineertoolbox-2.jpg) +![3](../static/img/docs/engineertoolbox-3.jpg) diff --git a/handbook/docs/enterprise.mdx b/handbook/docs/enterprise.mdx new file mode 100644 index 000000000..a6dabeae6 --- /dev/null +++ b/handbook/docs/enterprise.mdx @@ -0,0 +1,168 @@ +--- +id: enterprise +title: 企业版相关 +--- + +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 +TouchSocketPro是TouchSocket系的加强版本。其基础功能完全包含TouchSocket,除此之外,还有一些附加功能,这需要**付费购买密钥**,然后才能使用。具体详细区别**如下表格**所示。 + +同时TouchSocketPro还提供**企业定制服务**及必要的**远程协助**,具体收费可以咨询作者若汝棋茗,联系方式:QQ:505554090。 + +## 二、TouchSocket与TouchSocketPro + +### 2.1 Tcp组件 +- [轮询式断线重连](./reconnection.mdx#三使用pollingkeepalive插件-企业版) 企业版 +- [TLV适配器](./tlvdatahandlingadapter.mdx) 企业版 +- 其余功能 + +### 2.2 NAT组件 +- [转发客户端重连](./natservice.mdx#四转发断线重连-企业版) 企业版 +- 其余功能 + +### 2.3 UDP组件 +- 所有功能 + +### 2.4 JsonRpc +- 自定义解析 企业版 +- 其余功能 + +### 2.5 WebApi +- 所有功能 + +### 2.6 XmlRpc +- 所有功能 + +### 2.7 TouchRpc(tcp、udp、http、websocket) +- [远程文件操作](./remotefilecontrol.mdx) 企业版 +- [远程流访问](./remotestreamaccess.mdx) 企业版 +- 文件传输功能 +- [多线程文件传输](./multithreadingfiletransfer.mdx) 企业版 +- [小文件传输](./smallfiletransfer.mdx) +- 文件传输限速 企业版 +- [EventBus功能](https://www.yuque.com/rrqm/touchsocket/ipt4zr) 企业版 +- Redis + +### 2.8 Http组件 +- 超大文件传输 +- 多通道文件续传 +- 静态网页展示 +- 文件传输限速 + +### WebSocket +- 全部功能 + +:::tip 提示 + +上述的功能中,所有带有 企业版 的标识,均为`TouchSocketPro`包含的内容。其余功能`TouchSocket`也均支持。 + +::: + +## 三、能提供的个性服务 + +### 3.1 数据处理适配器的重写 + +在TouchSocketPro中,可以通过适配器对数据进行预处理和对象解析,目前TouchSocketPro拥有的适配器仅有`固定包头`、`固定长度`、`终止分割`、`Json字符串解析`、`Http对象解析`五种适配器。但是往往这些适配器不是我们想要的,例如:串口信号、AGV数据格式等。那么我们可以为您提供解析数据格式(对象)的服务。 + +### 3.2 增加或限制某个功能 + +程序库为的是能提供基础服务,所以某个功能的出现,均是为了具备更好的普适性,但是有时候也会与您的需求背道而驰,那么我们也可以为您定制某个功能(或禁用某个功能)。 + +## 四、TouchSocketPro + +| **类型** | **个人独立授权** | **个人企业授权** | **企业授权** | +| --- | --- | --- | --- | +| **功能** | 全部功能 | 全部功能 | 全部功能 | +| **使用期限** | 永久 | 永久 | 永久 | +| **授权归属** | 个人 | 个人 | 企业 | +| **协助服务** | 无 | 无 | 全部现有功能协助 | +| **个性化功能扩展** | 支持 | 支持 | 支持 | +| **激活方式** | 密钥激活 | 密钥激活 | 密钥激活和源码引用 | +| **后续升级** | Nuget升级 | Nuget升级 | Nuget升级或随时索要最新源码 | +| **源代码开放** | 不开放 | 不开放 | 开放 | +| **用于盈利** | 允许 | 允许 | 允许 | +| **个性化功能扩展** | 支持 | 支持 | 支持 | +| **开具发票** | 原则上不开具 | 开具 | 开具 | +| **赠品** | 送您1束玫瑰 | 送您2束玫瑰 | 送您3束玫瑰,和一个自定义适配器,或复杂度相同的个性化服务。 | +| **价格** | 298¥ | 已停售 | 998¥ | + + +### 4.1 个人独立授权 + +授权归属于购买者个人所有,规定购买者可将所购产品只能应用于所属个人的任何软件(产品)上,可以以此盈利,但必须遵守[个人使用协议](./description.mdx#qLp3q)。 + +### 4.2 个人企业授权 + +授权归属于购买者个人所有,规定购买者可将所购产品应用于购买者服务(工作)的企业的任何软件(产品)上,但授权期限与购买者服务(工作)期限一致,一旦购买者离职(或不再服务于企业),授权将在30个工作日后失效。同时,购买者在将所购产品应用于企业时,有必要告知义务,在离职(或不再服务于企业)时,也应当再次告知企业详情。 + +**(个人企业版在2023.1.1日后不再售卖。已售卖的个人企业版原始功能不变。或者联系作者,可免费升级至企业版)** + +### 4.3 企业授权 + +- 当授权归属于企业所有时,永久授权。且仅企业享有授权,所有职员均无授权。 +- 当授权归属个人所有时,永久授权。且保留一次企业冠名权益,现有授权自动降为“**个人企业授权**”条款。。 + +## 五、密钥使用 + +**首先请确保所有的项目完全卸载删除TouchSocket,并且在需要的项目中安装了TouchSocketPro。** + +当购买密钥后,您会获得类似“D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1”这样的密钥。然后在程序**初始化**(例如Main函数)时。使用以下代码即可。 + +```csharp + Enterprise.Default.LicenceKey = "密钥"; +``` + +AspNetCore中使用时,建议自定义服务注入的方式实现。步骤如下: + +1. 新建项目,引用`Microsoft.Extensions.DependencyInjection`和`TouchSocketPro.AspNetCore`。 +2. 新建静态类**ServiceCollectionExtension**,创建IServiceCollection的扩展方法。 +3. 在IServiceCollection的扩展方法中,注入密钥。 +4. 在AspNetCore引用新建的项目。 +5. 在服务中注入。 + +部分代码示例如下: + +```csharp +public static class ServiceCollectionExtension +{ + public static void AddLicence(this IServiceCollection service) + { + Enterprise.Default.LicenceKey = "D1D1D1D1D1D1D1"; + } +} +``` + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddLicence(); +} + +``` + +## 六、限时测试 + +为方便大家测试,TouchSocketPro提供**限时1小时**的测试功能,当时间结束时企业版功能关闭,**重启进程**即可再次试用1小时,以此往复。 + +**调用ForTest时,会抛出可控异常。如果坚持使用企业版,使用Try拦截即可。** + +```csharp +try +{ + Enterprise.ForTest(); +} +catch (Exception ex) +{ + Console.WriteLine(ex.Message); +} +``` + +## 七、购买通道 + +购买可通过以下方式。**购买前请先联系作者若汝棋茗**。联系QQ:505554090。 + +扫描下列微信码,或者点击[淘宝链接](https://item.taobao.com/item.htm?spm=a2126o.success.result.1.382c4831HDDIvA&id=691874706840)。 + + + diff --git a/handbook/docs/eventbus.mdx b/handbook/docs/eventbus.mdx new file mode 100644 index 000000000..16f98d3e1 --- /dev/null +++ b/handbook/docs/eventbus.mdx @@ -0,0 +1,74 @@ +--- +id: eventbus +title: EventBus +--- + +## 说明 + +EventBus功能是企业版专属功能,其职能类似MQTT的发布订阅模式,也类似RabbitMQ的Sub模式。如果没有使用密钥,可以[试用](https://www.yuque.com/eo2w71/rrqm/80696720a95e415d94c87fa03642513d#Dfy2T)参考。 + +## 创建服务器 + +服务器的创建就是TouchRpc服务器。除udp协议外,tcp、http、websocket协议的版本均支持该功能。 + +下列以TcpTouchRpcService为例。 + +```csharp +TcpTouchRpcService tcpRpcService = new TcpTouchRpcService(); + +var config = new RRQMConfig(); +config.SetListenIPHosts(new IPHost[] { new RRQMSocket.IPHost(7789) }); +tcpRpcService + .Setup(config) + .Start(); + +``` + +由**服务器**发布一个事件。 +第一个参数为事件名,第二个为访问权限。 + +```csharp +tcpRpcService.PublishEvent("Hello", AccessType.Owner | AccessType.Service | AccessType.Everyone); +``` + + + +## 创建客户端 + +客户端订阅该事件。 + +```csharp +TcpTouchRpcClient tcpRpcClient = new TcpTouchRpcClient(); +tcpRpcClient + .Setup("127.0.0.1:7789") + .Connect(); + +tcpRpcClient.SubscribeEvent("Hello", SubscribeEvent); + +``` + +其中SubscribeEvent是接收委托。此处用方法转换接收。其目的为,当服务器触发该方法时,就会分发到此处。 + +```csharp + private void SubscribeEvent(EventSender eventSender, string arg) + { + this.ShowMsg($"从{eventSender.RaiseSourceType}收到通知事件{eventSender.EventName},信息:{arg}"); + } +``` + + + +## 服务器触发 + +第一个参数是事件名,第二个是事件参数。可以是任意类型,但是目前仅支持一个参数。 + +```csharp +tcpRpcService.RaiseEvent("Hello", "Hi"); +``` + + + +## 其他 + +实际上在TouchRpc架构中。**TouchService**、**TouchSocketClient**、**TouchClient**三者均已实现**IEventObject**接口,这意味均可以**发布、取消发布、订阅、取消订阅、触发**等操作(会验证操作权限)。 + diff --git a/handbook/docs/fastbinaryformatter.mdx b/handbook/docs/fastbinaryformatter.mdx new file mode 100644 index 000000000..30cd34aa9 --- /dev/null +++ b/handbook/docs/fastbinaryformatter.mdx @@ -0,0 +1,193 @@ +--- +id: fastbinaryformatter +title: 高性能二进制序列化 +--- + +## 一、说明 +该序列化以二进制方式进行序列化,不要求序列化与反序列化类型相同,使用体验和兼容性与json相似。支持**基础类型**、**自定义实体类**、**结构体**、**元组**、**数组**、**字典**、**List**等。 + +## 二、序列化、反序列化 +```csharp +var obj = "TouchSocket"; +var data = SerializeConvert.FastBinarySerialize(obj); +var newobj = SerializeConvert.FastBinaryDeserialize(data); +``` + +## 三、自定义转换器 + +自定义转化器的使用,可以解决**所有类型**的序列化,但是这需要自己编写一些代码。具体操作如下: + +1. 声明转换器。 +```csharp +/// +/// 继承或者实现 +/// +class StudentFastBinaryConverter : FastBinaryConverter +{ + protected override Student Read(byte[] buffer, int offset, int len) + { + var byteBlock = new ValueByteBlock(buffer); + byteBlock.Pos = offset; + var obj = new Student(); + obj.P1 = byteBlock.ReadInt32(); + obj.P2 = byteBlock.ReadString(); + return obj; + } + + protected override int Write(ByteBlock byteBlock, Student obj) + { + //此处可以直接嵌套Json序列化,但是为演示效果,下列将依然使用二进制方式 + int pos = byteBlock.Pos; + byteBlock.Write(obj.P1); + byteBlock.Write(obj.P2); + return byteBlock.Pos - pos;//返回的即是obj所有的字节长度 + } +} +``` + +2. 附加转换器 + +```csharp {1} +[FastConverter(typeof(StudentFastBinaryConverter))] +class Student +{ + public int P1 { get; set; } + public string P2 { get; set; } +} +``` + +:::tip + +当类型已经定义,无法通过特性添加转换器时,可以通过`FastBinaryFormatter.AddFastBinaryConverter(typeof(Student),new StudentFastBinaryConverter());`直接添加。 + +::: + + +## 四、性能测试 + +### 4.1 简单测试 + +**待测试类型** + +```csharp +[Serializable] +public class MyPackPerson +{ + public int Age { get; set; } + public string Name { get; set; } +} +``` + +**结果** + +以下测试是执行10000次序列化和反序列的结果。 + +![](../static/img/docs/fastbinaryformatter-1.png) + +### 4.2 复杂类型测试 + +**待测试类** + +```csharp + [Serializable] +public class Student +{ + public int P1 { get; set; } + public string P2 { get; set; } + public long P3 { get; set; } + public byte P4 { get; set; } + public DateTime P5 { get; set; } + public double P6 { get; set; } + public byte[] P7 { get; set; } + + public List List1 { get; set; } + public List List2 { get; set; } + public List List3 { get; set; } + + public Dictionary Dic1 { get; set; } + public Dictionary Dic2 { get; set; } + public Dictionary Dic3 { get; set; } + public Dictionary Dic4 { get; set; } +} + +[Serializable] +public class Arg +{ + public Arg(int myProperty) + { + this.MyProperty = myProperty; + } + + public Arg() + { + Person person = new Person(); + person.Name = "张三"; + person.Age = 18; + } + + public int MyProperty { get; set; } +} +[Serializable] +public class Person +{ + public string Name { get; set; } + public int Age { get; set; } +} +``` + +**赋值** + +```csharp +Student student = new Student(); +student.P1 = 10; +student.P2 = "若汝棋茗"; +student.P3 = 100; +student.P4 = 0; +student.P5 = DateTime.Now; +student.P6 = 10; +student.P7 = new byte[1024 * 64]; + +Random random = new Random(); +random.NextBytes(student.P7); + +student.List1 = new List(); +student.List1.Add(1); +student.List1.Add(2); +student.List1.Add(3); + +student.List2 = new List(); +student.List2.Add("1"); +student.List2.Add("2"); +student.List2.Add("3"); + +student.List3 = new List(); +student.List3.Add(new byte[1024]); +student.List3.Add(new byte[1024]); +student.List3.Add(new byte[1024]); + +student.Dic1 = new Dictionary(); +student.Dic1.Add(1, 1); +student.Dic1.Add(2, 2); +student.Dic1.Add(3, 3); + +student.Dic2 = new Dictionary(); +student.Dic2.Add(1, "1"); +student.Dic2.Add(2, "2"); +student.Dic2.Add(3, "3"); + +student.Dic3 = new Dictionary(); +student.Dic3.Add("1", "1"); +student.Dic3.Add("2", "2"); +student.Dic3.Add("3", "3"); + +student.Dic4 = new Dictionary(); +student.Dic4.Add(1, new Arg(1)); +student.Dic4.Add(2, new Arg(2)); +student.Dic4.Add(3, new Arg(3)); +``` + +**结果** + +Fast的效率比System自带的,快了近7倍,比System.Text.Json快了4倍多,比NewtonsoftJson快了近30倍。 + +![](../static/img/docs/fastbinaryformatter-2.png) diff --git a/handbook/docs/filepool.mdx b/handbook/docs/filepool.mdx new file mode 100644 index 000000000..eee9cf488 --- /dev/null +++ b/handbook/docs/filepool.mdx @@ -0,0 +1,70 @@ +--- +id: filepool +title: 文件流池 +--- + +## 一、说明 + +文件在读,或写的时候,一直都是独占状态。这个问题在不同进程中,似乎是合理的,但是如果在相同进程里,就会显得很呆。例如:我们在下载文件的时候,希望能同一时间多个读取同一个文件。且能有一个闭环的管理。那么,使用FilePool,就显得非常必要了。 + +## 二、使用读 +从FilePool.GetReader的静态函数中,获取一个**线程安全**的文件读取访问器,该访问器具有读,和相关的操作属性。在每次读取后,Position会递增。 + +使用完成后,可以随时释放。 + +```csharp +int len = 0; +byte[] buffer = new byte[1024 * 1024]; + +using (var reader = FilePool.GetReader(path)) +{ + while (true) + { + int r = reader.Read(buffer, 0, buffer.Length); + if (r == 0) + { + break; + } + len += r; + } +} + +Console.WriteLine(len); +``` + +## 三、使用写 +从FilePool.GetWriter的静态函数中,获取一个文件写入访问器线程安全,该访问器,具有写,和相关的操作属性。在每次写入后,Position会递增。 + +使用完成后,可以随时释放。 + +注意默认调用**Dispose**后,文件会根据创建类型是否为**单一访问**而决定是否立即释放。 +```csharp +byte[] buffer = new byte[1024]; + +using (var writer = FilePool.GetWriter(path,true)) +{ + writer.Position = num * package; + int surLen = package; + while (surLen > 0) + { + int r = Math.Min(surLen, buffer.Length); + writer.Write(buffer, 0, r); + surLen -= r; + } +} +Console.WriteLine("完成"); +``` + +## 四、手动释放文件资源 +当某个文件没有及时释放,或者由于不可知异常而没有释放时,可以调用FilePool.TryReleaseFile减少引用,并尝试释放资源。 + +减少引用的意思是,当某个文件,被创建多个访问器时,会递增其引用数,当引用数不为0时,是不会释放的。所以当调用FilePool.TryReleaseFile时,首先会减少引用,然后才会判断是否可以释放。 + +当需要强制释放某个文件时,可以采取下列措施。 +```csharp +while (FilePool.TryReleaseFile(fileName, 0).ResultCode!= ResultCode.Success) +{ + +} +``` + diff --git a/handbook/docs/filesynchronization.mdx b/handbook/docs/filesynchronization.mdx new file mode 100644 index 000000000..0fb63ee12 --- /dev/null +++ b/handbook/docs/filesynchronization.mdx @@ -0,0 +1,17 @@ +--- +id: filesynchronization +title: 文件同步系统 +--- + +## 定制方 +网友“陶” +## 说明 +应该网友要求,需要开发一个服务器,一个客户端,客户端的职能就是同步本地文件服务器。有点类似**OneDrive**。 + +## 技术点 + +- 数据同步:设置配置数据、项目文件数据等。 +- 文件:断点续传、换网续传。 +- 登录:登录授权。登录验证。 +## 效果 +![image.png](../static/img/docs/filesynchronization-1.png) diff --git a/handbook/docs/fixedheaderpackageadapter.mdx b/handbook/docs/fixedheaderpackageadapter.mdx new file mode 100644 index 000000000..5f699dabd --- /dev/null +++ b/handbook/docs/fixedheaderpackageadapter.mdx @@ -0,0 +1,58 @@ +--- +id: fixedheaderpackageadapter +title: 固定包头数据处理适配器 +--- + + +## 一、说明 + +固定包头数据处理适配器是处理粘包、分包问题的最有力、最可靠、最高效、最稳定的一种方案,它基本上适用于**所有场景**。即使**跨语言**使用,也只需要在其他语言中设计**相同算法**就可以。 + +## 二、特点 + +1. 最有力的解决粘包。分包问题。 +2. 是自定义协议的不二选择。 +3. 支持指定包头长度,Byte、Ushort、Int三种类型作为包头。 +4. 最好在客户端与服务器均使用TouchSocket组件时使用。不然就需要非TouchSocket的一方适配包头算法。 + +## 三、协议算法 + +- Byte包头算法:以第一个字节作为后续整个数据的长度,整个数据长度区间为[0,255]。 +- Ushort包头算法:前2个字节,且为[默认端序(小端)](./touchsocketbitconverter.mdx#四默认端)的排列,作为后续整个数据的长度,整个数据长度区间为[0,65535]。 +- Int包头算法(默认配置):前4个字节,且为[默认端序(小端)](./touchsocketbitconverter.mdx#四默认端)排列,作为后续整个数据的长度,整个数据长度区间为[0,2^31]。 + + +## 四、使用 + +客户端与服务器均适用。下列以服务器为例。 + +步骤 + +1. TouchSocketConfig配置中设置(可以同时指定HeaderType等属性) +2. 通过Received(事件、方法、插件)中的ByteBlock读取数据。 + +```csharp {10} +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(() => { return new FixedHeaderPackageAdapter() { FixedHeaderType= FixedHeaderType.Int }; }))//配置适配器 + .Start();//启动 +``` + +:::caution 注意 + +接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。 + +::: + +:::tip 提示 + +该适配器,客户端与服务器均适用。 + +::: \ No newline at end of file diff --git a/handbook/docs/fixedsizepackageadapter.mdx b/handbook/docs/fixedsizepackageadapter.mdx new file mode 100644 index 000000000..630210d53 --- /dev/null +++ b/handbook/docs/fixedsizepackageadapter.mdx @@ -0,0 +1,51 @@ +--- +id: fixedsizepackageadapter +title: 固定长度数据处理适配器 +--- + + +## 一、说明 + +固定长度数据处理适配器是将发送的数据通过分割、填补的操作,以达到每次发送、接收的数据都是固定的长度来处理粘包、分包问题。这种方案一般适用于机械臂,机器人控制等场景。 + +## 二、特点 + +1. 无论何时,发送与接收的数据长度永远为设定值。 +2. 算法简单,可以比较轻松的实现跨语言、跨框架。 +3. 一般适用于业务数据固定场景, + + +## 三、使用 + +客户端与服务器均适用。下列以服务器为例。 + +步骤 + +1. TouchSocketConfig配置中设置,同时指定数据的长度。 +2. 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。 + +```csharp {10} +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(()=> { return new FixedSizePackageAdapter(10); }))//配置适配器,固定数据长度为10字节。 + .Start();//启动 +``` + +:::caution 注意 + +接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。 + +::: + +:::tip 提示 + +该适配器,客户端与服务器均适用。 + +::: \ No newline at end of file diff --git a/handbook/docs/fpsgame.mdx b/handbook/docs/fpsgame.mdx new file mode 100644 index 000000000..df4d0aa12 --- /dev/null +++ b/handbook/docs/fpsgame.mdx @@ -0,0 +1,6 @@ +--- +id: fpsgame +title: FPS实时游戏 +--- + +[B站首页](https://space.bilibili.com/41336899) diff --git a/handbook/docs/generateproxy.mdx b/handbook/docs/generateproxy.mdx new file mode 100644 index 000000000..206b81192 --- /dev/null +++ b/handbook/docs/generateproxy.mdx @@ -0,0 +1,243 @@ +--- +id: generateproxy +title: 生成、获取代理 +--- + +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 + +### 1.1 为什么要生成代理? + +使用rpc的原则就是像使用本地方法一样,让开发者感觉不到任何的不同。所以就必须把服务代理到本地,常见的方式有三种,**动态代理接口**,**静态织入**,**静态编译**。三种方式殊途同归,最终都是构建本地数据结构,然后和远程通信。三种方式各有优缺,具体如下: + +| **优缺点** | **动态代理接口** | **静态织入** | **静态编译** | +| --- | --- | --- | --- | +| **优点** | 动态构建类,灵活、适应性强。 | 静态代码生成,自定义类参数自动生成,修改较灵活,调用效率高 | 自定义类参数自动生成,密封性强,安全性高,调用效率高。 | +| **缺点** | 调用效率较低,自定义类参数须自行构建,实现须IL支持,对调用平台有要求,例如:IOS不允许动态类生成,则不可使用。 | 项目代码管理难统一,强迫症猝死 | 服务一旦有破坏性升级,则必须重新替换dll,灵活性几乎为0。 | + + +### 1.2 为什么不直接支持接口代理调用? + +【原因一】 +支持out和ref参数,在使用代理时,效率不高。 + +【原因二】 +需要在参数支持调用上下文,所以无法直接用接口调用。 + +【原因三】 +支持单次调用的调用配置(例如超时时间,取消调用,序列化方式等) + +【原因四】 +引用问题,当在服务接口中,使用了其他的项目的数据结构的话,在接口调用项目上也需要引用该项目。太麻烦。 + + +### 1.3 TouchRpc源文件代理相比接口代理,有什么优缺点? + +源文件代理相比接口代理,几乎没什么缺点。有人会觉得接口代理更整洁、方便?实际上源文件代理只会更整洁、方便。 + +假设一个场景,你需要开发服务器和客户端,这时,你需要做: + +1. 先单独定义一个接口项目 +2. 再定义一个实现项目 +3. 编译接口项目 +4. 引用到客户端 + +上述步骤中,还不包括,接口项目和实现项目需要引入其他引用的情况,也不包括,接口中包含了其他项目的自定义数据结构。如果包含了的话,客户端还需要引入其他项目。 + +而且,还需要考虑接口项目的编译目标平台和其他编译参数。最难受的是,如果这些工作,是你和同事合作的话,那可能就是出个bug,同事传你一个dll v1.0版本,再有问题,v1.1修复版,等等。 + +而最要命的,当属程序集数据泄露。设想一下,如果某个同事在写数据库操作的项目时,把连接信息直接放在了代码里(或某个逻辑),本身如果这个项目只在服务器应用,也没有关系,但是因为你懒,你在接口中使用了该项目的一个数据结构,这就使得你不得不把这个项目一同交给调用方的同事,但你对这些毫无察觉。嗷嚎,黑用户一反编译,直接帮你把数据整理了。 + +但是如果用生成的源代码,那上述的可怕问题根本不用考虑。其次,会更整洁,更方便。 + +假设相同场景,你需要开发服务器和客户端,这时,你需要做: + +1. 先定义一个服务项目(可以写接口,也能写逻辑,当然也可以分成两个项目) +2. 编译项目,然后导出代理源代码。 +3. 引用到客户端 + +- 不需要考虑数据结构引用问题,因为代理会转写。 +- 不需要考虑编译参数问题,因为客户端拿到的也是源码。 +- 不需要再让同事一次次发你dll,只需要,他启动服务,你更新引用就ok。 +- 不需要怕程序集数据泄露,因为一切都是转写的,而且只转写应用的、公共的部分。 + + +## 二、从服务端获取代理 + +### 2.1 生成代理 + +在开发过程中,如果服务器和客户端,都是我们自己开发的话(在同一个电脑),就可以使用本地代理生成。 + +调用下列代码,会将已注册的所有服务,导出代理为字符串。 + +RpcStore是**实例**,或者是IRpcParser的**属性**。 + +```csharp +string code=RpcStore.GetProxyCodes("MyNameSpace")); +``` + +【示例1】 +将代理字符串,写成.cs文件,然后通过链接的形式,将代码添加到客户端项目。 + +服务器代码,在服务器执行后,会在运行路径下,生成一个**WhisperServers.cs**的文件。 + +```csharp +var service = new TcpTouchRpcService(); +var config = new TouchSocketConfig()//配置 + .SetListenIPHosts(new IPHost[] { new IPHost(port) }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }) + .ConfigureRpcStore(a => + { + a.RegisterServer();//注册服务 + +#if DEBUG + File.WriteAllText("../../../WhisperServers.cs", a.GetProxyCodes("WhisperServers",new Type[] { typeof(TouchRpcAttribute) })); +#endif + }) + .SetVerifyToken("TouchRpc"); + + service.Setup(config) + .Start(); +``` + +然后打开需要引入的客户端解决方案。选择需要添加代理的项目,依次执行: + +**右击项目=》添加=》现有项** + +**然后选择服务器生成的.cs文件,选择“添加”的下拉框,选择“添加为连接”。** + + +最后确认文件被正确添加为链接。 + + +**这样,每次当服务有更新的时候,只需要启动一下服务器,代理就会自动刷新。** + +实际上在RpcStore完成**服务注册**、**解析器添加**以后,调用`GetProxyInfo`,输入代理类型、即可获得代理信息,然后再通过CodeGenerator.ConvertToCode方法,转换为可以**直接编译**的代码。 +此时,你可以复制、或者直接把代理代码写成`源代码`(cs文件)。 +然后你可以把这个代码引入到**客户端**。 + +```csharp +//或者直接本地导出代理文件。 +ServerCellCode[] codes = rpcStore.GetProxyInfo(RpcStore.ProxyAttributeMap.Values.ToArray()); +string codeString = CodeGenerator.ConvertToCode("RRQMProxy", codes); +``` + +亦或者,为防止篡改生成的代码,不想把代理代码直接投入使用,那可以考虑将代码单独编译成dll,然后将编译的程序集加载到客户端。 + +:::tip 提示 + +上述行为,均是导出所有已注册的服务,当需要在同一个服务端,生成多个不同代理的源码时,可通过CodeGenerator静态类的相关方法直接生成。例如: + +```csharp {1} +string codes=CodeGenerator.GetProxyCodes("Namespace",new Type[]{typeof(RpcServer) },new Type[] { typeof(TouchRpcAttribute)}); +``` + + +::: + + +### 2.2 代理类型添加 + +> 通过之前的学习,大家可能大概明白了,在RRQMRPC中,客户端与服务器在进行交互时,所需的数据结构不要求是同一类型,仅是[数据类型结构相同](https://gitee.com/RRQM_OS/RRQM/wikis/RRQM%E4%B8%93%E4%B8%9A%E5%90%8D%E7%A7%B0%E8%A7%A3%E9%87%8A?sort_id=4872799)即可。所以在声明了服务以后,服务中所包含的自定义类型,会被复刻成结构相同的类型,但是这也仅仅局限于参数与服务`相同程序集`的时候。如果服务中引入了其他程序集的数据结构,则不会复刻。所以在客户端调用时,需要引入同一程序集。 + +但是,往往在服务中,会引入其他程序集,例如,我们习惯在项目中建立一个Models程序集,用于存放所有的实体模型,那是不是意味着客户端也必须引入这个程序集才能调用呢?没别的方法了?? +***有,且不只有一种*** + +### 2.2.1 添加代理类型 + +在服务注册之前,任意时刻,可调用CodeGenerator.AddProxyType静态方法,添加代理类型,同时可传入一个bool值,表明是否深度搜索,比如,假如RpcArgsClassLib.ProxyClass1中还有其他类型,则参数为True时,依然会代理。 + +```csharp +RPCService rpcService = new RPCService(); +CodeGenerator.AddProxyType(); +CodeGenerator.AddProxyType(deepSearch:true); +``` + + + +### 2.2.2 标记自定义类 + +在需要代理的类上面声明RpcProxy标签,然后也可以重新指定代理类名。 + +```csharp +[RpcProxy("MyArgs")] +public class Args +{ +} +``` + +## 三、客户端源代码生成代理 企业版 + +前一种方式已经算是几近完美的代理生成方案,但是有时候,当大家协作时,喜欢全部自己敲写。 + +例如: + +对于下列服务,有时候就是喜欢自己写个接口,然后直接调用。 + +```csharp +public class MyRpcServer : RpcServer +{ + [TouchRpc] + public bool Login(string account, string password) + { + if (account == "123" && password == "abc") + { + return true; + } + + return false; + } +} +``` + +```csharp +public interface IMyRpcServer +{ + public bool Login(string account, string password); +} +``` + +以往来说,实现这种方式的绝大多数,大概是使用IL动态构建一个类,然后动态实现接口代理,伪代码如下: + +```csharp +IMyRpcServer myRpcServer=ProxyGenerator.CreateProxy(); +``` + +但是现在,时代变了,我们有了源代码生成,那么事情将变得无比简单。 + +同样,我们需要设置接口,如下: + +```csharp +/// +/// GeneratorRpcProxy的标识,表明这个接口应该被生成其他源代码。 +/// ConsoleApp2.MyRpcServer参数是整个rpc调用的前缀,即:除方法名的所有,包括服务的类名。 +/// +[GeneratorRpcProxy("ConsoleApp2.MyRpcServer")] +interface IMyRpcServer +{ + [Description("这是登录方法")]//该作用是生成注释 + [GeneratorRpcMethod]//表面该方法应该被代理,也可以通过参数,直接设置调用键 + public bool Login(string account, string password); +} +``` + +这时候,神奇的一幕发生了,凡是实现IRpcClient的接口的实例,都增加了扩展方法。而这功能,和服务器生成的扩展Rpc方法的功能是一致的。 + +![](../static/img/docs/generateproxy-1.png) + + +:::tip 提示 + +大家可能会疑问,源代码生成代理,和服务端生成代理,有什么区别?或者说有什么优点? +实际上没有区别,也没有优点。之所以设计这个,是因为之前有人提过需求,想要完全分离前、后端。即:后端写好服务后,前端自由定义服务接口,和调用参数,仅此而已。 + +所以,生成代理的方式,按照大家的习惯需求选择就可以。 + +::: + +[源代码生成代理示例代码](https://gitee.com/RRQM_Home/TouchSocket/tree/master/examples/TouchRpc%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B/%E6%BA%90%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E4%BB%A3%E7%90%86/GeneratorRpcProxyConsoleApp) diff --git a/handbook/docs/heartbeat.mdx b/handbook/docs/heartbeat.mdx new file mode 100644 index 000000000..37c38c1ff --- /dev/null +++ b/handbook/docs/heartbeat.mdx @@ -0,0 +1,289 @@ +--- +id: heartbeat +title: 心跳设计 +--- + +## 一、说明 + +### 1.1 为什么要设置心跳? + +心跳机制一般是**客户端**向**服务器**定时发送一个特定的数据包,让服务器知道自己还在线,以确保连接的有效性的机制。 网络中的接收和发送数据都是使用操作系统中的 SOCKET 进行实现。 但是如果此 套接字 已经断开,那发送数据和接收数据的时候就一定会有问题。 可是如何判断这个套接字是否还可以使用呢? 这个就需要在系统中创建心跳机制。 + +其实TCP中已经为我们实现了一个[内置心跳机制(SetKeepAliveValue)](./createtcpclient.mdx#setkeepalivevalue)。但是该机制受限于操作系统,而且很容易误报。所以很少被大家使用。 + +大家使用最多的,就是自己设计数据包,然后预留心跳格式,当对方收到心跳包时,直接返回响应包即可。 + +那么,按这个思路,让我们使用优雅的实现吧。 + +## 二、设计数据格式 + +使用心跳之前,必须要明确数据格式,绝对不能混淆业务数据。一般在适配Plc等现成模块时,他们是有固定的数据格式,这时候你可以参阅[数据处理适配器](./adapterdemodescription.mdx),快速的解析数据。 + +但是在本文中,并没有规定的格式,所以我们需要先设计一种简单高效的数据格式。 + +如下: + +| **数据长度** | **数据类型** | **载荷数据** | +| --- | --- | --- | +| 2字节(Ushort) | 1字节(Byte) | n字节(<65535) | + +### 2.1 解析数据格式 + +下列代码主要实现对上述数据格式的解析 + +```csharp +internal class MyFixedHeaderDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter +{ + public override int HeaderLength => 3; + + public override bool CanSendRequestInfo => false; + + protected override MyRequestInfo GetInstance() + { + return new MyRequestInfo(); + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } +} + +internal class MyRequestInfo : IFixedHeaderRequestInfo +{ + public DataType DataType { get; set; } + public byte[] Data { get; set; } + + public int BodyLength { get; private set; } + + public bool OnParsingBody(byte[] body) + { + if (body.Length == this.BodyLength) + { + this.Data = body; + return true; + } + return false; + } + + public bool OnParsingHeader(byte[] header) + { + if (header.Length == 3) + { + this.BodyLength = TouchSocketBitConverter.Default.ToUInt16(header, 0) - 1; + this.DataType = (DataType)header[2]; + return true; + } + return false; + } + + public void Package(ByteBlock byteBlock) + { + byteBlock.Write((ushort)((this.Data == null ? 0 : this.Data.Length) + 1)); + byteBlock.Write((byte)this.DataType); + if (Data != null) + { + byteBlock.Write(Data); + } + } + + public byte[] PackageAsBytes() + { + using ByteBlock byteBlock = new ByteBlock(); + this.Package(byteBlock); + return byteBlock.ToArray(); + } + + public override string ToString() + { + return $"数据类型={this.DataType},数据={(this.Data == null ? "null" : Encoding.UTF8.GetString(this.Data))}"; + } +} + +internal enum DataType : byte +{ + Ping, + Pong, + Data +} +``` + +## 三、创建扩展类 + +下列代码可选,主要实现对Client增加Ping的扩展方法。方便调用。 + +```csharp +/// +/// 一个心跳计数器扩展。 +/// +internal static class DependencyExtensions +{ + public static readonly DependencyProperty HeartbeatTimerProperty = + DependencyProperty.Register("HeartbeatTimer", typeof(DependencyExtensions), null); + + public static bool Ping(this TClient client) where TClient : ITcpClientBase + { + try + { + client.Send(new MyRequestInfo() { DataType = DataType.Ping }.PackageAsBytes()); + return true; + } + catch (Exception ex) + { + client.Logger.Exception(ex); + } + + return false; + } + + public static bool Pong(this TClient client) where TClient : ITcpClientBase + { + try + { + client.Send(new MyRequestInfo() { DataType = DataType.Pong }.PackageAsBytes()); + return true; + } + catch (Exception ex) + { + client.Logger.Exception(ex); + } + + return false; + } +} +``` + +## 四、创建心跳插件类 + +下列代码主要实现心跳插件的功能。默认每五秒自动触发一次。且接收方收到Ping后,直接会回复Pong。 + +```csharp +internal class HeartbeatAndReceivePlugin : TcpPluginBase +{ + private readonly int m_timeTick; + private readonly ILog logger; + + [DependencyInject(1000 * 5)] + public HeartbeatAndReceivePlugin(int timeTick, ILog logger) + { + this.m_timeTick = timeTick; + this.logger = logger; + } + + protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e) + { + if (client is ISocketClient) + { + return;//此处可判断,如果为服务器,则不用使用心跳。 + } + + if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer) + { + timer.Dispose(); + } + + client.SetValue(DependencyExtensions.HeartbeatTimerProperty, new Timer((o) => + { + client.Ping(); + }, null, 0, m_timeTick)); + + base.OnConnected(client, e); + } + + protected override void OnDisconnected(ITcpClientBase client, ClientDisconnectedEventArgs e) + { + base.OnDisconnected(client, e); + if (client.GetValue(DependencyExtensions.HeartbeatTimerProperty) is Timer timer) + { + timer.Dispose(); + client.SetValue(DependencyExtensions.HeartbeatTimerProperty, null); + } + } + + protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + if (e.RequestInfo is MyRequestInfo myRequest) + { + this.logger.Info(myRequest.ToString()); + if (myRequest.DataType == DataType.Ping) + { + client.Pong(); + } + } + base.OnReceivedData(client, e); + } +} +``` + +## 五、测试、启动 + +```csharp +/// +/// 示例心跳。 +/// 博客地址 +/// +/// +private static void Main(string[] args) +{ + ConsoleAction consoleAction = new ConsoleAction(); + + //服务器 + TcpService service = new TcpService(); + service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .UsePlugin() + .SetDataHandlingAdapter(()=>new MyFixedHeaderDataHandlingAdapter()) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + })) + .Start();//启动 + service.Logger.Info("服务器成功启动"); + + //客户端 + TcpClient tcpClient = new TcpClient(); + tcpClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost(new IPHost("127.0.0.1:7789")) + .UsePlugin() + .SetDataHandlingAdapter(() => new MyFixedHeaderDataHandlingAdapter()) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + })); + tcpClient.Connect(); + tcpClient.Logger.Info("客户端成功连接"); + + consoleAction.OnException += ConsoleAction_OnException; + consoleAction.Add("1", "发送心跳", () => + { + tcpClient.Ping(); + }); + consoleAction.Add("2", "发送数据", () => + { + tcpClient.Send(new MyRequestInfo() + { + DataType = DataType.Data, + Data = Encoding.UTF8.GetBytes(Console.ReadLine()) + } + .PackageAsBytes()); + }); + consoleAction.ShowAll(); + while (true) + { + consoleAction.Run(Console.ReadLine()); + } +} + +private static void ConsoleAction_OnException(Exception obj) +{ + Console.WriteLine(obj); +} +``` diff --git a/handbook/docs/httpfiletransfer.mdx b/handbook/docs/httpfiletransfer.mdx new file mode 100644 index 000000000..0b165766b --- /dev/null +++ b/handbook/docs/httpfiletransfer.mdx @@ -0,0 +1,78 @@ +--- +id: httpfiletransfer +title: 文件传输 +--- + +## 一、说明 + +该Http服务器及客户端,仅仅是轻量级的Http工具,不具备广泛的兼容性,所以请慎重使用。 + + +## 二、服务器响应文件 + +该操作支持大型文件,也支持断点续传、支持迅雷加速等。 + +```csharp +internal class MyHttpPlug : HttpPluginBase +{ + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (e.Context.Request.UrlEquals("/file")) + { + e.Context.Response + .SetStatus()//必须要有状态 + .FromFile(@"D:\System\Windows.iso", e.Context.Request);//直接回应文件。 + } + base.OnGet(client, e); + } +} + +``` + +## 三、服务器接收上传文件 + +该操作目前仅支持小文件上传,实测100Mb没问题。 + +```csharp +internal class MyHttpPlug : HttpPluginBase +{ + protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + if (e.Context.Request.UrlEquals("/uploadfile")) + { + try + { + if (e.Context.Request.ContentLen>1024*1024*100)//全部数据体超过100Mb则直接拒绝接收。 + { + e.Context.Response + .SetStatus("403", "数据过大") + .Answer(); + return; + } + //此操作会先接收全部数据,然后再分割数据。 + //所以上传文件不宜过大,不然会内存溢出。 + var multifileCollection = e.Context.Request.GetMultifileCollection(); + + foreach (var item in multifileCollection) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"文件名={item.FileName}\t"); + stringBuilder.Append($"数据长度={item.Length}"); + client.Logger.Info(stringBuilder.ToString()); + } + + e.Context.Response + .SetStatus() + .FromText("Ok") + .Answer(); + } + catch (Exception ex) + { + client.Logger.Exception(ex); + } + } + base.OnPost(client, e); + } +} + +``` diff --git a/handbook/docs/httpstaticpageplugin.mdx b/handbook/docs/httpstaticpageplugin.mdx new file mode 100644 index 000000000..4c0991fb0 --- /dev/null +++ b/handbook/docs/httpstaticpageplugin.mdx @@ -0,0 +1,24 @@ +--- +id: httpstaticpageplugin +title: 静态页面插件 +--- + +## 静态网页托管插件仅服务器支持 + +**HttpStaticPagePlugin**静态网页托管插件,是用于Http的内容响应。 + +```csharp +var service = new HttpService(); + +var config = new TouchSocketConfig(); +config.UsePlugin() + .SetReceiveType(ReceiveType.Auto) + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigurePlugins(a => + { + a.Add().AddFolder("../../../../../api");//添加静态页面文件夹 + }); + +service.Setup(config).Start(); +Console.WriteLine("Http服务器已启动"); +``` diff --git a/handbook/docs/ilog.mdx b/handbook/docs/ilog.mdx new file mode 100644 index 000000000..144727081 --- /dev/null +++ b/handbook/docs/ilog.mdx @@ -0,0 +1,48 @@ +--- +id: ilog +title: 日志记录器 +--- + +## 一、日志记录接口(ILog) +继承ILog接口,然后实现以下方法。即可实现内部的日志记录。 +当用户自行输出日志时,可自行实现过程。 +```csharp +class MyLogger : ILog +{ + public LogType LogType { get; set; } = LogType.Debug | LogType.Error; + + public void Log(LogType logType, object source, string message, Exception exception) + { + //此处就是日志实际输出的位置。 + } +} +``` +:::caution 注意 + +**LogType** 表示当前日志的可输出类型,并非输出级别,所以当需要输出多种类型时,请进行位域操作。 + +::: + + +## 二、控制台日志记录器(ConsoleLogger) +在使用控制台日志记录器时,会按照以下格式输出。 +![image.png](../static/img/docs/ilog-1.png) + +## 三、文件日志记录器(FileLogger) +在使用文件日志记录器时,先会在指定目录下创建“logs”目录,然后按日期生成“.log”文件。 +![image.png](../static/img/docs/ilog-2.png) + +## 四、日志组记录器(LoggerGroup) +使用日志组记录器时,可以同时记录多个日志,例如:下列示例就同时在控制台和文件记录日志。 +```csharp +LoggerGroup logger = new LoggerGroup(new ConsoleLogger(),new FileLogger()); +``` + +## 五、日志扩展 +引入命名空间。可快捷记录日志。 +```csharp +LoggerGroup logger = new LoggerGroup(new ConsoleLogger(),new FileLogger()); +logger.Info("Message"); +logger.Warning("Warning"); +logger.Error("Error"); +``` diff --git a/handbook/docs/independentusedatahandlingadapter.mdx b/handbook/docs/independentusedatahandlingadapter.mdx new file mode 100644 index 000000000..4076f8af2 --- /dev/null +++ b/handbook/docs/independentusedatahandlingadapter.mdx @@ -0,0 +1,59 @@ +--- +id: independentusedatahandlingadapter +title: 独立使用适配器 +--- + +## 一、说明 + +适配器的机制,是非常好的解封包机制,那这么好的机制,我们在设计的时候,也想到了单独使用适配器的情况。例如: + +1. 对于串口通信,可以使用适配器解包。 +2. 有时候可能大家只想用原生`Socket`实现。那么也可以使用适配器解包,或者封包。 + +## 二、使用 + +```csharp +FixedHeaderPackageAdapter adapter = new FixedHeaderPackageAdapter(); + +bool sendCallBack = false; +bool receivedCallBack = false; + +byte[] sentData = null; +adapter.SendCallBack = (buffer, offset, length) => +{ + //此处会回调发送的最终调用。例如:此处使用固定包头,则发送的数据为4+n的封装。 + sentData = new byte[length]; + Array.Copy(buffer, offset, sentData, 0, length); + if (length == 4 + 4) + { + sendCallBack = true; + } +}; + +adapter.ReceivedCallBack += (byteBlock, requestInfo) => +{ + //此处会回调接收的最终触发,例如:此处使用的固定包头,会解析4+n的数据为n。 + + if (byteBlock.Len == 4) + { + receivedCallBack = true; + } +}; + +byte[] data = Encoding.UTF8.GetBytes("RRQM"); + +adapter.SendInput(data, 0, data.Length);//模拟输入,会在SendCallBack中输出最终要发送的数据。 + +using (ByteBlock block = new ByteBlock()) +{ + block.Write(sentData); + block.Pos = 0; + adapter.ReceivedInput(block);//模拟输出,会在ReceivedCallBack中输出最终收到的实际数据。 +} +``` + +:::tip 提示 + +上述仅仅是以固定包头适配器示例的,实际上对于其他所有的适配器均可以使用。 + +::: \ No newline at end of file diff --git a/handbook/docs/ioc.mdx b/handbook/docs/ioc.mdx new file mode 100644 index 000000000..27a2a996d --- /dev/null +++ b/handbook/docs/ioc.mdx @@ -0,0 +1,449 @@ +--- +id: ioc +title: 依赖注入容器 +--- + +## 一、说明 +所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。通俗来讲,就是把有依赖关系的类放到容器中,然后在我们需要这些类时,容器自动解析出这些类的实例。依赖注入最大的好处时实现类的解耦,利于程序拓展、单元测试、自动化模拟测试等。依赖注入的英文为:Dependency Injection,简称 DI。(说明来自网络) + +TouchSocket内置了**_Container_**容器。只需要引入TouchSocket.Core即可使用。 + +## 二、特点 + +- 支持构造函数、属性、方法三种注入方式,可以选择其中部分生效。 +- 支持 Singleton、Scoped、Transient三种生命周期。 +- 支持单接口,多实现注入。 +- 支持当获取类型是可实例类型时,即使不注册,也能成功构造。 +- 支持默认参数注入。 +- 支持构建参数注入。 +- 支持标签参数注入。 +- 支持泛型注入。 +- 支持Object注入。 + +## 三、注入方式 + +对于一个类,默认情况下,会支持构造函数、属性、方法三种注入方式。但是,当明确知道该类型仅会使用其中部分方式注入时,可以设置注入类型,以此节约性能。 + +```csharp {4} +/// +/// 让MyClass仅支持构造函数和属性注入 +/// +[DependencyType(DependencyType.Constructor | DependencyType.Property)] +class MyClass +{ + +} +``` + +### 3.1 构造函数注入 +其中MyLog1,MyLog2虽然没有注册,但是因为是实例,所以依然可以成功构造。 +```csharp +[Fact] +public void CtorShouldBeOk() +{ + Container container = new Container(); + container.RegisterTransient(); + + var log3 = container.Resolve() as MyLog3; + + Assert.NotNull(log3.MyLog1); + Assert.NotNull(log3.MyLog2); +} +``` +```csharp +public class MyLog3 : ILog +{ + public MyLog3(MyLog1 myLog1, MyLog2 myLog2) + { + this.MyLog1 = myLog1; + this.MyLog2 = myLog2; + } + + public MyLog1 MyLog1 { get; } + public MyLog2 MyLog2 { get; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} +``` +### 3.2 属性注入 +使用**DependencyParamterInject**,或者**DependencyInject**标记属性,即可注入。 + +示例中使用的是单接口多实现,所以使用**DependencyParamterInject**标记。 +```csharp +[Fact] +public void PropertyShouldBeOk() +{ + Container container = new Container(); + container.RegisterTransient("MyLog1"); + container.RegisterTransient("MyLog2"); + container.RegisterTransient("MyLog3"); + container.RegisterTransient(); + + var log5 = container.Resolve() as MyLog5; + + Assert.NotNull(log5.MyLog1); + Assert.NotNull(log5.MyLog2); + Assert.True(log5.MyLog1.GetType() == typeof(MyLog1)); + Assert.True(log5.MyLog2.GetType() == typeof(MyLog2)); +} + +``` +```csharp +public class MyLog5 : ILog +{ + [DependencyParamterInject("MyLog1")] + public ILog MyLog1 { get; set; } + + [DependencyParamterInject("MyLog2")] + public ILog MyLog2 { get; set; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} +``` +### 3.2 方法注入 +使用**DependencyInject**标记属性,即可对方法注入。 + +同时,示例中演示了默认参数设定。在初始化MyLog6后,A=10,B="TouchSocket"。 + +同时,还能嵌套MyLog1和MyLog4的同一接口的不同实现,和实现的默认参数构造。 + +```csharp +[Fact] +public void MethodShouldBeOk() +{ + Container container = new Container(); + container.RegisterTransient("MyLog1"); + container.RegisterTransient("MyLog2"); + container.RegisterTransient("MyLog3"); + container.RegisterTransient("MyLog4"); + container.RegisterTransient("MyLog5"); + container.RegisterTransient(); + + var log6 = container.Resolve() as MyLog6; + + Assert.NotNull(log6.MyLog1); + Assert.NotNull(log6.MyLog4); + Assert.True(log6.MyLog1.GetType() == typeof(MyLog1)); + Assert.True(log6.MyLog4.GetType() == typeof(MyLog4)); + Assert.True(((MyLog4)log6.MyLog4).A == 20); + Assert.True(((MyLog4)log6.MyLog4).B == "IOU"); +} +``` +```csharp +public class MyLog6 : ILog +{ + [DependencyInject(10, "TouchSocket")] + public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4) + { + this.A = a; + this.B = b; + this.MyLog1 = myLog1; + this.MyLog4 = myLog4; + } + + public int A { get; set; } + public string B { get; set; } + public ILog MyLog1 { get; set; } + public ILog MyLog4 { get; set; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} +``` +Object注入 +```csharp +[Fact] +public void ObjectSingletonShouldBeOk() +{ + Container container = new Container(); + container.RegisterSingleton(); + container.RegisterSingleton("10"); + + var log10 = container.Resolve("10") as MyLog10; + Assert.NotNull(log10); + Assert.NotNull(log10.MyLog1); + Assert.True(log10.MyLog1.GetType() == typeof(MyLog1)); +} +``` +```csharp +public class MyLog10 : ILog +{ + [DependencyParamterInject(typeof(ILog))] + public object MyLog1 { get; set; } + + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} +``` + +## 四、生命周期 +生命周期是对注入构造的实例的有效性而言的。TouchSocket支持三种生命周期。 + +- Singleton:单例注入,当注入,并且实例化以后,全局唯一实例。 +- Transient:瞬时注入,每次获取的实例都是新实例。 +- Scoped:区域单例注入,当在一个IScopedContainer时,实例唯一。 + +对于前两种,熟悉IOC的同学,相信都知道到。那接下来就演示一下Scoped。 + +实际上使用Scoped时,得先明确区域,也就是创建一个IScopedContainer的区域容器(类似Aps.net的IServiceProvider)。然后后续实例从IScopedContainer获得即可。 +```csharp +[Fact] +public void ScopedShouldBeOk() +{ + Container container = new Container(); + container.RegisterScoped(); + + var log1 = container.Resolve(); + var log2 = container.Resolve(); + Assert.NotNull(log1); + Assert.False(log1 == log2); + + IScopedContainer scopedContainer = container.Resolve(); + log1 = scopedContainer.Resolve(); + log2 = scopedContainer.Resolve(); + Assert.NotNull(log1); + Assert.True(log1 == log2); +} +``` + +## 所有模型定义 +```csharp +public interface IGeneric +{ +} + +public class Generic : IGeneric +{ + +} + + + +public class MyLog1 : ILog +{ + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} +public class MyLog2 : ILog +{ + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} + +public class MyLog3 : ILog +{ + public MyLog3(MyLog1 myLog1, MyLog2 myLog2) + { + this.MyLog1 = myLog1; + this.MyLog2 = myLog2; + } + + public MyLog1 MyLog1 { get; } + public MyLog2 MyLog2 { get; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} + +public class MyLog4 : ILog +{ + [DependencyInject(10, "TouchSocket")] + public MyLog4(int a, string b, MyLog1 myLog1, MyLog2 myLog2) + { + this.A = a; + this.B = b; + this.MyLog1 = myLog1; + this.MyLog2 = myLog2; + } + + public int A { get; } + public string B { get; } + public MyLog1 MyLog1 { get; } + public MyLog2 MyLog2 { get; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} + +public class MyLog5 : ILog +{ + [DependencyParamterInject("MyLog1")] + public ILog MyLog1 { get; set; } + + [DependencyParamterInject("MyLog2")] + public ILog MyLog2 { get; set; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} + +public class MyLog6 : ILog +{ + [DependencyInject(10, "TouchSocket")] + public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4) + { + this.A = a; + this.B = b; + this.MyLog1 = myLog1; + this.MyLog4 = myLog4; + } + + public int A { get; set; } + public string B { get; set; } + public ILog MyLog1 { get; set; } + public ILog MyLog4 { get; set; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} + +public class MyLog7 : ILog +{ + public MyLog7(IGeneric generic) + { + this.Generic = generic; + } + + public IGeneric Generic { get; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} + +[DependencyType(DependencyType.Constructor)] +public class MyLog8 : ILog +{ + [DependencyInject(10, "RRQM")] + public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4) + { + this.A = a; + this.B = b; + this.MyLog1 = myLog1; + this.MyLog4 = myLog4; + } + + public int A { get; set; } + public string B { get; set; } + public ILog MyLog1 { get; set; } + public ILog MyLog4 { get; set; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} + +[DependencyType(DependencyType.Constructor | DependencyType.Method)] +public class MyLog9 : ILog +{ + [DependencyInject(10, "RRQM")] + public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4) + { + this.A = a; + this.B = b; + this.MyLog1 = myLog1; + this.MyLog4 = myLog4; + } + + public int A { get; set; } + public string B { get; set; } + public ILog MyLog1 { get; set; } + public ILog MyLog4 { get; set; } + + public void Debug(LogType logType, object source, string message, Exception exception) + { + + } + + public void Debug(LogType logType, object source, string message) + { + + } +} +``` + diff --git a/handbook/docs/ipackage.mdx b/handbook/docs/ipackage.mdx new file mode 100644 index 000000000..a220c453c --- /dev/null +++ b/handbook/docs/ipackage.mdx @@ -0,0 +1,151 @@ +--- +id: ipackage +title: 包序列化模式 +--- + +## 一、说明 +包序列化模式是为了解决**极限序列化**的问题。常规序列化的瓶颈,主要是反射、表达式树、创建对象等几个方面,这几个问题在运行时阶段,都没有一个好的解决方案。目前在net6以后,微软大力支持源代码生成,这使得这类问题得到了很大程度的解决。但是对于老项目,或者无法使用net6和vs2022以上的项目,是无法使用的。所以,这时候包序列化模式就显得非常需要了。 + +## 二、特点 +【优点】 + +1. 简单、可靠、高效 +2. 可以支持所有类型(需要自己编写代码) +3. 数据量最少(从理论来说这是占数据量最轻量的设计) + +【缺点】 + +1. 要求序列化端和反序列化端必须保持一致,可以存在数据差异,但是不能出现数据断层。 + +## 三、使用 +【实体类】 +```csharp +class MyClass : IPackage +{ + public int P1 { get; set; } + public string P2 { get; set; } + public char P3 { get; set; } + public double P4 { get; set; } + public List P5 { get; set; } + public Dictionary P6 { get; set; } + public void Package(ByteBlock byteBlock) + { + //基础类型直接写入。 + byteBlock.Write(P1); + byteBlock.Write(P2); + byteBlock.Write(P3); + byteBlock.Write(P4); + + //集合类型,可以先判断是否为null + byteBlock.WriteIsNull(P5); + if (P5 != null) + { + //如果不为null + //就先写入集合长度 + //然后遍历将每个项写入 + byteBlock.Write(P5.Count); + foreach (var item in P5) + { + byteBlock.Write(item); + } + } + + //字典类型,可以先判断是否为null + byteBlock.WriteIsNull(P6); + if (P6 != null) + { + //如果不为null + //就先写入字典长度 + //然后遍历将每个项,按键、值写入 + byteBlock.Write(P6.Count); + foreach (var item in P6) + { + byteBlock.Write(item.Key); + byteBlock.WritePackage(item.Value);//因为值MyClassModel实现了IPackage,所以可以直接写入 + } + } + } + + public void Unpackage(ByteBlock byteBlock) + { + //基础类型按序读取。 + this.P1 = byteBlock.ReadInt32(); + this.P2 = byteBlock.ReadString(); + this.P3 = byteBlock.ReadChar(); + this.P4 = byteBlock.ReadDouble(); + + var isNull = byteBlock.ReadIsNull(); + if (!isNull) + { + int count = byteBlock.ReadInt32(); + var list = new List(count); + for (int i = 0; i < count; i++) + { + list.Add(byteBlock.ReadInt32()); + } + this.P5 = list; + } + + + isNull = byteBlock.ReadIsNull();//复用前面的变量,省的重新声明 + if (!isNull) + { + int count = byteBlock.ReadInt32(); + var dic = new Dictionary(count); + for (int i = 0; i < count; i++) + { + dic.Add(byteBlock.ReadInt32(), byteBlock.ReadPackage()); + } + this.P6 = dic; + } + } +} + +class MyClassModel : PackageBase +{ + public DateTime P1 { get; set; } + public override void Package(ByteBlock byteBlock) + { + byteBlock.Write(P1); + } + + public override void Unpackage(ByteBlock byteBlock) + { + this.P1 = byteBlock.ReadDateTime(); + } +} +``` +【打包和解包】 +```csharp +var myClass = new MyClass(); +myClass.P1 = 1; +myClass.P2 = "若汝棋茗"; +myClass.P3 = 'a'; +myClass.P4= 3; + +myClass.P5=new List { 1, 2, 3 }; + +myClass.P6= new Dictionary() +{ + { 1,new MyClassModel(){ P1=DateTime.Now} }, + { 2,new MyClassModel(){ P1=DateTime.Now} } +}; + +using (ByteBlock byteBlock=new ByteBlock()) +{ + myClass.Package(byteBlock);//打包,相当于序列化 + + byteBlock.Seek(0);//将流位置重置为0 + + var myNewClass = new MyClass(); + myNewClass.Unpackage(byteBlock);//解包,相当于反序列化 +} +``` + +## 四、性能评测 + +基准测试表明: + +包序列化模式和使用源代码生成方式工作的MemoryPack几乎一样。比json方式快了10倍多,比微软的json快了近4倍。 + +![](../static/img/docs/ipackage-1.png) diff --git a/handbook/docs/jsonrpcdescription.mdx b/handbook/docs/jsonrpcdescription.mdx new file mode 100644 index 000000000..e307e24a4 --- /dev/null +++ b/handbook/docs/jsonrpcdescription.mdx @@ -0,0 +1,20 @@ +--- +id: jsonrpcdescription +title: 产品及架构介绍 +--- + +## 一、说明 + +JsonRpc是**通用**的RPC规范,与**编程语言无关、操作系统无关**。详细说明请参阅[JsonRpc 2.0 官方文档](https://www.jsonrpc.org/specification),在TouchSocket中封装了**前后端**,使其使用更加方便、高效。 + +目前支持Tcp、Http、Websocket三种协议调用。 + + + +## 二、特点: + +- **异常反馈** 。 +- 插件支持。 +- 支持自定义类型。 +- 支持类型嵌套。 +- 支持js、Android等调用。 diff --git a/handbook/docs/jsonrpcservice.mdx b/handbook/docs/jsonrpcservice.mdx new file mode 100644 index 000000000..4a1d35e74 --- /dev/null +++ b/handbook/docs/jsonrpcservice.mdx @@ -0,0 +1,131 @@ +--- +id: jsonrpcservice +title: 定义、发布、启动服务 +--- + +## 一、定义服务 + +在**服务器**端中新建一个类,继承于**RpcServer**类(或实现IRpcServer),然后在该类中写**公共方法**,并用**JsonRpc**属性标签标记,如果方法有**重载**,需要重新指定**函数键**。 + +- 支持代理生成**注释**。 + +```csharp +public class JsonRpcServer : RpcServer +{ + [JsonRpc] + public string TestJsonRpc(string str) + { + return "TouchSocket" + str; + } + + /// + /// 当标记为true时直接使用方法名称 + /// + /// + /// + [JsonRpc(true)] + public string TestJsonRpc1(string str) + { + return "TouchSocket" + str; + } + + /// + /// 使用调用上下文。 + /// 可以从上下文获取调用的SocketClient。从而获得IP和Port等相关信息。 + /// + /// + /// + /// + [JsonRpc(MethodFlags = MethodFlags.IncludeCallContext)] + public string TestGetContext(ICallContext callContext, string str) + { + if (callContext.Caller is HttpSocketClient) + { + Console.WriteLine("HTTP请求"); + var client = callContext.Caller as HttpSocketClient; + var ip = client.IP; + var port = client.Port; + Console.WriteLine($"HTTP请求{ip}:{port}"); + + } + + if (callContext.Caller is SocketClient) + { + Console.WriteLine("Tcp请求"); + var client = callContext.Caller as SocketClient; + var ip = client.IP; + var port = client.Port; + + client.Send(Encoding.UTF8.GetBytes("Hello Word")); + Console.WriteLine($"Tcp请求{ip}:{port}"); + + } + return "TouchSocket" + str; + } + + [JsonRpc] + public JObject TestJObject(JObject obj) + { + return obj; + } +} +``` + + + +## 二、使用Tcp创建服务解析器 + +服务解析器是实际的服务接收、触发、调用、反馈的实际载体,通俗来说就是**通信服务器**。 + +当**JsonRpcParserPlugin**插件添加在**TcpService**服务器时,会使用**TCP**协议。此时的调用,会根据适配器类型,决定是否需要有调用结束标识,一般以\r\n结尾。 + +```csharp +TcpService service = new TcpService(); +service.Setup(new TouchSocketConfig() + .UsePlugin() + .ConfigureRpcStore(a => + { + a.RegisterServer();//配置RpcStore必须在最前面。 + }) + .ConfigurePlugins(a => + { + a.Add();//tcp中路由路径无效 + }) + .SetDataHandlingAdapter(() => + { + return new NormalDataHandlingAdapter(); + //return new TerminatorPackageAdapter("\r\n");使用该适配器时,调用方必须在最后追加相应的结束调用符。 + }) + .SetListenIPHosts(new IPHost[] { new IPHost(7705) })) + .Start(); +``` + + + +## 三、使用Http或Websocket创建服务解析器 + +当**JsonRpcParserPlugin**插件添加在**HttpService**服务器时,会使用**Http、Websocket**协议。 + +创建后,如果想使用Http调用,只需要以Post方式,将调用Json字符串路由到设定路由地址即可(下文示例“/jsonRpc”)。 +如果想使用Websocket调用,只需要以**文本**形式,传递到服务器即可。服务器会判定:如果内容中包含“jsonrpc”则认定为调用,会做调用处理。 + +```csharp +HttpService service = new HttpService(); + +service.Setup(new TouchSocketConfig() + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost(7706) }) + .ConfigureRpcStore(a =>//Rpc的配置必须在插件之前。 + { + a.RegisterServer(); + }) + .ConfigurePlugins(a => + { + a.Add() + .SetWSUrl("/ws");//启用websocket,使用/ws路由连接。 + + a.Add() + .SetJsonRpcUrl("/jsonRpc"); + })) + .Start(); +``` diff --git a/handbook/docs/jsonserialize.mdx b/handbook/docs/jsonserialize.mdx new file mode 100644 index 000000000..1ae4c7101 --- /dev/null +++ b/handbook/docs/jsonserialize.mdx @@ -0,0 +1,154 @@ +--- +id: jsonserialize +title: Json序列化 +--- + +## 一、说明 +在TouchSocket中,内置了Json序列化与反序列化。 +```csharp +string jsonstr=SerializeConvert.ToJson(new object());//序列化 +object obj=SerializeConvert.FromJson(jsonstr);//反序列化 +``` + +## 二、动态调整的Json策略 +默认情况下: +在net45和netstandard2.0平台时,序列化方式是由[JsonFast(群友老江)](https://gitee.com/majorworld/jsonfast)提供的单文件json序列化。该json工具能够序列化大多数数据结构,且性能和Newtonsoft.Json不相上下(见下测试)。 +在netcoreapp3.1及以上平台时,序列化方式使用System.Text.Json。 + +但是 +当应用中加载了Newtonsoft.Json的程序集后,所有的平台的序列化,均会使用Newtonsoft.Json。可通过`**SerializeConvert.NewtonsoftJsonIsSupported**`静态属性获取当前是否支持Newtonsoft.Json。 + +也可以手动加载Newtonsoft.Json(一般在**Unity3d**中需要手动加载)。 +```csharp +bool IsSupported=SerializeConvert.LoadNewtonsoftJson(typeof(JsonConvert));//返回值指示是否成功加载 +``` + +当加载了Newtonsoft.Json的程序集,但是不想使用该工具序列化时,可将`**SerializeConvert.NewtonsoftJsonFirst**`静态属性设为false。 + + +## 三、JsonFast性能 + +【简单数据对象】 +```csharp +public class SimpleObject +{ + public int Age { get; set; } + public string Name { get; set; } +} +``` +```csharp +[Benchmark] +public void JsonFast_SimpleObject() +{ + var v = new SimpleObject { Age = 40, Name = "John" }; + for (int i = 0; i < Count; i++) + { + var str = JsonFastConverter.JsonTo(v); + var val = JsonFastConverter.JsonFrom(str); + } +} +``` +下图为1w次的序列化与反序列化。JsonFast的效率甚至还稍高一些。 +![image.png](../static/img/docs/jsonserialize-1.png) + +【复杂对象】 +```csharp +public class ComplexObject +{ + public Dictionary Dic1 { get; set; } + public Dictionary Dic2 { get; set; } + public Dictionary Dic3 { get; set; } + public Dictionary Dic4 { get; set; } + public List List1 { get; set; } + public List List2 { get; set; } + public List List3 { get; set; } + public int P1 { get; set; } + public string P2 { get; set; } + public long P3 { get; set; } + public byte P4 { get; set; } + public DateTime P5 { get; set; } + public double P6 { get; set; } + public byte[] P7 { get; set; } +} + +public class Arg +{ + public Arg() + { + } + + public Arg(int myProperty) + { + MyProperty = myProperty; + } + + public int MyProperty { get; set; } +} +``` +初始化 +```csharp +private ComplexObject GetComplexObject() +{ + ComplexObject complexObject = new ComplexObject(); + complexObject.P1 = 10; + complexObject.P2 = "天下无敌"; + complexObject.P3 = 100; + complexObject.P4 = 0; + complexObject.P5 = DateTime.Now; + complexObject.P6 = 10; + complexObject.P7 = new byte[1024 * 64]; + + Random random = new Random(); + random.NextBytes(complexObject.P7); + + complexObject.List1 = new List(); + complexObject.List1.Add(1); + complexObject.List1.Add(2); + complexObject.List1.Add(3); + + complexObject.List2 = new List(); + complexObject.List2.Add("1"); + complexObject.List2.Add("2"); + complexObject.List2.Add("3"); + + complexObject.List3 = new List(); + complexObject.List3.Add(new byte[1024]); + complexObject.List3.Add(new byte[1024]); + complexObject.List3.Add(new byte[1024]); + + complexObject.Dic1 = new Dictionary(); + complexObject.Dic1.Add(1, 1); + complexObject.Dic1.Add(2, 2); + complexObject.Dic1.Add(3, 3); + + complexObject.Dic2 = new Dictionary(); + complexObject.Dic2.Add(1, "1"); + complexObject.Dic2.Add(2, "2"); + complexObject.Dic2.Add(3, "3"); + + complexObject.Dic3 = new Dictionary(); + complexObject.Dic3.Add("1", "1"); + complexObject.Dic3.Add("2", "2"); + complexObject.Dic3.Add("3", "3"); + + complexObject.Dic4 = new Dictionary(); + complexObject.Dic4.Add(1, new Arg(1)); + complexObject.Dic4.Add(2, new Arg(2)); + complexObject.Dic4.Add(3, new Arg(3)); + return complexObject; +} +``` +```csharp +[Benchmark] +public void JsonFast_ComplexObject() +{ + var v = GetComplexObject(); + for (int i = 0; i < Count; i++) + { + var str = JsonFastConverter.JsonTo(v); + var val = JsonFastConverter.JsonFrom(str); + } +} +``` +下图为100次序列化与反序列化,JsonFast性能稍弱,但是基本满足要求。 +![image.png](../static/img/docs/jsonserialize-2.png) diff --git a/handbook/docs/multithreadingfiletransfer.mdx b/handbook/docs/multithreadingfiletransfer.mdx new file mode 100644 index 000000000..16f70c517 --- /dev/null +++ b/handbook/docs/multithreadingfiletransfer.mdx @@ -0,0 +1,177 @@ +--- +id: multithreadingfiletransfer +title: 多线程文件传输 +--- +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 企业版 + +多线程文件传输,顾名思义,就是多个连接链路,共同传输一个文件。 + +**多线程传输的优点是什么?和**[**常规文件传输**](./transferfile.mdx)**相比,场景有哪些不同?** + +首先,[常规文件传输](./transferfile.mdx)是基于单个连接链路的,所以,单个连接的传输速率上限,就是常规传输的上限。一般来说,局域网当中,单个连接即可占满所有带宽,所以这时候多线程传输和常规传输并无差别。但是,在云服务器,或者在有流量均衡算法的网络中,每个连接的最大速率不是带宽的最大速率,那么这时候,两个差距是比较大的。 + +例如,我自己租的一个单核云服务器,它的单个连接速率只有1Mb,但是弹性带宽却有10Mb。宏观表象就是,一个客户端连接时,可以用1Mb带宽,两个客户端连接时,就可以用2Mb。那么这时候,多线程传输就显得格外重要了。 + +其次,多线程传输是无状态的,所以对于断线重连,换网重连等操作,是完全无感的。 + + +## 二、使用 + +因为是多链路传输,所以,就必须建立多个客户端的连接到服务器。这里使用已经封装好的通信模型ClientFactory。 + +ClientFactory的通信模型使用的是一个主通信端+多个传输客户端。 + +对于客户端的配置,请详细参考[创建TouchRpc客户端](./createtouchrpcclient.mdx) + +```csharp +private TcpTouchRpcClientFactory CreateClientFactory() +{ + TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory() + { + MinCount = 5, + MaxCount = 10, + OnGetMainConfig = () =>//配置主通信 + { + return new TouchSocketConfig() + .SetRemoteIPHost("tcp://127.0.0.1:7789"); + }, + OnGetTransferConfig = () => //配置辅助通信 + { + return new TouchSocketConfig() + .SetRemoteIPHost("tcp://127.0.0.1:7789"); + } + }; + + return clientFactory; +} +``` + +【拉取文件】 + +```csharp +TcpTouchRpcClientFactory clientFactory = CreateClientFactory(); +var resultCon = clientFactory.CheckStatus();//检验主通信器连接状态。默认如果没有连接,则会建立。 +if (resultCon.IsSuccess()) +{ + var fileOperator = new MultithreadingFileOperator() + { + ResourcePath = path,//请求资源路径 + SavePath = savePath,//本地保存路径 + }; + //此处相当于Timer,每秒获取传输的速度和进度 + LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) => + { + if (fileOperator.IsEnd) + { + loop.SafeDispose(); + } + + Console.WriteLine($"速度:{fileOperator.Speed()},进度:{fileOperator.Progress}"); + }); + _=loopAction.RunAsync(); + + Result result= await clientFactory.PullFileAsync(fileOperator); + if (result.IsSuccess()) + { + MessageBox.Show(result.ToString()); + } +} +else +{ + MessageBox.Show(resultCon.ToString()); +} + +``` + +【推送文件】 + +```csharp +TcpTouchRpcClientFactory clientFactory = CreateClientFactory(); +var resultCon = clientFactory.CheckStatus();//检验主通信器连接状态。默认如果没有连接,则会建立。 +if (resultCon.IsSuccess()) +{ + var fileOperator = new MultithreadingFileOperator() + { + ResourcePath = path, + SavePath = savePath, + }; + + //此处相当于Timer,每秒获取传输的速度和进度 + LoopAction loopAction = LoopAction.CreateLoopAction(1000, (loop) => + { + if (fileOperator.IsEnd) + { + loop.SafeDispose(); + } + + Console.WriteLine($"速度:{fileOperator.Speed()},进度:{fileOperator.Progress}"); + }); + _=loopAction.RunAsync(); + + Result result=await clientFactory.PushFileAsync(fileOperator); + if (result.IsSuccess()) + { + MessageBox.Show(result.ToString()); + } +} +else +{ + MessageBox.Show(resultCon.ToString()); +} +``` + +## 三、客户端之间传输文件 + +该功能也支持客户端之间互相传输。使用方法基本一致,需要额外指定目标Id,以及**获取传输的Id集合**即可。 + +多线程的客户端之间传输文件,不像其他操作类型那么简单。因为除了需要指定目的Id外,还需要指定获取目标Id的,传输客户端的Id集合,不然,获取数据的时候,仍然会是单线程工作的。 + +此外,**服务器**也需要同意路由 + +```csharp +internal class MyTouchRpcPlugin : TouchRpcPluginBase +{ + protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e) + { + if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile) + { + e.IsPermitOperation = true; + } + base.OnRouting(client, e); + } +} +``` + +【获取目标传输客户端的Id集合】 +在TcpTouchRpcClientFactory属性中,有个OnFindTransferIds。通过实现该属性,使其能够获取到对应客户端的传输客户端Id集合(下列代码为模拟值,要具体实现该功能,还得自行实现)。 + +```csharp +TcpTouchRpcClientFactory clientFactory = new TcpTouchRpcClientFactory() +{ + MinCount = 5, + MaxCount = 10, + OnGetMainConfig = () =>//配置主通信 + { + return new TouchSocketConfig() + .SetRemoteIPHost("tcp://127.0.0.1:7789") + .SetVerifyToken("FileService"); + }, + OnGetTransferConfig = () => //配置辅助通信 + { + return new TouchSocketConfig() + .SetRemoteIPHost("tcp://127.0.0.1:7789") + .SetVerifyToken("FileService"); + } + , + OnFindTransferIds = (client,targetId) => + { + //此处的操作不唯一,可能需要rpc实现。 + //其目的比较简单,就是获取到targetId对应的主客户端的所有传输客户端的Id集合。 + //这样就实现了多个客户端向多个客户端传输文件的目的。 + + return new string[] { targetId};//此处为模拟结果。 + } +}; +``` diff --git a/handbook/docs/natservice.mdx b/handbook/docs/natservice.mdx new file mode 100644 index 000000000..4cf4e091a --- /dev/null +++ b/handbook/docs/natservice.mdx @@ -0,0 +1,101 @@ +--- +id: natservice +title: Tcp端口转发 +--- +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 +NATService是具有转发功能的TCP服务器。他的职能是将收到的TCP数据转发到多个目标服务器。也能将多个目标服务器的数据转发到连接客户端。 + +## 二、常见使用场景 + +- **调试场景:**在生产环境中,想要调试客户端,要么中断服务器,要么就将实际数据转发到NAT,然后在不影响实际场景的情况下进行调试。 +- **内网穿透场景:**一般tcp都会使用转发式的内网穿透。 + + +## 三、创建NATService + +```csharp +static void Main(string[] args) +{ + MyNATService service = new MyNATService(); + var config = new TouchSocketConfig(); + config.SetListenIPHosts(new IPHost[] { new IPHost(7788) }); + + service.Setup(config); + service.Start(); + + Console.WriteLine("转发服务器已启动。已将7788端口转发到127.0.0.1:7789与127.0.0.1:7790地址"); +} +``` + +:::tip 提示 + +NATService支持客户端适配器和Ssl。也支持转发适配器和Ssl。 + +::: + +```csharp + class MyNATService : NATService + { + protected override void OnConnected(NATSocketClient socketClient, RRQMEventArgs e) + { + base.OnConnected(socketClient, e); + + try + { + //此处模拟的是只要连接到NAT服务器,就转发。 + //实际上,这个方法可以随时调用。 + socketClient.AddTargetClient(new TouchSocketConfig().SetRemoteIPHost("127.0.0.1:7789")); + socketClient.AddTargetClient(new TouchSocketConfig().SetRemoteIPHost("127.0.0.1:7790")); + } + catch (Exception ex) + { + socketClient.Logger.Exception(ex); + } + } + + protected override void OnTargetClientDisconnected(NATSocketClient socketClient, ITcpClient tcpClient, ClientDisconnectedEventArgs e) + { + socketClient.Logger.Message($"{socketClient.IP}:{socketClient.Port}的转发客户端{tcpClient.IP}:{tcpClient.Port}已经断开连接。"); + base.OnTargetClientDisconnected(socketClient, tcpClient, e); + } + + protected override byte[] OnNATReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + //服务器收到的数据 + return base.OnNATReceived(socketClient, byteBlock, requestInfo); + } + + protected override byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + //连接的客户端收到的数据 + return base.OnTargetClientReceived(socketClient, tcpClient, byteBlock, requestInfo); + } + } + + +``` + +## 四、转发断线重连 企业版 + +```csharp +try +{ + //此处模拟的是只要连接到NAT服务器,就转发。 + //实际上,这个方法可以随时调用。 + socketClient.AddTargetClient(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .ConfigurePlugins(a=> + { + //在企业版中,使用以下任意方式,可实现转发客户端的断线重连。 + a.Add>() + .SetTick(1000);//每秒检查 + //a.UseReconnection(); + })); +} +catch (Exception ex) +{ + socketClient.Logger.Exception(ex); +} +``` diff --git a/handbook/docs/normaldatahandlingadapter.mdx b/handbook/docs/normaldatahandlingadapter.mdx new file mode 100644 index 000000000..6d87dcd5a --- /dev/null +++ b/handbook/docs/normaldatahandlingadapter.mdx @@ -0,0 +1,42 @@ +--- +id: normaldatahandlingadapter +title: a.正常数据处理适配器 +--- + + +## 一、说明 + +正常数据处理适配器就是处理**普通**的TCP报文,内部不进行任何数据处理,这也就意味着它并**不能解决粘、分包**的问题,它只是能够将数据进行接收和处理而已。 + +## 二、特点 + +1. 能够接收所有TCP报文,与语言、框架无关。 +2. 相当于加强版的Socket,但是数据发送与接收是完全一致的。 + + +## 三、使用 + +步骤 + +1. TouchSocketConfig配置中设置 +2. 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。 + +```csharp {10} +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(()=> { return new NormalDataHandlingAdapter(); }))//配置适配器 + .Start();//启动 +``` + +:::tip 提示 + +该适配器,客户端与服务器均适用。 + +::: \ No newline at end of file diff --git a/handbook/docs/othercore.mdx b/handbook/docs/othercore.mdx new file mode 100644 index 000000000..ea89901e3 --- /dev/null +++ b/handbook/docs/othercore.mdx @@ -0,0 +1,82 @@ +--- +id: othercore +title: 其他相关功能类 +--- + +## 一、Crc计算 +**TouchSocket**从网上搜集了Crc1-23的计算方法。并封装在了Crc类中。 +以最常用的Crc16为例。 +```csharp +byte[] data = new byte[10]; +byte[] result = Crc.Crc16(data, 0, data.Length); +``` + +## 二、时间测量器(TimeMeasurer) +功能:封装的Stopwatch,测量运行Action的时间。 +```csharp +TimeSpan timeSpan = TimeMeasurer.Run(() => + { + Thread.Sleep(1000); + }); + +``` + +## 三、MD5计算 +```csharp +string str = MD5.GetMD5Hash("TouchSocket"); +bool b = MD5.VerifyMD5Hash("TouchSocket",str); +``` + +## 四、16进制相关 +【将16进制的字符转换为数组】 +```csharp + public static byte[] ByHexStringToBytes(this string hexString, string splite = default) +``` +【将16进制的字符转换为int32】 +```csharp + public static int ByHexStringToInt32(this string hexString) +``` + +## 五、雪花ID生成 +雪花ID,会生成long类型的不重复ID。 +```csharp +SnowflakeIDGenerator generator = new SnowflakeIDGenerator(4); +long id=generator.NextID(); +``` + +## 六、数据压缩 +内部封装了Gzip的压缩。使用静态方法即可完成。 +```csharp + +byte[] data = new byte[1024]; +new Random().NextBytes(data); + +using (ByteBlock byteBlock=new ByteBlock()) +{ + GZip.Compress(byteBlock,data,0,data.Length);//压缩 + var decompressData2 = GZip.Decompress(byteBlock.ToArray());//解压 +} + + +``` + +压缩接口 +内部还定义了一个IDataCompressor的压缩接口。目的是为了向成熟框架传递压缩方法(例如TcpClient)。 +默认配备了一个GZipDataCompressor。可以直接使用。当然大家可以自由扩展其他压缩方法。 + +```csharp +class MyDataCompressor : IDataCompressor +{ + public byte[] Compress(ArraySegment data) + { + //此处实现压缩 + throw new NotImplementedException(); + } + + public byte[] Decompress(ArraySegment data) + { + //此处实现压缩 + throw new NotImplementedException(); + } +} +``` diff --git a/handbook/docs/pipelinedatahandlingadapter.mdx b/handbook/docs/pipelinedatahandlingadapter.mdx new file mode 100644 index 000000000..170eeba43 --- /dev/null +++ b/handbook/docs/pipelinedatahandlingadapter.mdx @@ -0,0 +1,51 @@ +--- +id: pipelinedatahandlingadapter +title: Pipeline数据适配器 +--- + + +## 一、说明 + +Pipeline适配器,是结合IOCP与管道模型结合的产物。功能类似于NetworkStream,但与之不同的是,Pipeline每当有数据到达时,会先触发一个事件(OnReveived),然后用户在事件中可无限制的Read或Write数据。如果本次接收完成,可退出接收。当下一段数据抵达时,会再次通知接收。 + + + +## 二、使用 + +下列示例代码实现,当读到换行时,结束本次接收。 + +```csharp +TcpService service = new TcpService(); + +service.Received += (client, byteBlock, requestInfo) => +{ + if (requestInfo is Pipeline pipeline)//实际上Pipeline继承自Stream + { + pipeline.ReadTimeout = 1000 * 60;//设置读取超时时间为60秒。 + StreamReader streamReader = new StreamReader(pipeline);//所以可以直接用StreamReader构造 + string ss = streamReader.ReadLine();//会一直等换行,直到等到换行,才继续向下执行 + Console.WriteLine(ss); + } + //当Pipeline退出该事件方法时,会被自动释放,下次会投递新的Pipeline实例。 + // 如果里面还有未Read完的数据,下次会继续投递,如果想直接丢弃,则在此处直接调用Disopose即可。 + +}; + +//声明配置 +var config = new TouchSocketConfig(); +config.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .SetDataHandlingAdapter(() => new PipelineDataHandlingAdapter());//配置适配器为Pipeline + +//载入配置 +service.Setup(config); + +//启动 +service.Start(); + +``` + +:::tip 提示 + +上述创建的适配器客户端与服务器均适用。 + +::: diff --git a/handbook/docs/pluginsmanager.mdx b/handbook/docs/pluginsmanager.mdx new file mode 100644 index 000000000..d7f0a6117 --- /dev/null +++ b/handbook/docs/pluginsmanager.mdx @@ -0,0 +1,68 @@ +--- +id: pluginsmanager +title: 插件系统 +--- + +## 说明 +- 插件是对TouchSocket产品的横向扩展。 + +## 产品特点 + +- 简单易用。 +- 易扩展。 + +## 产品应用场景 + +- TCP基础使用场景。 +- 自定义协议解析场景。 + +## 插件特性 +【多线程并发】 +插件的所有触发,均是同一实例,所以在服务器运行时,几乎都是并发触发的,所有应当考虑并发问题。 + +【插件先行】 +当启用插件时,插件的触发**仅次于**方法重写,而**优于**事件。 + +【执行顺序】 +每个插件都有一个**Order**属性,该属性表示该插件的执行顺序,数值小,越提前执行(Order在Add之前生效,后续修改无效)。 + +【中断传递】 +当某个插件在响应时,如果设置e.Handled=true,则该数据将**不会**再触发后续的插件、事件、重写方法。 + +## 用户自定义插件 +用户通过实现框架预设的插件接口,即可接收相应的触发。每个组件都有详细的插件支持说明。 + +例如:**ITcpPlugin**、**ITokenPlugin**、**IProtocolPlugin**等。 + +## 系统自定义插件 +当各位朋友使用TouchSocket封装自己的dll时,可能需要一些定义插件。那么这个需求TouchSocket也能满足大家。 +> 例如:实现基于TCP的特殊信息自定义插件,当收到字母‘A’时,希望触发实现IAPlugin接口插件的GoToA方法。 + +具体操作如下: + +1. 声明IAPlugin接口,继承**IPlugin**。 +2. 声明GoToA接口方法(该方法必须**两个**参数,第一参数无要求,一般为触发主体,第二参数**必须继承**自**TouchSocketEventArgs**)。 +3. 在合适时候,判断当前配置是否支持插件,然后使用服务器或客户端的**PluginsManager**属性调用**Raise**方法,此处的泛型(**IAPlugin**)必须为接口类型。 + +```csharp +public interface IAPlugin : IPlugin +{ + void GoToA(ITcpClientBase client,TouchSocketEventArgs e); +} +``` + +```csharp +public class MyTClient : TcpClient +{ + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (this.UsePlugin) + { + if (byteBlock.ToString()=="A") + { + this.PluginsManager.Raise("GoToA",this,new TouchSocketEventArgs()); + } + } + } +} +``` diff --git a/handbook/docs/reconnection.mdx b/handbook/docs/reconnection.mdx new file mode 100644 index 000000000..7cd9274ec --- /dev/null +++ b/handbook/docs/reconnection.mdx @@ -0,0 +1,54 @@ +--- +id: reconnection +title: 断线重连 +--- + +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 + +所谓断线重连,即tcp客户端在断开服务器后,主动发起的再次连接请求。 + +## 二、使用Reconnection插件 + +使用断线重连非常简单,仅一行代码完成。 + +```csharp +.UsePlugin() +.ConfigurePlugins(a=> +{ + a.UseReconnection(5, true, 1000);//如需永远尝试连接,tryCount设置为-1即可。 +}); +``` +:::caution 注意 + +**断线重连,必须满足以下几个要求:** + +1. 必须完成第一次连接 +2. 必须是被动断开,如果是客户端主动调用Close、Disconnect等方法主动断开的话,不会生效。 +3. 必须有显式的断开信息,也就是说,直接拔网线的话,不会立即生效,会等tcp保活到期后再生效。 + +::: + + +## 三、使用PollingKeepAlive插件 企业版 + +企业版使用断线重连,在兼容上述方法的同时,还支持一种无人值守的连接方式,即轮询式连接,使用也非常简单,仅一行代码完成。 + +```csharp +.UsePlugin() +.ConfigurePlugins(a=> +{ + a.Add>() + .SetTick(1000);//每秒检查 +}); +``` + +:::caution 注意 + +**PollingKeepAlive断线重连,必须满足以下几个要求:** + +1. 不要和UseReconnection一同使用 +2. 必须有显式的断开信息,也就是说,直接拔网线的话,不会立即生效,会等tcp保活到期后再生效。 + +::: \ No newline at end of file diff --git a/handbook/docs/remotefilecontrol.mdx b/handbook/docs/remotefilecontrol.mdx new file mode 100644 index 000000000..7921e2999 --- /dev/null +++ b/handbook/docs/remotefilecontrol.mdx @@ -0,0 +1,38 @@ +--- +id: remotefilecontrol +title: 远程文件操作 +--- +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 企业版 + +支持直接访问远程文件、文件夹的快捷操作。 + +## 二、支持的操作 + +以下内容,所有TouchRpc均支持(包括基于udp协议的)。 + +| **操作** | **文件** | **文件夹** | +| --- | --- | --- | +| 获取信息 | 支持:获取文件名称,大小,修改时间等。 | 支持:获取文件夹名称,大小,子文件夹,文件名称、修改时间等。 | +| 创建 | 不支持文件的直接创建。 | 支持 | +| 删除 | 支持 | 支持 | +| 复制 | 支持 | 支持 | +| 移动 | 支持 | 支持 | + + +## 三、代码示例 + +以获取文件夹信息为例: + +client为TouchRpc的终端。可以是逻辑客户端,也可以是逻辑服务器所包含的SocketClient + +```csharp +//client必选先建立连接(udp协议的除外) +//Metadata可以向对方传递更多的有用信息。 +//5000是超时时间,单位毫秒。 +//CancellationToken包含一个可取消令箭 +RemoteDirectoryInfoResult rootDirectoryInfoResult = client.GetDirectoryInfo(dirPath,new Metadata(),5000,new CancellationToken()); +``` + +其余操作基本一致。 diff --git a/handbook/docs/remotemonitoring.mdx b/handbook/docs/remotemonitoring.mdx new file mode 100644 index 000000000..81db849d2 --- /dev/null +++ b/handbook/docs/remotemonitoring.mdx @@ -0,0 +1,27 @@ +--- +id: remotemonitoring +title: 远程监测、控制项目 +--- + +## 定制方 +网友 +## 说明 +应该网友要求,基本完成了预定的所有功能,包括远程更新、远程屏幕监测、屏幕操作、远程文件资源管理器、远程控制台、远程注册表操作、远程文件操作(删除、复制、重命名、压缩)、等等。 + +## 技术点 + +- 整体界面:应定制方要求,界面使用原始控件。 +- 各种远程操作:均采用的是RRQM通信框架。 +## 效果 +【客户端——被控制端】 + +客户端是个winform的无界面程序。 + +![image.png](../static/img/docs/remotemonitoring-1.png) + +【服务器——管理端】 +![1.gif](../static/img/docs/remotemonitoring-2.gif) +![2.gif](../static/img/docs/remotemonitoring-3.gif) +![3.gif](../static/img/docs/remotemonitoring-4.gif) +![4.gif](../static/img/docs/remotemonitoring-5.gif) +![5.gif](../static/img/docs/remotemonitoring-6.gif) diff --git a/handbook/docs/remotestreamaccess.mdx b/handbook/docs/remotestreamaccess.mdx new file mode 100644 index 000000000..8aaa2d0d7 --- /dev/null +++ b/handbook/docs/remotestreamaccess.mdx @@ -0,0 +1,81 @@ +--- +id: remotestreamaccess +title: b.远程流访问 +--- + +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 企业版 + +可以在通信对方,创建一个Stream,然后映射到本地,由本地直接进行读、写等操作。 + + +## 二、场景 + +当远程主机拥有一个超大流数据(可能是文件,或者其他)时,本地只想访问其部分数据的话,就可以使用该功能。 +例如,假设C服务器有个10Gb的文件。A客户端需要其10000-20000字节之间的数据,那你此时可以使用该功能,直接进行读取。 + + +## 三、代码示例 + +下列以客户端作为请求端,以服务器作为响应端。实际上服务器也可以做请求端。 + +【请求端】 +任意TouchRpc终端(除udp协议)均可以调用LoadRemoteStream创建一个流数据映射。 +同时可以传递一个元数据组。用于载入自定义消息。 + +```csharp +RemoteStream remoteStream = client.LoadRemoteStream(new Metadata().AddOrUpdate("1", "1")); +``` + +【响应端】 +响应端定义一个插件,重写OnLoadingStream,然后实现需要载入的具体流信息。示例中是以MemoryStream作为流主体。 + +```csharp +class MyTcpTouchRpcPlugin : TouchRpcPluginBase +{ + protected override void OnLoadingStream(ITouchRpc client, LoadingStreamEventArgs e) + { + if (e.Metadata["1"]=="1") + { + e.Stream = new MemoryStream(); + } + base.OnLoadingStream(client, e); + } +} + +``` + +## 四、读写 + +当RemoteStream被成功创建以后,即可直接Read、Write。因为RemoteStream继承自Stream。 + +```csharp +var client = GetClient(); +RemoteStream remoteStream = client.LoadRemoteStream(new Metadata().AddOrUpdate("1", "1")); + +byte[] data = new byte[] { 0, 1, 2, 3, 4 }; +remoteStream.Write(data); +Assert.True(remoteStream.Length==5); +Assert.True(remoteStream.Position==5); + +remoteStream.Position = 0; +byte[] buffer=new byte[5]; +remoteStream.Read(buffer); +Assert.True(buffer.SequenceEqual(data)); +Assert.True(remoteStream.Position == 5); +Assert.True(remoteStream.Length == 5); + +remoteStream.SafeDispose(); +``` + +## 五、释放 + +当**断开连接**,或者请求方主动调用Dispose时,响应方的Stream均会被实际的Dispose掉。 + + +## 六、性能 + +图中示例为直接读取一个Window.iso文件所示。 + + diff --git a/handbook/docs/resetid.mdx b/handbook/docs/resetid.mdx new file mode 100644 index 000000000..9e9c87945 --- /dev/null +++ b/handbook/docs/resetid.mdx @@ -0,0 +1,62 @@ +--- +id: resetid +title: 服务器重置ID +--- + +## 一、说明 + +每个客户端在连接时,服务器都会为连接的客户端**新分配**一个唯一的ID。也就是说,在服务器中ID与SocketClient实例就是一一对应的。 + +## 二、配置初始ID策略 + +默认情况下服务器都会根据**历史连接数量**,为连接的客户端新分配ID。也就是说,第一个连接的,其ID就是1,以此类推。 + +当然我们可以自由的定义ID策略,只需要在Config配置中,配置[SetGetDefaultNewID](../docs/createtcpservice.mdx#setgetdefaultnewid),自定义新ID来源即可。要求不和现连接的客户端ID重复。 + +下列示例,就是使用Guid作为初始ID。 + +```csharp +.SetGetDefaultNewID(()=> { return new Guid().ToString(); }) +``` + +## 三、创建能代表连接的ID + +上述这种ID规范,是与连接信息没有任何关联的,这也就意味着,这种方式是无法关联SocketClient的。 + +但往往,有时候,我们希望,SocketClient的ID,能一定程度的代表一些信息。例如:以客户端的IP和端口,作为唯一ID。 + +那这时候,**服务器**可以订阅**Connecting**,然后,为新连接的SocketClient,设置与之有关联信息的ID。 + +```csharp +m_service.Connecting = (client, e) => +{ + e.ID = $"{client.IP}:{client.Port}"; +};//有客户端正在连接 +``` + +:::tip 提示 + +上述行为通过插件实现可能更加优雅。 + +::: + +## 四、即时修改ID + +上述修改ID的方式,应该还不足以应对所有情况。有时候我们希望,在该连接完成,且经过某种验证之后再设置新的ID,那么我们可以通过**ResetID**的方法,来实现需求。 + +### 4.1 通过Service直接修改 + +```csharp +service.ResetID("oldId","newId"); +``` + +### 4.2 通过SocketClient修改 +```csharp +socketClient.ResetID("newId"); +``` + +:::note 备注 + +上述的ID标识,仅仅是服务器(TcpService)和辅助客户端(SocketClient)之间的关联。与客户端(TcpClient)是没有任何关系的。 + +::: \ No newline at end of file diff --git a/handbook/docs/rpcactionfilter.mdx b/handbook/docs/rpcactionfilter.mdx new file mode 100644 index 000000000..9b2f68ce1 --- /dev/null +++ b/handbook/docs/rpcactionfilter.mdx @@ -0,0 +1,68 @@ +--- +id: rpcactionfilter +title: Rpc服务AOP +--- + +## 一、说明 + +RPC服务在被调用是,可以使用实现**IRpcActionFilter**的**特性(Attribute)**,进行相关AOP操作。 + +## 二、声明特性 + +```csharp +public class MyRpcActionFilterAttribute : RpcActionFilterAttribute +{ + public override void Executing(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + //invokeResult = new InvokeResult() + //{ + // Status = InvokeStatus.UnEnable, + // Message = "不允许执行", + // Result = default + //}; + if (callContext.Caller is TcpTouchRpcSocketClient client) + { + client.Logger.Info($"即将执行RPC-{callContext.MethodInstance.Name}"); + } + base.Executing(callContext, parameters, ref invokeResult); + } + + public override void Executed(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + if (callContext.Caller is TcpTouchRpcSocketClient client) + { + client.Logger.Info($"执行RPC-{callContext.MethodInstance.Name}完成,状态={invokeResult.Status}"); + } + base.Executed(callContext, parameters, ref invokeResult); + } + + public override void ExecutException(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception) + { + if (callContext.Caller is TcpTouchRpcSocketClient client) + { + client.Logger.Info($"执行RPC-{callContext.MethodInstance.Name}异常,信息={invokeResult.Message}"); + } + + base.ExecutException(callContext, parameters, ref invokeResult, exception); + } +} +``` + +:::tip 提示 + +每个方法都有详细的注释,仔细查看可能会事半功倍。 + +::: + + +## 三、使用 + +```csharp + [Description("性能测试")] + [TouchRpc] + [MyRpcActionFilter] + public int Performance(int a) + { + return a; + } +``` \ No newline at end of file diff --git a/handbook/docs/rpcallcontext.mdx b/handbook/docs/rpcallcontext.mdx new file mode 100644 index 000000000..05019a568 --- /dev/null +++ b/handbook/docs/rpcallcontext.mdx @@ -0,0 +1,67 @@ +--- +id: rpcallcontext +title: 调用上下文 +--- + +## 一、说明 + +> RPC服务是无状态的,即只知道当前服务被调用,但无法得知是被谁调用,这个问题给日志记录、RPC回调等带来了很多麻烦事。但是,Touch的Rpc支持调用上下文获取。在上下文中可以获得调用者(`ICaller`)信息等。 + + +## 二、通过标签参数获取 + +**步骤:** + +1. Rpc标签需要传入`MethodFlags.IncludeCallContext`参数。 +2. 定义的服务的第一个参数必须是`ICallContext`或其派生类。 +3. 最后获得其Caller属性即可得到调用者。 + +```csharp +public class MyRpcServer : RpcServer +{ + [Description("登录")] + [TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]//使用调用上才文 + public bool Login(ICallContext callContext,string account,string password) + { + if (callContext.Caller is TcpTouchRpcSocketClient) + { + Console.WriteLine("TcpTouchRpc请求"); + } + if (account=="123"&&password=="abc") + { + return true; + } + + return false; + } +} +``` + +## 三、通过瞬时生命周期获取 + +步骤: + +1. 继承TransientRpcServer或者实现ITransientRpcServer接口。 + +```csharp +public class MyRpcServer : TransientRpcServer +{ + [Description("登录")] + [TouchRpc] + public bool Login(string account,string password) + { + if ( this.CallContext.Caller is TcpTouchRpcSocketClient) + { + Console.WriteLine("TcpTouchRpc请求"); + } + if (account=="123"&&password=="abc") + { + return true; + } + + return false; + } +} +``` + + diff --git a/handbook/docs/rpcoption.mdx b/handbook/docs/rpcoption.mdx new file mode 100644 index 000000000..0030dfaa6 --- /dev/null +++ b/handbook/docs/rpcoption.mdx @@ -0,0 +1,79 @@ +--- +id: rpcoption +title: 调用配置 +--- + +## 一、调用反馈类型 + +RPC在调用时,的调用状态有三种状态可选,分别为:`OnlySend`、`WaitSend`、`WaitInvoke`。区别是: + +| OnlySend | WaitSend | WaitInvoke | +| --- | --- | --- | +| 仅发送RPC请求,在TCP底层协议下,能保证发送成功,但是不反馈服务器**任何状态**,也不会取得**返回值**、**异常**等信息。在UDP底层协议下,不保证发送成功,仅仅是具有请求动作而已。 | 发送RPC请求,并且等待收到状态返回,能保证RPC请求顺利到达服务,但是不能得知RPC服务是否成功执行,也不会取得**返回值**、**异常**等信息 | 发送RPC请求,且返回所有信息,包括是否成功调用,执行后的**返回值**或**异常**等信息。 | + +### 1.1 使用 + +同样的,在InvokeOption中可以直接赋值使用。 + +```csharp +InvokeOption invokeOption = new InvokeOption(); +invokeOption.FeedbackType = FeedbackType.WaitInvoke; +//invokeOption.FeedbackType = FeedbackType.OnlySend; +//invokeOption.FeedbackType = FeedbackType.WaitSend; +string returnString = client.Invoke("TestOne", invokeOption, "10"); +``` + +***注意:假如IInvokeOption使用的是InvokeOption的话,在new的时候,应该对其他参数也进行设置(因为它是结构体)。*** + +## 二、调用超时设置 + +调用RPC,不能无限制等待,必须要有计时器,或者任务取消的功能。 + +### 2.1 计时器设置 + +直接对`InvokeOption`的`Timeout` 属性赋值即可,单位为`毫秒`。 + +```csharp +InvokeOption invokeOption = new InvokeOption(); +invokeOption.Timeout = 1000 * 10;//10秒后无反应,则抛出RRQMTimeoutException异常 +string returnString = client.Invoke("TestOne", invokeOption, "10"); +``` + +### 2.2 任务取消 + +在RPC调用时,计时器是一个好的选择,但是还不够完美,有时候我们希望能手动终结某个调用任务。这时候,计时器就不堪重任,需要能主动取消任务的功能。熟悉.net的小伙伴都知道,CancellationToken是具备这个功能的。同样的,只需要对`InvokeOption`的`CancellationToken` 赋值即可。 + +```csharp +InvokeOption invokeOption = new InvokeOption(); +CancellationTokenSource tokenSource = new CancellationTokenSource(); +invokeOption.CancellationToken = tokenSource.Token; +//tokenSource.Cancel();//调用时取消任务 +string returnString = client.Invoke("TestOne", invokeOption, "10"); +``` + +### 2.3 服务任务取消 + +实际上7.2的取消任务,仅仅能实现让客户端取消请求,但是服务器并不知道,如果想让服务器也感知任务消息,就必须依托于调用上下文。 + +此处的取消,有可能是调用者主动取消。也有可能是调用者已经掉线。 + +```csharp +public class ElapsedTimeRpcServer : ServerProvider +{ + [Description("测试可取消的调用")] + [RRQMRPC(MethodFlags.IncludeCallContext)] + public bool DelayInvoke(ICallContext serverCallContext,int tick)//同步服务 + { + for (int i = 0; i < tick; i++) + { + Thread.Sleep(100); + if (serverCallContext.TokenSource.IsCancellationRequested) + { + Console.WriteLine("客户端已经取消该任务!"); + return false;//实际上在取消时,客户端得不到该值 + } + } + return true; + } +} +``` diff --git a/handbook/docs/rpcstream.mdx b/handbook/docs/rpcstream.mdx new file mode 100644 index 000000000..e368cb930 --- /dev/null +++ b/handbook/docs/rpcstream.mdx @@ -0,0 +1,139 @@ +--- +id: rpcstream +title: Rpc大数据流式传输 +--- + +## 一、说明 + +> **在RPC中,并没有对传输的数据做限制,但是因为RPC默认使用的固定包头适配器中,默认设置的可传递数据为10Mb,所以在RPC中,用户可一次性传递的数据包大约为9.9Mb。所以,如果用户传递超出阈值的数据,适配器则会触发异常,而无法接收。但在实际上RPC的使用中,大数据的传输也是很重要的一个环节,所以RRQM已经做了大数据的传输思路建议,希望能有效解决大家的麻烦。** + + + +## 二、设置适配器参数(推荐指数:⭐) + +> 操作原理:在固定包头适配器中,默认限制了单次可发送数据包的最大值,所以可以修改此值实现目的。 + +该方法简单粗暴,能够解决一定程度的大数据问题,但并不建议这么做。 + +***注意:客户端必须同样设置。*** + +```csharp +TouchSocketConfig config = new TouchSocketConfig()//配置 + .SetMaxPackageSize(1024 * 1024 * 10) +``` + + + +## 三、RPC嵌套Channel(推荐指数:⭐⭐⭐⭐⭐) + +> 操作原理:先利用RPC让客户端与服务器约定特定的Channel,然后后续数据通过Channel传递,最后由RPC返回结果。 + + + +### 3.1 请求流数据 + +【Service端】 + +```csharp +/// +/// "测试ServiceToClient创建通道,从而实现流数据的传输" +/// +/// +/// +[Description("测试ServiceToClient创建通道,从而实现流数据的传输")] +[TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)] +public int RpcPullChannel(ICallContext callContext, int channelID) +{ + int size = 0; + int package = 1024 * 1024; + if (callContext.Caller is TcpTouchRpcSocketClient socketClient) + { + if (socketClient.TrySubscribeChannel(channelID, out Channel channel)) + { + for (int i = 0; i < 1024; i++) + { + size += package; + channel.Write(new byte[package]); + } + channel.Complete();//必须调用指令函数,如Complete,Cancel,Dispose + } + } + return size; +} +``` + +【Client端】 + +```csharp +ChannelStatus status = ChannelStatus.Default; +int size = 0; +Channel channel = client.CreateChannel();//创建通道 +Task task = Task.Run(() =>//这里必须用异步 + { + using (channel) + { + while (channel.MoveNext()) + { + byte[] data = channel.GetCurrent(); + size += data.Length; + } + status = channel.Status; + } + }); +int result = client.RpcPullChannel(channel.ID);//RpcPullChannel是代理方法,此处会阻塞至服务器全部发送完成。 +await task;//等待异步接收完成 +Console.WriteLine($"状态:{status},size={size}"); +``` + + + +### 3.2 推送流数据 + +【Service端】 + +```csharp +/// +/// "测试推送" +/// +/// +/// +[Description("测试ServiceToClient创建通道,从而实现流数据的传输")] +[TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)] +public int RpcPushChannel(ICallContext callContext, int channelID) +{ + int size = 0; + + if (callContext.Caller is TcpTouchRpcSocketClient socketClient) + { + if (socketClient.TrySubscribeChannel(channelID, out Channel channel)) + { + while (channel.MoveNext()) + { + size += channel.GetCurrent().Length; + } + } + } + return size; +} +``` + +【Client端】 + +```csharp +ChannelStatus status = ChannelStatus.Default; +int size = 0; +int package = 1024 * 1024; +Channel channel = client.CreateChannel();//创建通道 +Task task = Task.Run(() =>//这里必须用异步 +{ + for (int i = 0; i < 1024; i++) + { + size += package; + channel.Write(new byte[package]); + } + channel.Complete();//必须调用指令函数,如Complete,Cancel,Dispose +}); +int result = client.RpcPushChannel(channel.ID);//RpcPushChannel是代理方法,此处会阻塞至服务器全部完成。 +await task;//等待异步接收完成 +Console.WriteLine($"状态:{status},result={result}"); +``` diff --git a/handbook/docs/serializationselector.mdx b/handbook/docs/serializationselector.mdx new file mode 100644 index 000000000..9eadb6296 --- /dev/null +++ b/handbook/docs/serializationselector.mdx @@ -0,0 +1,104 @@ +--- +id: serializationselector +title: 序列化选择器 +--- + +## 一、说明 + +从下图(图片来源[网络](https://www.jianshu.com/p/7d6853140e13))可以看出,序列化是RPC中至关重要的一个环节,可以说,序列化的优劣,会很大程度的影响RPC调用性能。 + + + +## 二、支持的序列化 + +在TouchRpc中,内置了四种序列化方式,分别为`FastBinary`、`Json`、`Xml`、`SystemBinary`。这四种方式的特点,就是其序列化的特点。 + +| | FastBinary | Json | Xml | SystemBinary | +| --- | --- | --- | --- | --- | +| 特点 | 序列化方式速度快,数据量小,但是兼容的数据格式也比较有限。仅支持基础类型、自定义实体类、数组、List、字典 | 兼容性好,可读性强,但是受字符串影响,性能不出众,且数据量受限制 | 兼容性一般,可读性强,同样受字符串影响,性能不出众,且数据量受限制 | 序列化速度快。但是兼容性低。且要求类必须一致,不然需要重新指定图根。 | + +## 三、使用预设序列化 + +在TouchRpc中,选择序列化是非常简单的,且序列化方式完全由`调用端`决定。 +在实际的调用中,通过`InvokeOption`的参数指定。 + +实际上,只需要传入相关参数即可。 + +```csharp +InvokeOption invokeOption = new InvokeOption() //InvokeOption是结构体,所以成员必须全部初始化。 +{ + FeedbackType = FeedbackType.WaitInvoke, + Timeout = 1000 * 10 +}; +; +invokeOption.SerializationType = SerializationType.FastBinary; +//invokeOption.SerializationType = Serialization.SerializationType.Json; +//invokeOption.SerializationType = Serialization.SerializationType.Xml; +string returnString = client.Invoke("TestOne", invokeOption, "10"); +``` + + +## 四、自定义序列化 + +### 4.1 定义自定义序列化器 + +想要实现自定义序列化,必须通过重写序列化选择器,实现`SerializeParameter`和`DeserializeParameter`函数。 + +下列代码将以`MemoryPack`序列化作为示例,并且保留了预设序列化。 + +```csharp +public class MemoryPackSerializationSelector:DefaultSerializationSelector +{ + public override byte[] SerializeParameter(SerializationType serializationType, object parameter) + { + if ((byte)serializationType == 4) + { + return MemoryPackSerializer.Serialize(parameter.GetType(),parameter); + } + return base.SerializeParameter(serializationType, parameter); + } + + public override object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType) + { + if ((byte)serializationType == 4) + { + if (parameterBytes==null) + { + return default; + } + return MemoryPackSerializer.Deserialize(parameterType,parameterBytes); + } + return base.DeserializeParameter(serializationType, parameterBytes, parameterType); + } +} +``` + +### 4.2 使用 + +必须在`服务器`和`客户端`的**Config配置**中设置解析器。 + +```csharp +var config = new TouchSocketConfig()//配置 + .SetSerializationSelector(new MemoryPackSerializationSelector()); +``` + +然后,因为赋值时是`SerializationType`的枚举类型,所以执行强制类型转换即可。 + +```csharp +InvokeOption invokeOption = new InvokeOption() +{ + FeedbackType = FeedbackType.WaitInvoke, + SerializationType = (SerializationType)4, + Timeout = 1000 * 10 +}; + +var msg = client.Login(new LoginModel() { Account = "Account", Password = "Password" }, invokeOption); +``` + +:::tip 提示 + +因为使用的是`MemoryPack`序列化,所以最好将Rpc的所有参数声明在单独的程序集中。这样客户端与服务器项目都可以直接引用。 + +::: + +[序列化选择器示例代码](https://gitee.com/RRQM_Home/TouchSocket/tree/master/examples/TouchRpc%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B/%E5%BA%8F%E5%88%97%E5%8C%96%E9%80%89%E6%8B%A9%E5%99%A8) diff --git a/handbook/docs/smallfiletransfer.mdx b/handbook/docs/smallfiletransfer.mdx new file mode 100644 index 000000000..4bfc3c6a8 --- /dev/null +++ b/handbook/docs/smallfiletransfer.mdx @@ -0,0 +1,69 @@ +--- +id: smallfiletransfer +title: 小文件传输 +--- + + + +## 一、说明 + +小文件传输是指,当传输文件小于设定大小(默认1024*1024字节)时的传输。 + +为什么要设立小文件传输?与常规文件传输相比,优点在哪里? +常规传输,建立一个传输通道,大约需要传输两端,往返通信4-6次。这在本地局域网中,显得无所谓。但是在互联网环境中,一次ping延迟平均50ms,那么建立一个传输,就大约需要200-300ms。这也就意味着,即使一个文件只有一字节,也需要这些时间。所以,这明显是不合理的。所以TouchRpc又新增了小文件传输,只要文件在1Mb以内,仅往返1次,就可以完成传输。 + +当然,对于小文件的最高效传输方式依然是先压缩,后传输的方式。 + + + +## 二、使用 + +【拉取文件】 + +1. 直接调用PullSmallFile或者PullSmallFileAsync,获取到实际的文件数据。 +2. 通过Save方法,将数据写入文件。也可以自行保存。 + +```csharp +var result = await this.fileClient.PullSmallFileAsync(path);//拉取文件 +var saveResult = result.Save(savePath);//将拉取的数据进行保存。 +``` + +【推送文件】 + +1. 直接调用PushSmallFile或者PushSmallFileAsync。 +2. 返回值即表示是否成功。 + +```csharp +var result = await this.fileClient.PushSmallFileAsync(savePath, fileInfo); +if (result.IsSuccess()) +{ +} +``` + +> 其他可选参数可以自己定义。 + + + +## 三、客户端之间传输 + +该功能也支持客户端之间互相传输。使用方法基本一致,需要额外指定目标Id即可。 + +此外,**服务器**也需要同意路由 + +```csharp +internal class MyTouchRpcPlugin : TouchRpcPluginBase +{ + protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e) + { + if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile) + { + e.IsPermitOperation = true; + } + base.OnRouting(client, e); + } +} +``` + + + +## diff --git a/handbook/docs/startguide.mdx b/handbook/docs/startguide.mdx new file mode 100644 index 000000000..e53a15026 --- /dev/null +++ b/handbook/docs/startguide.mdx @@ -0,0 +1,102 @@ +--- +id: startguide +title: 入门指南 +--- + +## 一、说明 + +TouchSocket(Pro)是基于.Net发布的程序集,所以它可以被用于对应.Net版本的C#、F#、VB.net等语言项目。它不区分您的项目是控制台、Winform、Wpf、或者是Aspnetcore,它统统都支持。 + +下面我们将以最简单的`C# 控制台`程序作为入门,让您最直观的感受ToucSocket的强大。 + +## 二、创建项目 + +由于TouchSocket(Pro)是基于net45、netstandard2.0、netcoreapp3.1三个平台作为常期支持平台,net7.0作为最新发布平台的程序,所以您可以用vs2010及以上的任意版本创建项目。 + +下面我们将以vs2022作为示例: + +:::info 说明 + +如果您选择vs code等其他的编译工具,那么我相信您已不是新手。那么您只需要安装TouchSocket(Pro)的最新nuget包即可。 + +::: + +### 2.1 创建新项目 + + + +### 2.2 选择项目类型 + + +### 2.3 配置项目名称和路径 + + +### 2.4 选择Net版本 + + + +## 三、安装 + +### 3.1 Nuget安装 + +右击项目=》点击“管理Nuget程序包”。 + + + +点击“浏览”,然后在搜索框输入`TouchSocket`,然后在搜索结果中选择。最后点击安装。 + + + +### 3.2 PackageReference + +单击项目,打开项目编辑,然后在空白根内部引用。 + +```xml + + + +``` +:::tip 提示 + +Version="1.2.3"可能不是最新的版本,请前往[Nuget官网](https://www.nuget.org/packages?q=TouchSocket)查看。 + +::: + + + +### 3.3 Dll直接引用 + +在[Nuget官网](https://www.nuget.org/packages?q=TouchSocket)中,选择需要的,然后选择“Download package”,即可下载一个后缀为`.nupkg`文件。 + + + +:::tip 提示 + +如果下载速度较慢,可以考虑使用迅雷等工具加速。 + +::: + +将下载的后缀为`.nupkg`的文件,通过压缩工具`解压`。得到如下目录结构。 + + + +然后进入“lib”的文件夹。选择对应平台。 + +:::tip 提示 + +一般来说,所有基于.NET Framework的项目,都最好引用net45的库。然后其他版本的,选择最近的,较低的库即可。在本示例中,选择netcoreapp3.1的库。 + +::: + +把下列文件引用到项目即可。 + + + + + + +## 四、结束 + +恭喜你,到这里,你就完成了入门的教学,你可能会好奇,做了这么多,还是什么都没有做啊。这是因为TouchSocket并不是一个单功能的,而是一个多功能程序库。所以,你必须在其他模块中查看你所需要的内容。 + +祝你好运!!! diff --git a/handbook/docs/stategridtransmission.mdx b/handbook/docs/stategridtransmission.mdx new file mode 100644 index 000000000..c12b33e7b --- /dev/null +++ b/handbook/docs/stategridtransmission.mdx @@ -0,0 +1,166 @@ +--- +id: stategridtransmission +title: 国网输电i1标准版 +--- + +## 说明 + +本代码仅适用以下协议。 +协议中,由Packet\_Length表示序号7-11的长度。也就是Packet\_Length=N+2+2+1+1。 +但是在设计时,会将序号1-10,视为固定包头。序号11-13为Body。 + +## 版权 + +该代码所有版权归若汝棋茗所有,使用时请务必注明。 + +## 协议类型 + + +## 代码 + +```csharp +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace AdapterConsoleApp +{ + /// + /// 国网输电i1标准版 + /// + internal class SGCCCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter + { + public override int HeaderLength => 30; + + public override bool CanSendRequestInfo => false; + + protected override SGCCRequestInfo GetInstance() + { + return new SGCCRequestInfo(); + } + + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + } + + public class SGCCRequestInfo : IFixedHeaderRequestInfo + { + private byte[] m_sync; + private int m_bodyLength; + private byte[] m_cMDID; + private byte[] m_sample; + private byte[] m_cRC16; + + public int BodyLength { get => m_bodyLength; } + + /// + /// 报文头:5AA5 + /// + public byte[] Sync { get => m_sync; set => m_sync = value; } + + /// + /// 报文长度 + /// + public ushort PacketLength { get => (ushort)(this.m_bodyLength - 3); } + + /// + /// 状态监测装置ID(17位编码) + /// + public byte[] CMDID { get => m_cMDID; set => m_cMDID = value; } + + /// + /// 帧类型—参考附表C8-1相关含义 + /// + public byte FrameType { get; set; } + + /// + /// 报文类型—参考附表C8-2相关含义 + /// + public byte PacketType { get; set; } + + /// + /// 帧序列号(无符号整数) + /// + public byte FrameNo { get; set; } + + /// + /// 通道号—表示采集装置上的摄像机编号。如:一个装连接⒉部摄像机,则分别标号为1、2 + /// + public byte ChannelNo { get; set; } + + /// + /// 预置位号—即云台摄像所设置的预置位号,不带云台摄像机,预置位号为255 + /// + public byte PresettingNo { get; set; } + + /// + /// 总包数(无符号整数,取值范围:大于等于0) + /// + public ushort PacketNo { get; set; } + + /// + /// 子包包号(无符号整数,取值范围:大于等于0> + /// + public ushort SubpacketNo { get; set; } + + /// + /// 数据区 + /// + public byte[] Sample { get => m_sample; set => m_sample = value; } + + /// + /// 校验位 + /// + public byte[] CRC16 { get => m_cRC16; } + + /// + /// 报文尾:0x96 + /// + public byte End { get; set; } + + public bool OnParsingHeader(byte[] header) + { + if (header.Length == 30) + { + using (ByteBlock byteBlock = new ByteBlock(header)) + { + byteBlock.Pos = 0; + byteBlock.Read(out m_sync, 2); + + byte[] lenBuffer; + byteBlock.Read(out lenBuffer, 2); + + this.m_bodyLength = TouchSocketBitConverter.LittleEndian.ToUInt16(lenBuffer, 0) + 3 - 6;//先把crc校验和end都获取。 + byteBlock.Read(out m_cMDID, 17); + this.FrameType = (byte)byteBlock.ReadByte(); + this.PacketType = (byte)byteBlock.ReadByte(); + this.FrameNo = (byte)byteBlock.ReadByte(); + this.ChannelNo = (byte)byteBlock.ReadByte(); + this.PresettingNo = (byte)byteBlock.ReadByte(); + this.PacketNo = byteBlock.ReadUInt16(); + this.SubpacketNo = byteBlock.ReadUInt16(); + + return true; + } + } + return false; + } + + public bool OnParsingBody(byte[] body) + { + if (body.Length == this.BodyLength && body[^1] == 150) + { + using (ByteBlock byteBlock = new ByteBlock(body)) + { + byteBlock.Read(out this.m_sample, this.m_bodyLength - 3); + byteBlock.Read(out this.m_cRC16, 2); + this.End = (byte)byteBlock.ReadByte(); + } + return true; + } + return false; + } + } +} +``` diff --git a/handbook/docs/streamtransfer.mdx b/handbook/docs/streamtransfer.mdx new file mode 100644 index 000000000..917548a75 --- /dev/null +++ b/handbook/docs/streamtransfer.mdx @@ -0,0 +1,108 @@ +--- +id: streamtransfer +title: Stream传输 +--- + + +## 一、说明 + +Stream的直接发送,**单个**TCP连接上可以**同时**进行多个传输。客户端与服务器之间可以任意相互发送。 + + + +## 二、特性 + +1. 实时检测速度,进度等信息。 +2. 从Stream.Position开始,直到Read结束。 + + + +## 三、示例 + +下列以服务器作为Stream的接收方。客户端为发送方。 + +【服务器】 + +```csharp +TcpTouceRpcService service = CreateTcpTouceRpcService(); + +service.StreamTransfering += (socketClient, e) => +{ + e.Bucket = new MemoryStream();//此处用MemoryStream作为接收容器,也可以使用FileStream。 + e.AddOperation(Operation.Permit);//允许接收该流 + Metadata metadata = e.Metadata;//获取元数据 + StreamOperator streamOperator = e.StreamOperator;//获取操作器,可用于取消任务,获取进度等。 + + //Console.WriteLine("设置最大传输速度为1024byte"); + //streamOperator.SetMaxSpeed(1024); + + //Console.WriteLine("5秒后设置为5Mb"); + //RRQMCore.Run.EasyAction.DelayRun(5, () => + //{ + // streamOperator.SetMaxSpeed(1024 * 1024 * 5); + //}); + + Task.Run(async () => + { + while (streamOperator.Result.ResultCode == ResultCode.Default) + { + Console.WriteLine($"速度={streamOperator.Speed()},进度={streamOperator.Progress}"); + + await Task.Delay(1000); + } + + Console.WriteLine($"从循环传输结束,状态={streamOperator.Result}"); + }); + Console.WriteLine("开始接收流数据"); +}; + +service.StreamTransfered += (socketClient, e) => +{ + //此处不管传输成功与否,都会执行,具体状态通过e.Status判断。 + if (e.Result.ResultCode == ResultCode.Success) + { + + } + e.Bucket.Dispose();//必须手动释放流数据。 + Console.WriteLine($"从ReceivedStream传输结束,状态={e.Result}"); +}; + +``` + +【客户端】 + +```csharp +TcpTouchRpcClient client = CreateTcpTouchRpcClient(); + +byte[] data = new byte[1024 * 1024 * 50]; +new Random().NextBytes(data); +MemoryStream stream = new MemoryStream(data); +stream.Position = 0; + +Console.WriteLine($"即将发送流数据,长度为:{stream.Length}"); + +StreamOperator streamOperator = new StreamOperator(); +streamOperator.PackageSize = 1024 * 64;//分包长度 +//streamOperator.SetMaxSpeed(1024 * 1024 * 5);//最大传输值 + +//streamOperator.Cancel();//随时取消传输 + +LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (a) => +{ + if (streamOperator.Result.ResultCode != ResultCode.Default) + { + a.Dispose(); + } + Console.WriteLine($"速度:{streamOperator.Speed()},进度:{streamOperator.Progress}"); +}); +loopAction.RunAsync(); + +Metadata metadata = new Metadata();//将键值对的元数据传到接收端 +metadata.Add("1", "1"); +metadata.Add("2", "2"); + +//该方法会阻塞,直到结束 +Result result = client.SendStream(stream, streamOperator, metadata); +Console.WriteLine(result); + +``` diff --git a/handbook/docs/tcpcommandlineplugin.mdx b/handbook/docs/tcpcommandlineplugin.mdx new file mode 100644 index 000000000..be3105b8c --- /dev/null +++ b/handbook/docs/tcpcommandlineplugin.mdx @@ -0,0 +1,109 @@ +--- +id: tcpcommandlineplugin +title: 命令行执行插件 +--- + +## 一、说明 + +**TcpCommandLinePlugin**命令行执行插件,是用于TCP的快捷事务实现。该类是抽象类,必须通过继承,在继承类中,声明的具的**公共的**且名称以**Command**结尾的方法,均可被快捷执行。 + +## 二、创建快捷执行插件 + +```csharp +/// +/// 命令执行插件。方法必须以Command结尾。 +/// +class MyCommandLinePlugin : TcpCommandLinePlugin +{ + private readonly ILog logger; + + public MyCommandLinePlugin(ILog logger) : base(logger) + { + this.ReturnException = true;//表示执行异常的时候,是否返回异常信息 + this.logger = logger; + } + + /// + /// 加法 + /// + /// + /// + /// + public int AddCommand(int a, int b) + { + this.logger.Info($"执行{nameof(AddCommand)}"); + return a + b; + } + + /// + /// 乘法,并且获取调用者信息 + /// + /// + /// + /// + /// + public int MULCommand(ISocketClient socketClient,int a, int b) + { + this.logger.Info($"{socketClient.IP}:{socketClient.Port}执行{nameof(MULCommand)}"); + return a * b; + } + + /// + /// 测试异常 + /// + /// + public void ExcCommand() + { + throw new Exception("我异常了"); + } +} +``` + +## 三、创建服务器 + +```csharp +TcpService service = new TcpService(); + +var config = new TouchSocketConfig(); +config.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) }) //同时监听两个地址 + .SetDataHandlingAdapter(() => + { + //return new TerminatorPackageAdapter(1024, "\r\n");//命令行中使用\r\n结尾 + return new NormalDataHandlingAdapter();//亦或者省略\r\n,但此时调用方不能高速调用,会粘包 + }) + .UsePlugin() + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + }); + +//载入配置 +service.Setup(config); + +//启动 +service.Start(); + +service.Logger.Info("服务器成功启动。"); +service.Logger.Info("使用:“Add 10 20”测试"); +service.Logger.Info("使用:“MUL 10 20”测试"); +service.Logger.Info("使用:“Exc”测试异常"); +``` + +## 四、调用 + +上述快捷执行插件,即可被普通tcp客户端,或cmd/telnet等便捷调用。 + +调用数据格式: + +`Add 10 20 /r/n` **/r/n**非必须,但是当适配器选为[终止字符分割适配器](../docs/terminatorpackageadapter.mdx)时,则必须。不然,则不可连续调用,会粘包。 + +:::tip 提示 + +调用的参数也支持自定义实体类,届时蚕食使用Json数据格式即可。 + +::: + diff --git a/handbook/docs/tcpother.mdx b/handbook/docs/tcpother.mdx new file mode 100644 index 000000000..799c30d09 --- /dev/null +++ b/handbook/docs/tcpother.mdx @@ -0,0 +1,10 @@ +--- +id: tcpother +title: 其他场景应用 +--- + + +- [C# TCP如何限制单个客户端的访问流量](https://blog.csdn.net/qq_40374647/article/details/125496769) +- [C# Tcp服务器如何限制同一个IP的连接数量?](https://blog.csdn.net/qq_40374647/article/details/125390655) +- [C# 实现为Tcp服务器设计访问黑名单、白名单](https://blog.csdn.net/qq_40374647/article/details/128640132) +- [C# Tcp服务器实现多端口、多协议解析](https://blog.csdn.net/qq_40374647/article/details/128641766) \ No newline at end of file diff --git a/handbook/docs/terminatorpackageadapter.mdx b/handbook/docs/terminatorpackageadapter.mdx new file mode 100644 index 000000000..fcba4e577 --- /dev/null +++ b/handbook/docs/terminatorpackageadapter.mdx @@ -0,0 +1,58 @@ +--- +id: terminatorpackageadapter +title: 终止因子分割数据处理适配器 +--- + + +## 一、说明 + +终止因子数据处理适配器是通过**特殊字符或数值**的方式,来达到处理粘包、分包的目的。可随意设置分割因子的值,以及编码方式。不仅如此,还有异常数据设置,在达到设定值时,如果还没有发现分割因子,则抛弃数据。其稳定性仅次于固定包头,且使用场景也比较广泛。 + + +## 二、特点 + +1. 最适用于字符串类(Json,Xml等)的信息交互。 +2. 算法简单,非常容易实现跨语言、跨框架。 +3. 发送普通流数据时,有很小的概率发生提前终止的情况(可设置复杂终止因子来解决)。 + + +## 三、使用 + +客户端与服务器均适用。下列以服务器为例。 + +步骤 + +1. TouchSocketConfig配置中设置,同时指定数据的长度。 +2. 通过Received(事件、方法、插件)中的ByteBlock读取数据(注意:数据长度是byteBlock.Len)。 + +```csharp {10} +TcpService service = new TcpService(); +service.Received += (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7790) }) + .SetDataHandlingAdapter(()=> { return new TerminatorPackageAdapter("\r\n"); }))//配置终止字符适配器,以\r\n结尾。 + .Start();//启动 +``` + +:::tip 提示 + +默认情况下终止因子不会保留在数据中,用户可通过ReserveTerminatorCode属性,设为true,来保留终止因子。 + +::: + +:::caution 注意 + +接收的数据长度是byteBlock.Len,而不是byteBlock.Buffer.Length。 + +::: + +:::tip 提示 + +该适配器,客户端与服务器均适用。 + +::: diff --git a/handbook/docs/tlvdatahandlingadapter.mdx b/handbook/docs/tlvdatahandlingadapter.mdx new file mode 100644 index 000000000..9f2688c1d --- /dev/null +++ b/handbook/docs/tlvdatahandlingadapter.mdx @@ -0,0 +1,113 @@ +--- +id: tlvdatahandlingadapter +title: 三元组编码(TLV)适配器 +--- +import Tag from "@site/src/components/Tag.js"; + +## 一、说明 企业版 + +TLV适配器,定义了一种简单高效的三元组编码,简称TLV编码。它是由数据的类型Tag(T),数据的长度Length(L),数据的值Value(V)构成的一组数据报文。TLV是基于二进制编码的,将数据以(T -L- V)的形式编码为字节数组,即TLV是字节流的数据传输协议。它规定了一帧数据的首个字节或几个字节来表示数据类型,紧接着一个或几个字节表示数据长度,最后是数据的内容。 + +数据协议如下: + +**Tag** + +- 标识数据的类型。 +- 占2字节 +- 大端序无符号整型。 +- 0-9保留系统使用。\[10,65535]客户端自行定义。 +- 已用Tag:0表示Close,载荷Value为关闭消息。 +- 已用Tag:1表示Ping,无载荷,对方收到后必须无条件返回Pong。 +- 已用Tag:2表示Pong,无载荷。 + +**Length** + +- 标识后续Value的长度。 +- 按LengtType的指定,可以用1字节、2字节、4字节来表示长度,分别对应255、65535、2147483647字节的对应值。 +- 1字节时,不区分端序。 +- 2字节时,大端序无符号整型。 +- 4字节时,大端序有符号整型。 +- 默认使用2字节的Ushort类型。 + +**Value** + +载荷数据。可以为任意类型。 + +## 二、使用 + +【适配器使用】 +设置的FixedHeaderType类型后,实际的支持最大数据还受SetMaxPackageSize影响。默认为1024*1024*10字节。 + +```csharp +.SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//如果使用TLVPlugin插件,此步骤可省略。 +``` + +【插件】 + +只需要添加TLVPlugin插件即可。客户端亦然。 + +使用插件,相当于自动设置适配器,并且主动回应Ping。 + +```csharp +var config = new TouchSocketConfig(); + +config.UsePlugin() +.SetMaxPackageSize(1024 * 1024 * 10) +//.SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//如果使用TLVPlugin插件,此步骤可省略。 +.ConfigurePlugins(a => +{ + a.Add()//使用插件,相当于自动设置适配器,并且主动回应Ping。 + .SetLengthType(FixedHeaderType.Int);//设置支持的最大数据类型,该值还受SetMaxPackageSize影响。 +}); +``` + + +## 三、保活机制 + +- TLV数据协议中,定义了Tag=1时为ping,Tag=2时为Pong。所以可以依靠这套机制,进行保活。 +- 实际上,在插件中,已经做了Ping,Pong的处理。客户端可以直接调用。 +- 该操作,服务器也可以直接ping客户端。 + +```csharp +bool result=this.m_client.Ping();//返回值为true时,对端一定在线。此方法服务器也可以主动ping客户端。 +``` + + +### 自动ping + +利用PollingKeepAlivePlugin插件自动Ping。 + + +## 四、构建数据 + +如果对方是其他语言,请使用约定的方式发送数据。 +如果是CSharp的话,构建数据非常简单。 +构建数据时,可用TLVDataFrame构建。或者其值类型构建,此处推荐**ValueTLVDataFrame** +【直接构造】 + +```csharp +ValueTLVDataFrame requestInfo = new ValueTLVDataFrame(10, new byte[] { 0, 1, 2, 3 }); +``` + +【追加型构建】 + +```csharp + ValueTLVDataFrame requestInfo = new ValueTLVDataFrame(); + requestInfo.AppendValue(new byte[] { 0, 1, 2, 3 }); + requestInfo.AppendValue(new byte[] { 4, 5, 6, 7 }); +``` + + +## 五、发送数据 + +构建完数据后,直接发送。 + +```csharp +client.Send(new ValueTLVDataFrame(10,Encoding.UTF8.GetBytes("rrqm")));//推荐写法,如果使用自己Build,则需要明确指出FixedHeaderType的值。 +``` + +:::tip 提示 + +上述创建的适配器客户端与服务器均适用。 + +::: diff --git a/handbook/docs/touchrpcbase.mdx b/handbook/docs/touchrpcbase.mdx new file mode 100644 index 000000000..ad7a31453 --- /dev/null +++ b/handbook/docs/touchrpcbase.mdx @@ -0,0 +1,88 @@ +--- +id: touchrpcbase +title: 基础功能 +--- + +## 一、连接验证 + +连接验证可以初步保证连接客户端的安全性。框架内部默认使用一个string类型的Token作为验证凭证。当然也允许服务器进行其他验证。具体如下: + +### 1.1 Token验证 +在服务器或客户端的配置上,设置VerifyToken,即可实现字符串Token验证。 + +```csharp +var config = new TouchSocketConfig()//配置 + .SetVerifyToken("TouchRpc"); + +``` + +### 1.2 动态验证 + +使用插件,重写**OnHandshaking**相关。然后可以自行判断一些信息,比如:IP地址、元数据等。 + +```csharp +internal class MyTouchRpcPlugin : TouchRpcPluginBase +{ + protected override void OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e) + { + if (e.Metadata["a"] != "a") + { + e.IsPermitOperation = false;//不允许连接 + e.Message = "元数据不对";//同时返回消息 + e.Handled= true;//表示该消息已在此处处理。 + return; + } + if (e.Token == "123") + { + e.IsPermitOperation = true; + e.Handled = true; + return; + } + base.OnHandshaking(client, e); + } +} +``` + +## 二、ID同步 + +在TouchRpc中,存在于服务器的辅助客户端(SocketClient),与远程客户端(Client)是一一对应关系,其ID也**完全一致**。所以在任意一方修改ID(调用ResetID),都会同时修改远程ID。所以合理使用该操作,可以完成复用ID(重置ID)的需求。 + + +## 三、协议扩展 + +协议扩展功能,就是对现有的TouchRpc进行自定义的扩展协议。其目的就是为了应对更加复杂,高要求的需求。 + +例1:当需要广播消息时,可能大家都会想到使用rpc直接进行广播。但是如此一来,每广播一个客户端,就需要序列化一次。因为数据都是一样的,所以多次序列化显得非常没有必要。那么这时候,可以自定义协议,然后先序列化,然后直接广播数据。 + +自定义协议效率如何呢? +自定义协议的效率是非常高的,99%接近于底层协议(可能是tcp、udp、websocket)效率。 + + +### 3.1 使用 + +使用起来是非常简单的,每个TouchRpc客户端或者TouchRpc服务端,都实现了Send方法接口。 +第一个参数为short类型,使用者可以**约定任意数值**(**不要使用小于0的,因为框架内部在使用**)。 + +在**接收方**在OnReceivedProtocolData函数中,已经包含了协议参数,所以直接自行筛选即可。 + +```csharp +internal class MyTouchRpcPlugin : TouchRpcPluginBase +{ + protected override void OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e) + { + if (e.Protocol == 10) + { + //判断完协议以后,从e.ByteBlock可以拿到实际的数据 + //但是需要注意的是,真实数据会整体向右偏移2个字节。 + string msg = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 2, e.ByteBlock.Len - 2); + } + base.OnReceivedProtocolData(client, e); + } +} +``` + +:::caution 注意 + +从ProtocolDataEventArgs解析的ByteBlock,其真实数据会整体向右偏移2个字节。因为前两个字节是ushort的Protocol。 + +::: diff --git a/handbook/docs/touchrpcdescription.mdx b/handbook/docs/touchrpcdescription.mdx new file mode 100644 index 000000000..2bbf22ded --- /dev/null +++ b/handbook/docs/touchrpcdescription.mdx @@ -0,0 +1,115 @@ +--- +id: touchrpcdescription +title: 产品及架构介绍 +--- + + +## 一、说明 + +TouchRpc是一个简单易用,便捷高效,且易于扩展的**自定义数据格式**的**可靠执行传输协议**。 + +【协议格式】 + +| 2字节 | n字节 | + +协议格式非常简单。 +前两个字节为默认端序的小端,int16有符号类型。其中小于0的协议一般不要占用,因为框架在使用。 +后续字节则为本次协议的载荷数据。 + +细心的小伙伴可能会问,这个数据协议没有分包标识啊,也就是无法分辨一个数据包是不是完整的。这是因为TouchRpc支持多种协议运行,可能在一些协议上,就已经涵盖了分包机制,所以为避免过度封装,所以TouchRpc并未制定分包。所以TouchRpc在不同协议工作时,可能实际的数据格式也不相同。 + +例如:在Tcp工作时,其分包算法使用的是[固定包头](./fixedheaderpackageadapter.mdx)。在websocket工作时,使用的就是其自身的分包算法。 + +可能好多人会疑惑,TouchRpc和tcp、udp有什么关系?或者说,类似tcp,本身就是可靠传输协议了,那TouchRpc的可靠又体现在什么地方呢? + +### 1.1 TouchRpc和Tcp、Udp有什么关系? + +TouchRpc像http和websocket一样,也是封装的应用层协议。它可以基于最基本的tcp或udp工作,也能基于http和websocket工作。所以,可以认为TouchRpc是更为高级的应用层协议。 + +### 1.2 Tcp本身就是可靠传输协议了,那TouchRpc的可靠又体现在什么地方呢? + +首先呢,我们得明确,tcp的可靠,是在保持连接的时候,才可靠。当突然断网时,这种可靠将被打破。其次这种可靠是单项的,举例来说,发送方只是负责将数据发给接收方,至于接收方处理了没有,或者处理结果如何,都是未知的。那么这时候聪明的小伙伴就会想到让接收方回复一个状态不就行了?是的,这就是TouchRpc工作的场景之一了。 + +当然,TouchRpc的功能远非上述的两个场景,详细概览如下: + + +## 二、特点 + +### 2.1 基础功能 + +- 支持[连接验证](./touchrpcbase.mdx),也支持动态信息验证。 +- 支持[ID同步](./touchrpcbase.mdx),每个客户端连接到服务器后,自身ID会与服务器ID同步,且支持重置。 +- 支持ssl加密。 +- 支持[协议扩展](./touchrpcbase.mdx)。 + +### 2.2 Rpc功能 + +- 支持常规[rpc](./touchrpcbase.mdx)操作。 +- 支持代理代码生成。 +- 支持自定义类型的参数。 +- 支持out、ref关键字参数。 +- 支持服务器主动Call客户端和客户端之间互Call。 +- 支持调用上下文,可进行服务AOP。 +- 支持异步调用。 +- 支持调用超时、调用中断。 +- 支持全异常反馈,被调用方发生的一切异常,都会传递到调用方。 +- 支持.NET二进制序列化、Json序列化、xml序列化、Fast序列化,以及自定义序列化扩展。 +- 高性能调用,在保证送达但不返回的情况下,10w次调用用时0.8s,在返回的情况下,用时3.9s。 + +### 2.3 文件传输 + +- 支持任意大小的文件传输。 +- 支持断点续传。 +- 支持传输限速。 +- 支持服务器主动向客户端请求、发送文件。 +- 支持客户端之间互相请求、发送文件。 +- 支持小文件快速传输。 +- 支持超大文件多链路、多线程传输。 + +### 2.4 远程操作 + +- 支持创建文件夹。 +- 支持文件的删除、移动、重命名等操作。 +- 支持服务器对客户端的主动操作。 +- 支持客户端之间的操作。 + +### 2.5 流数据方面 + +- 支持发送任意类型的Stream。 +- 支持将远程的流数据映射到本地,然后直接Read或Write。 +- 支持实施传输压缩。 + +### 2.6 Channel数据 + +- 支持独立通道数据,可进行数据隔离。 +- 支持服务器到客户端,客户端到客户端的操作。 + +### 2.7 EventBus + +- 支持事件的创建、订阅、取消、触发等。 +- 支持触发权限。 +- 支持事件广播。 + +### 2.8 Redis + +- 支持string为键的任意类型的数据。 +- 支持服务器向客户端存储。 +- 支持存储持久化。 + + +## 三、场景 + +什么情况下使用TouchRpc比较好呢?首先,你得先了解RPC,了解完后,因为TouchRpc无法跨语言,所以,建议以下场景使用TouchRpc比较稳妥。 + +1. 不需要跨语言的终端,例如:Unity游戏,Winform、WPF、MAUI等软件。 +2. 服务器之间集群。 +3. 扩展微服务,此时可以使用反向RPC实现。 + +*实际上TouchRpc有四个版本,分别为:* + +| **类型** | **特性** | +| --- | --- | +| **Tcp版** | 基于TCP协议,连接性能最好,执行效率最高,支持TouchRpc所有功能。 | +| **Udp版** | 基于UDP Package协议,无连接,执行效率高,仅支持TouchRpc的Rpc功能。 | +| **Http版** | 基于Http握手连接,数据交互仍然使用TCP。连接性能一般,但兼容性强,支持JsonRpc,WebApi,XmlRpc,WebSocket等一系列Http组件,且执行效率和TCP版一样高,支持TouchRpc所有功能。 | +| **WebSocket版** | 该版本是仅适用于Asp.Net Core的版本,特点就是和Asp.Net Core共用端口。但是执行数据使用的是WebSocket,所有效率只有Tcp版的80%。支持TouchRpc所有功能 | \ No newline at end of file diff --git a/handbook/docs/touchsocketbitconverter.mdx b/handbook/docs/touchsocketbitconverter.mdx new file mode 100644 index 000000000..394c59e4d --- /dev/null +++ b/handbook/docs/touchsocketbitconverter.mdx @@ -0,0 +1,34 @@ +--- +id: touchsocketbitconverter +title: 大小端转换器 +--- + +## 一、说明 + +大小端在计算机业界,**Endian**表示数据在存储器中的存放顺序。 + +- **大端模式**,是指**数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中**,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放; +- **小端模式**,是指**数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中**,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。 + +## 二、绝对大端 + +```csharp +byte[] data= TouchSocketBitConverter.BigEndian.GetBytes(10); +//结果 {0,0,0,10} +``` +## 三、绝对小端 + +```csharp +byte[] data= TouchSocketBitConverter.LittleEndian.GetBytes(10); +//结果 {10,0,0,0} +``` + +## 四、默认端 + +TouchSocket系全采用默认“小端”模式。可通过DefaultEndianType属性,修改为大端。 + +```csharp +TouchSocketBitConverter.DefaultEndianType = EndianType.Big; +byte[] data= TouchSocketBitConverter.Default.GetBytes(10); +``` + diff --git a/handbook/docs/transferfile.mdx b/handbook/docs/transferfile.mdx new file mode 100644 index 000000000..0f6d68d91 --- /dev/null +++ b/handbook/docs/transferfile.mdx @@ -0,0 +1,198 @@ +--- +id: transferfile +title: 传输文件 +--- + +**演示:** 可以看到,下图正在上传一个Window的系统镜像文件,大约4.2Gb,传输速度已达到800Mb/s,GC基本上没有释放,性能非常强悍(中间有稍微停顿,因为程序在获取文件MD5值)。 + + + +## 产品应用场景 + +- 常规C/S应用使用场景:开发使用非常方便,连接验证,数据业务,文件传输等一系列功能完全集成。 +- Unity游戏场景:性能卓越,功能丰富,使用方便。 + +## 服务架构 + +- 其传输架构是基于Channel工作的。所以当在同一时间,可进行多个传输并行,且数据互不影响。 +- 在文件传输时,每个连接端和服务器均是平等权利的,所以RRQM将其命名为对点。任意两个对点之间均可Pull(拉取或下载)或Push(推送或上传)文件,例如下图中,Client1、SocketClient1、Client2、SocketClient2四个互相为对点,均可自由传输文件。 + + + +## 一、说明 + +文件传输是每个框架都需要的功能,也是检验一个框架性能的非常重要的指标。 + +TouchRpc开辟了对点文件传输。即,当客户端连接服务器以后,两者可以任意,随时的互相发送文件。不仅如此,即使是客户端之间,可以发送文件。 + +下列示例仅演示由**TcpTouchRpcClient**到**TcpTouchRpcService**(实际上是**TcpTouchRpcSocketClient**)的操作。 + +对点之间可以任意pull(拉取)、push(推送)文件。**接收对点**可以订阅**FileTransfering**和**FileTransfered**事件,来获取相关信息,发起对点直接通过传输控制器或返回值获取传输信息。 + +值得注意的是,**FileTransfered**事件的触发并**不意味着完成传输**,具体结果还要通过**Result**属性值进行判断。 + +## 二、Pull文件 + +由**TcpTouchRpcClient**向**TcpTouchRpcService**发起Pull请求时,相当于由客户端从服务器下载文件。 + +**响应流程:** + +1. 发起Pull请求。 +2. 接收对点(即此处的服务器)触发**FileTransfering**事件。 +3. 返回文件信息,然后检验是否续传等,然后开始接收。 +4. 接收完成或异常。 +5. **接收对点**触发**FileTransfered**事件。 +6. **发起对点**函数返回,控制器状态改变。 + +**具体请求:** + +| 请求参数 | 参数属性 | 请求参数属性描述 | +| --- | --- | --- | +| **FileOperator:**FileOperator是本次传输的请求操作器,主要用于获取传输进度、速度、状态以及取消传输等操作。**接收方的控制器从FileTransfering事件的参数e中获得。** + +| ResourcePath | ResourcePath属性为请求文件在接收对点的路径,当该值为相对路径时,会与接收对点的RootPath组合路径。当为绝对路径时,则会直接访问路径文件**(此时如果不在对点设置条件,则有可能会有文件安全隐患,设置详情**[链接](https://www.yuque.com/eo2w71/rrqm/motlw5#zZBRq)**)**。 | +| | SavePath | SavePath属性是发起对点本地的保存路径。 | +| | Flags | 可通过叠加位域的形式,尝试断点续传。 | +| | CompletedLength | 已完成流长度。 | +| | Speed 函数 | 从上次获取到此次获得的速度。一般请每秒钟调用一次获取速度值。 | +| | Progress | 传输进度,范围0-1。 | +| | Result | 获取传输状态以及状态信息。当ResultCode为Default时,意味着传输正在进行。 | +| | Token | CancellationToken类型的可取消令箭。 | +| | Metadata | string类型的键值对,用于和接收方交互数据。 | + + + +### 示例代码: + +**【服务器】** + +```csharp +var service = new TouchSocketConfig()//配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .UsePlugin() + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + }) + .SetVerifyToken("File")//连接验证口令。 + .BuildWithTcpTouchRpcService();//此处build相当于new TcpTouchRpcService,然后Setup,然后Start。 +service.Logger.Info("服务器成功启动"); +``` + +```csharp +class MyPlugin : TouchRpcPluginBase +{ + protected override void OnFileTransfering(TcpTouchRpcSocketClient client, FileOperationEventArgs e) + { + e.IsPermitOperation = true;//运行操作 + + //有可能是上传,也有可能是下载 + client.Logger.Info($"有客户端请求传输文件,ID={client.ID},请求类型={e.TransferType},请求文件名={e.ResourcePath}"); + } + + protected override void OnFileTransfered(TcpTouchRpcSocketClient client, FileTransferStatusEventArgs e) + { + //传输结束,但是不一定成功,需要从e.Result判断状态。 + client.Logger.Info($"客户端传输文件结束,ID={client.ID},请求类型={e.TransferType},文件名={e.ResourcePath},请求状态={e.Result}"); + } + + protected override void OnHandshaked(TcpTouchRpcSocketClient client, VerifyOptionEventArgs e) + { + client.Logger.Info($"有客户端成功验证,ID={client.ID}"); + } + + protected override void OnDisconnected(TcpTouchRpcSocketClient client, ClientDisconnectedEventArgs e) + { + client.Logger.Info($"有客户端断开,ID={client.ID}"); + base.OnDisconnected(client, e); + } +} +``` + +【客户端】 + +```csharp +TcpTouchRpcClient client = new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("File") + .UsePlugin() + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddFileLogger(); + }) + .ConfigurePlugins(a => + { + a.UseTouchRpcHeartbeat(); + }) + .BuildWithTcpTouchRpcClient(); + +client.Logger.Info("连接成功"); + +Metadata metadata = new Metadata();//传递到服务器的元数据 +metadata.Add("1", "1"); +metadata.Add("2", "2"); + +FileOperator fileOperator = new FileOperator()//实例化本次传输的控制器,用于获取传输进度、速度、状态等。 +{ + Flags = TransferFlags.BreakpointResume,//尝试断点续传,使用断点续传时,会验证MD5值 + SavePath = $@"Windows.iso",//保存路径 + ResourcePath = @"D:\System\Windows.iso",//请求路径 + Metadata= metadata//传递到服务器的元数据 +}; + +fileOperator.Timeout = TimeSpan.FromSeconds(60);//当传输大文件,且启用断点续传时,服务器可能会先计算MD5,而延时响应,所以需要设置超时时间。 + +//此处的作用相当于Timer,定时每秒输出当前的传输进度和速度。 +LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) => +{ + if (fileOperator.Result.ResultCode != ResultCode.Default) + { + loop.Dispose(); + } + + client.Logger.Info($"进度:{fileOperator.Progress},速度:{fileOperator.Speed()}"); +}); + +loopAction.RunAsync(); + + + +//此方法会阻塞,直到传输结束,也可以使用PullFileAsync +IResult result = client.PullFile(fileOperator); + +client.Logger.Info(result.ToString()); +``` + + + +## 三、Push文件 + +Push和Pull操作一致,仅需要在最后调用PushFile即可。 + + + +## 四、客户端之间传输文件 + +该功能支持客户端之间传输文件,使用方法基本一致,只需要额外增加目标Id即可。 + +此外,**服务器**也需要同意路由。需要注意的是,使用该方式文件传输时,还会发起通道路由,所以,需要允许的路由应该还额外增加**通道类型**。 + +```csharp +internal class MyTouchRpcPlugin : TouchRpcPluginBase +{ + protected override void OnRouting(ITouchRpc client, PackageRouterEventArgs e) + { + if (e.RouterType== RouteType.PushFile||e.RouterType== RouteType.PullFile||e.RouterType== RouteType.CreateChannel) + { + e.IsPermitOperation = true; + } + base.OnRouting(client, e); + } +} +``` diff --git a/handbook/docs/udpbroadcast.mdx b/handbook/docs/udpbroadcast.mdx new file mode 100644 index 000000000..1607383d7 --- /dev/null +++ b/handbook/docs/udpbroadcast.mdx @@ -0,0 +1,89 @@ +--- +id: udpbroadcast +title: 组播、广播 +--- + +## 一、说明 + +- 广播BroadCast:主机之间“一对所有”的通讯模式,广播者可以向网络中所有主机发送信息。广播禁止在Internet宽带网上传输(广播风暴)。 +- 多播MultiCast:主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据。 + +## 二、组播使用 + +组播使用非常简单, + +1. 配置中启用广播**UseBroadcast**重要 +2. 在UdpSession**启动**后。调用**JoinMulticastGroup**即可加入组播。调用**DropMulticastGroup**,退出组播。 + +### 2.1 创建组播服务器 + +```csharp {9} +//创建udpService +UdpSession udpService = new UdpSession(); +udpService.Received = (remote, byteBlock, requestInfo) => +{ + Console.WriteLine(byteBlock.ToString()); +}; +udpService.Setup(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7789)) + .UseBroadcast() + .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) + .Start(); + +//加入组播组 +udpService.JoinMulticastGroup(IPAddress.Parse("224.5.6.7")); +``` + +### 2.2 发送组播数据 + +```csharp {7} +UdpSession udpClient = new UdpSession(); +udpClient.Setup(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7788)) + .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) + .Start(); + +udpClient.Send(new IPEndPoint(IPAddress.Parse("224.5.6.7"), 7789), Encoding.UTF8.GetBytes("我是组播")); +``` + +## 三、广播 + +广播使用非常简单, + +1. 配置中启用广播**UseBroadcast**重要 + +### 3.1 创建广播服务器 + +广播接收时,是不需要加入组播组的。 + +```csharp {9} +//创建udpService +UdpSession udpService = new UdpSession(); +udpService.Received = (remote, byteBlock, requestInfo) => +{ + Console.WriteLine(byteBlock.ToString()); +}; +udpService.Setup(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7789)) + .UseBroadcast() + .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) + .Start(); +``` + +### 3.2 发送广播数据 + +```csharp {3,8} +UdpSession udpClient = new UdpSession(); +udpClient.Setup(new TouchSocketConfig() + .UseBroadcast()//该配置在发送广播时是必须的 + .SetBindIPHost(new IPHost(7788)) + .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())) + .Start(); + +udpClient.Send(new IPEndPoint(IPAddress.Parse("255.255.255.255"), 7789), Encoding.UTF8.GetBytes("我是广播")); +``` +:::caution 注意 + +在发送广播数据时,发送端配置UseBroadcast是必须的。 + +::: diff --git a/handbook/docs/udpdatahandlingadapter.mdx b/handbook/docs/udpdatahandlingadapter.mdx new file mode 100644 index 000000000..77c22999b --- /dev/null +++ b/handbook/docs/udpdatahandlingadapter.mdx @@ -0,0 +1,43 @@ +--- +id: udpdatahandlingadapter +sidebar_position: 1 +title: 原始自定义适配器 +sidebar_label: a.原始自定义适配器 +--- + + +## 说明 + +Udp的适配器,主要承担组包和解析数据。其基本逻辑和Tcp相似。但是需要注意的是,Udp适配器是**多线程**操作。在解析数据时,应当充分考虑并发问题。 + +```csharp +class MyUdpAdatper : UdpDataHandlingAdapter +{ + public override bool CanSplicingSend => false; + + protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + + } + + protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length, bool isAsync) + { + + } + + protected override void PreviewSend(EndPoint endPoint, IList transferBytes, bool isAsync) + { + + } + + protected override void Reset() + { + + } +} +``` + + +## 单元测试 + +使用**UdpDataAdapterTester**即可测试。 diff --git a/handbook/docs/udptransmitbigdata.mdx b/handbook/docs/udptransmitbigdata.mdx new file mode 100644 index 000000000..4617bd4d0 --- /dev/null +++ b/handbook/docs/udptransmitbigdata.mdx @@ -0,0 +1,60 @@ +--- +id: udptransmitbigdata +title: 传输大于64K的数据 +--- + +## 一、说明 +UDP由于自身限制,每次发送的数据包最大约64K,但是在局域网内,有时候希望传输更大的数据。所以必须有策略发送。 + +TouchSocket可通过简单设置,实现该功能。 + +## 二、使用 + +只需要在配置中,设置其适配器为**UdpPackageAdapter**类型即可(默认为**NormalUdpDataHandlingAdapter**)。同时可以根据传输数据的大小,修改相关属性,如:**MTU**,**Timeout**等。 + +```csharp +UdpSession udpSession = new UdpSession(); +udpSession.Received += (endpoint, byteBlock, requestInfo) => +{ + +}; + +udpSession.Setup(new TouchSocketConfig() + .SetBindIPHost(new IPHost($"127.0.0.1:7789")) + .SetUdpDataHandlingAdapter(()=> new UdpPackageAdapter()));//加载配置 +udpSession.Start();//启动 +``` +:::caution 注意 + +**此模式下,发送端与接收端均必须为TouchSocket(或实现相同算法),且为相同设置。** + +::: + +## 三、原理 + +在发送时,会将要发送的数据分割成MTU长度的数据。然后为其编号,然后发送,最后由接收方重组。 + +### 3.1 数据格式 + +**ID:由雪花算法生成,在并发请求时1毫秒中有400w分之一的概率发生ID重复。但基本可以忽略不计。** + +| Bit | 说明 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 协议名 | | | | | | | | | | +| byte1 | PackageID为long类型,占用8字节,标识数据包唯一性。 | | | | | | | | | +| byte2 | | | | | | | | | | +| byte3 | | | | | | | | | | +| byte4 | | | | | | | | | | +| byte5 | | | | | | | | | | +| byte6 | | | | | | | | | | +| byte7 | | | | | | | | | | +| byte8 | SN为Ushort占2字节,标识帧序 | | | | | | | | | +| byte9 | | | | | | | | | | +| byte10 | flag,占1字节,最高位标识是否为结束,其他位保留。 | 1 | | | | | | | | +| byte? | 有效载荷数据 | | | | | | | | | +| byte^2 | 当不为终结帧时,此处仍然为载荷数据。当是终结帧时,倒数两个字节为Crc16校验。 | | | | | | | | | +| byte^1 | | | | | | | | | | + + + + diff --git a/handbook/docs/upgrade.mdx b/handbook/docs/upgrade.mdx new file mode 100644 index 000000000..88174cd39 --- /dev/null +++ b/handbook/docs/upgrade.mdx @@ -0,0 +1,329 @@ +--- +id: upgrade +title: 历史更新 +--- + +import useBaseUrl from "@docusaurus/useBaseUrl"; +import Tag from "@site/src/components/Tag.js"; + +:::tip `TouchSocket` 框架升级/发版规则 + +**升级前重点关注可能造成【破坏性】的标签类型**:修复调整移除升级 + +版本号规则:`主版本号.次版本号.修订版本号` + +- 只要【确认】为框架 `bug`,则当天修复,当天发版,修订版本号 `加 1`。 +- 如果 `.csproj` 文件有变更,则当天发版,修订版本号 `加 1`。 +- 其余情况,每年发布一个 `主版本`。 + +::: + +## v1.2.1 + +更新日期:2023.2.2 + +更新描述:兼容性更新。 + + -  优化 TouchRpc支持命名元组。 + -  修复 TouchRpc在调用WaitSend下失败的bug。 + -  修复 TouchRpc在Handshaked时,调用Rpc超时bug。 + -  修复 序列化、反射在unity中使用il2cpp编译的bug。 + -  新增 ByteBlock对于int,long等数据,写入和读取的时候支持大小端指定。 + -  新增 IServicePlugin插件,用于显示通知服务器的启动状态。 + -  调整 将BytePool由静态调整为实例,且由其Default实例作为默认。 +--- + +## v1.1.0 + +更新日期:2023.1.13 + +更新描述:小版本升级,可能会有不兼容。请按下列提示修改。 + + -  优化 TouchRpc系文件传输时,文件夹不存在的提示。 + -  优化 WaitingClient,当客户端断开连接时,可选是否抛出异常。 + -  优化 Fast序列化时。可选序列化只读属性。 + -  修复 多个不稳定Bug。 + -  新增 Tcp客户端新增Disconnecting事件。在主动Close时生效。 + -  调整 多个事件类名称修改,请按照提示修改即可。 + -  移除 多个无用方法参数。 +--- + +## v1.0.0 + +更新日期:2023.1.1 + +更新描述:大版本升级,请详细阅读下列更新日志。 + + -  升级 将最高版本升级为NET7。 + -  优化 Tcp系异步发送效率。 + -  优化 TouchRpc系Channel的稳健性。 + -  修复 多个不稳定Bug。 + -  新增 ValueByteBlock,在简单代码块里面能有效减少创建的类。 + -  新增 MemoryCache类,其功能类似微软官方。但是支持全部泛型。 + -  新增 [IPackage系](https://www.yuque.com/rrqm/touchsocket/ag9tyar9mmhsme0m)。该系列能以超高效率的进行二进制序列化。 + -  新增 SingleTimer类,不可重入的Timer。 + -  新增 Jsonrpc支持自定义适配器解析(EE) + -  新增 严重TouchRpc系OnRouting通知,所有的客户端之间的通信,都必须经过OnRouting的筛查。 + -  新增 TouchRpc系小文件传输,在文件小于1Mb时,其传输效率是常规传输的10倍以上。 + -  新增 TouchRpc系超大文件多链路传输,支持多个客户端协同传输同一个文件,这在互联网环境中,效率比常规传输提高类3-5倍。 + -  新增 TouchRpc系Redis组件,能实现双端共同存储。 + -  调整 严重精简所有命名空间,删除所有三级命名空间。例如:TouchSocket.Core.ByteManager精简为TouchSocket.Core。 + -  调整 严重删除Newtonsoft.Json的源代码嵌入。全局的Json会根据环境动态调整,详情见[Json工具](https://www.yuque.com/rrqm/touchsocket/emqy43#PfVh1) + -  调整 严重框架默认日志由ConsoleLogger,替换为EmptyLogger(不输出任何东西)。 + -  调整 严重Tcp全系,在连接时,ID的初始值使用long类型从0递增。 + -  调整 严重Tcp服务器,将定时清理无数据交互的选项替换为UseCheckClear插件。并且默认没有启用,需要手动加入。 + -  调整 Tcp系适配器,取消部分参数。 + -  调整 DataLock改名为DataSecurity。 + -  调整 EasyAction改名EasyTask。 + -  调整 IMessage改名IMessageObject。 + -  调整 TokenInstance改名MessageInstance。 + -  调整 TouchRpc系,精简常规文件传输操作。 + -  调整 严重TouchRpc系,所有插件通知参数,默认都设为不允许操作,需要手动设置e.IsPermitOperation=true。 + -  移除 Newtonsoft.Json的源代码嵌入。全局的Json会根据环境动态调整,详情见[Json工具](https://www.yuque.com/rrqm/touchsocket/emqy43#PfVh1)。 + +*** 更新示例指南 *** + +(1)适配器参数报错:直接删除isAsync参数,以及isAsync为**True**的所有逻辑。 +![image.png](../static/img/docs/upgrade-1.png) +(2)依赖属性的声明报错:增加泛型约束即可,详情查看[依赖属性](https://www.yuque.com/rrqm/touchsocket/ubk57o#jyzSl) +![image.png](../static/img/docs/upgrade-2.png) +(3)服务端定时清理警告:在配置插件中使用UseCheckClear,并且进行相关配置。 +![image.png](../static/img/docs/upgrade-3.png) +![image.png](../static/img/docs/upgrade-4.png) + +--- + + +## 版本号: 0.7.0 +更新日期:2022.9.21 +更新描述:兼容性更新,增强型更新。**RPC内容需要客户端与服务器同步更新**。 +更新详情: + +优化 +1. Fast二进制序列化,支持自定义序列化。 +2. TouchRpc全系,在文件传输等大型IO时,由于心跳失败而断开连接。 +3. 优化AspNetCore的IContainer。 +4. TcpCommandLinePlugin与WSCommandLinePlugin支持获取客户端参数。 + +新增 +1. 插件实例会以单例注入容器。 +2. 所有适配器支持[缓存超时](https://www.yuque.com/rrqm/touchsocket/83526e6320dfc85fef317d850aa51e92#Z0S0g)设定。 +3. 修改所有事件为委托。 +4. 开放[AspnetCore](https://www.yuque.com/rrqm/touchsocket/55e5bbf58745fa639dba511c7bcd54d1#WqOmh)创建Tcp,Http等服务器的配置。 +5. IClient增加发送、接收的最后时间记录。 +6. Http支持多文件上传(目前仅支持小文件,具体大小以实际运行内存为准,实测100Mb没问题)。 +7. Websocket插件默认会处理Close报文。且插件支持Close。 +8. Rpc支持模板代码重写。 +9. TouchRpc支持元组。 +10. JsonRpc支持Websocket协议。 + +修改 +1. IScopedContainer修改为IContainerProvider + +修复 +1. BytePool回收内存时不判断大小的bug。 + +删除 +1. 无。 + + +--- + +## 版本号: 0.6.0 +更新日期:2022.9.10 +更新描述:兼容性更新,增强型更新。**专为Unity 3D适配**。 +更新详情: + +优化 +1. Gzip的压缩效率。 +2. 发送效率。 + +新增 +1. IDataCompressor数据传输压缩接口。 +2. [RemoteStream](https://www.yuque.com/rrqm/touchsocket/ukq0mu)支持数据读写压缩。 +3. WaitResultPackageBase类,专属非序列化的数据格式化。 +4. DelaySender[延迟缓存发送](https://www.yuque.com/rrqm/touchsocket/1f21a56ee75f896a5b5b38b37b071881#RL0kx)。 + +修改 +1. 无 + +修复 +1. Rpc注册服务为单例时,实际上是瞬时服务的bug。 + +删除 +1. 独立线程发送。 + +--- + +## 版本号: 0.5.0 +更新日期:2022.9.1 +更新描述:兼容性更新,增强型更新。 +更新详情: + +优化 +1. 全局资源的获取逻辑。 + +新增 +1. Container增加卸载注册功能。 +2. FilePool新增FileStorageStream的获取。 +3. http客户端(及websocket)支持代理和验证代理。 +4. TouchRpc全系新增[远程文件操作](https://www.yuque.com/rrqm/touchsocket/pearz0) +5. TouchRpc(除udp)新增[远程流访问](https://www.yuque.com/rrqm/touchsocket/ukq0mu) + +修改 +1. 无 + +修复 +1. 修复Http客户端请求重复Header时的bug。 + +删除 +1. TouchRpc全系的事件操作,推荐直接插件的方式,或者使用TouchRpcActionPlugin然后添加委托。 + + +更新示例 +TouchRpc的相关事件均已使用插件代替。所以请使用插件实现操作。如果需要事件等功能的话,可以用TouchRpcActionPlugin的插件实现。例如: +```csharp +.UsePlugin() +.ConfigurePlugins(a=> +{ + a.Add>()//此处的逻辑可用插件替代完成。 + .SetFileTransfering((client, e) => + { + //有可能是上传,也有可能是下载 + client.Logger.Info($"服务器请求传输文件,ID={client.ID},请求类型={e.TransferType},文件名={e.FileInfo.FileName}"); + }) + .SetFileTransfered((client, e) => + { + //传输结束,但是不一定成功,需要从e.Result判断状态。 + client.Logger.Info($"服务器传输文件结束,ID={client.ID},请求类型={e.TransferType},文件名={e.FileInfo.FileName},请求状态={e.Result}"); + }); +}) +``` + +--- + +## 版本号: 0.4.5 +更新日期:2022.8.25 +更新描述:兼容性更新,增强型更新。 +更新详情: + +优化 +1. FileLogger的写入逻辑,大大地提升了写入效率。 + +新增 +1. [Pipeline适配器](https://www.yuque.com/rrqm/touchsocket/ofnliu) +2. [TLV适配器](https://www.yuque.com/rrqm/touchsocket/wug4bv) +3. WaitingClient支持按条件等待返回。 +4. 日志系统可以筛选日志的输出类型 +5. Rpc系统,可以使用单例、瞬时生命周期的服务。 +6. Rpc系统,可定义持久化模型。 +7. Rpc在使用瞬时生命周期的服务时,可以直接获取调用上下文。 +8. XmlRpc增加调用上下文。 + +修改 +1. 日志系统。 +2. Rpc的调用上下文均采用接口,例如:JsonRpc改为IJsonRpcCallContext,WebApi为IWebApiCallContext。 +3. IRpcActionFilter的参数列表。 + +修复 +1. UdpSession资源不释放的Bug。 + +删除 +1. 冗余元素。 + + +--- + +## 版本号: 0.3.5 +更新日期:2022.8.12 +更新描述:兼容性更新,增强型更新。 +更新详情: + +优化 +1. 各类客户端发送逻辑。 +2. Method类的调用逻辑。 + +新增 +1. 适配器可以设定发送IRequestInfo对象。 +2. 插件新增UseWebSocket的快捷方式。 +3. ReconnectionPlugin插件可以获得重连次数的重载设置。 +4. 【企业版】TcpService的服务注入。 +5. 【企业版】HttpService的服务注入。 +6. 【企业版】IOC容器的共享使用。 + +修改 +1. 各类发送逻辑,以最小化发送方法为基础,其余方法改为扩展方法。 +2. 相关接口的实现。 +3. 由网友[修改GetInfo](https://gitee.com/dotnetchina/TouchSocket/pulls/11) + +修复 +1. Container获取泛型失败bug。 +2. BetweenAnd适配器适配器部分bug。 +3. Router标签无法路由的bug。 +4. 修复TouchRpc推送文件状态不正确bug +5. 修复独立线程在断线重连后发送bug。 + +删除 +1. 冗余的发送方法,不影响上版本任何使用。 + + +--- + + +## 版本号: 0.2.4 +更新日期:2022.7.28 +更新描述:兼容性更新。 +更新详情: + +优化 +1. 优化IOC容器。 +2. 优化Metadata的写入方式。 +3. FileLogger,当日志文件达到1Mb时,会再新增文件序号。 + +新增 +1. Mapper类,支持简单类型映射 +2. Tcp服务器、客户端、udp等增加端口复用配置。 +3. 【企业版】轮询式断线重连。 +4. 【企业版】NATService转发客户端重连。 + +修改 +1. RRQM二进制序列化,改名为Fast。 +2. TouchRpcClient连接时的Metadata,改为由Config配置注入。 +3. FilePool,取消延迟释放机制。 + +修复 +1. 修复WebSocket连接问题 + +删除 +1. 客户端直接调用的短线重连方式。仅保留在Config注入的功能。 + +--- + +## 版本号: 0.1.0 +更新日期:2022.7.16 +更新描述:初始化版本发布。由RRQMSocket迁移而来。 + +迁移指南: +### 1.所有类的命名空间修改,此处如果类型名未修改的话,可由vs智能提示解决。 +### 2.类型名称修改 +| 原类型名称 | 新类型名称 | +| --- | --- | +| RRQMBitConverter | TouchSocketBitConverter | +| RRQMConfig | TouchSocketConfig | +| RRQMConverter | TouchSocketConverter | +| RRQMDependencyObject | DependencyObject | +| MsgEventArgs | MsgEventArgs | +| RRQMEventAgrs | TouchSocketEventArgs | +| IServerProvider | IRpcServer | +| ServerProvider | RpcServer | +| RRQMOverlengthException | OverlengthException | + +### 3.使用逻辑修改 +1)原RRQMConfig设置Logger的方法,改为容器注入: +![image.png](../static/img/docs/upgrade-5.png) +断线重连逻辑 +![image.png](../static/img/docs/upgrade-6.png) +RpcStore使用变更 +如果是仅有一个Rpc解析器,那么可以直接删除RpcStore的声明,从而使用对应的**解析器实例**,直接注册服务。然后可以通过其属性RpcStore,获取到具体的RpcStore实例。 + +如果是有多个解析器,那么,首先可以使用任意一个解析器的RpcStore属性实例,作为主RpcStore,然后添加其他解析器。当然也可以直接new RpcStore,然后统一管理解析器。其中构造函数中的Container容器,可以直接new Container(),但是更建议使用和解析器相同的容器,这样注入的服务会变得全局可用。 diff --git a/handbook/docs/waitingclient.mdx b/handbook/docs/waitingclient.mdx new file mode 100644 index 000000000..b82a0408b --- /dev/null +++ b/handbook/docs/waitingclient.mdx @@ -0,0 +1,92 @@ +--- +id: waitingclient +title: 同步请求 +--- + +## 一、说明 + +有很多小伙伴一直有一些需求: + +1. 客户端发送一个数据,然后等待服务器回应。 +2. 服务器向客户端发送一个数据,然后等待客户端回应。 + +那针对这些需求,可以使用**WaitingClient。**其内部实现了**IWaitSender**接口,能够在发送完成后,等待返回。 + +## 二、创建及使用 + +### 2.1 以TcpClient为例 + +```csharp +TcpClient m_tcpClient = new TcpClient(); +var config = new TouchSocketConfig(); +config.SetRemoteIPHost(new IPHost("127.0.0.1:7789")); + +//载入配置 +m_tcpClient.Setup(config); +m_tcpClient.Connect(); + +//调用GetWaitingClient获取到IWaitingClient的对象。 +var waitClient = m_tcpClient.GetWaitingClient(new WaitingOptions() +{ + AdapterFilter = AdapterFilter.AllAdapter,//表示发送和接收的数据都会经过适配器 + BreakTrigger = true,//表示当连接断开时,会立即触发 + ThrowBreakException = true//表示当连接断开时,是否触发异常 +}); + +//然后使用SendThenReturn。 +byte[] returnData = waitClient.SendThenReturn(Encoding.UTF8.GetBytes("RRQM")); +m_tcpClient.Logger.Info($"收到回应消息:{Encoding.UTF8.GetString(returnData)}"); + +//同时,如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时,可以使用SendThenResponse. +ResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes("RRQM")); +IRequestInfo requestInfo = responsedData.RequestInfo;//同步收到的RequestInfo +``` + +### 2.2 以TcpService为例 + +```csharp +var service = new TcpService(); +service.Received = (client, byteBlock, requestInfo) => +{ + //调用GetWaitingClient获取到IWaitingClient的对象。 + var waitClient = client.GetWaitingClient(new WaitingOptions() + { + AdapterFilter = AdapterFilter.AllAdapter,//表示发送和接收的数据都会经过适配器 + BreakTrigger = true,//表示当连接断开时,会立即触发 + ThrowBreakException = true//表示当连接断开时,是否触发异常 + }); + + //然后使用SendThenReturn。 + byte[] returnData = waitClient.SendThenReturn(Encoding.UTF8.GetBytes("RRQM")); + client.Logger.Info($"收到回应消息:{Encoding.UTF8.GetString(returnData)}"); + + //同时,如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时,可以使用SendThenResponse. + ResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes("RRQM")); + IRequestInfo responseRequestInfo = responsedData.RequestInfo;//同步收到的RequestInfo +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + }) + .ConfigurePlugins(a => + { + //a.Add();//此处可以添加插件 + })) + .Start();//启动 +``` + +:::tip 提示 + +实际上上述行为,只要实现IClient, IDefaultSender, ISend三个接口的类均可以使用。 + +::: + +:::danger 注意事项 + +1. 发送完数据,在等待时,如果收到其他返回数据,则可能得到错误结果。 +2. 发送采用Lock锁,一个事务没结束,另一个请求也发不出去。 + +::: \ No newline at end of file diff --git a/handbook/docs/webapidescription.mdx b/handbook/docs/webapidescription.mdx new file mode 100644 index 000000000..c44bfa9b9 --- /dev/null +++ b/handbook/docs/webapidescription.mdx @@ -0,0 +1,17 @@ +--- +id: webapidescription +title: 产品及架构介绍 +--- + +## 一、说明 + +WebApi是**通用**的RPC调用,与**编程语言无关**,与**操作系统无关**。其路由机制模仿AspNetCore,可实现很多路由机制。但是因为http兼容性错综复杂,所以目前TouchSocket的WebApi仅支持**GET**、**POST**函数。使用体验接近于AspNetCore。 + + + +## 二、特点 + +- 高性能,100个客户端,10w次调用,仅用时17s。 +- **全异常反馈** 。 +- 支持大部分路由规则。 +- 支持js、Android等调用。 diff --git a/handbook/docs/webapiservice.mdx b/handbook/docs/webapiservice.mdx new file mode 100644 index 000000000..0992652a3 --- /dev/null +++ b/handbook/docs/webapiservice.mdx @@ -0,0 +1,78 @@ +--- +id: webapiservice +title: 定义、发布、启动服务 +--- + +## 定义服务 + +在**服务器**端中新建一个类,继承于**RpcServer**类(或实现IRpcServer),然后在该类中写**公共方法**,并用**WebApi**属性标签标记,如果方法有**重载**,需要重新指定**函数键**。 + +- 支持代理生成**注释**。 + +```csharp +public class ApiServer : RpcServer +{ + [Router("[api]/[action]ab")]//此路由会以"/Server/Sumab"实现 + [WebApi(HttpMethodType.GET)] + public int Sum(int a, int b) + { + return a + b; + } + + [WebApi(HttpMethodType.POST)] + public int TestPost(MyClass myClass) + { + return myClass.A + myClass.B; + } + + /// + /// 使用调用上下文,响应文件下载。 + /// + /// + [WebApi(HttpMethodType.GET, MethodFlags = MethodFlags.IncludeCallContext)] + public Task DownloadFile(IWebApiCallContext callContext, string id) + { + if (id == "rrqm") + { + callContext.HttpContext.Response.FromFile(@"D:\System\Windows.iso", callContext.HttpContext.Request); + return Task.FromResult("ok"); + } + return Task.FromResult("id不正确。"); + } +} + +public class MyClass +{ + public int A { get; set; } + public int B { get; set; } +} +``` + + + +## 创建简单服务器 + +```csharp + HttpService service = new HttpService(); + service.Setup(new TouchSocketConfig() + .UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a => + { + a.SetSingletonLogger();//注册一个日志 + }) + .ConfigureRpcStore(a => + { + a.RegisterServer();//注册服务 + }) + .ConfigurePlugins(a => + { + a.Add();//添加支持WebApi的插件。此处可能需要using TouchSocket.Core.Plugins; + })) + .Start(); + + Console.WriteLine("以下连接用于测试webApi"); + Console.WriteLine($"使用:http://127.0.0.1:7789/ApiServer/Sum?a=10&b=20"); + + Console.ReadKey(); +``` diff --git a/handbook/docs/webdataforwarding.mdx b/handbook/docs/webdataforwarding.mdx new file mode 100644 index 000000000..214dfe08e --- /dev/null +++ b/handbook/docs/webdataforwarding.mdx @@ -0,0 +1,16 @@ +--- +id: webdataforwarding +title: Web数据转发Winform项目 +--- + +## 定制方 +网友“软件开发” +## 说明 +应该网友要求,需要实现Web端数据向Winform端转发的功能。 + +## 技术点 + +- 网络编程 +## 效果 +![6.gif](../static/img/docs/webdataforwarding-1.gif) + diff --git a/handbook/docs/websocketdescription.mdx b/handbook/docs/websocketdescription.mdx new file mode 100644 index 000000000..1d6c55b5c --- /dev/null +++ b/handbook/docs/websocketdescription.mdx @@ -0,0 +1,26 @@ +--- +id: websocketdescription +title: 产品及架构介绍 +--- + +## 产品介绍 + +- WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。 + +## 产品特点 + +- 简单易用。 +- 多线程。 +- 内存池 +- 高性能 +- **多种数据接收模式**(IOCP,BIO,Select)。 +- **多地址监听**(可以一次性监听多个IP及端口) + +## 产品应用场景 + +- WebSocket基础使用场景:可跨平台、跨语言使用。 +- 自定义协议解析场景:可解析任意数据格式的WebSocket数据报文。 + +## 服务器架构 + +服务器运行挂载在HttpService上,所以架构和HttpService一致。 diff --git a/handbook/docs/wpfuifiletransfer.mdx b/handbook/docs/wpfuifiletransfer.mdx new file mode 100644 index 000000000..0080ad1bc --- /dev/null +++ b/handbook/docs/wpfuifiletransfer.mdx @@ -0,0 +1,15 @@ +--- +id: wpfuifiletransfer +title: WPF界面、文件传输项目 +--- + +定制方 +凯******有限公司 +说明 +应该公司要求,开发以WPF为技术框架的桌面项目管理应用,其界面类似QQ(此处因为涉及UI版权,不展示实际效果)。并且以RRQMSocket为通信基础,解决项目文件的上传和下载。实际的解决了在2G网,甚至更差的网络环境下的大文件传输。 + +技术点 +- 整体界面:圆角窗体、窗体阴影、最小化嵌入、拖拽效果等。 +- 项目树视图:样式、搜索、定向搜索、搜索项定位、树视图连线。 +- 数据同步:设置配置数据、项目文件数据等。 + diff --git a/handbook/docs/wscommandlineplugin.mdx b/handbook/docs/wscommandlineplugin.mdx new file mode 100644 index 000000000..f48e99bca --- /dev/null +++ b/handbook/docs/wscommandlineplugin.mdx @@ -0,0 +1,64 @@ +--- +id: wscommandlineplugin +title: WSCommandLinePlugin +--- + + +## 命令行执行插件客户端、服务器均支持 + +**WSCommandLinePlugin**命令行执行插件,是用于**WebSocket**的快捷事务实现,让WS在**Text**文本中,用最简单的文字消息即可完成相关事务的执行。该类是抽象类,必须通过继承,在继承类中,声明的具的**公共的**且名称以**Command**结尾的方法,均可被快捷执行。 + +例如:下列插件,即可被普通WS客户端,或服务器便捷调用。 + +调用数据格式: +`Add 10 20`支持Json数据格式 + +```csharp +var service = new HttpService(); + +var config = new TouchSocketConfig(); +config.UsePlugin() + .SetReceiveType(ReceiveType.Auto) + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a=> + { + a.SetSingletonLogger(); + }) + .ConfigurePlugins(a=> + { + a.Add();//添加WebSocket功能 + a.Add();//添加WS命令行事务。 + }); + +service.Setup(config) + .Start(); +service.Logger.Message("Http服务器已启动"); +service.Logger.Message("WS访问:ws://127.0.0.1:7789/ws"); +``` + +```csharp +/// +/// 命令行插件。 +/// 声明的方法必须以"Command"结尾,支持json字符串,参数之间空格隔开。 +/// +class MyWSCommandLinePlugin : WSCommandLinePlugin +{ + public int AddCommand(int a, int b) + { + return a + b; + } + + public SumClass SumCommand(SumClass sumClass) + { + sumClass.Sum = sumClass.A + sumClass.B; + return sumClass; + } +} +class SumClass +{ + public int A { get; set; } + public int B { get; set; } + public int Sum { get; set; } + +} +``` diff --git a/handbook/docs/wsjsonrpc.mdx b/handbook/docs/wsjsonrpc.mdx new file mode 100644 index 000000000..f386af5ac --- /dev/null +++ b/handbook/docs/wsjsonrpc.mdx @@ -0,0 +1,4 @@ +--- +id: wsjsonrpc +title: 基于WS的JsonRpc +--- diff --git a/handbook/docs/xmlrpcdescription.mdx b/handbook/docs/xmlrpcdescription.mdx new file mode 100644 index 000000000..e33927325 --- /dev/null +++ b/handbook/docs/xmlrpcdescription.mdx @@ -0,0 +1,21 @@ +--- +id: xmlrpcdescription +title: 产品及架构介绍 +--- + +XmlRpc是**通用**的工作在**Internet**上的RPC。一个XML-RPC消息就是一个请求体为xml的**http-post**请求,被调用的方法在服务器端执行并将执行结果以xml格式编码后返回。这与**编程语言无关**,与**操作系统无关**。在RRQM中封装了**前后端**,使其使用更加方便、高效。 + + + +## 特点: + +- **异常反馈** 。 +- 支持自定义类型。 +- 支持类型嵌套。 +- 支持Web等调用。 + + + +## 示例代码 + +[XmlRpc示例](https://gitee.com/RRQM_Home/RRQMBox/tree/master/%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3%E7%A4%BA%E4%BE%8B/XmlRpc%E7%A4%BA%E4%BE%8B) diff --git a/handbook/docs/xmlrpcservice.mdx b/handbook/docs/xmlrpcservice.mdx new file mode 100644 index 000000000..d25f489d7 --- /dev/null +++ b/handbook/docs/xmlrpcservice.mdx @@ -0,0 +1,86 @@ +--- +id: xmlrpcservice +title: 定义、发布、启动服务 +--- + + +## 定义服务 + +在**服务器**端中新建一个类,继承于**ServerProvider**类(或实现IServerProvider),然后在该类中写**公共方法**,并用**XmlRpc**属性标签标记,如果方法有**重载**,需要重新指定**函数键**。 + +- 支持代理生成**注释**。 + +```csharp +public class Server : ServerProvider +{ + [XmlRpc] + public int Sum(int a, int b) + { + return a + b; + } + + [XmlRpc] + public int TestClass(MyClass myClass) + { + return myClass.A + myClass.B; + } +} + +public class MyClass +{ + public int A { get; set; } + public int B { get; set; } +} + +``` + + + +## 创建服务解析器 + +服务解析器是实际的服务接收、触发、调用、反馈的实际载体,通俗来说就是**通信服务器**。 + +```csharp +static IRpcParser CreateXmlRpcRpcParser() +{ + HttpService service = new HttpService(); + + service.Setup(new RRQMConfig().UsePlugin() + .SetListenIPHosts(new IPHost[] { new IPHost(7706) })) + .Start(); + + return service.AddPlugin() + .SetProxyToken("RPC") + .SetXmlRpcUrl("/xmlRpc"); +} +``` + + + +## 注册、发布服务 + +添加解析器(添加时需要以键、值方式添加,方便后续查找),然后`注册服务`即可。 + +```csharp +static void Main(string[] args) +{ + RpcService rpcService = new RpcService(); + + //添加解析器,解析器根据传输协议,序列化方式的不同,调用RPC服务 + rpcService.AddRpcParser("xmlRpcParser ", CreateXmlRpcRpcParser()); + + //注册当前程序集的所有服务 + rpcService.RegisterAllServer(); + + //分享代理,代理文件可通过RRQMTool远程获取。 + rpcService.ShareProxy(new IPHost(8848)); + + //或者直接本地导出代理文件。 + //RpcProxyInfo proxyInfo = rpcService.GetProxyInfo(RpcType.RRQMRPC, "RPC"); + //string codeString = CodeGenerator.ConvertToCode("RRQMProxy", proxyInfo.Codes); + + Console.WriteLine("服务器已启动"); + Console.ReadKey(); + +} +``` diff --git a/handbook/docusaurus.config.js b/handbook/docusaurus.config.js new file mode 100644 index 000000000..388e97283 --- /dev/null +++ b/handbook/docusaurus.config.js @@ -0,0 +1,154 @@ +module.exports = { + title: "TouchSocket", + tagline: "网络开发", + url: "https://rrqm_home.gitee.io", + baseUrl: "/touchsocket", + onBrokenLinks: "throw", + onBrokenMarkdownLinks: "warn", + favicon: "img/favicon.ico", + projectName: "TouchSocket", + scripts: [], + themeConfig: { + zoom: { + selector: + ".markdown :not(em) > img,.markdown > img, article img[loading]", + background: { + light: "rgb(255, 255, 255)", + dark: "rgb(50, 50, 50)", + }, + // options you can specify via https://github.com/francoischalifour/medium-zoom#usage + config: {}, + }, + docs: { + sidebar: { + hideable: true, + autoCollapseCategories: true, + }, + }, + prism: { + additionalLanguages: ["powershell", "csharp", "sql"], + }, + navbar: { + title: "TouchSocket", + logo: { + alt: "TouchSocket Logo", + src: "img/TouchSocketlogo.png", + }, + hideOnScroll: true, + items: [ + { + to: "docs", + activeBasePath: "docs", + label: "文档", + position: "left", + }, + { + label: "更新日志", + position: "left", + to: "docs/upgrade" + }, + { + label: "源码", + position: "right", + items: [ + { + label: "Gitee(主库)", + href: "https://gitee.com/rrqm_home/touchsocket", + }, + { + label: "GitHub", + href: "https://github.com/RRQM/TouchSocket", + }, + { + label: "Nuget", + href: "https://www.nuget.org/profiles/rrqm", + }, + ], + }, + { + label: "社区", + position: "right", + href: "https://gitee.com/dotnetchina", + }, + ], + }, + footer: { + style: "dark", + links: [ + { + title: "文档", + items: [ + { + label: "入门", + to: "docs", + }, + { + label: "手册", + to: "docs", + }, + ], + }, + { + title: "社区", + items: [ + { + label: "讨论", + href: "https://gitee.com/rrqm_home/touchsocket/issues", + }, + { + label: "看板", + href: "https://gitee.com/rrqm_home/touchsocket/board", + }, + ], + }, + { + title: "更多", + items: [ + { + label: "仓库", + href: "https://gitee.com/rrqm_home/touchsocket", + }, + ], + }, + ], + copyright: `Copyright © 2020-${new Date().getFullYear()} 若汝棋茗.`, + }, + }, + presets: [ + [ + "@docusaurus/preset-classic", + { + docs: { + sidebarPath: require.resolve("./sidebars.js"), + editUrl: + "https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/", + showLastUpdateTime: true, + showLastUpdateAuthor: true, + sidebarCollapsible: true, + sidebarCollapsed: true, + // sidebarCollapsible: true, + }, + // blog: { + // showReadingTime: true, + // editUrl: + // "https://gitee.com/rrqm_home/touchsocket/tree/master/handbook/", + // }, + theme: { + customCss: require.resolve("./src/css/custom.css"), + }, + }, + ], + ], + plugins: [require.resolve("docusaurus-plugin-image-zoom")], + themes: [ + [ + "@easyops-cn/docusaurus-search-local", + { + hashed: true, + language: ["en", "zh"], + highlightSearchTermsOnTargetPage: true, + explicitSearchResultPath: true, + }, + ], + ], +}; diff --git a/handbook/iconfont.json b/handbook/iconfont.json new file mode 100644 index 000000000..4e53040c1 --- /dev/null +++ b/handbook/iconfont.json @@ -0,0 +1,8 @@ +{ + "symbol_url": "//at.alicdn.com/t/c/font_3276321_js2bwtaq9jc.js", + "use_typescript": false, + "save_dir": "./src/components/iconfonts", + "trim_icon_prefix": "icon", + "unit": "px", + "default_icon_size": 18 +} diff --git a/handbook/package-lock.json b/handbook/package-lock.json new file mode 100644 index 000000000..02f5866fe --- /dev/null +++ b/handbook/package-lock.json @@ -0,0 +1,22322 @@ +{ + "name": "touchsocket", + "version": "v1.2", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "touchsocket", + "version": "v1.2", + "dependencies": { + "@docusaurus/core": "^2.3.1", + "@docusaurus/preset-classic": "^2.3.1", + "@easyops-cn/docusaurus-search-local": "^0.33.5", + "@mdx-js/react": "^1.6.22", + "@svgr/webpack": "^6.5.1", + "animate.css": "^4.1.1", + "clsx": "^1.2.1", + "docusaurus-plugin-image-zoom": "^0.1.1", + "file-loader": "^6.2.0", + "prism-react-renderer": "^1.3.5", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "url-loader": "^4.1.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^2.3.1", + "react-iconfont-cli": "^2.0.2" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", + "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", + "dependencies": { + "@algolia/autocomplete-shared": "1.7.4" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", + "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", + "dependencies": { + "@algolia/autocomplete-shared": "1.7.4" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", + "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" + }, + "node_modules/@algolia/cache-browser-local-storage": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.3.tgz", + "integrity": "sha512-hWH1yCxgG3+R/xZIscmUrWAIBnmBFHH5j30fY/+aPkEZWt90wYILfAHIOZ1/Wxhho5SkPfwFmT7ooX2d9JeQBw==", + "dependencies": { + "@algolia/cache-common": "4.14.3" + } + }, + "node_modules/@algolia/cache-common": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.14.3.tgz", + "integrity": "sha512-oZJofOoD9FQOwiGTzyRnmzvh3ZP8WVTNPBLH5xU5JNF7drDbRT0ocVT0h/xB2rPHYzOeXRrLaQQBwRT/CKom0Q==" + }, + "node_modules/@algolia/cache-in-memory": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.14.3.tgz", + "integrity": "sha512-ES0hHQnzWjeioLQf5Nq+x1AWdZJ50znNPSH3puB/Y4Xsg4Av1bvLmTJe7SY2uqONaeMTvL0OaVcoVtQgJVw0vg==", + "dependencies": { + "@algolia/cache-common": "4.14.3" + } + }, + "node_modules/@algolia/client-account": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.14.3.tgz", + "integrity": "sha512-PBcPb0+f5Xbh5UfLZNx2Ow589OdP8WYjB4CnvupfYBrl9JyC1sdH4jcq/ri8osO/mCZYjZrQsKAPIqW/gQmizQ==", + "dependencies": { + "@algolia/client-common": "4.14.3", + "@algolia/client-search": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.14.3.tgz", + "integrity": "sha512-eAwQq0Hb/aauv9NhCH5Dp3Nm29oFx28sayFN2fdOWemwSeJHIl7TmcsxVlRsO50fsD8CtPcDhtGeD3AIFLNvqw==", + "dependencies": { + "@algolia/client-common": "4.14.3", + "@algolia/client-search": "4.14.3", + "@algolia/requester-common": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "node_modules/@algolia/client-common": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.14.3.tgz", + "integrity": "sha512-jkPPDZdi63IK64Yg4WccdCsAP4pHxSkr4usplkUZM5C1l1oEpZXsy2c579LQ0rvwCs5JFmwfNG4ahOszidfWPw==", + "dependencies": { + "@algolia/requester-common": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.14.3.tgz", + "integrity": "sha512-UCX1MtkVNgaOL9f0e22x6tC9e2H3unZQlSUdnVaSKpZ+hdSChXGaRjp2UIT7pxmPqNCyv51F597KEX5WT60jNg==", + "dependencies": { + "@algolia/client-common": "4.14.3", + "@algolia/requester-common": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "node_modules/@algolia/client-search": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.3.tgz", + "integrity": "sha512-I2U7xBx5OPFdPLA8AXKUPPxGY3HDxZ4r7+mlZ8ZpLbI8/ri6fnu6B4z3wcL7sgHhDYMwnAE8Xr0AB0h3Hnkp4A==", + "dependencies": { + "@algolia/client-common": "4.14.3", + "@algolia/requester-common": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" + }, + "node_modules/@algolia/logger-common": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.14.3.tgz", + "integrity": "sha512-kUEAZaBt/J3RjYi8MEBT2QEexJR2kAE2mtLmezsmqMQZTV502TkHCxYzTwY2dE7OKcUTxi4OFlMuS4GId9CWPw==" + }, + "node_modules/@algolia/logger-console": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.14.3.tgz", + "integrity": "sha512-ZWqAlUITktiMN2EiFpQIFCJS10N96A++yrexqC2Z+3hgF/JcKrOxOdT4nSCQoEPvU4Ki9QKbpzbebRDemZt/hw==", + "dependencies": { + "@algolia/logger-common": "4.14.3" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.3.tgz", + "integrity": "sha512-AZeg2T08WLUPvDncl2XLX2O67W5wIO8MNaT7z5ii5LgBTuk/rU4CikTjCe2xsUleIZeFl++QrPAi4Bdxws6r/Q==", + "dependencies": { + "@algolia/requester-common": "4.14.3" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.14.3.tgz", + "integrity": "sha512-RrRzqNyKFDP7IkTuV3XvYGF9cDPn9h6qEDl595lXva3YUk9YSS8+MGZnnkOMHvjkrSCKfoLeLbm/T4tmoIeclw==" + }, + "node_modules/@algolia/requester-node-http": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.14.3.tgz", + "integrity": "sha512-O5wnPxtDRPuW2U0EaOz9rMMWdlhwP0J0eSL1Z7TtXF8xnUeeUyNJrdhV5uy2CAp6RbhM1VuC3sOJcIR6Av+vbA==", + "dependencies": { + "@algolia/requester-common": "4.14.3" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.14.3.tgz", + "integrity": "sha512-2qlKlKsnGJ008exFRb5RTeTOqhLZj0bkMCMVskxoqWejs2Q2QtWmsiH98hDfpw0fmnyhzHEt0Z7lqxBYp8bW2w==", + "dependencies": { + "@algolia/cache-common": "4.14.3", + "@algolia/logger-common": "4.14.3", + "@algolia/requester-common": "4.14.3" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.0.tgz", + "integrity": "sha512-Gt9jszFJYq7qzXVK4slhc6NzJXnOVmRECWcVjF/T23rNXD9NtWQ0W3qxdg+p9wWIB+VQw3GYV/U2Ha9bRTfs4w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", + "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.6", + "@babel/helper-compilation-targets": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helpers": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.0.tgz", + "integrity": "sha512-GUPcXxWibClgmYJuIwC2Bc2Lg+8b9VjaJ+HlNdACEVt+Wlr1eoU1OPZjZRm7Hzl0gaTsUZNQfeihvZJhG7oc3w==", + "dependencies": { + "@babel/types": "^7.20.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.6.tgz", + "integrity": "sha512-KT10c1oWEpmrIRYnthbzHgoOf6B+Xd6a5yhdbNtdhtG7aO1or5HViuf1TQR36xY/QprXA5nvxO6nAjhJ4y38jw==", + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "dependencies": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz", + "integrity": "sha512-YfDzdnoxHGV8CzqHGyCbFvXg5QESPFkXlHtvdCkesLjjVMT2Adxe4FGUR5ChIb3DxSaXO12iIOCWoXdsUVwnqw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-function-name": "^7.18.6", + "@babel/helper-member-expression-to-functions": "^7.18.6", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", + "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "dependencies": { + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dependencies": { + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.0.tgz", + "integrity": "sha512-aGMjYraN0zosCEthoGLdqot1oRsmxVTQRHadsUPz5QM44Zej2PYRz7XiDE7GqnkZnNtLbOuxqoZw42vkU7+XEQ==", + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0= sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.0.tgz", + "integrity": "sha512-G9VgAhEaICnz8iiJeGJQyVl6J2nTjbW0xeisva0PK6XcKsga7BIaqm4ZF8Rg1Wbaqmy6znspNqhPaPkyukujzg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", + "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", + "dependencies": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.0.tgz", + "integrity": "sha512-sXOohbpHZSk7GjxK9b3dKB7CfqUD5DwOH+DggKzOQ7TXYP+RCSbRykfjQmn/zq+rBjycVRtLf9pYhAaEJA786w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.0.tgz", + "integrity": "sha512-1dIhvZfkDVx/zn2S1aFwlruspTt4189j7fEkH0Y0VyuDM6bQt7bD6kLcz3l4IlLG+e5OReaBz9ROAbttRtUHqA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.18.12.tgz", + "integrity": "sha512-Q99U9/ttiu+LMnRU8psd23HhvwXmKWDQIpocm0JKaICcZHnw+mdQbHm6xnSy7dOl8I5PELakYtNBubNQlBXbZw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz", + "integrity": "sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", + "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz", + "integrity": "sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA==", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-polyfill-corejs2": "^0.3.1", + "babel-plugin-polyfill-corejs3": "^0.5.2", + "babel-plugin-polyfill-regenerator": "^0.3.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.8.tgz", + "integrity": "sha512-p2xM8HI83UObjsZGofMV/EdYjamsDm6MoN3hXPYIT0+gxIoopE+B7rPYKAxfrz9K9PK7JafTTjqYC6qipLExYA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-typescript": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", + "dependencies": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.19.4", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", + "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", + "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-typescript": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", + "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.6.tgz", + "integrity": "sha512-cOu5wH2JFBgMjje+a+fz2JNIWU4GzYpl05oSob3UDvBEh6EuIn+TXFHMmBbhSb+k/4HMzgKCQfEEDArAWNF9Cw==", + "dependencies": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.0.tgz", + "integrity": "sha512-5+cAXQNARgjRUK0JWu2UBwja4JLSO/rBMPJzpsKb+oBF5xlUuCfljQepS4XypBQoiigL0VQjTZy6WiONtUdScQ==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.0", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", + "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@docsearch/css": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.2.tgz", + "integrity": "sha512-dctFYiwbvDZkksMlsmc7pj6W6By/EjnVXJq5TEPd05MwQe+dcdHJgaIn1c8wfsucxHpIsdrUcgSkACHCq6aIhw==" + }, + "node_modules/@docsearch/react": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.2.tgz", + "integrity": "sha512-ugILab2TYKSh6IEHf6Z9xZbOovsYbsdfo60PBj+Bw+oMJ1MHJ7pBt1TTcmPki1hSgg8mysgKy2hDiVdPm7XWSQ==", + "dependencies": { + "@algolia/autocomplete-core": "1.7.4", + "@algolia/autocomplete-preset-algolia": "1.7.4", + "@docsearch/css": "3.3.2", + "algoliasearch": "^4.0.0" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.3.1.tgz", + "integrity": "sha512-0Jd4jtizqnRAr7svWaBbbrCCN8mzBNd2xFLoT/IM7bGfFie5y58oz97KzXliwiLY3zWjqMXjQcuP1a5VgCv2JA==", + "dependencies": { + "@babel/core": "^7.18.6", + "@babel/generator": "^7.18.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.18.6", + "@babel/preset-env": "^7.18.6", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@babel/runtime": "^7.18.6", + "@babel/runtime-corejs3": "^7.18.6", + "@babel/traverse": "^7.18.8", + "@docusaurus/cssnano-preset": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-common": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "@slorber/static-site-generator-webpack-plugin": "^4.0.7", + "@svgr/webpack": "^6.2.1", + "autoprefixer": "^10.4.7", + "babel-loader": "^8.2.5", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.0", + "cli-table3": "^0.6.2", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.23.3", + "css-loader": "^6.7.1", + "css-minimizer-webpack-plugin": "^4.0.0", + "cssnano": "^5.1.12", + "del": "^6.1.1", + "detect-port": "^1.3.0", + "escape-html": "^1.0.3", + "eta": "^2.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "html-minifier-terser": "^6.1.0", + "html-tags": "^3.2.0", + "html-webpack-plugin": "^5.5.0", + "import-fresh": "^3.3.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.6.1", + "postcss": "^8.4.14", + "postcss-loader": "^7.0.0", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.3", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.3", + "rtl-detect": "^1.0.4", + "semver": "^7.3.7", + "serve-handler": "^6.1.3", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.3", + "tslib": "^2.4.0", + "update-notifier": "^5.1.0", + "url-loader": "^4.1.1", + "wait-on": "^6.0.1", + "webpack": "^5.73.0", + "webpack-bundle-analyzer": "^4.5.0", + "webpack-dev-server": "^4.9.3", + "webpack-merge": "^5.8.0", + "webpackbar": "^5.0.2" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.3.1.tgz", + "integrity": "sha512-7mIhAROES6CY1GmCjR4CZkUfjTL6B3u6rKHK0ChQl2d1IevYXq/k/vFgvOrJfcKxiObpMnE9+X6R2Wt1KqxC6w==", + "dependencies": { + "cssnano-preset-advanced": "^5.3.8", + "postcss": "^8.4.14", + "postcss-sort-media-queries": "^4.2.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@docusaurus/logger": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.3.1.tgz", + "integrity": "sha512-2lAV/olKKVr9qJhfHFCaqBIl8FgYjbUFwgUnX76+cULwQYss+42ZQ3grHGFvI0ocN2X55WcYe64ellQXz7suqg==", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.3.1.tgz", + "integrity": "sha512-Gzga7OsxQRpt3392K9lv/bW4jGppdLFJh3luKRknCKSAaZrmVkOQv2gvCn8LAOSZ3uRg5No7AgYs/vpL8K94lA==", + "dependencies": { + "@babel/parser": "^7.18.8", + "@babel/traverse": "^7.18.8", + "@docusaurus/logger": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@mdx-js/mdx": "^1.6.22", + "escape-html": "^1.0.3", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "image-size": "^1.0.1", + "mdast-util-to-string": "^2.0.0", + "remark-emoji": "^2.2.0", + "stringify-object": "^3.3.0", + "tslib": "^2.4.0", + "unified": "^9.2.2", + "unist-util-visit": "^2.0.3", + "url-loader": "^4.1.1", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.3.1.tgz", + "integrity": "sha512-6KkxfAVOJqIUynTRb/tphYCl+co3cP0PlHiMDbi+SzmYxMdgIrwYqH9yAnGSDoN6Jk2ZE/JY/Azs/8LPgKP48A==", + "dependencies": { + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/types": "2.3.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.3.1.tgz", + "integrity": "sha512-f5LjqX+9WkiLyGiQ41x/KGSJ/9bOjSD8lsVhPvYeUYHCtYpuiDKfhZE07O4EqpHkBx4NQdtQDbp+aptgHSTuiw==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-common": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "cheerio": "^1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "tslib": "^2.4.0", + "unist-util-visit": "^2.0.3", + "utility-types": "^3.10.0", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.3.1.tgz", + "integrity": "sha512-DxztTOBEruv7qFxqUtbsqXeNcHqcVEIEe+NQoI1oi2DBmKBhW/o0MIal8lt+9gvmpx3oYtlwmLOOGepxZgJGkw==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/module-type-aliases": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "@types/react-router-config": "^5.0.6", + "combine-promises": "^1.1.0", + "fs-extra": "^10.1.0", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "utility-types": "^3.10.0", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.3.1.tgz", + "integrity": "sha512-E80UL6hvKm5VVw8Ka8YaVDtO6kWWDVUK4fffGvkpQ/AJQDOg99LwOXKujPoICC22nUFTsZ2Hp70XvpezCsFQaA==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "fs-extra": "^10.1.0", + "tslib": "^2.4.0", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.3.1.tgz", + "integrity": "sha512-Ujpml1Ppg4geB/2hyu2diWnO49az9U2bxM9Shen7b6qVcyFisNJTkVG2ocvLC7wM1efTJcUhBO6zAku2vKJGMw==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "fs-extra": "^10.1.0", + "react-json-view": "^1.21.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.3.1.tgz", + "integrity": "sha512-OHip0GQxKOFU8n7gkt3TM4HOYTXPCFDjqKbMClDD3KaDnyTuMp/Zvd9HSr770lLEscgPWIvzhJByRAClqsUWiQ==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.3.1.tgz", + "integrity": "sha512-uXtDhfu4+Hm+oqWUySr3DNI5cWC/rmP6XJyAk83Heor3dFjZqDwCbkX8yWPywkRiWev3Dk/rVF8lEn0vIGVocA==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.3.1.tgz", + "integrity": "sha512-Ww2BPEYSqg8q8tJdLYPFFM3FMDBCVhEM4UUqKzJaiRMx3NEoly3qqDRAoRDGdIhlC//Rf0iJV9cWAoq2m6k3sw==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.3.1.tgz", + "integrity": "sha512-8Yxile/v6QGYV9vgFiYL+8d2N4z4Er3pSHsrD08c5XI8bUXxTppMwjarDUTH/TRTfgAWotRbhJ6WZLyajLpozA==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-common": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "fs-extra": "^10.1.0", + "sitemap": "^7.1.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.3.1.tgz", + "integrity": "sha512-OQ5W0AHyfdUk0IldwJ3BlnZ1EqoJuu2L2BMhqLbqwNWdkmzmSUvlFLH1Pe7CZSQgB2YUUC/DnmjbPKk/qQD0lQ==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/plugin-content-blog": "2.3.1", + "@docusaurus/plugin-content-docs": "2.3.1", + "@docusaurus/plugin-content-pages": "2.3.1", + "@docusaurus/plugin-debug": "2.3.1", + "@docusaurus/plugin-google-analytics": "2.3.1", + "@docusaurus/plugin-google-gtag": "2.3.1", + "@docusaurus/plugin-google-tag-manager": "2.3.1", + "@docusaurus/plugin-sitemap": "2.3.1", + "@docusaurus/theme-classic": "2.3.1", + "@docusaurus/theme-common": "2.3.1", + "@docusaurus/theme-search-algolia": "2.3.1", + "@docusaurus/types": "2.3.1" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/react-loadable": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "dependencies": { + "@types/react": "*", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.3.1.tgz", + "integrity": "sha512-SelSIDvyttb7ZYHj8vEUhqykhAqfOPKk+uP0z85jH72IMC58e7O8DIlcAeBv+CWsLbNIl9/Hcg71X0jazuxJug==", + "dependencies": { + "@docusaurus/core": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/module-type-aliases": "2.3.1", + "@docusaurus/plugin-content-blog": "2.3.1", + "@docusaurus/plugin-content-docs": "2.3.1", + "@docusaurus/plugin-content-pages": "2.3.1", + "@docusaurus/theme-common": "2.3.1", + "@docusaurus/theme-translations": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-common": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "@mdx-js/react": "^1.6.22", + "clsx": "^1.2.1", + "copy-text-to-clipboard": "^3.0.1", + "infima": "0.2.0-alpha.42", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.14", + "prism-react-renderer": "^1.3.5", + "prismjs": "^1.28.0", + "react-router-dom": "^5.3.3", + "rtlcss": "^3.5.0", + "tslib": "^2.4.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.3.1.tgz", + "integrity": "sha512-RYmYl2OR2biO+yhmW1aS5FyEvnrItPINa+0U2dMxcHpah8reSCjQ9eJGRmAgkZFchV1+aIQzXOI1K7LCW38O0g==", + "dependencies": { + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/module-type-aliases": "2.3.1", + "@docusaurus/plugin-content-blog": "2.3.1", + "@docusaurus/plugin-content-docs": "2.3.1", + "@docusaurus/plugin-content-pages": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^1.2.1", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^1.3.5", + "tslib": "^2.4.0", + "use-sync-external-store": "^1.2.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.3.1.tgz", + "integrity": "sha512-JdHaRqRuH1X++g5fEMLnq7OtULSGQdrs9AbhcWRQ428ZB8/HOiaN6mj3hzHvcD3DFgu7koIVtWPQnvnN7iwzHA==", + "dependencies": { + "@docsearch/react": "^3.1.1", + "@docusaurus/core": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/plugin-content-docs": "2.3.1", + "@docusaurus/theme-common": "2.3.1", + "@docusaurus/theme-translations": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "algoliasearch": "^4.13.1", + "algoliasearch-helper": "^3.10.0", + "clsx": "^1.2.1", + "eta": "^2.0.0", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.3.1.tgz", + "integrity": "sha512-BsBZzAewJabVhoGG1Ij2u4pMS3MPW6gZ6sS4pc+Y7czevRpzxoFNJXRtQDVGe7mOpv/MmRmqg4owDK+lcOTCVQ==", + "dependencies": { + "fs-extra": "^10.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@docusaurus/types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.3.1.tgz", + "integrity": "sha512-PREbIRhTaNNY042qmfSE372Jb7djZt+oVTZkoqHJ8eff8vOIc2zqqDqBVc5BhOfpZGPTrE078yy/torUEZy08A==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.6.0", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.73.0", + "webpack-merge": "^5.8.0" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.3.1.tgz", + "integrity": "sha512-9WcQROCV0MmrpOQDXDGhtGMd52DHpSFbKLfkyaYumzbTstrbA5pPOtiGtxK1nqUHkiIv8UwexS54p0Vod2I1lg==", + "dependencies": { + "@docusaurus/logger": "2.3.1", + "@svgr/webpack": "^6.2.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "github-slugger": "^1.4.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.4.0", + "url-loader": "^4.1.1", + "webpack": "^5.73.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.3.1.tgz", + "integrity": "sha512-pVlRpXkdNcxmKNxAaB1ya2hfCEvVsLDp2joeM6K6uv55Oc5nVIqgyYSgSNKZyMdw66NnvMfsu0RBylcwZQKo9A==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.3.1.tgz", + "integrity": "sha512-7n0208IG3k1HVTByMHlZoIDjjOFC8sbViHVXJx0r3Q+3Ezrx+VQ1RZ/zjNn6lT+QBCRCXlnlaoJ8ug4HIVgQ3w==", + "dependencies": { + "@docusaurus/logger": "2.3.1", + "@docusaurus/utils": "2.3.1", + "joi": "^17.6.0", + "js-yaml": "^4.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + } + }, + "node_modules/@easyops-cn/autocomplete.js": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@easyops-cn/autocomplete.js/-/autocomplete.js-0.38.1.tgz", + "integrity": "sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==", + "dependencies": { + "cssesc": "^3.0.0", + "immediate": "^3.2.3" + } + }, + "node_modules/@easyops-cn/docusaurus-search-local": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.33.5.tgz", + "integrity": "sha512-9juHGVUy6N37Ezg1Msz1paMqT3zrQIlRLNJVw/NTG3aSctaYw1W0zAIRieXgBKvBAPkcCn95GsUrcziH13Grsw==", + "dependencies": { + "@docusaurus/plugin-content-docs": "^2.0.0-rc.1", + "@docusaurus/theme-translations": "^2.0.0-rc.1", + "@docusaurus/utils": "^2.0.0-rc.1", + "@docusaurus/utils-common": "^2.0.0-rc.1", + "@docusaurus/utils-validation": "^2.0.0-rc.1", + "@easyops-cn/autocomplete.js": "^0.38.1", + "@node-rs/jieba": "^1.6.0", + "cheerio": "^1.0.0-rc.3", + "clsx": "^1.1.1", + "debug": "^4.2.0", + "fs-extra": "^10.0.0", + "klaw-sync": "^6.0.0", + "lunr": "^2.3.9", + "lunr-languages": "^1.4.0", + "mark.js": "^8.11.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@docusaurus/theme-common": "^2.0.0-rc.1", + "react": "^16.14.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", + "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", + "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==" + }, + "node_modules/@mdx-js/mdx": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", + "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", + "dependencies": { + "@babel/core": "7.12.9", + "@babel/plugin-syntax-jsx": "7.12.1", + "@babel/plugin-syntax-object-rest-spread": "7.8.3", + "@mdx-js/util": "1.6.22", + "babel-plugin-apply-mdx-type-prop": "1.6.22", + "babel-plugin-extract-import-names": "1.6.22", + "camelcase-css": "2.0.1", + "detab": "2.0.4", + "hast-util-raw": "6.0.1", + "lodash.uniq": "4.5.0", + "mdast-util-to-hast": "10.0.1", + "remark-footnotes": "2.0.0", + "remark-mdx": "1.6.22", + "remark-parse": "8.0.3", + "remark-squeeze-paragraphs": "4.0.0", + "style-to-object": "0.3.0", + "unified": "9.2.0", + "unist-builder": "2.0.3", + "unist-util-visit": "2.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@mdx-js/mdx/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@mdx-js/mdx/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", + "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + } + }, + "node_modules/@mdx-js/util": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", + "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@node-rs/jieba": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba/-/jieba-1.6.1.tgz", + "integrity": "sha512-pISKu8NIYKRvZp7mhYZYA8VCjJMqTsCe+mQcFFnAi3GNJsijGjef2peMFeDcvP72X8MsnNeYeg3rHkAybtefyQ==", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@node-rs/jieba-android-arm-eabi": "1.6.1", + "@node-rs/jieba-android-arm64": "1.6.1", + "@node-rs/jieba-darwin-arm64": "1.6.1", + "@node-rs/jieba-darwin-x64": "1.6.1", + "@node-rs/jieba-freebsd-x64": "1.6.1", + "@node-rs/jieba-linux-arm-gnueabihf": "1.6.1", + "@node-rs/jieba-linux-arm64-gnu": "1.6.1", + "@node-rs/jieba-linux-arm64-musl": "1.6.1", + "@node-rs/jieba-linux-x64-gnu": "1.6.1", + "@node-rs/jieba-linux-x64-musl": "1.6.1", + "@node-rs/jieba-win32-arm64-msvc": "1.6.1", + "@node-rs/jieba-win32-ia32-msvc": "1.6.1", + "@node-rs/jieba-win32-x64-msvc": "1.6.1" + } + }, + "node_modules/@node-rs/jieba-android-arm-eabi": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm-eabi/-/jieba-android-arm-eabi-1.6.1.tgz", + "integrity": "sha512-R1YQfsPr7sK3Tq1sM0//6lNAGJK9RnMT0ShITT+7EJYr5OufUBb38lf/mRhrLxR0NF1pycEsMjdCAwrWrHd8rA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-android-arm64": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm64/-/jieba-android-arm64-1.6.1.tgz", + "integrity": "sha512-hBRbj2uLmRFYDw2lWppTAPoyjeXkBKUT84h4fHUQj7CMU94Gc1IWkE4ocCqhvUhbaUXlCpocS9mB0/fc2641bw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-darwin-arm64": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-1.6.1.tgz", + "integrity": "sha512-GeoDe7XVTF6z8JUtD98QvwudsMaHV5EBXs5uO43SobeIkShH3Nujq5gLMD5kWoJXTxDrTgJe4wT42EwUaBEH2Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-darwin-x64": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-x64/-/jieba-darwin-x64-1.6.1.tgz", + "integrity": "sha512-ENHYIS8b8JdMaUXEm0f8Y3+sHXu2UdukG1D/XGUNx+q5cn07HbwIg6L0tlGhE8dw4AhqoWHsExVaZ241Igh4iA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-freebsd-x64": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-freebsd-x64/-/jieba-freebsd-x64-1.6.1.tgz", + "integrity": "sha512-chwB/9edtxqS8Jm3j4RMaJjH9AlXmijUgKv02oMw36e77HKpko+tENUN25Vrn/9GKsKGqIPeXpmCjeXCN1HVQA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm-gnueabihf": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm-gnueabihf/-/jieba-linux-arm-gnueabihf-1.6.1.tgz", + "integrity": "sha512-tsb5fMGj4p8bHGfkf7bJ+HE2jxaixLTp3YnGg5D+kp8+HQRq8cp3ScG5cn8cq0phnJS/zfAp8rVfWInDagzKKQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm64-gnu": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-gnu/-/jieba-linux-arm64-gnu-1.6.1.tgz", + "integrity": "sha512-bSInORkJFfeZNR+i4rFoSZGbwkQtQlnZ0XfT/noTK9JUBDYErqQZPFjoaYAU45NWTk7p6Zkg30SuV1NTdWLaPw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-arm64-musl": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-musl/-/jieba-linux-arm64-musl-1.6.1.tgz", + "integrity": "sha512-qphL6xM7owfU8Hsh7GX73SDr/iApbnc+35mSLxbibAfCQnY89+WcBeWUUOSGM/Ov3VFaq4pyVlDFj0YjR01W2w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-x64-gnu": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-1.6.1.tgz", + "integrity": "sha512-f6hhlrbi2wel0xZG7m3Wvksimt9MSu1f3aYO2Kwavf4qjMRZqJzLz9HlCJAal6AXB9Qgg+685P+gftsWve47qw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-linux-x64-musl": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-1.6.1.tgz", + "integrity": "sha512-cTVcdR6zWqpnmdEUyWEII9zfE5lTeWN53TbiOPx8TCA+291/31Vqd7GA8YEPndUO8qgCx5uShSDFStBAEIhYNQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-win32-arm64-msvc": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-arm64-msvc/-/jieba-win32-arm64-msvc-1.6.1.tgz", + "integrity": "sha512-YuOTrjHazDraXcGXRHgPQ53nyJuH8QtTCngYKjAzxsdt8uN+txb1AY69OLMLBBZqLTOwY9dgcW70vGiLQMCTeg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-win32-ia32-msvc": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-ia32-msvc/-/jieba-win32-ia32-msvc-1.6.1.tgz", + "integrity": "sha512-4+E843ImGpVlZ+LlT9E/13NHmmUg3UHQx419D6fFMorJUUQuK4cZJfE1z4tCgcrbV8S5Wew5LIFywlJeJLu0LQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/jieba-win32-x64-msvc": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-x64-msvc/-/jieba-win32-x64-msvc-1.6.1.tgz", + "integrity": "sha512-veXNwm2VlseOzl7vaC7A/nZ4okp5/6edN7/Atj6mXnUbze/m/my5Rv5zUcW3U1D9VElnQ3srCHCa5vXljJuk6g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@slorber/static-site-generator-webpack-plugin": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz", + "integrity": "sha512-Ug7x6z5lwrz0WqdnNFOMYrDQNTPAprvHLSh6+/fmml3qUiz6l5eq+2MzLKWtn/q5K5NpSiFsZTP/fck/3vjSxA==", + "dependencies": { + "eval": "^0.1.8", + "p-map": "^4.0.0", + "webpack-sources": "^3.2.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", + "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz", + "integrity": "sha512-8zYdkym7qNyfXpWvu4yq46k41pyNM9SOstoWhKlm+IfdCE1DdnRKeMUPsWIEO/DEkaWxJ8T9esNdG3QwQ93jBA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.5.0.tgz", + "integrity": "sha512-NFdxMq3xA42Kb1UbzCVxplUc0iqSyM9X8kopImvFnB+uSDdzIHOdbs1op8ofAvVRtbg4oZiyRl3fTYeKcOe9Iw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", + "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", + "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", + "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", + "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", + "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", + "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", + "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/core/node_modules/@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@svgr/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", + "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", + "dependencies": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", + "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "^6.0.0" + } + }, + "node_modules/@svgr/plugin-jsx/node_modules/@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@svgr/plugin-jsx/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", + "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", + "dependencies": { + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "svgo": "^2.8.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz", + "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==", + "dependencies": { + "@babel/core": "^7.19.6", + "@babel/plugin-transform-react-constant-elements": "^7.18.12", + "@babel/preset-env": "^7.19.4", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@svgr/core": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "@svgr/plugin-svgo": "^6.5.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack/node_modules/@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@svgr/webpack/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.8", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", + "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "node_modules/@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "node_modules/@types/node": { + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==" + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "node_modules/@types/parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", + "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "node_modules/@types/react": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.0.tgz", + "integrity": "sha512-7+K7zEQYu7NzOwQGLR91KwWXXDzmTFODRVizJyIALf6RfLv2GDpqpknX64pvRVILXCpXi7O/pua8NGk44dLvJw==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.18", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz", + "integrity": "sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.6.tgz", + "integrity": "sha512-db1mx37a1EJDf1XeX8jJN7R3PZABmJQXR8r28yUjVMFSjkmnQo6X6pOEEmNl+Tp2gYQOGPdYbFIipBtdElZ3Yg==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", + "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" + }, + "node_modules/@types/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/algoliasearch": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.3.tgz", + "integrity": "sha512-GZTEuxzfWbP/vr7ZJfGzIl8fOsoxN916Z6FY2Egc9q2TmZ6hvq5KfAxY89pPW01oW/2HDEKA8d30f9iAH9eXYg==", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.14.3", + "@algolia/cache-common": "4.14.3", + "@algolia/cache-in-memory": "4.14.3", + "@algolia/client-account": "4.14.3", + "@algolia/client-analytics": "4.14.3", + "@algolia/client-common": "4.14.3", + "@algolia/client-personalization": "4.14.3", + "@algolia/client-search": "4.14.3", + "@algolia/logger-common": "4.14.3", + "@algolia/logger-console": "4.14.3", + "@algolia/requester-browser-xhr": "4.14.3", + "@algolia/requester-common": "4.14.3", + "@algolia/requester-node-http": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.11.3.tgz", + "integrity": "sha512-TbaEvLwiuGygHQIB8y+OsJKQQ40+JKUua5B91X66tMUHyyhbNHvqyr0lqd3wCoyKx7WybyQrC0WJvzoIeh24Aw==", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/animate.css": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/animate.css/-/animate.css-4.1.1.tgz", + "integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==" + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "deprecated": "Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410", + "dev": true, + "dependencies": { + "follow-redirects": "1.5.10" + } + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-plugin-apply-mdx-type-prop": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", + "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", + "dependencies": { + "@babel/helper-plugin-utils": "7.10.4", + "@mdx-js/util": "1.6.22" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@babel/core": "^7.11.6" + } + }, + "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-extract-import-names": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", + "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", + "dependencies": { + "@babel/helper-plugin-utils": "7.10.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/babel-plugin-extract-import-names/node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base16": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", + "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bonjour-service": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.11.tgz", + "integrity": "sha512-drMprzr2rDTCtgEE3VgdA9uUFaUHF+jXduwYSThHJnKMYM+FhI9Z3ph+TX3xy0LtgYHae6CHYPJ/2UnK8nQHcA==", + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.4" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24= sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001427", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001427.tgz", + "integrity": "sha512-lfXQ73oB9c8DP5Suxaszm+Ta2sr/4tf8+381GkIm1MLj/YdLf+rEDyDSRCzeltuyTVGm+/s18gdZ0q+Wmp8VsQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/ccount": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", + "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/clean-css": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", + "integrity": "sha512-YYuuxv4H/iNb1Z/5IbMRoxgrzjWGhOEFfd+groZ5dMCVkpENiMZmwspdrzBo9286JjM1gZJPAyL7ZIdzuvu2AQ==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", + "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", + "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/colord": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", + "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==" + }, + "node_modules/colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combine-promises": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", + "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ= sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw= sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-text-to-clipboard": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", + "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", + "integrity": "sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.23.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.3.tgz", + "integrity": "sha512-oAKwkj9xcWNBAvGbT//WiCdOMpb9XQG92/Fe3ABFM/R16BsHgePG00mFOgKf7IsCtfj8tA1kHtf/VwErhriz5Q==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", + "dependencies": { + "browserslist": "^4.21.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", + "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==", + "deprecated": "core-js-pure@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js-pure.", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", + "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.0.0.tgz", + "integrity": "sha512-7ZXXRzRHvofv3Uac5Y+RkWRNo0ZMlcg8e9/OtrqUYmwDWJo+qs67GvdeFrXLsFb7czKNwjQhPkM0avlIYl+1nA==", + "dependencies": { + "cssnano": "^5.1.8", + "jest-worker": "^27.5.1", + "postcss": "^8.4.13", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.12.tgz", + "integrity": "sha512-TgvArbEZu0lk/dvg2ja+B7kYoD7BBCmn3+k58xD0qjrGHsFzXY/wKTo9M5egcUCabPol05e/PVoIu79s2JN4WQ==", + "dependencies": { + "cssnano-preset-default": "^5.2.12", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.9.tgz", + "integrity": "sha512-njnh4pp1xCsibJcEHnWZb4EEzni0ePMqPuPNyuWT4Z+YeXmsgqNuTPIljXFEXhxGsWs9183JkXgHxc1TcsahIg==", + "dependencies": { + "autoprefixer": "^10.4.12", + "cssnano-preset-default": "^5.2.13", + "postcss-discard-unused": "^5.1.0", + "postcss-merge-idents": "^5.1.1", + "postcss-reduce-idents": "^5.2.0", + "postcss-zindex": "^5.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.13", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz", + "integrity": "sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.0", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.3", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.1", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + }, + "node_modules/detab": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", + "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", + "dependencies": { + "repeat-string": "^1.5.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", + "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/detect-port/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0= sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "node_modules/dns-packet": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.1.tgz", + "integrity": "sha512-spBwIj0TK0Ey3666GwIdWVfUpLyubpU53BTCu8iPn4r4oXd9O14Hjg3EHw3ts2oed77/SeckunUYCyRlSngqHw==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/docusaurus-plugin-image-zoom": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/docusaurus-plugin-image-zoom/-/docusaurus-plugin-image-zoom-0.1.1.tgz", + "integrity": "sha512-cJXo5TKh9OR1gE4B5iS5ovLWYYDFwatqRm00iXFPOaShZG99l5tgkDKgbQPAwSL9wg4I+wz3aMwkOtDhMIpKDQ==", + "dependencies": { + "medium-zoom": "^1.0.6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", + "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.0.0.tgz", + "integrity": "sha512-NqE7S2VmVwgMS8yBxsH4VgNQjNjLq1gfGU0u9I6Cjh468nPRMoDfGdK9n1p/3Dvsw3ebklDkZsFAnKJ9sefjBA==", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", + "dependencies": { + "fbjs": "^3.0.0" + } + }, + "node_modules/fbjs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz", + "integrity": "sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==", + "dependencies": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flux": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", + "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", + "dependencies": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.1" + }, + "peerDependencies": { + "react": "^15.0.2 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dependencies": { + "debug": "=3.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/follow-redirects/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/follow-redirects/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.1.tgz", + "integrity": "sha512-x1wumpHOEf4gDROmKTaB6i4/Q6H3LwmjVO7fIX47vBwlZbtPjU33hgoMuD/Q/y6SU8bnuYSoN6ZQOLshGp0T/g==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/github-slugger": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", + "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/hast-to-hyperscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", + "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", + "dependencies": { + "@types/unist": "^2.0.3", + "comma-separated-tokens": "^1.0.0", + "property-information": "^5.3.0", + "space-separated-tokens": "^1.0.0", + "style-to-object": "^0.3.0", + "unist-util-is": "^4.0.0", + "web-namespaces": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", + "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", + "dependencies": { + "@types/parse5": "^5.0.0", + "hastscript": "^6.0.0", + "property-information": "^5.0.0", + "vfile": "^4.0.0", + "vfile-location": "^3.2.0", + "web-namespaces": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", + "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", + "dependencies": { + "@types/hast": "^2.0.0", + "hast-util-from-parse5": "^6.0.0", + "hast-util-to-parse5": "^6.0.0", + "html-void-elements": "^1.0.0", + "parse5": "^6.0.0", + "unist-util-position": "^3.0.0", + "vfile": "^4.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/hast-util-to-parse5": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", + "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", + "dependencies": { + "hast-to-hyperscript": "^9.0.0", + "property-information": "^5.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", + "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz", + "integrity": "sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconfont-parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iconfont-parser/-/iconfont-parser-1.0.0.tgz", + "integrity": "sha512-3RJceYHEjaqYyeDdfSAb1vP1x1Eb7ZtC9Xwetj+axm85sBlJU7HMvdNLVpwm/3g5eghYOdkQK+epUITZGAIqKQ==", + "dev": true, + "dependencies": { + "axios": "^0.19.0", + "colors": "^1.4.0", + "tslib": "^1.10.0", + "xml2js": "^0.4.22" + } + }, + "node_modules/iconfont-parser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.1.tgz", + "integrity": "sha512-VAwkvNSNGClRw9mDHhc5Efax8PLlsOGcUTh0T/LIriC8vPA3U5PdqXWqkz406MoYHMKW8Uf9gWr05T/rYB44kQ==", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" + }, + "node_modules/immer": { + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", + "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o= sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.42", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.42.tgz", + "integrity": "sha512-ift8OXNbQQwtbIt6z16KnSWP7uJ/SysSMFI4F87MNRTicypfl4Pv3E2OGVv6N3nSZFJvA8imYulCBS64iyHYww==", + "engines": { + "node": ">=12" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8= sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk= sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-whitespace-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", + "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-word-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", + "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8= sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", + "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168= sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, + "node_modules/lunr-languages": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.9.0.tgz", + "integrity": "sha512-Be5vFuc8NAheOIjviCRms3ZqFFBlzns3u9DXpPSZvALetgnydAN0poV71pVLFn0keYy/s4VblMMkqewTLe+KPg==" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==" + }, + "node_modules/markdown-escapes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", + "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", + "dependencies": { + "unist-util-remove": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", + "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "dependencies": { + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", + "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "mdast-util-definitions": "^4.0.0", + "mdurl": "^1.0.0", + "unist-builder": "^2.0.0", + "unist-util-generated": "^1.0.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/medium-zoom": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.0.8.tgz", + "integrity": "sha512-CjFVuFq/IfrdqesAXfg+hzlDKu6A2n80ZIq0Kl9kWjoHh9j1N9Uvk5X0/MmN0hOfm5F9YBswlClhcwnmtwz7gA==" + }, + "node_modules/memfs": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", + "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", + "dependencies": { + "fs-monkey": "1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mrmime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", + "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.4.tgz", + "integrity": "sha512-XkCYOU+rr2Ft3LI6w4ye51M3VK31qJXFIxu0XLw169PtKG0Zx47OrXeVW/GCYOfpC9s1yyyf1S+L8/4LY0J9Zw==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, + "node_modules/nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", + "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "dependencies": { + "@types/retry": "^0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" + }, + "node_modules/parse5": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "dependencies": { + "entities": "^4.3.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.0.tgz", + "integrity": "sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==", + "dependencies": { + "browserslist": "^4.16.6", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-unused": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", + "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.0.tgz", + "integrity": "sha512-IDyttebFzTSY6DI24KuHUcBjbAev1i+RyICoPEWcAstZsj03r533uMXtDn506l6/wlsRYiS5XBdx7TpccCsyUg==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-merge-idents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", + "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz", + "integrity": "sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", + "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz", + "integrity": "sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.3.0.tgz", + "integrity": "sha512-jAl8gJM2DvuIJiI9sL1CuiHtKM4s5aEIomkU8G3LFvbP+p8i7Sz8VV63uieTgoewGqKbi+hxBTiOKJlB35upCg==", + "dependencies": { + "sort-css-media-queries": "2.1.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.16" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/postcss-zindex": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", + "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", + "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", + "peerDependencies": { + "react": ">=0.14.9" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4= sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", + "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" + }, + "node_modules/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo= sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", + "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==", + "dependencies": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", + "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "node_modules/react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, + "node_modules/react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-iconfont-cli": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-iconfont-cli/-/react-iconfont-cli-2.0.2.tgz", + "integrity": "sha512-43NP+dsk08XwJf8oXfrDwHk1WeE76vy1Xzbd2zz7WjjxsdblF9h/oalFMPclZSibIirwsckz3L0IV+42Yu//iQ==", + "dev": true, + "dependencies": { + "colors": "^1.3.3", + "glob": "^7.1.4", + "iconfont-parser": "^1.0.0", + "lodash": "^4.17.15", + "minimist": "^1.2.5", + "mkdirp": "^0.5.1", + "tslib": "^1.10.0" + }, + "bin": { + "iconfont": "commands/help.js", + "iconfont-h5": "commands/createIcon.js", + "iconfont-init": "commands/createJson.js" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-iconfont-cli/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-json-view": { + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", + "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", + "dependencies": { + "flux": "^4.0.1", + "react-base16-styling": "^0.6.0", + "react-lifecycles-compat": "^3.0.4", + "react-textarea-autosize": "^8.3.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^16.3.0 || ^15.5.4", + "react-dom": "^17.0.0 || ^16.3.0 || ^15.5.4" + } + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "dependencies": { + "@types/react": "*", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.3.tgz", + "integrity": "sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-Ov0tGPMBgqmbu5CDmN++tv2HQ9HlWDuWIIqn4b88gjlAN5IHI+4ZUZRcpz9Hl0azFIwihbLDYw1OiHGRo7ZIng==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.3", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-textarea-autosize": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.0.tgz", + "integrity": "sha512-YrTFaEHLgJsi8sJVYHBzYn+mkP3prGkmP2DKb/tm0t7CLJY5t1Rxix8070LAKb0wby7bl/lf2EeHkuMihMZMwQ==", + "dependencies": { + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dependencies": { + "minimatch": "3.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/recursive-readdir/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", + "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + }, + "node_modules/regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", + "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", + "dependencies": { + "emoticon": "^3.2.0", + "node-emoji": "^1.10.0", + "unist-util-visit": "^2.0.3" + } + }, + "node_modules/remark-footnotes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", + "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", + "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", + "dependencies": { + "@babel/core": "7.12.9", + "@babel/helper-plugin-utils": "7.10.4", + "@babel/plugin-proposal-object-rest-spread": "7.12.1", + "@babel/plugin-syntax-jsx": "7.12.1", + "@mdx-js/util": "1.6.22", + "is-alphabetical": "1.0.4", + "remark-parse": "8.0.3", + "unified": "9.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx/node_modules/@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/remark-mdx/node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "node_modules/remark-mdx/node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", + "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/remark-mdx/node_modules/@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/remark-mdx/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/remark-mdx/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remark-mdx/node_modules/unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", + "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", + "dependencies": { + "ccount": "^1.0.0", + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^2.0.0", + "vfile-location": "^3.0.0", + "xtend": "^4.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", + "dependencies": { + "mdast-squeeze-paragraphs": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc= sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o= sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rtl-detect": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", + "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" + }, + "node_modules/rtlcss": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", + "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", + "dependencies": { + "find-up": "^5.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.3.11", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + } + }, + "node_modules/rtlcss/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rtlcss/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rtlcss/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rtlcss/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", + "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.0.4", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/sitemap": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", + "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", + "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, + "node_modules/state-toggle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", + "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/std-env": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.0.1.tgz", + "integrity": "sha512-mC1Ps9l77/97qeOZc+HrOL7TIaOboHqMZ24dGVQrlxFcpPpfCHpH+qfUT7Dz+6mlG8+JPA1KfBQo19iC/+Ngcw==" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", + "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==", + "dependencies": { + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz", + "integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.7", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.7.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0= sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==" + }, + "node_modules/trim-trailing-lines": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", + "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/type-fest": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", + "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", + "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unherit": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", + "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", + "dependencies": { + "inherits": "^2.0.0", + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unist-builder": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", + "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-generated": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", + "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", + "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", + "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", + "dependencies": { + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", + "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", + "dependencies": { + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/update-notifier/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/use-composed-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", + "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", + "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", + "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/wait-on": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", + "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "dependencies": { + "axios": "^0.25.0", + "joi": "^17.6.0", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "rxjs": "^7.5.4" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/wait-on/node_modules/axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "dependencies": { + "follow-redirects": "^1.14.7" + } + }, + "node_modules/wait-on/node_modules/follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", + "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", + "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "dependencies": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz", + "integrity": "sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.1", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz", + "integrity": "sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpackbar": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", + "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.3", + "pretty-time": "^1.1.0", + "std-env": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + }, + "node_modules/wrap-ansi": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", + "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", + "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + }, + "dependencies": { + "@algolia/autocomplete-core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", + "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", + "requires": { + "@algolia/autocomplete-shared": "1.7.4" + } + }, + "@algolia/autocomplete-preset-algolia": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", + "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", + "requires": { + "@algolia/autocomplete-shared": "1.7.4" + } + }, + "@algolia/autocomplete-shared": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", + "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" + }, + "@algolia/cache-browser-local-storage": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.3.tgz", + "integrity": "sha512-hWH1yCxgG3+R/xZIscmUrWAIBnmBFHH5j30fY/+aPkEZWt90wYILfAHIOZ1/Wxhho5SkPfwFmT7ooX2d9JeQBw==", + "requires": { + "@algolia/cache-common": "4.14.3" + } + }, + "@algolia/cache-common": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.14.3.tgz", + "integrity": "sha512-oZJofOoD9FQOwiGTzyRnmzvh3ZP8WVTNPBLH5xU5JNF7drDbRT0ocVT0h/xB2rPHYzOeXRrLaQQBwRT/CKom0Q==" + }, + "@algolia/cache-in-memory": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.14.3.tgz", + "integrity": "sha512-ES0hHQnzWjeioLQf5Nq+x1AWdZJ50znNPSH3puB/Y4Xsg4Av1bvLmTJe7SY2uqONaeMTvL0OaVcoVtQgJVw0vg==", + "requires": { + "@algolia/cache-common": "4.14.3" + } + }, + "@algolia/client-account": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.14.3.tgz", + "integrity": "sha512-PBcPb0+f5Xbh5UfLZNx2Ow589OdP8WYjB4CnvupfYBrl9JyC1sdH4jcq/ri8osO/mCZYjZrQsKAPIqW/gQmizQ==", + "requires": { + "@algolia/client-common": "4.14.3", + "@algolia/client-search": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "@algolia/client-analytics": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.14.3.tgz", + "integrity": "sha512-eAwQq0Hb/aauv9NhCH5Dp3Nm29oFx28sayFN2fdOWemwSeJHIl7TmcsxVlRsO50fsD8CtPcDhtGeD3AIFLNvqw==", + "requires": { + "@algolia/client-common": "4.14.3", + "@algolia/client-search": "4.14.3", + "@algolia/requester-common": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "@algolia/client-common": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.14.3.tgz", + "integrity": "sha512-jkPPDZdi63IK64Yg4WccdCsAP4pHxSkr4usplkUZM5C1l1oEpZXsy2c579LQ0rvwCs5JFmwfNG4ahOszidfWPw==", + "requires": { + "@algolia/requester-common": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "@algolia/client-personalization": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.14.3.tgz", + "integrity": "sha512-UCX1MtkVNgaOL9f0e22x6tC9e2H3unZQlSUdnVaSKpZ+hdSChXGaRjp2UIT7pxmPqNCyv51F597KEX5WT60jNg==", + "requires": { + "@algolia/client-common": "4.14.3", + "@algolia/requester-common": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "@algolia/client-search": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.3.tgz", + "integrity": "sha512-I2U7xBx5OPFdPLA8AXKUPPxGY3HDxZ4r7+mlZ8ZpLbI8/ri6fnu6B4z3wcL7sgHhDYMwnAE8Xr0AB0h3Hnkp4A==", + "requires": { + "@algolia/client-common": "4.14.3", + "@algolia/requester-common": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" + }, + "@algolia/logger-common": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.14.3.tgz", + "integrity": "sha512-kUEAZaBt/J3RjYi8MEBT2QEexJR2kAE2mtLmezsmqMQZTV502TkHCxYzTwY2dE7OKcUTxi4OFlMuS4GId9CWPw==" + }, + "@algolia/logger-console": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.14.3.tgz", + "integrity": "sha512-ZWqAlUITktiMN2EiFpQIFCJS10N96A++yrexqC2Z+3hgF/JcKrOxOdT4nSCQoEPvU4Ki9QKbpzbebRDemZt/hw==", + "requires": { + "@algolia/logger-common": "4.14.3" + } + }, + "@algolia/requester-browser-xhr": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.3.tgz", + "integrity": "sha512-AZeg2T08WLUPvDncl2XLX2O67W5wIO8MNaT7z5ii5LgBTuk/rU4CikTjCe2xsUleIZeFl++QrPAi4Bdxws6r/Q==", + "requires": { + "@algolia/requester-common": "4.14.3" + } + }, + "@algolia/requester-common": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.14.3.tgz", + "integrity": "sha512-RrRzqNyKFDP7IkTuV3XvYGF9cDPn9h6qEDl595lXva3YUk9YSS8+MGZnnkOMHvjkrSCKfoLeLbm/T4tmoIeclw==" + }, + "@algolia/requester-node-http": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.14.3.tgz", + "integrity": "sha512-O5wnPxtDRPuW2U0EaOz9rMMWdlhwP0J0eSL1Z7TtXF8xnUeeUyNJrdhV5uy2CAp6RbhM1VuC3sOJcIR6Av+vbA==", + "requires": { + "@algolia/requester-common": "4.14.3" + } + }, + "@algolia/transporter": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.14.3.tgz", + "integrity": "sha512-2qlKlKsnGJ008exFRb5RTeTOqhLZj0bkMCMVskxoqWejs2Q2QtWmsiH98hDfpw0fmnyhzHEt0Z7lqxBYp8bW2w==", + "requires": { + "@algolia/cache-common": "4.14.3", + "@algolia/logger-common": "4.14.3", + "@algolia/requester-common": "4.14.3" + } + }, + "@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.0" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.0.tgz", + "integrity": "sha512-Gt9jszFJYq7qzXVK4slhc6NzJXnOVmRECWcVjF/T23rNXD9NtWQ0W3qxdg+p9wWIB+VQw3GYV/U2Ha9bRTfs4w==" + }, + "@babel/core": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", + "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.6", + "@babel/helper-compilation-targets": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helpers": "^7.18.6", + "@babel/parser": "^7.18.6", + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.6", + "@babel/types": "^7.18.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/generator": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.0.tgz", + "integrity": "sha512-GUPcXxWibClgmYJuIwC2Bc2Lg+8b9VjaJ+HlNdACEVt+Wlr1eoU1OPZjZRm7Hzl0gaTsUZNQfeihvZJhG7oc3w==", + "requires": { + "@babel/types": "^7.20.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.6.tgz", + "integrity": "sha512-KT10c1oWEpmrIRYnthbzHgoOf6B+Xd6a5yhdbNtdhtG7aO1or5HViuf1TQR36xY/QprXA5nvxO6nAjhJ4y38jw==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "requires": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz", + "integrity": "sha512-YfDzdnoxHGV8CzqHGyCbFvXg5QESPFkXlHtvdCkesLjjVMT2Adxe4FGUR5ChIb3DxSaXO12iIOCWoXdsUVwnqw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-function-name": "^7.18.6", + "@babel/helper-member-expression-to-functions": "^7.18.6", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", + "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "requires": { + "@babel/types": "^7.19.4" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "requires": { + "@babel/types": "^7.20.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + }, + "@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "requires": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helpers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.0.tgz", + "integrity": "sha512-aGMjYraN0zosCEthoGLdqot1oRsmxVTQRHadsUPz5QM44Zej2PYRz7XiDE7GqnkZnNtLbOuxqoZw42vkU7+XEQ==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0= sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.0.tgz", + "integrity": "sha512-G9VgAhEaICnz8iiJeGJQyVl6J2nTjbW0xeisva0PK6XcKsga7BIaqm4ZF8Rg1Wbaqmy6znspNqhPaPkyukujzg==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", + "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", + "requires": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.0.tgz", + "integrity": "sha512-sXOohbpHZSk7GjxK9b3dKB7CfqUD5DwOH+DggKzOQ7TXYP+RCSbRykfjQmn/zq+rBjycVRtLf9pYhAaEJA786w==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-classes": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.0.tgz", + "integrity": "sha512-1dIhvZfkDVx/zn2S1aFwlruspTt4189j7fEkH0Y0VyuDM6bQt7bD6kLcz3l4IlLG+e5OReaBz9ROAbttRtUHqA==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.19.1" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.18.12.tgz", + "integrity": "sha512-Q99U9/ttiu+LMnRU8psd23HhvwXmKWDQIpocm0JKaICcZHnw+mdQbHm6xnSy7dOl8I5PELakYtNBubNQlBXbZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz", + "integrity": "sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.18.6" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "requires": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", + "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz", + "integrity": "sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA==", + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-polyfill-corejs2": "^0.3.1", + "babel-plugin-polyfill-corejs3": "^0.5.2", + "babel-plugin-polyfill-regenerator": "^0.3.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.8.tgz", + "integrity": "sha512-p2xM8HI83UObjsZGofMV/EdYjamsDm6MoN3hXPYIT0+gxIoopE+B7rPYKAxfrz9K9PK7JafTTjqYC6qipLExYA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-typescript": "^7.18.6" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + } + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", + "requires": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.19.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.19.4", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", + "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + } + }, + "@babel/preset-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", + "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-typescript": "^7.18.6" + } + }, + "@babel/runtime": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", + "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.6.tgz", + "integrity": "sha512-cOu5wH2JFBgMjje+a+fz2JNIWU4GzYpl05oSob3UDvBEh6EuIn+TXFHMmBbhSb+k/4HMzgKCQfEEDArAWNF9Cw==", + "requires": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.0.tgz", + "integrity": "sha512-5+cAXQNARgjRUK0JWu2UBwja4JLSO/rBMPJzpsKb+oBF5xlUuCfljQepS4XypBQoiigL0VQjTZy6WiONtUdScQ==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.0", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", + "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true + }, + "@docsearch/css": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.2.tgz", + "integrity": "sha512-dctFYiwbvDZkksMlsmc7pj6W6By/EjnVXJq5TEPd05MwQe+dcdHJgaIn1c8wfsucxHpIsdrUcgSkACHCq6aIhw==" + }, + "@docsearch/react": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.2.tgz", + "integrity": "sha512-ugILab2TYKSh6IEHf6Z9xZbOovsYbsdfo60PBj+Bw+oMJ1MHJ7pBt1TTcmPki1hSgg8mysgKy2hDiVdPm7XWSQ==", + "requires": { + "@algolia/autocomplete-core": "1.7.4", + "@algolia/autocomplete-preset-algolia": "1.7.4", + "@docsearch/css": "3.3.2", + "algoliasearch": "^4.0.0" + } + }, + "@docusaurus/core": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.3.1.tgz", + "integrity": "sha512-0Jd4jtizqnRAr7svWaBbbrCCN8mzBNd2xFLoT/IM7bGfFie5y58oz97KzXliwiLY3zWjqMXjQcuP1a5VgCv2JA==", + "requires": { + "@babel/core": "^7.18.6", + "@babel/generator": "^7.18.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.18.6", + "@babel/preset-env": "^7.18.6", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@babel/runtime": "^7.18.6", + "@babel/runtime-corejs3": "^7.18.6", + "@babel/traverse": "^7.18.8", + "@docusaurus/cssnano-preset": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-common": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "@slorber/static-site-generator-webpack-plugin": "^4.0.7", + "@svgr/webpack": "^6.2.1", + "autoprefixer": "^10.4.7", + "babel-loader": "^8.2.5", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.0", + "cli-table3": "^0.6.2", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.23.3", + "css-loader": "^6.7.1", + "css-minimizer-webpack-plugin": "^4.0.0", + "cssnano": "^5.1.12", + "del": "^6.1.1", + "detect-port": "^1.3.0", + "escape-html": "^1.0.3", + "eta": "^2.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "html-minifier-terser": "^6.1.0", + "html-tags": "^3.2.0", + "html-webpack-plugin": "^5.5.0", + "import-fresh": "^3.3.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.6.1", + "postcss": "^8.4.14", + "postcss-loader": "^7.0.0", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.3", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.3", + "rtl-detect": "^1.0.4", + "semver": "^7.3.7", + "serve-handler": "^6.1.3", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.3", + "tslib": "^2.4.0", + "update-notifier": "^5.1.0", + "url-loader": "^4.1.1", + "wait-on": "^6.0.1", + "webpack": "^5.73.0", + "webpack-bundle-analyzer": "^4.5.0", + "webpack-dev-server": "^4.9.3", + "webpack-merge": "^5.8.0", + "webpackbar": "^5.0.2" + } + }, + "@docusaurus/cssnano-preset": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.3.1.tgz", + "integrity": "sha512-7mIhAROES6CY1GmCjR4CZkUfjTL6B3u6rKHK0ChQl2d1IevYXq/k/vFgvOrJfcKxiObpMnE9+X6R2Wt1KqxC6w==", + "requires": { + "cssnano-preset-advanced": "^5.3.8", + "postcss": "^8.4.14", + "postcss-sort-media-queries": "^4.2.1", + "tslib": "^2.4.0" + } + }, + "@docusaurus/logger": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.3.1.tgz", + "integrity": "sha512-2lAV/olKKVr9qJhfHFCaqBIl8FgYjbUFwgUnX76+cULwQYss+42ZQ3grHGFvI0ocN2X55WcYe64ellQXz7suqg==", + "requires": { + "chalk": "^4.1.2", + "tslib": "^2.4.0" + } + }, + "@docusaurus/mdx-loader": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.3.1.tgz", + "integrity": "sha512-Gzga7OsxQRpt3392K9lv/bW4jGppdLFJh3luKRknCKSAaZrmVkOQv2gvCn8LAOSZ3uRg5No7AgYs/vpL8K94lA==", + "requires": { + "@babel/parser": "^7.18.8", + "@babel/traverse": "^7.18.8", + "@docusaurus/logger": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@mdx-js/mdx": "^1.6.22", + "escape-html": "^1.0.3", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "image-size": "^1.0.1", + "mdast-util-to-string": "^2.0.0", + "remark-emoji": "^2.2.0", + "stringify-object": "^3.3.0", + "tslib": "^2.4.0", + "unified": "^9.2.2", + "unist-util-visit": "^2.0.3", + "url-loader": "^4.1.1", + "webpack": "^5.73.0" + } + }, + "@docusaurus/module-type-aliases": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.3.1.tgz", + "integrity": "sha512-6KkxfAVOJqIUynTRb/tphYCl+co3cP0PlHiMDbi+SzmYxMdgIrwYqH9yAnGSDoN6Jk2ZE/JY/Azs/8LPgKP48A==", + "requires": { + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/types": "2.3.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" + } + }, + "@docusaurus/plugin-content-blog": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.3.1.tgz", + "integrity": "sha512-f5LjqX+9WkiLyGiQ41x/KGSJ/9bOjSD8lsVhPvYeUYHCtYpuiDKfhZE07O4EqpHkBx4NQdtQDbp+aptgHSTuiw==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-common": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "cheerio": "^1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "tslib": "^2.4.0", + "unist-util-visit": "^2.0.3", + "utility-types": "^3.10.0", + "webpack": "^5.73.0" + } + }, + "@docusaurus/plugin-content-docs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.3.1.tgz", + "integrity": "sha512-DxztTOBEruv7qFxqUtbsqXeNcHqcVEIEe+NQoI1oi2DBmKBhW/o0MIal8lt+9gvmpx3oYtlwmLOOGepxZgJGkw==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/module-type-aliases": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "@types/react-router-config": "^5.0.6", + "combine-promises": "^1.1.0", + "fs-extra": "^10.1.0", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "utility-types": "^3.10.0", + "webpack": "^5.73.0" + } + }, + "@docusaurus/plugin-content-pages": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.3.1.tgz", + "integrity": "sha512-E80UL6hvKm5VVw8Ka8YaVDtO6kWWDVUK4fffGvkpQ/AJQDOg99LwOXKujPoICC22nUFTsZ2Hp70XvpezCsFQaA==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "fs-extra": "^10.1.0", + "tslib": "^2.4.0", + "webpack": "^5.73.0" + } + }, + "@docusaurus/plugin-debug": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.3.1.tgz", + "integrity": "sha512-Ujpml1Ppg4geB/2hyu2diWnO49az9U2bxM9Shen7b6qVcyFisNJTkVG2ocvLC7wM1efTJcUhBO6zAku2vKJGMw==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "fs-extra": "^10.1.0", + "react-json-view": "^1.21.3", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-google-analytics": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.3.1.tgz", + "integrity": "sha512-OHip0GQxKOFU8n7gkt3TM4HOYTXPCFDjqKbMClDD3KaDnyTuMp/Zvd9HSr770lLEscgPWIvzhJByRAClqsUWiQ==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-google-gtag": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.3.1.tgz", + "integrity": "sha512-uXtDhfu4+Hm+oqWUySr3DNI5cWC/rmP6XJyAk83Heor3dFjZqDwCbkX8yWPywkRiWev3Dk/rVF8lEn0vIGVocA==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-google-tag-manager": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.3.1.tgz", + "integrity": "sha512-Ww2BPEYSqg8q8tJdLYPFFM3FMDBCVhEM4UUqKzJaiRMx3NEoly3qqDRAoRDGdIhlC//Rf0iJV9cWAoq2m6k3sw==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-sitemap": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.3.1.tgz", + "integrity": "sha512-8Yxile/v6QGYV9vgFiYL+8d2N4z4Er3pSHsrD08c5XI8bUXxTppMwjarDUTH/TRTfgAWotRbhJ6WZLyajLpozA==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-common": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "fs-extra": "^10.1.0", + "sitemap": "^7.1.1", + "tslib": "^2.4.0" + } + }, + "@docusaurus/preset-classic": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.3.1.tgz", + "integrity": "sha512-OQ5W0AHyfdUk0IldwJ3BlnZ1EqoJuu2L2BMhqLbqwNWdkmzmSUvlFLH1Pe7CZSQgB2YUUC/DnmjbPKk/qQD0lQ==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/plugin-content-blog": "2.3.1", + "@docusaurus/plugin-content-docs": "2.3.1", + "@docusaurus/plugin-content-pages": "2.3.1", + "@docusaurus/plugin-debug": "2.3.1", + "@docusaurus/plugin-google-analytics": "2.3.1", + "@docusaurus/plugin-google-gtag": "2.3.1", + "@docusaurus/plugin-google-tag-manager": "2.3.1", + "@docusaurus/plugin-sitemap": "2.3.1", + "@docusaurus/theme-classic": "2.3.1", + "@docusaurus/theme-common": "2.3.1", + "@docusaurus/theme-search-algolia": "2.3.1", + "@docusaurus/types": "2.3.1" + } + }, + "@docusaurus/react-loadable": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "requires": { + "@types/react": "*", + "prop-types": "^15.6.2" + } + }, + "@docusaurus/theme-classic": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.3.1.tgz", + "integrity": "sha512-SelSIDvyttb7ZYHj8vEUhqykhAqfOPKk+uP0z85jH72IMC58e7O8DIlcAeBv+CWsLbNIl9/Hcg71X0jazuxJug==", + "requires": { + "@docusaurus/core": "2.3.1", + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/module-type-aliases": "2.3.1", + "@docusaurus/plugin-content-blog": "2.3.1", + "@docusaurus/plugin-content-docs": "2.3.1", + "@docusaurus/plugin-content-pages": "2.3.1", + "@docusaurus/theme-common": "2.3.1", + "@docusaurus/theme-translations": "2.3.1", + "@docusaurus/types": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-common": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "@mdx-js/react": "^1.6.22", + "clsx": "^1.2.1", + "copy-text-to-clipboard": "^3.0.1", + "infima": "0.2.0-alpha.42", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.14", + "prism-react-renderer": "^1.3.5", + "prismjs": "^1.28.0", + "react-router-dom": "^5.3.3", + "rtlcss": "^3.5.0", + "tslib": "^2.4.0", + "utility-types": "^3.10.0" + } + }, + "@docusaurus/theme-common": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.3.1.tgz", + "integrity": "sha512-RYmYl2OR2biO+yhmW1aS5FyEvnrItPINa+0U2dMxcHpah8reSCjQ9eJGRmAgkZFchV1+aIQzXOI1K7LCW38O0g==", + "requires": { + "@docusaurus/mdx-loader": "2.3.1", + "@docusaurus/module-type-aliases": "2.3.1", + "@docusaurus/plugin-content-blog": "2.3.1", + "@docusaurus/plugin-content-docs": "2.3.1", + "@docusaurus/plugin-content-pages": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^1.2.1", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^1.3.5", + "tslib": "^2.4.0", + "use-sync-external-store": "^1.2.0", + "utility-types": "^3.10.0" + } + }, + "@docusaurus/theme-search-algolia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.3.1.tgz", + "integrity": "sha512-JdHaRqRuH1X++g5fEMLnq7OtULSGQdrs9AbhcWRQ428ZB8/HOiaN6mj3hzHvcD3DFgu7koIVtWPQnvnN7iwzHA==", + "requires": { + "@docsearch/react": "^3.1.1", + "@docusaurus/core": "2.3.1", + "@docusaurus/logger": "2.3.1", + "@docusaurus/plugin-content-docs": "2.3.1", + "@docusaurus/theme-common": "2.3.1", + "@docusaurus/theme-translations": "2.3.1", + "@docusaurus/utils": "2.3.1", + "@docusaurus/utils-validation": "2.3.1", + "algoliasearch": "^4.13.1", + "algoliasearch-helper": "^3.10.0", + "clsx": "^1.2.1", + "eta": "^2.0.0", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "tslib": "^2.4.0", + "utility-types": "^3.10.0" + } + }, + "@docusaurus/theme-translations": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.3.1.tgz", + "integrity": "sha512-BsBZzAewJabVhoGG1Ij2u4pMS3MPW6gZ6sS4pc+Y7czevRpzxoFNJXRtQDVGe7mOpv/MmRmqg4owDK+lcOTCVQ==", + "requires": { + "fs-extra": "^10.1.0", + "tslib": "^2.4.0" + } + }, + "@docusaurus/types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.3.1.tgz", + "integrity": "sha512-PREbIRhTaNNY042qmfSE372Jb7djZt+oVTZkoqHJ8eff8vOIc2zqqDqBVc5BhOfpZGPTrE078yy/torUEZy08A==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.6.0", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.73.0", + "webpack-merge": "^5.8.0" + } + }, + "@docusaurus/utils": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.3.1.tgz", + "integrity": "sha512-9WcQROCV0MmrpOQDXDGhtGMd52DHpSFbKLfkyaYumzbTstrbA5pPOtiGtxK1nqUHkiIv8UwexS54p0Vod2I1lg==", + "requires": { + "@docusaurus/logger": "2.3.1", + "@svgr/webpack": "^6.2.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^10.1.0", + "github-slugger": "^1.4.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.4.0", + "url-loader": "^4.1.1", + "webpack": "^5.73.0" + } + }, + "@docusaurus/utils-common": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.3.1.tgz", + "integrity": "sha512-pVlRpXkdNcxmKNxAaB1ya2hfCEvVsLDp2joeM6K6uv55Oc5nVIqgyYSgSNKZyMdw66NnvMfsu0RBylcwZQKo9A==", + "requires": { + "tslib": "^2.4.0" + } + }, + "@docusaurus/utils-validation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.3.1.tgz", + "integrity": "sha512-7n0208IG3k1HVTByMHlZoIDjjOFC8sbViHVXJx0r3Q+3Ezrx+VQ1RZ/zjNn6lT+QBCRCXlnlaoJ8ug4HIVgQ3w==", + "requires": { + "@docusaurus/logger": "2.3.1", + "@docusaurus/utils": "2.3.1", + "joi": "^17.6.0", + "js-yaml": "^4.1.0", + "tslib": "^2.4.0" + } + }, + "@easyops-cn/autocomplete.js": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@easyops-cn/autocomplete.js/-/autocomplete.js-0.38.1.tgz", + "integrity": "sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==", + "requires": { + "cssesc": "^3.0.0", + "immediate": "^3.2.3" + } + }, + "@easyops-cn/docusaurus-search-local": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.33.5.tgz", + "integrity": "sha512-9juHGVUy6N37Ezg1Msz1paMqT3zrQIlRLNJVw/NTG3aSctaYw1W0zAIRieXgBKvBAPkcCn95GsUrcziH13Grsw==", + "requires": { + "@docusaurus/plugin-content-docs": "^2.0.0-rc.1", + "@docusaurus/theme-translations": "^2.0.0-rc.1", + "@docusaurus/utils": "^2.0.0-rc.1", + "@docusaurus/utils-common": "^2.0.0-rc.1", + "@docusaurus/utils-validation": "^2.0.0-rc.1", + "@easyops-cn/autocomplete.js": "^0.38.1", + "@node-rs/jieba": "^1.6.0", + "cheerio": "^1.0.0-rc.3", + "clsx": "^1.1.1", + "debug": "^4.2.0", + "fs-extra": "^10.0.0", + "klaw-sync": "^6.0.0", + "lunr": "^2.3.9", + "lunr-languages": "^1.4.0", + "mark.js": "^8.11.1", + "tslib": "^2.4.0" + } + }, + "@hapi/hoek": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", + "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", + "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==" + }, + "@mdx-js/mdx": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", + "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", + "requires": { + "@babel/core": "7.12.9", + "@babel/plugin-syntax-jsx": "7.12.1", + "@babel/plugin-syntax-object-rest-spread": "7.8.3", + "@mdx-js/util": "1.6.22", + "babel-plugin-apply-mdx-type-prop": "1.6.22", + "babel-plugin-extract-import-names": "1.6.22", + "camelcase-css": "2.0.1", + "detab": "2.0.4", + "hast-util-raw": "6.0.1", + "lodash.uniq": "4.5.0", + "mdast-util-to-hast": "10.0.1", + "remark-footnotes": "2.0.0", + "remark-mdx": "1.6.22", + "remark-parse": "8.0.3", + "remark-squeeze-paragraphs": "4.0.0", + "style-to-object": "0.3.0", + "unified": "9.2.0", + "unist-builder": "2.0.3", + "unist-util-visit": "2.0.3" + }, + "dependencies": { + "@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, + "unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + } + } + } + }, + "@mdx-js/react": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", + "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==", + "requires": {} + }, + "@mdx-js/util": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", + "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==" + }, + "@node-rs/jieba": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba/-/jieba-1.6.1.tgz", + "integrity": "sha512-pISKu8NIYKRvZp7mhYZYA8VCjJMqTsCe+mQcFFnAi3GNJsijGjef2peMFeDcvP72X8MsnNeYeg3rHkAybtefyQ==", + "requires": { + "@node-rs/jieba-android-arm-eabi": "1.6.1", + "@node-rs/jieba-android-arm64": "1.6.1", + "@node-rs/jieba-darwin-arm64": "1.6.1", + "@node-rs/jieba-darwin-x64": "1.6.1", + "@node-rs/jieba-freebsd-x64": "1.6.1", + "@node-rs/jieba-linux-arm-gnueabihf": "1.6.1", + "@node-rs/jieba-linux-arm64-gnu": "1.6.1", + "@node-rs/jieba-linux-arm64-musl": "1.6.1", + "@node-rs/jieba-linux-x64-gnu": "1.6.1", + "@node-rs/jieba-linux-x64-musl": "1.6.1", + "@node-rs/jieba-win32-arm64-msvc": "1.6.1", + "@node-rs/jieba-win32-ia32-msvc": "1.6.1", + "@node-rs/jieba-win32-x64-msvc": "1.6.1" + } + }, + "@node-rs/jieba-android-arm-eabi": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm-eabi/-/jieba-android-arm-eabi-1.6.1.tgz", + "integrity": "sha512-R1YQfsPr7sK3Tq1sM0//6lNAGJK9RnMT0ShITT+7EJYr5OufUBb38lf/mRhrLxR0NF1pycEsMjdCAwrWrHd8rA==", + "optional": true + }, + "@node-rs/jieba-android-arm64": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-android-arm64/-/jieba-android-arm64-1.6.1.tgz", + "integrity": "sha512-hBRbj2uLmRFYDw2lWppTAPoyjeXkBKUT84h4fHUQj7CMU94Gc1IWkE4ocCqhvUhbaUXlCpocS9mB0/fc2641bw==", + "optional": true + }, + "@node-rs/jieba-darwin-arm64": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-1.6.1.tgz", + "integrity": "sha512-GeoDe7XVTF6z8JUtD98QvwudsMaHV5EBXs5uO43SobeIkShH3Nujq5gLMD5kWoJXTxDrTgJe4wT42EwUaBEH2Q==", + "optional": true + }, + "@node-rs/jieba-darwin-x64": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-darwin-x64/-/jieba-darwin-x64-1.6.1.tgz", + "integrity": "sha512-ENHYIS8b8JdMaUXEm0f8Y3+sHXu2UdukG1D/XGUNx+q5cn07HbwIg6L0tlGhE8dw4AhqoWHsExVaZ241Igh4iA==", + "optional": true + }, + "@node-rs/jieba-freebsd-x64": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-freebsd-x64/-/jieba-freebsd-x64-1.6.1.tgz", + "integrity": "sha512-chwB/9edtxqS8Jm3j4RMaJjH9AlXmijUgKv02oMw36e77HKpko+tENUN25Vrn/9GKsKGqIPeXpmCjeXCN1HVQA==", + "optional": true + }, + "@node-rs/jieba-linux-arm-gnueabihf": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm-gnueabihf/-/jieba-linux-arm-gnueabihf-1.6.1.tgz", + "integrity": "sha512-tsb5fMGj4p8bHGfkf7bJ+HE2jxaixLTp3YnGg5D+kp8+HQRq8cp3ScG5cn8cq0phnJS/zfAp8rVfWInDagzKKQ==", + "optional": true + }, + "@node-rs/jieba-linux-arm64-gnu": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-gnu/-/jieba-linux-arm64-gnu-1.6.1.tgz", + "integrity": "sha512-bSInORkJFfeZNR+i4rFoSZGbwkQtQlnZ0XfT/noTK9JUBDYErqQZPFjoaYAU45NWTk7p6Zkg30SuV1NTdWLaPw==", + "optional": true + }, + "@node-rs/jieba-linux-arm64-musl": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-arm64-musl/-/jieba-linux-arm64-musl-1.6.1.tgz", + "integrity": "sha512-qphL6xM7owfU8Hsh7GX73SDr/iApbnc+35mSLxbibAfCQnY89+WcBeWUUOSGM/Ov3VFaq4pyVlDFj0YjR01W2w==", + "optional": true + }, + "@node-rs/jieba-linux-x64-gnu": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-1.6.1.tgz", + "integrity": "sha512-f6hhlrbi2wel0xZG7m3Wvksimt9MSu1f3aYO2Kwavf4qjMRZqJzLz9HlCJAal6AXB9Qgg+685P+gftsWve47qw==", + "optional": true + }, + "@node-rs/jieba-linux-x64-musl": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-1.6.1.tgz", + "integrity": "sha512-cTVcdR6zWqpnmdEUyWEII9zfE5lTeWN53TbiOPx8TCA+291/31Vqd7GA8YEPndUO8qgCx5uShSDFStBAEIhYNQ==", + "optional": true + }, + "@node-rs/jieba-win32-arm64-msvc": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-arm64-msvc/-/jieba-win32-arm64-msvc-1.6.1.tgz", + "integrity": "sha512-YuOTrjHazDraXcGXRHgPQ53nyJuH8QtTCngYKjAzxsdt8uN+txb1AY69OLMLBBZqLTOwY9dgcW70vGiLQMCTeg==", + "optional": true + }, + "@node-rs/jieba-win32-ia32-msvc": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-ia32-msvc/-/jieba-win32-ia32-msvc-1.6.1.tgz", + "integrity": "sha512-4+E843ImGpVlZ+LlT9E/13NHmmUg3UHQx419D6fFMorJUUQuK4cZJfE1z4tCgcrbV8S5Wew5LIFywlJeJLu0LQ==", + "optional": true + }, + "@node-rs/jieba-win32-x64-msvc": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@node-rs/jieba-win32-x64-msvc/-/jieba-win32-x64-msvc-1.6.1.tgz", + "integrity": "sha512-veXNwm2VlseOzl7vaC7A/nZ4okp5/6edN7/Atj6mXnUbze/m/my5Rv5zUcW3U1D9VElnQ3srCHCa5vXljJuk6g==", + "optional": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + }, + "@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@slorber/static-site-generator-webpack-plugin": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.7.tgz", + "integrity": "sha512-Ug7x6z5lwrz0WqdnNFOMYrDQNTPAprvHLSh6+/fmml3qUiz6l5eq+2MzLKWtn/q5K5NpSiFsZTP/fck/3vjSxA==", + "requires": { + "eval": "^0.1.8", + "p-map": "^4.0.0", + "webpack-sources": "^3.2.2" + } + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", + "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", + "requires": {} + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz", + "integrity": "sha512-8zYdkym7qNyfXpWvu4yq46k41pyNM9SOstoWhKlm+IfdCE1DdnRKeMUPsWIEO/DEkaWxJ8T9esNdG3QwQ93jBA==", + "requires": {} + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.5.0.tgz", + "integrity": "sha512-NFdxMq3xA42Kb1UbzCVxplUc0iqSyM9X8kopImvFnB+uSDdzIHOdbs1op8ofAvVRtbg4oZiyRl3fTYeKcOe9Iw==", + "requires": {} + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", + "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", + "requires": {} + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", + "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", + "requires": {} + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", + "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", + "requires": {} + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", + "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", + "requires": {} + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", + "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", + "requires": {} + }, + "@svgr/babel-preset": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", + "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + } + }, + "@svgr/core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", + "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", + "requires": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + }, + "dependencies": { + "@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", + "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", + "requires": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + } + }, + "@svgr/plugin-jsx": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", + "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", + "requires": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" + }, + "dependencies": { + "@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@svgr/plugin-svgo": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", + "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", + "requires": { + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "svgo": "^2.8.0" + } + }, + "@svgr/webpack": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz", + "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==", + "requires": { + "@babel/core": "^7.19.6", + "@babel/plugin-transform-react-constant-elements": "^7.18.12", + "@babel/preset-env": "^7.19.4", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@svgr/core": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "@svgr/plugin-svgo": "^6.5.1" + }, + "dependencies": { + "@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/eslint": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "requires": { + "@types/unist": "*" + } + }, + "@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, + "@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "@types/http-proxy": { + "version": "1.17.8", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", + "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "requires": { + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "requires": { + "@types/unist": "*" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/node": { + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==" + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "@types/parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", + "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "@types/react": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.0.tgz", + "integrity": "sha512-7+K7zEQYu7NzOwQGLR91KwWXXDzmTFODRVizJyIALf6RfLv2GDpqpknX64pvRVILXCpXi7O/pua8NGk44dLvJw==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-router": { + "version": "5.1.18", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz", + "integrity": "sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "@types/react-router-config": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.6.tgz", + "integrity": "sha512-db1mx37a1EJDf1XeX8jJN7R3PZABmJQXR8r28yUjVMFSjkmnQo6X6pOEEmNl+Tp2gYQOGPdYbFIipBtdElZ3Yg==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@types/retry": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", + "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" + }, + "@types/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==", + "requires": { + "@types/node": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "requires": { + "@types/node": "*" + } + }, + "@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "requires": { + "@types/node": "*" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + } + } + }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "algoliasearch": { + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.3.tgz", + "integrity": "sha512-GZTEuxzfWbP/vr7ZJfGzIl8fOsoxN916Z6FY2Egc9q2TmZ6hvq5KfAxY89pPW01oW/2HDEKA8d30f9iAH9eXYg==", + "requires": { + "@algolia/cache-browser-local-storage": "4.14.3", + "@algolia/cache-common": "4.14.3", + "@algolia/cache-in-memory": "4.14.3", + "@algolia/client-account": "4.14.3", + "@algolia/client-analytics": "4.14.3", + "@algolia/client-common": "4.14.3", + "@algolia/client-personalization": "4.14.3", + "@algolia/client-search": "4.14.3", + "@algolia/logger-common": "4.14.3", + "@algolia/logger-console": "4.14.3", + "@algolia/requester-browser-xhr": "4.14.3", + "@algolia/requester-common": "4.14.3", + "@algolia/requester-node-http": "4.14.3", + "@algolia/transporter": "4.14.3" + } + }, + "algoliasearch-helper": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.11.3.tgz", + "integrity": "sha512-TbaEvLwiuGygHQIB8y+OsJKQQ40+JKUua5B91X66tMUHyyhbNHvqyr0lqd3wCoyKx7WybyQrC0WJvzoIeh24Aw==", + "requires": { + "@algolia/events": "^4.0.1" + } + }, + "animate.css": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/animate.css/-/animate.css-4.1.1.tgz", + "integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==" + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "requires": { + "string-width": "^4.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "dev": true, + "requires": { + "follow-redirects": "1.5.10" + } + }, + "babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + } + }, + "babel-plugin-apply-mdx-type-prop": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", + "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", + "requires": { + "@babel/helper-plugin-utils": "7.10.4", + "@mdx-js/util": "1.6.22" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-extract-import-names": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", + "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", + "requires": { + "@babel/helper-plugin-utils": "7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + } + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + } + }, + "bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base16": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", + "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "bonjour-service": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.11.tgz", + "integrity": "sha512-drMprzr2rDTCtgEE3VgdA9uUFaUHF+jXduwYSThHJnKMYM+FhI9Z3ph+TX3xy0LtgYHae6CHYPJ/2UnK8nQHcA==", + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.4" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24= sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "requires": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001427", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001427.tgz", + "integrity": "sha512-lfXQ73oB9c8DP5Suxaszm+Ta2sr/4tf8+381GkIm1MLj/YdLf+rEDyDSRCzeltuyTVGm+/s18gdZ0q+Wmp8VsQ==" + }, + "ccount": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", + "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" + }, + "character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" + }, + "character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" + }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "clean-css": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", + "integrity": "sha512-YYuuxv4H/iNb1Z/5IbMRoxgrzjWGhOEFfd+groZ5dMCVkpENiMZmwspdrzBo9286JjM1gZJPAyL7ZIdzuvu2AQ==", + "requires": { + "source-map": "~0.6.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==" + }, + "cli-table3": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", + "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, + "collapse-white-space": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", + "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "colord": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", + "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==" + }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==" + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "combine-promises": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", + "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==" + }, + "comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + } + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==" + }, + "consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ= sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw= sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "copy-text-to-clipboard": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", + "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==" + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "globby": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", + "integrity": "sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==", + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + } + } + }, + "core-js": { + "version": "3.23.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.3.tgz", + "integrity": "sha512-oAKwkj9xcWNBAvGbT//WiCdOMpb9XQG92/Fe3ABFM/R16BsHgePG00mFOgKf7IsCtfj8tA1kHtf/VwErhriz5Q==" + }, + "core-js-compat": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", + "requires": { + "browserslist": "^4.21.4" + } + }, + "core-js-pure": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", + "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "requires": { + "node-fetch": "2.6.7" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "css-declaration-sorter": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", + "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", + "requires": {} + }, + "css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + } + }, + "css-minimizer-webpack-plugin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.0.0.tgz", + "integrity": "sha512-7ZXXRzRHvofv3Uac5Y+RkWRNo0ZMlcg8e9/OtrqUYmwDWJo+qs67GvdeFrXLsFb7czKNwjQhPkM0avlIYl+1nA==", + "requires": { + "cssnano": "^5.1.8", + "jest-worker": "^27.5.1", + "postcss": "^8.4.13", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.12.tgz", + "integrity": "sha512-TgvArbEZu0lk/dvg2ja+B7kYoD7BBCmn3+k58xD0qjrGHsFzXY/wKTo9M5egcUCabPol05e/PVoIu79s2JN4WQ==", + "requires": { + "cssnano-preset-default": "^5.2.12", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "cssnano-preset-advanced": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.9.tgz", + "integrity": "sha512-njnh4pp1xCsibJcEHnWZb4EEzni0ePMqPuPNyuWT4Z+YeXmsgqNuTPIljXFEXhxGsWs9183JkXgHxc1TcsahIg==", + "requires": { + "autoprefixer": "^10.4.12", + "cssnano-preset-default": "^5.2.13", + "postcss-discard-unused": "^5.1.0", + "postcss-merge-idents": "^5.1.1", + "postcss-reduce-idents": "^5.2.0", + "postcss-zindex": "^5.1.0" + } + }, + "cssnano-preset-default": { + "version": "5.2.13", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz", + "integrity": "sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==", + "requires": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.0", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.3", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.1", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + } + }, + "cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "requires": {} + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "requires": { + "css-tree": "^1.1.2" + } + }, + "csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "requires": { + "execa": "^5.0.0" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "requires": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + }, + "detab": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", + "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", + "requires": { + "repeat-string": "^1.5.4" + } + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "detect-port": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", + "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0= sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "dns-packet": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.1.tgz", + "integrity": "sha512-spBwIj0TK0Ey3666GwIdWVfUpLyubpU53BTCu8iPn4r4oXd9O14Hjg3EHw3ts2oed77/SeckunUYCyRlSngqHw==", + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "docusaurus-plugin-image-zoom": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/docusaurus-plugin-image-zoom/-/docusaurus-plugin-image-zoom-0.1.1.tgz", + "integrity": "sha512-cJXo5TKh9OR1gE4B5iS5ovLWYYDFwatqRm00iXFPOaShZG99l5tgkDKgbQPAwSL9wg4I+wz3aMwkOtDhMIpKDQ==", + "requires": { + "medium-zoom": "^1.0.6" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + }, + "dependencies": { + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + } + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==" + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "emoticon": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", + "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "eta": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.0.0.tgz", + "integrity": "sha512-NqE7S2VmVwgMS8yBxsH4VgNQjNjLq1gfGU0u9I6Cjh468nPRMoDfGdK9n1p/3Dvsw3ebklDkZsFAnKJ9sefjBA==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "requires": { + "@types/node": "*", + "require-like": ">= 0.1.1" + } + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + } + } + }, + "express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "requires": { + "punycode": "^1.3.2" + } + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fbemitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", + "requires": { + "fbjs": "^3.0.0" + } + }, + "fbjs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz", + "integrity": "sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==", + "requires": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + }, + "fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, + "feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "requires": { + "xml-js": "^1.6.11" + } + }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flux": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", + "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", + "requires": { + "fbemitter": "^3.0.0", + "fbjs": "^3.0.1" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "fork-ts-checker-webpack-plugin": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.1.tgz", + "integrity": "sha512-x1wumpHOEf4gDROmKTaB6i4/Q6H3LwmjVO7fIX47vBwlZbtPjU33hgoMuD/Q/y6SU8bnuYSoN6ZQOLshGp0T/g==", + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + } + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "github-slugger": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", + "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "requires": { + "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" + } + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "requires": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "requires": { + "duplexer": "^0.1.2" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" + }, + "hast-to-hyperscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", + "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", + "requires": { + "@types/unist": "^2.0.3", + "comma-separated-tokens": "^1.0.0", + "property-information": "^5.3.0", + "space-separated-tokens": "^1.0.0", + "style-to-object": "^0.3.0", + "unist-util-is": "^4.0.0", + "web-namespaces": "^1.0.0" + } + }, + "hast-util-from-parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", + "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", + "requires": { + "@types/parse5": "^5.0.0", + "hastscript": "^6.0.0", + "property-information": "^5.0.0", + "vfile": "^4.0.0", + "vfile-location": "^3.2.0", + "web-namespaces": "^1.0.0" + } + }, + "hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==" + }, + "hast-util-raw": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", + "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", + "requires": { + "@types/hast": "^2.0.0", + "hast-util-from-parse5": "^6.0.0", + "hast-util-to-parse5": "^6.0.0", + "html-void-elements": "^1.0.0", + "parse5": "^6.0.0", + "unist-util-position": "^3.0.0", + "vfile": "^4.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + } + } + }, + "hast-util-to-parse5": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", + "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", + "requires": { + "hast-to-hyperscript": "^9.0.0", + "property-information": "^5.0.0", + "web-namespaces": "^1.0.0", + "xtend": "^4.0.0", + "zwitch": "^1.0.0" + } + }, + "hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "requires": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" + }, + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "requires": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "dependencies": { + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + } + } + }, + "html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==" + }, + "html-void-elements": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", + "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==" + }, + "html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "requires": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + } + }, + "htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==" + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz", + "integrity": "sha512-m/4FxX17SUvz4lJ5WPXOHDUuCwIqXLfLHs1s0uZ3oYjhoXlx9csYxaOa0ElDEJ+h8Q4iJ1s+lTMbiCa4EXIJqg==", + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "dependencies": { + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" + } + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + }, + "iconfont-parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iconfont-parser/-/iconfont-parser-1.0.0.tgz", + "integrity": "sha512-3RJceYHEjaqYyeDdfSAb1vP1x1Eb7ZtC9Xwetj+axm85sBlJU7HMvdNLVpwm/3g5eghYOdkQK+epUITZGAIqKQ==", + "dev": true, + "requires": { + "axios": "^0.19.0", + "colors": "^1.4.0", + "tslib": "^1.10.0", + "xml2js": "^0.4.22" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + }, + "image-size": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.1.tgz", + "integrity": "sha512-VAwkvNSNGClRw9mDHhc5Efax8PLlsOGcUTh0T/LIriC8vPA3U5PdqXWqkz406MoYHMKW8Uf9gWr05T/rYB44kQ==", + "requires": { + "queue": "6.0.2" + } + }, + "immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" + }, + "immer": { + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", + "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o= sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "infima": { + "version": "0.2.0-alpha.42", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.42.tgz", + "integrity": "sha512-ift8OXNbQQwtbIt6z16KnSWP7uJ/SysSMFI4F87MNRTicypfl4Pv3E2OGVv6N3nSZFJvA8imYulCBS64iyHYww==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==" + }, + "is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" + }, + "is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "requires": { + "has": "^1.0.3" + } + }, + "is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8= sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk= sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==" + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "is-whitespace-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", + "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==" + }, + "is-word-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", + "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==" + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8= sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "joi": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", + "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "requires": { + "graceful-fs": "^4.1.11" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==" + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "requires": { + "package-json": "^6.3.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + }, + "lilconfig": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==" + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" + }, + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.curry": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168= sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "requires": { + "tslib": "^2.0.3" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, + "lunr-languages": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.9.0.tgz", + "integrity": "sha512-Be5vFuc8NAheOIjviCRms3ZqFFBlzns3u9DXpPSZvALetgnydAN0poV71pVLFn0keYy/s4VblMMkqewTLe+KPg==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==" + }, + "markdown-escapes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", + "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==" + }, + "mdast-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", + "requires": { + "unist-util-remove": "^2.0.0" + } + }, + "mdast-util-definitions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", + "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "requires": { + "unist-util-visit": "^2.0.0" + } + }, + "mdast-util-to-hast": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", + "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "mdast-util-definitions": "^4.0.0", + "mdurl": "^1.0.0", + "unist-builder": "^2.0.0", + "unist-util-generated": "^1.0.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^2.0.0" + } + }, + "mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==" + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "medium-zoom": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.0.8.tgz", + "integrity": "sha512-CjFVuFq/IfrdqesAXfg+hzlDKu6A2n80ZIq0Kl9kWjoHh9j1N9Uvk5X0/MmN0hOfm5F9YBswlClhcwnmtwz7gA==" + }, + "memfs": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", + "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", + "requires": { + "fs-monkey": "1.0.3" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "requires": { + "mime-db": "~1.33.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "requires": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + } + }, + "mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mrmime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", + "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.4.tgz", + "integrity": "sha512-XkCYOU+rr2Ft3LI6w4ye51M3VK31qJXFIxu0XLw169PtKG0Zx47OrXeVW/GCYOfpC9s1yyyf1S+L8/4LY0J9Zw==", + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "requires": { + "lodash": "^4.17.21" + } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", + "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "requires": { + "@types/retry": "^0.12.0", + "retry": "^0.13.1" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" + }, + "parse5": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz", + "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==", + "requires": { + "entities": "^4.3.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "requires": { + "find-up": "^4.0.0" + } + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" + } + } + }, + "postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "requires": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-colormin": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.0.tgz", + "integrity": "sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==", + "requires": { + "browserslist": "^4.16.6", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "requires": {} + }, + "postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "requires": {} + }, + "postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "requires": {} + }, + "postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "requires": {} + }, + "postcss-discard-unused": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", + "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.0.tgz", + "integrity": "sha512-IDyttebFzTSY6DI24KuHUcBjbAev1i+RyICoPEWcAstZsj03r533uMXtDn506l6/wlsRYiS5XBdx7TpccCsyUg==", + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + } + }, + "postcss-merge-idents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", + "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "requires": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + } + }, + "postcss-merge-rules": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz", + "integrity": "sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "requires": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "requires": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "requires": {} + }, + "postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "requires": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-reduce-idents": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", + "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-reduce-initial": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz", + "integrity": "sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-sort-media-queries": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.3.0.tgz", + "integrity": "sha512-jAl8gJM2DvuIJiI9sL1CuiHtKM4s5aEIomkU8G3LFvbP+p8i7Sz8VV63uieTgoewGqKbi+hxBTiOKJlB35upCg==", + "requires": { + "sort-css-media-queries": "2.1.0" + } + }, + "postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "requires": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + } + }, + "postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "postcss-zindex": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", + "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", + "requires": {} + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==" + }, + "pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "requires": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" + }, + "prism-react-renderer": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", + "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", + "requires": {} + }, + "prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "requires": { + "xtend": "^4.0.0" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4= sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "requires": { + "escape-goat": "^2.0.0" + } + }, + "pure-color": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", + "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" + }, + "qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + }, + "queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "requires": { + "inherits": "~2.0.3" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==" + }, + "raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "requires": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo= sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + } + } + }, + "react": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-base16-styling": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", + "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==", + "requires": { + "base16": "^1.0.0", + "lodash.curry": "^4.0.1", + "lodash.flow": "^3.3.0", + "pure-color": "^1.2.0" + } + }, + "react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "requires": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "loader-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", + "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==" + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "requires": { + "p-limit": "^3.0.2" + } + } + } + }, + "react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, + "react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, + "react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "requires": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + } + }, + "react-iconfont-cli": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-iconfont-cli/-/react-iconfont-cli-2.0.2.tgz", + "integrity": "sha512-43NP+dsk08XwJf8oXfrDwHk1WeE76vy1Xzbd2zz7WjjxsdblF9h/oalFMPclZSibIirwsckz3L0IV+42Yu//iQ==", + "dev": true, + "requires": { + "colors": "^1.3.3", + "glob": "^7.1.4", + "iconfont-parser": "^1.0.0", + "lodash": "^4.17.15", + "minimist": "^1.2.5", + "mkdirp": "^0.5.1", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-json-view": { + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", + "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", + "requires": { + "flux": "^4.0.1", + "react-base16-styling": "^0.6.0", + "react-lifecycles-compat": "^3.0.4", + "react-textarea-autosize": "^8.3.2" + } + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-loadable": { + "version": "npm:@docusaurus/react-loadable@5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "requires": { + "@types/react": "*", + "prop-types": "^15.6.2" + } + }, + "react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "requires": { + "@babel/runtime": "^7.10.3" + } + }, + "react-router": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.3.tgz", + "integrity": "sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w==", + "requires": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-Ov0tGPMBgqmbu5CDmN++tv2HQ9HlWDuWIIqn4b88gjlAN5IHI+4ZUZRcpz9Hl0azFIwihbLDYw1OiHGRo7ZIng==", + "requires": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.3", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-textarea-autosize": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.0.tgz", + "integrity": "sha512-YrTFaEHLgJsi8sJVYHBzYn+mkP3prGkmP2DKb/tm0t7CLJY5t1Rxix8070LAKb0wby7bl/lf2EeHkuMihMZMwQ==", + "requires": { + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "requires": { + "resolve": "^1.1.6" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "requires": { + "minimatch": "3.0.4" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexpu-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", + "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "requires": { + "rc": "^1.2.8" + } + }, + "regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + }, + "regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + }, + "remark-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", + "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", + "requires": { + "emoticon": "^3.2.0", + "node-emoji": "^1.10.0", + "unist-util-visit": "^2.0.3" + } + }, + "remark-footnotes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", + "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==" + }, + "remark-mdx": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", + "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", + "requires": { + "@babel/core": "7.12.9", + "@babel/helper-plugin-utils": "7.10.4", + "@babel/plugin-proposal-object-rest-spread": "7.12.1", + "@babel/plugin-syntax-jsx": "7.12.1", + "@mdx-js/util": "1.6.22", + "is-alphabetical": "1.0.4", + "remark-parse": "8.0.3", + "unified": "9.2.0" + }, + "dependencies": { + "@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", + "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.12.1" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", + "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, + "unified": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", + "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + } + } + } + }, + "remark-parse": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", + "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", + "requires": { + "ccount": "^1.0.0", + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^2.0.0", + "vfile-location": "^3.0.0", + "xtend": "^4.0.1" + } + }, + "remark-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", + "requires": { + "mdast-squeeze-paragraphs": "^4.0.0" + } + }, + "renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + } + } + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc= sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o= sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "rtl-detect": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", + "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" + }, + "rtlcss": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", + "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", + "requires": { + "find-up": "^5.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.3.11", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "requires": { + "p-limit": "^3.0.2" + } + } + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "requires": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "selfsigned": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-handler": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", + "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "requires": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.0.4", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + } + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "requires": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "sitemap": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", + "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", + "requires": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "sort-css-media-queries": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", + "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==" + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "state-toggle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", + "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" + }, + "std-env": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.0.1.tgz", + "integrity": "sha512-mC1Ps9l77/97qeOZc+HrOL7TIaOboHqMZ24dGVQrlxFcpPpfCHpH+qfUT7Dz+6mlG8+JPA1KfBQo19iC/+Ngcw==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==" + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "requires": { + "inline-style-parser": "0.1.1" + } + }, + "stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "requires": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + }, + "terser": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", + "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==", + "requires": { + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz", + "integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.7", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.7.2" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0= sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==" + }, + "trim-trailing-lines": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", + "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==" + }, + "trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "type-fest": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", + "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + } + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "peer": true + }, + "ua-parser-js": { + "version": "0.7.33", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", + "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==" + }, + "unherit": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", + "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", + "requires": { + "inherits": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" + }, + "unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" + }, + "unified": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unist-builder": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", + "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==" + }, + "unist-util-generated": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", + "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==" + }, + "unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + }, + "unist-util-position": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", + "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==" + }, + "unist-util-remove": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", + "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", + "requires": { + "unist-util-is": "^4.0.0" + } + }, + "unist-util-remove-position": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", + "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", + "requires": { + "unist-util-visit": "^2.0.0" + } + }, + "unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "requires": { + "@types/unist": "^2.0.2" + } + }, + "unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + } + }, + "unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "requires": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + } + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use-composed-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", + "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", + "requires": {} + }, + "use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "requires": {} + }, + "use-latest": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", + "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", + "requires": { + "use-isomorphic-layout-effect": "^1.1.1" + } + }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + } + }, + "vfile-location": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", + "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==" + }, + "vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + } + }, + "wait-on": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", + "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", + "requires": { + "axios": "^0.25.0", + "joi": "^17.6.0", + "lodash": "^4.17.21", + "minimist": "^1.2.5", + "rxjs": "^7.5.4" + }, + "dependencies": { + "axios": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", + "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "requires": { + "follow-redirects": "^1.14.7" + } + }, + "follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + } + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "web-namespaces": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", + "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "webpack": { + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-bundle-analyzer": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", + "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", + "requires": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz", + "integrity": "sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==", + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.1", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz", + "integrity": "sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==", + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "requires": {} + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" + }, + "webpackbar": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", + "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", + "requires": { + "chalk": "^4.1.0", + "consola": "^2.15.3", + "pretty-time": "^1.1.0", + "std-env": "^3.0.1" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "requires": { + "string-width": "^5.0.1" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + }, + "wrap-ansi": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", + "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "ansi-styles": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", + "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==" + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "requires": {} + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "requires": { + "sax": "^1.2.4" + } + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + }, + "zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==" + } + } +} diff --git a/handbook/package.json b/handbook/package.json new file mode 100644 index 000000000..03a0ef9a4 --- /dev/null +++ b/handbook/package.json @@ -0,0 +1,50 @@ +{ + "name": "touchsocket", + "version": "v1.2", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids" + }, + "dependencies": { + "@docusaurus/core": "^2.3.1", + "@docusaurus/preset-classic": "^2.3.1", + "@easyops-cn/docusaurus-search-local": "^0.33.5", + "@mdx-js/react": "^1.6.22", + "@svgr/webpack": "^6.5.1", + "animate.css": "^4.1.1", + "clsx": "^1.2.1", + "docusaurus-plugin-image-zoom": "^0.1.1", + "file-loader": "^6.2.0", + "prism-react-renderer": "^1.3.5", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "url-loader": "^4.1.1" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^2.3.1", + "react-iconfont-cli": "^2.0.2" + }, + "engines": { + "node": ">=16.14" + } +} diff --git a/handbook/sidebars.js b/handbook/sidebars.js new file mode 100644 index 000000000..c06ff9532 --- /dev/null +++ b/handbook/sidebars.js @@ -0,0 +1,628 @@ +// /** +// * Creating a sidebar enables you to: +// - create an ordered group of docs +// - render a sidebar for each doc of that group +// - provide next/previous navigation + +// The sidebars can be generated from the filesystem, or explicitly defined here. + +// Create as many sidebars as you want. +// */ + +// // @ts-check + +// /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +// const sidebars = { +// // By default, Docusaurus generates a sidebar from the docs folder structure +// tutorialSidebar: [{ type: "autogenerated",dirName: "." }], + +// // But you can create a sidebar manually +// /* +// tutorialSidebar: [ +// 'intro', +// 'hello', +// { +// type: 'category', +// label: 'Tutorial', +// items: ['tutorial-basics/create-a-document'], +// }, +// ], +// */ +// }; + +// module.exports = sidebars; + + +module.exports = { + docs: [ + { + type: "doc", + id: "description", + label: "01、说明(使用前必要阅读)" + }, + { + type: "doc", + id: "upgrade", + label: "02、历史更新" + }, + { + type: "category", + label: "03、支持作者及商业运营", + items: [ + { + type: "doc", + id: "donate", + label: "3.1 支持作者" + }, + { + type: "doc", + id: "enterprise", + label: "3.2 企业版相关" + }, + { + type: "category", + label: "3.3 商业项目", + items: [ + { + type: "doc", + id: "cooperation", + label: "a.商业合作" + }, + { + type: "doc", + id: "wpfuifiletransfer", + label: "b.WPF界面、文件传输项目" + }, + { + type: "doc", + id: "remotemonitoring", + label: "c.远程监测、控制项目" + }, + { + type: "doc", + id: "filesynchronization", + label: "d.文件同步系统" + }, + { + type: "doc", + id: "dataforwarding", + label: "e.数据转发项目" + }, + { + type: "doc", + id: "webdataforwarding", + label: "f.Web数据转发Winform项目" + }, + ], + }, + { + type: "category", + label: "3.4 使用者项目", + items: [ + { + type: "doc", + id: "fpsgame", + label: "a.FPS实时游戏" + }, + { + type: "doc", + id: "engineertoolbox", + label: "b.工程师软件工具箱" + } + ], + } + ], + }, + { + type: "doc", + id:"startguide", + label: "04、入门指南", + }, + { + type: "category", + label: "05、Core", + items: + [ + { + type: "doc", + id: "bytepool", + label: "5.1 内存池" + }, + { + type: "doc", + id: "consoleaction", + label: "5.2 控制台行为" + }, + { + type: "doc", + id: "touchsocketbitconverter", + label: "5.3 大小端转换器" + }, + { + type: "doc", + id: "datasecurity", + label: "5.4 数据加密" + }, + { + type: "doc", + id: "ilog", + label: "5.5 日志记录器" + }, + { + type: "doc", + id: "appmessenger", + label: "5.6 应用信使" + }, + { + type: "doc", + id: "fastbinaryformatter", + label: "5.7 高性能二进制序列化" + }, + { + type: "doc", + id: "jsonserialize", + label: "5.8 Json序列化" + }, + { + type: "doc", + id: "ioc", + label: "5.9 依赖注入容器" + }, + { + type: "doc", + id: "dependencyproperty", + label: "5.10 依赖属性" + }, + { + type: "doc", + id: "filepool", + label: "5.11 文件流池" + }, + { + type: "doc", + id: "pluginsmanager", + label: "5.12 插件系统" + }, + { + type: "doc", + id: "ipackage", + label: "5.13 包序列化模式" + }, + { + type: "doc", + id: "othercore", + label: "5.14 其他相关功能类" + }, + ] + }, + { + type: "category", + label: "06、Tcp组件", + items: + [ + { + type: "doc", + id: "createtcpservice", + label: "6.1 创建TcpService" + }, + { + type: "doc", + id: "createtcpclient", + label: "6.2 创建TcpClient" + }, + { + type: "doc", + id: "waitingclient", + label: "6.3 同步请求" + }, + { + type: "doc", + id: "natservice", + label: "6.4 Tcp端口转发" + }, + { + type: "doc", + id: "resetid", + label: "6.5 服务器重置ID" + }, + { + type: "doc", + id: "reconnection", + label: "6.6 断线重连" + }, + { + type: "doc", + id: "tcpcommandlineplugin", + label: "6.7 命令行执行插件" + }, + { + type: "doc", + id: "heartbeat", + label: "6.8 心跳设计" + }, + { + type: "doc", + id: "tcpother", + label: "6.9 其他场景应用" + }, + ] + }, + { + type: "category", + label: "07、Udp组件", + items: + [ + { + type: "doc", + id: "createudpsession", + label: "7.1 创建UdpSession" + }, + { + type: "doc", + id: "udptransmitbigdata", + label: "7.2 传输大于64K的数据" + }, + { + type: "doc", + id: "udpbroadcast", + label: "7.3 组播、广播" + }, + ] + }, + { + type: "category", + label: "08、数据处理适配器", + items: + [ + { + type: "doc", + id: "adapterdescription", + label: "8.1 介绍及使用" + }, + { + type: "category", + label: "8.2 Tcp适配器", + items: + [ + { + type: "doc", + id: "normaldatahandlingadapter", + label: "a.正常数据处理适配器" + }, + { + type: "doc", + id: "fixedheaderpackageadapter", + label: "b.固定包头数据处理适配器" + }, + { + type: "doc", + id: "fixedsizepackageadapter", + label: "c.固定长度数据处理适配器" + }, + { + type: "doc", + id: "terminatorpackageadapter", + label: "d.终止因子数据处理适配器" + }, + { + type: "doc", + id: "datahandleadapter", + label: "e.原始自定义适配器" + }, + { + type: "doc", + id: "customdatahandlingadapter", + label: "f.用户自定义适配器" + }, + { + type: "doc", + id: "customfixedheaderdatahandlingadapter", + label: "g.模板解析固定包头适配器" + }, + { + type: "doc", + id: "customunfixedheaderdatahandlingadapter", + label: "h.模板解析非固定包头适配器" + }, + { + type: "doc", + id: "bigfixedheadercustomdatahandlingadapter", + label: "i.模板解析大数据固定包头适配器" + }, + { + type: "doc", + id: "custombetweenanddatahandlingadapter", + label: "j.模板解析区间数据适配器" + }, + { + type: "doc", + id: "pipelinedatahandlingadapter", + label: "k.Pipeline数据适配器" + }, + { + type: "doc", + id: "tlvdatahandlingadapter", + label: "l.三元组编码TLV适配器" + }, + ] + }, + { + type: "category", + label: "8.3 Udp适配器", + items: + [ + { + type: "doc", + id: "udpdatahandlingadapter", + label: "a.原始自定义适配器" + }, + ] + }, + { + type: "category", + label: "8.4 适配器案例赏析", + items: + [ + { + type: "doc", + id: "adapterdemodescription", + label: "a.说明" + }, + { + type: "doc", + id: "stategridtransmission", + label: "b.国网输电i1标准版" + }, + ] + }, + { + type: "doc", + id: "independentusedatahandlingadapter", + label: "8.5 独立使用适配器" + }, + { + type: "doc", + id: "dataadaptertester", + label: "8.6 适配器完整性、性能测试" + }, + ] + }, + { + type: "category", + label: "09、Http组件", + items: + [ + { + type: "doc", + id: "createhttpservice", + label: "9.1 创建HttpService" + }, + { + type: "doc", + id: "createhttpclient", + label: "9.2 创建HttpClient" + }, + { + type: "doc", + id: "httpstaticpageplugin", + label: "9.3 静态页面插件" + }, + { + type: "doc", + id: "httpfiletransfer", + label: "9.4 文件传输" + }, + ] + }, + { + type: "category", + label: "10、WebSocket组件", + items: + [ + { + type: "doc", + id: "websocketdescription", + label: "10.1 产品及架构介绍" + }, + { + type: "doc", + id: "createwebsocketservice", + label: "10.2 创建WebSocket服务器" + }, + { + type: "doc", + id: "createwebsocketclient", + label: "10.3 创建WebSocket客户端" + }, + { + type: "doc", + id: "wscommandlineplugin", + label: "10.4 WSCommandLinePlugin" + }, + { + type: "doc", + id: "wsjsonrpc", + label: "10.5 基于WS的JsonRpc" + }, + ] + }, + { + type: "category", + label: "11、TouchRpc组件", + items: + [ + { + type: "doc", + id: "touchrpcdescription", + label: "11.1 产品及架构介绍" + }, + { + type: "doc", + id: "createtouchrpcservice", + label: "11.2 创建TouchRpc服务器" + }, + { + type: "doc", + id: "createtouchrpcclient", + label: "11.3 创建TouchRpc客户端" + }, + { + type: "doc", + id: "touchrpcbase", + label: "11.4 基础功能" + }, + { + type: "category", + label: "11.5 Rpc功能", + items: + [ + { + type: "doc", + id: "createandcallrpc", + label: "a.创建、调用rpc服务" + }, + { + type: "doc", + id: "rpcstream", + label: "b.Rpc大数据流式传输" + }, + { + type: "doc", + id: "rpcoption", + label: "c.调用配置" + }, + { + type: "doc", + id: "serializationselector", + label: "d.序列化选择器" + }, + { + type: "doc", + id: "rpcallcontext", + label: "e.调用上下文" + }, + { + type: "doc", + id: "rpcactionfilter", + label: "f.Rpc服务AOP" + }, + { + type: "doc", + id: "generateproxy", + label: "f.生成、获取代理" + } + ] + }, + { + type: "category", + label: "11.6 文件传输", + items: + [ + { + type: "doc", + id: "transferfile", + label: "a.传输文件" + }, + { + type: "doc", + id: "smallfiletransfer", + label: "c.小文件传输" + }, + { + type: "doc", + id: "multithreadingfiletransfer", + label: "c.多线程文件传输" + } + ] + }, + { + type: "doc", + id: "remotefilecontrol", + label: "11.7 远程文件操作" + }, + { + type: "doc", + id: "streamtransfer", + label: "11.8 Stream传输" + }, + { + type: "doc", + id: "remotestreamaccess", + label: "11.9 远程流访问" + }, + { + type: "doc", + id: "eventbus", + label: "11.10 EventBus" + } + ] + }, + { + type: "category", + label: "12、WebApi组件", + items: + [ + { + type: "doc", + id: "webapidescription", + label: "12.1 产品及架构介绍" + }, + { + type: "doc", + id: "webapiservice", + label: "12.2 定义、发布、启动服务" + }, + { + type: "doc", + id: "callwebapi", + label: "12.3 发现、调用服务" + }, + ] + }, + { + type: "category", + label: "13、JsonRpc组件", + items: + [ + { + type: "doc", + id: "jsonrpcdescription", + label: "13.1 产品及架构介绍" + }, + { + type: "doc", + id: "jsonrpcservice", + label: "13.2 定义、发布、启动服务" + }, + { + type: "doc", + id: "calljsonrpc", + label: "13.3 发现、调用服务" + }, + ] + }, + { + type: "category", + label: "14、XmlRpc组件件", + items: + [ + { + type: "doc", + id: "xmlrpcdescription", + label: "14.1 产品及架构介绍" + }, + { + type: "doc", + id: "xmlrpcservice", + label: "14.2 定义、发布、启动服务" + }, + { + type: "doc", + id: "callxmlrpc", + label: "14.3 发现、调用服务" + }, + ] + } + ] +}; + diff --git a/handbook/src/components/Highlight.js b/handbook/src/components/Highlight.js new file mode 100644 index 000000000..acf76e551 --- /dev/null +++ b/handbook/src/components/Highlight.js @@ -0,0 +1,15 @@ +import React from 'react'; + +export default function Highlight({children, color}) { + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/handbook/src/components/Tag.js b/handbook/src/components/Tag.js new file mode 100644 index 000000000..8eb581bbb --- /dev/null +++ b/handbook/src/components/Tag.js @@ -0,0 +1,68 @@ +import React from "react"; +import IconFont from "./iconfonts"; +import classes from "./Tag.module.css"; + +export default function (props) { + const { children } = props; + const operates = { + 新增: { + icon: "xinzeng", + bgColor: "#39b54a", + }, + 修复: { + icon: "bug", + bgColor: "#9c26b0", + }, + 文档: { + icon: "wendang", + bgColor: "rgb(79, 147, 255)", + }, + 更新: { + icon: "gengxin", + bgColor: "#0081ff", + }, + 调整: { + icon: "tiaozheng", + bgColor: "#333", + }, + 升级: { + icon: "shengji", + bgColor: "#e03997", + }, + 移除: { + icon: "shanchu", + bgColor: "#666", + }, + 答疑: { + icon: "dayi", + bgColor: "#bbb", + }, + 优化: { + icon: "youhua", + bgColor: "#38e550", + }, + + 推荐: { + bgColor: "#38e550", + }, + + 企业版: { + bgColor: "#23AAF2", + }, + }; + return ( + + ); +} diff --git a/handbook/src/components/Tag.module.css b/handbook/src/components/Tag.module.css new file mode 100644 index 000000000..8565ff2e3 --- /dev/null +++ b/handbook/src/components/Tag.module.css @@ -0,0 +1,17 @@ +.label { + display: inline-flex; + align-items: center; + color: #fff; + padding: 4px 6px; + font-size: 12px; + color: #fff; + border-radius: 3px; + line-height: normal; + margin-left: -3px; + vertical-align: middle; + margin-right: 6px; +} + +.icon { + margin-right: 4px; +} \ No newline at end of file diff --git a/handbook/src/components/iconfonts/IconBug.d.ts b/handbook/src/components/iconfonts/IconBug.d.ts new file mode 100644 index 000000000..741f1e675 --- /dev/null +++ b/handbook/src/components/iconfonts/IconBug.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconBug: FunctionComponent; + +export default IconBug; diff --git a/handbook/src/components/iconfonts/IconBug.js b/handbook/src/components/iconfonts/IconBug.js new file mode 100644 index 000000000..b5654cc43 --- /dev/null +++ b/handbook/src/components/iconfonts/IconBug.js @@ -0,0 +1,31 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconBug = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + + ); +}; + +IconBug.defaultProps = { + size: 18, +}; + +export default IconBug; diff --git a/handbook/src/components/iconfonts/IconDayi.d.ts b/handbook/src/components/iconfonts/IconDayi.d.ts new file mode 100644 index 000000000..aecc11461 --- /dev/null +++ b/handbook/src/components/iconfonts/IconDayi.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconDayi: FunctionComponent; + +export default IconDayi; diff --git a/handbook/src/components/iconfonts/IconDayi.js b/handbook/src/components/iconfonts/IconDayi.js new file mode 100644 index 000000000..fd7f63475 --- /dev/null +++ b/handbook/src/components/iconfonts/IconDayi.js @@ -0,0 +1,31 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconDayi = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + + ); +}; + +IconDayi.defaultProps = { + size: 18, +}; + +export default IconDayi; diff --git a/handbook/src/components/iconfonts/IconDown.d.ts b/handbook/src/components/iconfonts/IconDown.d.ts new file mode 100644 index 000000000..4d06f276c --- /dev/null +++ b/handbook/src/components/iconfonts/IconDown.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconDown: FunctionComponent; + +export default IconDown; diff --git a/handbook/src/components/iconfonts/IconDown.js b/handbook/src/components/iconfonts/IconDown.js new file mode 100644 index 000000000..e25ecf6b4 --- /dev/null +++ b/handbook/src/components/iconfonts/IconDown.js @@ -0,0 +1,27 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconDown = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + ); +}; + +IconDown.defaultProps = { + size: 18, +}; + +export default IconDown; diff --git a/handbook/src/components/iconfonts/IconFuwu.d.ts b/handbook/src/components/iconfonts/IconFuwu.d.ts new file mode 100644 index 000000000..44e8e3d81 --- /dev/null +++ b/handbook/src/components/iconfonts/IconFuwu.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconFuwu: FunctionComponent; + +export default IconFuwu; diff --git a/handbook/src/components/iconfonts/IconFuwu.js b/handbook/src/components/iconfonts/IconFuwu.js new file mode 100644 index 000000000..a1770ed73 --- /dev/null +++ b/handbook/src/components/iconfonts/IconFuwu.js @@ -0,0 +1,27 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconFuwu = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + ); +}; + +IconFuwu.defaultProps = { + size: 18, +}; + +export default IconFuwu; diff --git a/handbook/src/components/iconfonts/IconGengxin.d.ts b/handbook/src/components/iconfonts/IconGengxin.d.ts new file mode 100644 index 000000000..6d0f8e89a --- /dev/null +++ b/handbook/src/components/iconfonts/IconGengxin.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconGengxin: FunctionComponent; + +export default IconGengxin; diff --git a/handbook/src/components/iconfonts/IconGengxin.js b/handbook/src/components/iconfonts/IconGengxin.js new file mode 100644 index 000000000..e58ce4953 --- /dev/null +++ b/handbook/src/components/iconfonts/IconGengxin.js @@ -0,0 +1,27 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconGengxin = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + ); +}; + +IconGengxin.defaultProps = { + size: 18, +}; + +export default IconGengxin; diff --git a/handbook/src/components/iconfonts/IconShanchu.d.ts b/handbook/src/components/iconfonts/IconShanchu.d.ts new file mode 100644 index 000000000..bc478b775 --- /dev/null +++ b/handbook/src/components/iconfonts/IconShanchu.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconShanchu: FunctionComponent; + +export default IconShanchu; diff --git a/handbook/src/components/iconfonts/IconShanchu.js b/handbook/src/components/iconfonts/IconShanchu.js new file mode 100644 index 000000000..6b40a3247 --- /dev/null +++ b/handbook/src/components/iconfonts/IconShanchu.js @@ -0,0 +1,31 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconShanchu = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + + ); +}; + +IconShanchu.defaultProps = { + size: 18, +}; + +export default IconShanchu; diff --git a/handbook/src/components/iconfonts/IconShengji.d.ts b/handbook/src/components/iconfonts/IconShengji.d.ts new file mode 100644 index 000000000..b56a539ad --- /dev/null +++ b/handbook/src/components/iconfonts/IconShengji.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconShengji: FunctionComponent; + +export default IconShengji; diff --git a/handbook/src/components/iconfonts/IconShengji.js b/handbook/src/components/iconfonts/IconShengji.js new file mode 100644 index 000000000..a338addab --- /dev/null +++ b/handbook/src/components/iconfonts/IconShengji.js @@ -0,0 +1,35 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconShengji = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + + + ); +}; + +IconShengji.defaultProps = { + size: 18, +}; + +export default IconShengji; diff --git a/handbook/src/components/iconfonts/IconTiaozheng.d.ts b/handbook/src/components/iconfonts/IconTiaozheng.d.ts new file mode 100644 index 000000000..bce4bfa8e --- /dev/null +++ b/handbook/src/components/iconfonts/IconTiaozheng.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconTiaozheng: FunctionComponent; + +export default IconTiaozheng; diff --git a/handbook/src/components/iconfonts/IconTiaozheng.js b/handbook/src/components/iconfonts/IconTiaozheng.js new file mode 100644 index 000000000..32230b2c6 --- /dev/null +++ b/handbook/src/components/iconfonts/IconTiaozheng.js @@ -0,0 +1,27 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconTiaozheng = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + ); +}; + +IconTiaozheng.defaultProps = { + size: 18, +}; + +export default IconTiaozheng; diff --git a/handbook/src/components/iconfonts/IconUp.d.ts b/handbook/src/components/iconfonts/IconUp.d.ts new file mode 100644 index 000000000..e80e34c5d --- /dev/null +++ b/handbook/src/components/iconfonts/IconUp.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconUp: FunctionComponent; + +export default IconUp; diff --git a/handbook/src/components/iconfonts/IconUp.js b/handbook/src/components/iconfonts/IconUp.js new file mode 100644 index 000000000..0f13d7561 --- /dev/null +++ b/handbook/src/components/iconfonts/IconUp.js @@ -0,0 +1,27 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconUp = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + ); +}; + +IconUp.defaultProps = { + size: 18, +}; + +export default IconUp; diff --git a/handbook/src/components/iconfonts/IconWendang.d.ts b/handbook/src/components/iconfonts/IconWendang.d.ts new file mode 100644 index 000000000..9a94d9de3 --- /dev/null +++ b/handbook/src/components/iconfonts/IconWendang.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconWendang: FunctionComponent; + +export default IconWendang; diff --git a/handbook/src/components/iconfonts/IconWendang.js b/handbook/src/components/iconfonts/IconWendang.js new file mode 100644 index 000000000..318206f94 --- /dev/null +++ b/handbook/src/components/iconfonts/IconWendang.js @@ -0,0 +1,35 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconWendang = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + + + ); +}; + +IconWendang.defaultProps = { + size: 18, +}; + +export default IconWendang; diff --git a/handbook/src/components/iconfonts/IconXinzeng.d.ts b/handbook/src/components/iconfonts/IconXinzeng.d.ts new file mode 100644 index 000000000..5a0360afd --- /dev/null +++ b/handbook/src/components/iconfonts/IconXinzeng.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconXinzeng: FunctionComponent; + +export default IconXinzeng; diff --git a/handbook/src/components/iconfonts/IconXinzeng.js b/handbook/src/components/iconfonts/IconXinzeng.js new file mode 100644 index 000000000..808dcbf09 --- /dev/null +++ b/handbook/src/components/iconfonts/IconXinzeng.js @@ -0,0 +1,31 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconXinzeng = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + + ); +}; + +IconXinzeng.defaultProps = { + size: 18, +}; + +export default IconXinzeng; diff --git a/handbook/src/components/iconfonts/IconYouhua.d.ts b/handbook/src/components/iconfonts/IconYouhua.d.ts new file mode 100644 index 000000000..ff2448879 --- /dev/null +++ b/handbook/src/components/iconfonts/IconYouhua.d.ts @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +declare const IconYouhua: FunctionComponent; + +export default IconYouhua; diff --git a/handbook/src/components/iconfonts/IconYouhua.js b/handbook/src/components/iconfonts/IconYouhua.js new file mode 100644 index 000000000..5af3063a9 --- /dev/null +++ b/handbook/src/components/iconfonts/IconYouhua.js @@ -0,0 +1,27 @@ +/* eslint-disable */ + +import React from 'react'; +import { getIconColor } from './helper'; + +const DEFAULT_STYLE = { + display: 'block', +}; + +const IconYouhua = ({ size, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + ); +}; + +IconYouhua.defaultProps = { + size: 18, +}; + +export default IconYouhua; diff --git a/handbook/src/components/iconfonts/helper.d.ts b/handbook/src/components/iconfonts/helper.d.ts new file mode 100644 index 000000000..7d22b9b98 --- /dev/null +++ b/handbook/src/components/iconfonts/helper.d.ts @@ -0,0 +1,3 @@ +/* eslint-disable */ + +export declare const getIconColor: (color: string | string[] | undefined, index: number, defaultColor: string) => string; diff --git a/handbook/src/components/iconfonts/helper.js b/handbook/src/components/iconfonts/helper.js new file mode 100644 index 000000000..b566c4cc7 --- /dev/null +++ b/handbook/src/components/iconfonts/helper.js @@ -0,0 +1,17 @@ +/* eslint-disable */ + +/** + * @param {string | string[] | undefined} color + * @param {number} index + * @param {string} defaultColor + * @return {string} + */ +export const getIconColor = (color, index, defaultColor) => { + return color + ? ( + typeof color === 'string' + ? color + : color[index] || defaultColor + ) + : defaultColor; +}; diff --git a/handbook/src/components/iconfonts/index.d.ts b/handbook/src/components/iconfonts/index.d.ts new file mode 100644 index 000000000..928ddc5d1 --- /dev/null +++ b/handbook/src/components/iconfonts/index.d.ts @@ -0,0 +1,25 @@ +/* eslint-disable */ + +import { SVGAttributes, FunctionComponent } from 'react'; +export { default as IconYouhua } from './IconYouhua'; +export { default as IconDayi } from './IconDayi'; +export { default as IconShengji } from './IconShengji'; +export { default as IconTiaozheng } from './IconTiaozheng'; +export { default as IconGengxin } from './IconGengxin'; +export { default as IconWendang } from './IconWendang'; +export { default as IconShanchu } from './IconShanchu'; +export { default as IconBug } from './IconBug'; +export { default as IconXinzeng } from './IconXinzeng'; +export { default as IconFuwu } from './IconFuwu'; +export { default as IconDown } from './IconDown'; +export { default as IconUp } from './IconUp'; + +interface Props extends Omit, 'color'> { + name: 'youhua' | 'dayi' | 'shengji' | 'tiaozheng' | 'gengxin' | 'wendang' | 'shanchu' | 'bug' | 'xinzeng' | 'fuwu' | 'down' | 'up'; + size?: number; + color?: string | string[]; +} + +declare const IconFont: FunctionComponent; + +export default IconFont; diff --git a/handbook/src/components/iconfonts/index.js b/handbook/src/components/iconfonts/index.js new file mode 100644 index 000000000..9e7980868 --- /dev/null +++ b/handbook/src/components/iconfonts/index.js @@ -0,0 +1,61 @@ +/* eslint-disable */ + +import React from 'react'; +import IconYouhua from './IconYouhua'; +import IconDayi from './IconDayi'; +import IconShengji from './IconShengji'; +import IconTiaozheng from './IconTiaozheng'; +import IconGengxin from './IconGengxin'; +import IconWendang from './IconWendang'; +import IconShanchu from './IconShanchu'; +import IconBug from './IconBug'; +import IconXinzeng from './IconXinzeng'; +import IconFuwu from './IconFuwu'; +import IconDown from './IconDown'; +import IconUp from './IconUp'; +export { default as IconYouhua } from './IconYouhua'; +export { default as IconDayi } from './IconDayi'; +export { default as IconShengji } from './IconShengji'; +export { default as IconTiaozheng } from './IconTiaozheng'; +export { default as IconGengxin } from './IconGengxin'; +export { default as IconWendang } from './IconWendang'; +export { default as IconShanchu } from './IconShanchu'; +export { default as IconBug } from './IconBug'; +export { default as IconXinzeng } from './IconXinzeng'; +export { default as IconFuwu } from './IconFuwu'; +export { default as IconDown } from './IconDown'; +export { default as IconUp } from './IconUp'; + +const IconFont = ({ name, ...rest }) => { + switch (name) { + case 'youhua': + return ; + case 'dayi': + return ; + case 'shengji': + return ; + case 'tiaozheng': + return ; + case 'gengxin': + return ; + case 'wendang': + return ; + case 'shanchu': + return ; + case 'bug': + return ; + case 'xinzeng': + return ; + case 'fuwu': + return ; + case 'down': + return ; + case 'up': + return ; + + } + + return null; +}; + +export default IconFont; diff --git a/handbook/src/css/custom.css b/handbook/src/css/custom.css new file mode 100644 index 000000000..74ba0f27f --- /dev/null +++ b/handbook/src/css/custom.css @@ -0,0 +1,25 @@ +/* stylelint-disable docusaurus/copyright-header */ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #25c2a0; + --ifm-color-primary-dark: rgb(33, 175, 144); + --ifm-color-primary-darker: rgb(31, 165, 136); + --ifm-color-primary-darkest: rgb(26, 136, 112); + --ifm-color-primary-light: rgb(70, 203, 174); + --ifm-color-primary-lighter: rgb(102, 212, 189); + --ifm-color-primary-lightest: rgb(146, 224, 208); + --ifm-code-font-size: 95%; +} + +.docusaurus-highlight-code-line { + background-color: rgb(72, 77, 91); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); +} diff --git a/handbook/src/pages/android.svg b/handbook/src/pages/android.svg new file mode 100644 index 000000000..87021d1d0 --- /dev/null +++ b/handbook/src/pages/android.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/handbook/src/pages/docker.svg b/handbook/src/pages/docker.svg new file mode 100644 index 000000000..9a33c4750 --- /dev/null +++ b/handbook/src/pages/docker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/handbook/src/pages/index.css b/handbook/src/pages/index.css new file mode 100644 index 000000000..7cca6a75e --- /dev/null +++ b/handbook/src/pages/index.css @@ -0,0 +1,588 @@ +.TouchSocket-banner { + padding: 4rem 2rem; + align-items: center; + background-color: #211b50; + color: #fff; +} + +.TouchSocket-banner-container { + display: flex; + justify-content: space-between; + max-width: 1140px; + margin: 0 auto; +} + +.TouchSocket-banner-item { + flex: 1; +} + +.TouchSocket-banner-project { + font-size: 1.5em; + font-weight: 700; +} + +.TouchSocket-banner-description { + margin: 24px 0; + font-size: 2.2em; + font-weight: 700; + line-height: 1.25; + background-image: linear-gradient(81deg, #8759ff, #3fc4fe, #42ffac); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.TouchSocket-banner-spec { + padding: 0; + opacity: 0.7; + font-family: Muli; + font-size: 1em; + font-weight: 500; + line-height: 1.33; +} + +.TouchSocket-banner-spec li { + list-style: none; + position: relative; + padding-left: 1em; + margin-bottom: 1em; +} + +.TouchSocket-banner-spec li::before { + content: ""; + position: absolute; + top: 0.5em; + left: 0; + width: 4px; + height: 4px; + background-color: rgb(135, 89, 255); +} + +.TouchSocket-support-platform { + font-size: 0.85em; + line-height: 2; + margin-top: 3em; + font-weight: 500; + opacity: 0.6; + color: white; + font-family: Muli; +} + +.TouchSocket-support-icons { + display: flex; + margin-top: 12px; +} + +.TouchSocket-support-icons span { + margin-right: 20px; +} + +.TouchSocket-get-start, +.TouchSocket-try-demo { + margin-top: 4em; + border-radius: 2em; + min-width: 145px; + color: #fff; + background: #8759ff; + position: relative; + line-height: 1.5; + text-align: center; + padding: 8px 32px; + text-decoration: none; + display: inline-block; + white-space: nowrap; +} + +.TouchSocket-try-demo { + background-color: rgb(33, 176, 145); + margin-left: 20px; +} + +.TouchSocket-get-start:hover { + background: rgba(135, 89, 255, 0.9); +} + +.TouchSocket-try-demo:hover { + opacity: 0.9; +} + +.TouchSocket-banner-item .system-window { + width: 34rem; +} + +.TouchSocket-get-start:hover, +.TouchSocket-try-demo:hover { + color: #fff; + text-decoration: none; +} + +.system-top-bar { + background-image: linear-gradient(to right, + rgba(136, 89, 255, 0.2), + rgba(63, 196, 254, 0.2) 90%, + rgba(66, 255, 172, 0.2)); + padding: 0.25em 1em; +} + +.system-top-bar-circle { + display: inline-block; + width: 0.5em; + height: 0.5em; + margin-left: 0.3em; + border-radius: 50%; + filter: brightness(100%); +} + +.system-window { + --ifm-leading: 0; + width: 95%; + padding: 0; + border-radius: 1em; + overflow: hidden; + background: rgb(33, 27, 80); +} + +.system-window iframe { + border-radius: unset; +} + +.system-window pre { + margin-bottom: 0 !important; +} + +.blue-accent { + --uni-border-color: #3fbbfe; + --uni-box-shadow-color: rgba(63, 187, 254, 0.1); + --ifm-menu-color-active: #3fbbfe; +} + +.preview-border { + box-shadow: 0 6px 58px 0 rgba(63, 187, 254, 0.1); + border: solid 1px #3fbbfe; +} + +.TouchSocket-content { + margin-top: 4em; + margin-bottom: 4em; + text-align: center; +} + +.TouchSocket-small-title { + color: #412a94; + font-family: Muli; + font-size: 1em; + font-weight: 600; + letter-spacing: 1px; + opacity: 0.6; +} + +.TouchSocket-small-title.dark { + color: #f5f6f7; +} + +.TouchSocket-big-title { + color: #412a94; + font-family: Poppins; + font-size: 2em; + font-weight: 700; + line-height: 1.31; + margin-bottom: 2em; +} + +.TouchSocket-big-title.dark { + color: #f5f6f7; +} + +.TouchSocket-gitee-log { + display: flex; + justify-content: center; + flex-wrap: nowrap; +} + +.TouchSocket-log-item { + width: 260px; + height: 173px; + box-sizing: border-box; + margin-right: 65px; + position: relative; +} + +.TouchSocket-log-jiao { + width: 100px; + height: 100px; + background: #fff; + position: absolute; + top: 0; + right: 0; + top: -6px; + right: -6px; + border-top: 1px dashed #a795e8; + border-right: 1px dashed #a795e8; +} + +.TouchSocket-log-jiao.dark { + background: #18191a; +} + +.TouchSocket-log-item:last-child { + margin-right: 0; +} + +.TouchSocket-log-number { + position: relative; + z-index: 2; + height: 100%; + display: flex; + width: 100%; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.TouchSocket-log-number div { + font-size: 3em; + font-weight: 700; +} + +.TouchSocket-log-number span { + font-family: Poppins, sans-serif; + font-stretch: normal; + font-style: normal; + letter-spacing: normal; + line-height: normal; + color: #1c1e21; +} + +.TouchSocket-log-number span.dark { + color: #f5f6f7; +} + +.TouchSocket-remark { + display: flex; + justify-content: center; +} + +.TouchSocket-remark-item { + margin: 2em; + max-width: 320px; + height: 100%; + padding: 4em 2em; + border-style: solid; + border-width: 6px; + border-image-source: linear-gradient(var(--uni-border-gradient-degrees), + #8759ff, + #3fc4fe 51%, + #42ffac); + border-image-slice: 1; +} + +.TouchSocket-remark-item:first-child { + border-top: 0; + border-right: 0; + --uni-border-gradient-degrees: 41deg; +} + +.TouchSocket-remark-item:nth-child(2) { + --uni-border-gradient-degrees: 100deg; + border-right: 0; + border-left: 0; + border-top: 0; + border-bottom: 0; +} + +.TouchSocket-remark-item:last-child { + --uni-border-gradient-degrees: 221deg; + border-bottom: 0; + border-left: 0; +} + +.TouchSocket-remark-p { + height: 150px; +} + +.TouchSocket-remark-p h1 { + font-size: 24px; +} + +.TouchSocket-remark-p p { + color: rgb(71, 71, 71); + font-family: Muli; + font-size: 1em; + line-height: 1.75; + opacity: 0.8; + text-align: center; +} + +.TouchSocket-remark-p p.dark { + color: #f5f6f7; +} + +.TouchSocket-whouse { + align-items: center; + background-color: #412a94 !important; + color: #fff; + display: flex; + padding: 5rem 0; +} + +.TouchSocket-who-custom { + background-color: #fff; + min-height: 500px; + width: 60%; + box-sizing: border-box; + padding: 6rem; + justify-content: flex-end; + align-items: center; + color: #723cff; + text-align: right; + display: flex; + flex-wrap: wrap; +} + +.TouchSocket-custom-img { + text-decoration: none; + color: transparent; + margin-left: 3em; +} + +.TouchSocket-who-des { + padding: 0 5rem; + box-sizing: border-box; +} + +.TouchSocket-who-des p { + color: #fff; + font-family: Muli; + font-size: 1em; + line-height: 1.75; + margin-bottom: 0.8em; + opacity: 0.8; +} + +.footer { + background-color: #211b50 !important; +} + +.TouchSocket-links { + margin: 4em; + text-align: center; +} + +.TouchSocket-links-content a { + display: inline-block; + margin: 0 1em; + font-size: 20px; + font-weight: 600; +} + +.TouchSocket-proccesson { + margin: 4em 0; + text-align: center; +} + +#dotnet-china { + height: 100px; +} + +.TouchSocket-contributors { + margin: 4em 0; + text-align: center; +} + +.TouchSocket-contributor-item { + display: inline-block; + margin: 10px 5px; + text-align: center; + background-color: #f3f3f3; + color: #333; + padding: 10px; + width: 130px; + overflow: hidden; + border-radius: 4px; + height: 170px; + box-shadow: 4px 3px 16px -3px #0009; + box-sizing: border-box; + position: relative; +} + +.TouchSocket-contributor-extra { + position: absolute; + top: -9px; + right: 0; + padding: 2px 5px; + background-color: #412a94; + color: #fff; + font-size: 12px; + border-radius: 4px; + text-align: left; +} + +.TouchSocket-contributor-item a { + text-decoration: none; + color: #333; + font-weight: bold; + display: block; + font-size: 10pt; +} + +.TouchSocket-contributor-item div { + margin-top: 10px; +} + +.TouchSocket-contributor-item img { + display: block; + width: 100%; +} + +.TouchSocket-contributor-item.dark { + background: #333; +} + +.TouchSocket-contributor-item.dark a { + color: #f5f6f7; +} + +.TouchSocket-get-start-btn { + position: relative; + display: flex; +} + +.TouchSocket-version { + position: absolute; + z-index: 10; + right: 0; + top: -10px; + color: yellow; + font-size: 16px; +} + +@media screen and (max-width: 1024px) { + .TouchSocket-banner-container { + justify-content: unset; + flex-direction: column; + } + + .TouchSocket-get-start-btn { + text-align: center; + } + + #dotnet-china { + height: 45px; + } + + .TouchSocket-banner-item .system-window { + width: 100%; + margin-top: 3rem; + } + + .TouchSocket-gitee-log { + justify-content: center; + flex-wrap: unset; + flex-direction: column; + align-items: center; + padding: 20px; + } + + .TouchSocket-log-item { + width: 100%; + height: 173px; + margin-right: 0; + margin-top: 25px; + } + + .TouchSocket-big-title { + margin-bottom: 1em; + } + + .TouchSocket-remark { + flex-direction: column; + } + + .TouchSocket-whouse { + flex-direction: column; + padding-bottom: 1em; + } + + .TouchSocket-who-des { + padding-top: 1em; + padding-bottom: 2em; + } + + .TouchSocket-remark-item { + border: none; + margin: 0; + width: 100%; + max-width: unset; + padding-bottom: 0; + } + + .TouchSocket-custom-img { + margin-left: 0; + margin-bottom: 2em; + } + + .TouchSocket-custom-img img { + max-width: unset; + } + + .TouchSocket-who-custom { + justify-content: center; + align-items: center; + width: 100%; + text-align: center; + } + + .TouchSocket-contributors { + margin: 4em 0; + } +} + +.TouchSocket-bifa { + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + color: #fff; + display: flex; + flex-direction: row-reverse; + justify-content: center; + padding: 100px 0; +} + +.TouchSocket-wzi { + border-left: 1px solid rgba(137, 147, 180, 0.5); + writing-mode: vertical-lr; + font-size: 20px; + font-family: Arial, Helvetica, sans-serif; + letter-spacing: 10px; + padding: 25px; + height: 320px; +} + +.TouchSocket-wzi span { + color: rgb(68, 188, 254); + font-weight: 500; +} + +.TouchSocket-wzi-title { + width: 84px; + height: 320px; + writing-mode: vertical-lr; + background: rgb(68, 114, 196); + background-image: linear-gradient(rgb(91, 128, 212) 1px, transparent 0), + linear-gradient(90deg, rgb(91, 128, 212) 1px, transparent 0); + background-size: 8px 8px; + margin-left: 40px; + font-size: 22px; + font-weight: 500; + letter-spacing: 12px; + display: flex; + align-items: center; +} + +.TouchSocket-wzi-title b { + font-size: 20px; + writing-mode: horizontal-tb; + font-family: Arial, Helvetica, sans-serif; + margin: 20px 0; + letter-spacing: 2px; +} \ No newline at end of file diff --git a/handbook/src/pages/index.js b/handbook/src/pages/index.js new file mode 100644 index 000000000..388854c59 --- /dev/null +++ b/handbook/src/pages/index.js @@ -0,0 +1,235 @@ +import Link from "@docusaurus/Link"; +import { useColorMode } from "@docusaurus/theme-common"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import Layout from "@theme/Layout"; +import components from "@theme/MDXComponents"; +import React from "react"; +import AndroidIcon from "./android.svg"; +import DockerIcon from "./docker.svg"; +import "./index.css"; +import "./index.own.css"; +import KubernetesIcon from "./kubernetes.svg"; +import LinuxIcon from "./linux.svg"; +import MacOSIcon from "./macos.svg"; +import WindowIcon from "./windows.svg"; + +function Home() { + const context = useDocusaurusContext(); + const { siteConfig = {} } = context; + + React.useEffect(() => {}, []); + + return ( + + + + + ); +} + +function Banner() { + return ( +
+
+
+
+ TouchSocket{" "} + +
+
+ 一款简单易用的基础网络通讯组件库。 +
+
+ 两岸猿声啼不住,轻舟已过万重山。 +
+
    +
  • Apache-2.0 宽松开源协议,商业免费授权
  • +
  • + 支持 .NET Framework 4.5及以上, .NET Core3.1及以上,.NET + Standard2.0及以上 +
  • +
  • 无依赖
  • +
  • 极速上手,极简使用
  • +
+
受支持平台:
+
+ + + + + + + + + + + + + + + + + + +
+
+ + 入门指南 + {/* v1.0 */} + +
+
+
+ + { };//有客户端正在连接 +service.Connected = (client, e) => { };//有客户端成功连接 +service.Disconnected = (client, e) => { };//有客户端断开连接 +service.Received = (client, byteBlock, requestInfo) => +{ + //从客户端收到信息 + string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len); + client.Logger.Info($"已从{client.ID}接收到信息:{mes}"); +}; + +service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost("tcp://127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + }) + .ConfigurePlugins(a => + { + //a.Add();//此处可以添加插件 + })) + .Start();//启动 +`} + /> + +
+
+
+ ); +} + +function Gitee() { + const { colorMode, setLightTheme, setDarkTheme } = useColorMode(); + const isDarkTheme = colorMode === "dark"; + + return ( +
+

+ 开源免费/商业免费授权 +

+

+ ⭐️ Apache-2.0 开源协议,代码在 Gitee/Github 平台托管 ⭐️ +

+
+
+
+
+
1000 +
+ Stars +
+
+
+
+
+
400 +
+ Forks +
+
+
+
+
+
106,125
+ Downloads +
+
+
+
+ ); +} + +function CodeSection(props) { + let { language, replace, section, source } = props; + + source = source.replace(/\/\/ <.*?\n/g, ""); + + if (replace) { + for (const [pattern, value] of Object.entries(replace)) { + source = source.replace(new RegExp(pattern, "gs"), value); + } + } + + source = source.trim(); + if (!source.includes("\n")) { + source += "\n"; + } + + return ( + + + + ); +} + +function SystemWindow(systemWindowProps) { + const { children, className, ...props } = systemWindowProps; + return ( +
+
+ + + +
+ {children} +
+ ); +} + +export default Home; diff --git a/handbook/src/pages/index.own.css b/handbook/src/pages/index.own.css new file mode 100644 index 000000000..e6869a0a3 --- /dev/null +++ b/handbook/src/pages/index.own.css @@ -0,0 +1,25 @@ +.navbar { + background-color: #211b50; +} + +.navbar__brand { + color: #fff; +} + +.navbar__link { + color: #fff; +} + +.navbar__link:hover, +.navbar__link--active { + color: yellow; +} + +.navbar__items { + color: #fff; +} + +.menu__list-item .navbar__link--active, +.menu__list-item .navbar__link:hover { + color: #743dff; +} \ No newline at end of file diff --git a/handbook/src/pages/kubernetes.svg b/handbook/src/pages/kubernetes.svg new file mode 100644 index 000000000..224bc3596 --- /dev/null +++ b/handbook/src/pages/kubernetes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/handbook/src/pages/linux.svg b/handbook/src/pages/linux.svg new file mode 100644 index 000000000..fdf3b4cbe --- /dev/null +++ b/handbook/src/pages/linux.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/handbook/src/pages/macos.svg b/handbook/src/pages/macos.svg new file mode 100644 index 000000000..684071c2b --- /dev/null +++ b/handbook/src/pages/macos.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/handbook/src/pages/windows.svg b/handbook/src/pages/windows.svg new file mode 100644 index 000000000..c67da7c3c --- /dev/null +++ b/handbook/src/pages/windows.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/handbook/static/.nojekyll b/handbook/static/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/handbook/static/img/TouchSocketlogo.png b/handbook/static/img/TouchSocketlogo.png new file mode 100644 index 000000000..d4199b5c3 Binary files /dev/null and b/handbook/static/img/TouchSocketlogo.png differ diff --git a/handbook/static/img/chinadotnet.png b/handbook/static/img/chinadotnet.png new file mode 100644 index 000000000..cbe49d197 Binary files /dev/null and b/handbook/static/img/chinadotnet.png differ diff --git a/handbook/static/img/docs/consoleaction-1.gif b/handbook/static/img/docs/consoleaction-1.gif new file mode 100644 index 000000000..3e24d573d Binary files /dev/null and b/handbook/static/img/docs/consoleaction-1.gif differ diff --git a/handbook/static/img/docs/createhttpservice-1.png b/handbook/static/img/docs/createhttpservice-1.png new file mode 100644 index 000000000..c6a6e3c54 Binary files /dev/null and b/handbook/static/img/docs/createhttpservice-1.png differ diff --git a/handbook/static/img/docs/createtcpservice-1.png b/handbook/static/img/docs/createtcpservice-1.png new file mode 100644 index 000000000..dc7300f00 Binary files /dev/null and b/handbook/static/img/docs/createtcpservice-1.png differ diff --git a/handbook/static/img/docs/createtcpservice-2.png b/handbook/static/img/docs/createtcpservice-2.png new file mode 100644 index 000000000..7f3fcc503 Binary files /dev/null and b/handbook/static/img/docs/createtcpservice-2.png differ diff --git a/handbook/static/img/docs/customdatahandlingadapter-1.png b/handbook/static/img/docs/customdatahandlingadapter-1.png new file mode 100644 index 000000000..b1d189ed0 Binary files /dev/null and b/handbook/static/img/docs/customdatahandlingadapter-1.png differ diff --git a/handbook/static/img/docs/dataforwarding-1.png b/handbook/static/img/docs/dataforwarding-1.png new file mode 100644 index 000000000..b59df3df8 Binary files /dev/null and b/handbook/static/img/docs/dataforwarding-1.png differ diff --git a/handbook/static/img/docs/datahandleadapter-1.png b/handbook/static/img/docs/datahandleadapter-1.png new file mode 100644 index 000000000..253449fb4 Binary files /dev/null and b/handbook/static/img/docs/datahandleadapter-1.png differ diff --git a/handbook/static/img/docs/donate-1.png b/handbook/static/img/docs/donate-1.png new file mode 100644 index 000000000..da3686d2e Binary files /dev/null and b/handbook/static/img/docs/donate-1.png differ diff --git a/handbook/static/img/docs/engineertoolbox-1.jpg b/handbook/static/img/docs/engineertoolbox-1.jpg new file mode 100644 index 000000000..e716e8475 Binary files /dev/null and b/handbook/static/img/docs/engineertoolbox-1.jpg differ diff --git a/handbook/static/img/docs/engineertoolbox-2.jpg b/handbook/static/img/docs/engineertoolbox-2.jpg new file mode 100644 index 000000000..3253d4595 Binary files /dev/null and b/handbook/static/img/docs/engineertoolbox-2.jpg differ diff --git a/handbook/static/img/docs/engineertoolbox-3.jpg b/handbook/static/img/docs/engineertoolbox-3.jpg new file mode 100644 index 000000000..4f79f1092 Binary files /dev/null and b/handbook/static/img/docs/engineertoolbox-3.jpg differ diff --git a/handbook/static/img/docs/enterprise-1.jpg b/handbook/static/img/docs/enterprise-1.jpg new file mode 100644 index 000000000..1973cf479 Binary files /dev/null and b/handbook/static/img/docs/enterprise-1.jpg differ diff --git a/handbook/static/img/docs/enterprise-1.png b/handbook/static/img/docs/enterprise-1.png new file mode 100644 index 000000000..7be60d7b9 Binary files /dev/null and b/handbook/static/img/docs/enterprise-1.png differ diff --git a/handbook/static/img/docs/fastbinaryformatter-1.png b/handbook/static/img/docs/fastbinaryformatter-1.png new file mode 100644 index 000000000..c967c17da Binary files /dev/null and b/handbook/static/img/docs/fastbinaryformatter-1.png differ diff --git a/handbook/static/img/docs/fastbinaryformatter-2.png b/handbook/static/img/docs/fastbinaryformatter-2.png new file mode 100644 index 000000000..fe7a8322d Binary files /dev/null and b/handbook/static/img/docs/fastbinaryformatter-2.png differ diff --git a/handbook/static/img/docs/filesynchronization-1.png b/handbook/static/img/docs/filesynchronization-1.png new file mode 100644 index 000000000..afbb6d214 Binary files /dev/null and b/handbook/static/img/docs/filesynchronization-1.png differ diff --git a/handbook/static/img/docs/generateproxy-1.png b/handbook/static/img/docs/generateproxy-1.png new file mode 100644 index 000000000..d35238bc9 Binary files /dev/null and b/handbook/static/img/docs/generateproxy-1.png differ diff --git a/handbook/static/img/docs/ilog-1.png b/handbook/static/img/docs/ilog-1.png new file mode 100644 index 000000000..bb07cacb3 Binary files /dev/null and b/handbook/static/img/docs/ilog-1.png differ diff --git a/handbook/static/img/docs/ilog-2.png b/handbook/static/img/docs/ilog-2.png new file mode 100644 index 000000000..324b73cd6 Binary files /dev/null and b/handbook/static/img/docs/ilog-2.png differ diff --git a/handbook/static/img/docs/ipackage-1.jpg b/handbook/static/img/docs/ipackage-1.jpg new file mode 100644 index 000000000..19e5e98e2 Binary files /dev/null and b/handbook/static/img/docs/ipackage-1.jpg differ diff --git a/handbook/static/img/docs/ipackage-1.png b/handbook/static/img/docs/ipackage-1.png new file mode 100644 index 000000000..a732995a2 Binary files /dev/null and b/handbook/static/img/docs/ipackage-1.png differ diff --git a/handbook/static/img/docs/jsonserialize-1.png b/handbook/static/img/docs/jsonserialize-1.png new file mode 100644 index 000000000..9a107177c Binary files /dev/null and b/handbook/static/img/docs/jsonserialize-1.png differ diff --git a/handbook/static/img/docs/jsonserialize-2.png b/handbook/static/img/docs/jsonserialize-2.png new file mode 100644 index 000000000..0565b38db Binary files /dev/null and b/handbook/static/img/docs/jsonserialize-2.png differ diff --git a/handbook/static/img/docs/remotemonitoring-1.png b/handbook/static/img/docs/remotemonitoring-1.png new file mode 100644 index 000000000..3cce7ebe6 Binary files /dev/null and b/handbook/static/img/docs/remotemonitoring-1.png differ diff --git a/handbook/static/img/docs/remotemonitoring-2.gif b/handbook/static/img/docs/remotemonitoring-2.gif new file mode 100644 index 000000000..097618946 Binary files /dev/null and b/handbook/static/img/docs/remotemonitoring-2.gif differ diff --git a/handbook/static/img/docs/remotemonitoring-3.gif b/handbook/static/img/docs/remotemonitoring-3.gif new file mode 100644 index 000000000..c8d786049 Binary files /dev/null and b/handbook/static/img/docs/remotemonitoring-3.gif differ diff --git a/handbook/static/img/docs/remotemonitoring-4.gif b/handbook/static/img/docs/remotemonitoring-4.gif new file mode 100644 index 000000000..055f89d54 Binary files /dev/null and b/handbook/static/img/docs/remotemonitoring-4.gif differ diff --git a/handbook/static/img/docs/remotemonitoring-5.gif b/handbook/static/img/docs/remotemonitoring-5.gif new file mode 100644 index 000000000..e11b88e2d Binary files /dev/null and b/handbook/static/img/docs/remotemonitoring-5.gif differ diff --git a/handbook/static/img/docs/remotemonitoring-6.gif b/handbook/static/img/docs/remotemonitoring-6.gif new file mode 100644 index 000000000..2af03f1c2 Binary files /dev/null and b/handbook/static/img/docs/remotemonitoring-6.gif differ diff --git a/handbook/static/img/docs/remotestreamaccess-1.gif b/handbook/static/img/docs/remotestreamaccess-1.gif new file mode 100644 index 000000000..b7d8db21c Binary files /dev/null and b/handbook/static/img/docs/remotestreamaccess-1.gif differ diff --git a/handbook/static/img/docs/serializationselector-1.png b/handbook/static/img/docs/serializationselector-1.png new file mode 100644 index 000000000..e6ac69c3d Binary files /dev/null and b/handbook/static/img/docs/serializationselector-1.png differ diff --git a/handbook/static/img/docs/startguide-1.png b/handbook/static/img/docs/startguide-1.png new file mode 100644 index 000000000..7d3ad3a60 Binary files /dev/null and b/handbook/static/img/docs/startguide-1.png differ diff --git a/handbook/static/img/docs/startguide-10.png b/handbook/static/img/docs/startguide-10.png new file mode 100644 index 000000000..2227e02e6 Binary files /dev/null and b/handbook/static/img/docs/startguide-10.png differ diff --git a/handbook/static/img/docs/startguide-11.png b/handbook/static/img/docs/startguide-11.png new file mode 100644 index 000000000..368c2094b Binary files /dev/null and b/handbook/static/img/docs/startguide-11.png differ diff --git a/handbook/static/img/docs/startguide-12.png b/handbook/static/img/docs/startguide-12.png new file mode 100644 index 000000000..f805b6454 Binary files /dev/null and b/handbook/static/img/docs/startguide-12.png differ diff --git a/handbook/static/img/docs/startguide-2.png b/handbook/static/img/docs/startguide-2.png new file mode 100644 index 000000000..bdf0131ac Binary files /dev/null and b/handbook/static/img/docs/startguide-2.png differ diff --git a/handbook/static/img/docs/startguide-3.png b/handbook/static/img/docs/startguide-3.png new file mode 100644 index 000000000..24240cda9 Binary files /dev/null and b/handbook/static/img/docs/startguide-3.png differ diff --git a/handbook/static/img/docs/startguide-4.png b/handbook/static/img/docs/startguide-4.png new file mode 100644 index 000000000..221ba949a Binary files /dev/null and b/handbook/static/img/docs/startguide-4.png differ diff --git a/handbook/static/img/docs/startguide-5.png b/handbook/static/img/docs/startguide-5.png new file mode 100644 index 000000000..6a81f5305 Binary files /dev/null and b/handbook/static/img/docs/startguide-5.png differ diff --git a/handbook/static/img/docs/startguide-6.png b/handbook/static/img/docs/startguide-6.png new file mode 100644 index 000000000..3a85f739f Binary files /dev/null and b/handbook/static/img/docs/startguide-6.png differ diff --git a/handbook/static/img/docs/startguide-7.png b/handbook/static/img/docs/startguide-7.png new file mode 100644 index 000000000..bd0c1b668 Binary files /dev/null and b/handbook/static/img/docs/startguide-7.png differ diff --git a/handbook/static/img/docs/startguide-8.png b/handbook/static/img/docs/startguide-8.png new file mode 100644 index 000000000..f2f2f7395 Binary files /dev/null and b/handbook/static/img/docs/startguide-8.png differ diff --git a/handbook/static/img/docs/startguide-9.png b/handbook/static/img/docs/startguide-9.png new file mode 100644 index 000000000..6b4cb70b5 Binary files /dev/null and b/handbook/static/img/docs/startguide-9.png differ diff --git a/handbook/static/img/docs/upgrade-1.png b/handbook/static/img/docs/upgrade-1.png new file mode 100644 index 000000000..7ed97fbed Binary files /dev/null and b/handbook/static/img/docs/upgrade-1.png differ diff --git a/handbook/static/img/docs/upgrade-2.png b/handbook/static/img/docs/upgrade-2.png new file mode 100644 index 000000000..e887f5c39 Binary files /dev/null and b/handbook/static/img/docs/upgrade-2.png differ diff --git a/handbook/static/img/docs/upgrade-3.png b/handbook/static/img/docs/upgrade-3.png new file mode 100644 index 000000000..f6bf023c8 Binary files /dev/null and b/handbook/static/img/docs/upgrade-3.png differ diff --git a/handbook/static/img/docs/upgrade-4.png b/handbook/static/img/docs/upgrade-4.png new file mode 100644 index 000000000..4f4b108f6 Binary files /dev/null and b/handbook/static/img/docs/upgrade-4.png differ diff --git a/handbook/static/img/docs/upgrade-5.png b/handbook/static/img/docs/upgrade-5.png new file mode 100644 index 000000000..dd2298cd5 Binary files /dev/null and b/handbook/static/img/docs/upgrade-5.png differ diff --git a/handbook/static/img/docs/upgrade-6.png b/handbook/static/img/docs/upgrade-6.png new file mode 100644 index 000000000..c79cd6e7b Binary files /dev/null and b/handbook/static/img/docs/upgrade-6.png differ diff --git a/handbook/static/img/docs/webdataforwarding-1.gif b/handbook/static/img/docs/webdataforwarding-1.gif new file mode 100644 index 000000000..55d9ca5ca Binary files /dev/null and b/handbook/static/img/docs/webdataforwarding-1.gif differ diff --git a/handbook/static/img/favicon.ico b/handbook/static/img/favicon.ico new file mode 100644 index 000000000..404af9424 Binary files /dev/null and b/handbook/static/img/favicon.ico differ diff --git a/images/1.png b/images/1.png new file mode 100644 index 000000000..5b50695d8 Binary files /dev/null and b/images/1.png differ diff --git a/logo.png b/logo.png new file mode 100644 index 000000000..d4199b5c3 Binary files /dev/null and b/logo.png differ diff --git a/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/BeetleXRpc.cs b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/BeetleXRpc.cs new file mode 100644 index 000000000..66809d2bc --- /dev/null +++ b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/BeetleXRpc.cs @@ -0,0 +1,113 @@ +using BeetleX.XRPC.Clients; +using BeetleX.XRPC.Hosting; +using BeetleX.XRPC.Packets; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace RpcPerformanceConsoleApp +{ + public static class BeetleXRpc + { + public static void StartServer() + { + var builder = new HostBuilder() + .ConfigureServices((hostContext, services) => + { + services.UseXRPC(s => + { + s.ServerOptions.LogLevel = BeetleX.EventArgs.LogType.Error; + s.ServerOptions.DefaultListen.Port = 9090; + s.RPCOptions.ParameterFormater = new MsgPacket();//default messagepack + }, + typeof(Program).Assembly); + }); + builder.Build().RunAsync(); + } + + public static void StartSumClient(int count) + { + XRPCClient client = new XRPCClient("localhost", 9090); + client.Options.ParameterFormater = new MsgPacket();//default messagepack + ITestTaskController testController = client.Create(); + + var rs = testController.Sum(10, 20);//试调一次,保持在线 + rs.Wait(); + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 0; i < count; i++) + { + var rs = testController.Sum(i, i); + rs.Wait(); + if (rs.Result != i + i) + { + Console.WriteLine("调用结果不一致"); + } + + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + } + + public static void StartGetBytesClient(int count) + { + XRPCClient client = new XRPCClient("localhost", 9090); + client.Options.ParameterFormater = new MsgPacket();//default messagepack + ITestTaskController testController = client.Create(); + + var rs = testController.GetBytes(10);//试调一次,保持在线 + rs.Wait(); + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 1; i < count; i++) + { + var rs = testController.GetBytes(i);//测试10k数据 + rs.Wait(); + if (rs.Result.Length != i) + { + Console.WriteLine("调用结果不一致"); + } + + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + + } + + public static void StartBigStringClient(int count) + { + XRPCClient client = new XRPCClient("localhost", 9090); + client.Options.ParameterFormater = new MsgPacket();//default messagepack + ITestTaskController testController = client.Create(); + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 0; i < count; i++) + { + var rs = testController.GetBigString(); + + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + + } + } +} diff --git a/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/NewLifeRpc.cs b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/NewLifeRpc.cs new file mode 100644 index 000000000..255be5030 --- /dev/null +++ b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/NewLifeRpc.cs @@ -0,0 +1,116 @@ +using NewLife.Log; +using NewLife.Net; +using NewLife.Remoting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace RpcPerformanceConsoleApp +{ + public static class NewLifeRpc + { + public static void StartServer() + { + XTrace.UseConsole(); + var netUri = new NetUri(NetType.Tcp, IPAddress.Any, 5001); + var server = new ApiServer(netUri) + { + //Log = XTrace.Log, + //EncoderLog = XTrace.Log, + //ShowError = true + + //不输出调用日志 + }; + server.Register(); + server.Start(); + Console.WriteLine("NewLifeRpc启动成功"); + } + + public static void StartSumClient(int count) + { + var client = new ApiClient("tcp://127.0.0.1:5001") + { + //Log = XTrace.Log, + //EncoderLog = XTrace.Log + }; + + var rs = client.Invoke("Test/Sum", new { a = 10, b = 20 });//先试调一下,保证已经建立了完整的连接 + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 0; i < count; i++) + { + var rs = client.Invoke("Test/Sum", new { a = i, b = i }); + if (rs != i + i) + { + Console.WriteLine("调用结果不一致"); + } + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + + } + + public static void StartGetBytesClient(int count) + { + var client = new ApiClient("tcp://127.0.0.1:5001") + { + //Log = XTrace.Log, + //EncoderLog = XTrace.Log + }; + + + var rs = client.Invoke("Test/GetBytes", new { a = 10 });//先试调一下,保证已经建立了完整的连接 + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 1; i < count; i++) + { + var rs = client.Invoke("Test/GetBytes", new { a = i });//测试10k数据 + if (rs.Length != i) + { + Console.WriteLine("调用结果不一致"); + } + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + + } + + public static void StartBigStringClient(int count) + { + var client = new ApiClient("tcp://127.0.0.1:5001") + { + //Log = XTrace.Log, + //EncoderLog = XTrace.Log + }; + + + var rs = client.Invoke("Test/GetBigString");//先试调一下,保证已经建立了完整的连接 + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 0; i < count; i++) + { + var rs = client.Invoke("Test/GetBigString"); + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + } + } +} diff --git a/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/Program.cs b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/Program.cs new file mode 100644 index 000000000..1d4f75791 --- /dev/null +++ b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/Program.cs @@ -0,0 +1,45 @@ +using TouchSocket.Core; + +namespace RpcPerformanceConsoleApp +{ + internal class Program + { + static void Main(string[] args) + { + ConsoleAction consoleAction = new ConsoleAction("h|help|?");//设置帮助命令 + consoleAction.OnException += ConsoleAction_OnException;//订阅执行异常输出 + + BeetleXRpc.StartServer(); + NewLifeRpc.StartServer(); + TouchSocketRpc.StartServer(); + + int count = 100000; + + consoleAction.Add("1.1", "BeetleXRpc测试Sum", () => BeetleXRpc.StartSumClient(count)); + consoleAction.Add("1.2", "BeetleXRpc测试GetBytes", () => BeetleXRpc.StartGetBytesClient(count)); + consoleAction.Add("1.3", "BeetleXRpc测试BigString", () => BeetleXRpc.StartBigStringClient(count)); + + consoleAction.Add("2.1", "NewLifeRpc测试Sum", () => NewLifeRpc.StartSumClient(count)); + consoleAction.Add("2.2", "NewLifeRpc测试GetBytes", () => NewLifeRpc.StartGetBytesClient(count)); + consoleAction.Add("2.3", "NewLifeRpc测试BigString", () => NewLifeRpc.StartBigStringClient(count)); + + consoleAction.Add("3.1", "TouchSocketRpc测试Sum", () => TouchSocketRpc.StartSumClient(count)); + consoleAction.Add("3.2", "TouchSocketRpc测试GetBytes", () => TouchSocketRpc.StartGetBytesClient(count)); + consoleAction.Add("3.3", "TouchSocketRpc测试BigString", () => TouchSocketRpc.StartBigStringClient(count)); + + consoleAction.ShowAll(); + while (true) + { + if (!consoleAction.Run(Console.ReadLine())) + { + Console.WriteLine("命令不正确,请输入“h|help|?”获得帮助。"); + } + } + } + + private static void ConsoleAction_OnException(Exception ex) + { + ConsoleLogger.Default.Exception(ex); + } + } +} \ No newline at end of file diff --git a/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/RpcPerformanceConsoleApp.csproj b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/RpcPerformanceConsoleApp.csproj new file mode 100644 index 000000000..3ec3d551a --- /dev/null +++ b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/RpcPerformanceConsoleApp.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + diff --git a/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/TestController.cs b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/TestController.cs new file mode 100644 index 000000000..1097d4674 --- /dev/null +++ b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/TestController.cs @@ -0,0 +1,76 @@ +using EventNext; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Rpc; + +namespace RpcPerformanceConsoleApp +{ + public interface ITestTaskController + { + Task Sum(int a, int b); + + Task GetBytes(int length); + + Task GetBigString(); + } + + /// + /// BeetleXRPC仅支持Task返回。 + /// NewLifeRPC仅支持常规参数返回。 + /// 只有RRQM全兼容。哎!!还得写两个服务类。 + /// + [Service(typeof(ITestTaskController))] + public class TestTaskController : ITestTaskController + { + [TouchRpc(true)] + public Task Sum(int a, int b) + { + return Task.FromResult(a + b); + } + + [TouchRpc(true)] + public Task GetBytes(int length) + { + return Task.FromResult(new byte[length]); + } + + [TouchRpc(true)] + public Task GetBigString() + { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < 10; i++) + { + stringBuilder.Append("RRQM"); + } + return Task.FromResult(stringBuilder.ToString()); + } + } + + + public class TestController : RpcServer + { + [TouchRpc(true)] + public int Sum(int a, int b) => a + b; + + [TouchRpc(true)] + public byte[] GetBytes(int length) + { + return new byte[length]; + } + + [TouchRpc(true)] + public string GetBigString() + { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < 10; i++) + { + stringBuilder.Append("RRQM"); + } + return stringBuilder.ToString(); + } + } +} diff --git a/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/TouchSocketRpc.cs b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/TouchSocketRpc.cs new file mode 100644 index 000000000..98af93d4a --- /dev/null +++ b/performancetest/Rpc对比测试/RpcPerformanceConsoleApp/TouchSocketRpc.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Rpc; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace RpcPerformanceConsoleApp +{ + public static class TouchSocketRpc + { + public static void StartServer() + { + var service = new TcpTouchRpcService(); + var config = new TouchSocketConfig()//配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigureRpcStore(a => + { + a.RegisterServer(); + }) + .SetVerifyToken("TouchRpc");//设定连接口令,作用类似账号密码 + + service.Setup(config) + .Start(); + + service.Logger.Info($"{service.GetType().Name}已启动"); + } + + public static void StartSumClient(int count) + { + TcpTouchRpcClient client = new TcpTouchRpcClient(); + client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("TouchRpc")); + client.Connect(); + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 0; i < count; i++) + { + var rs = client.Invoke("Sum", InvokeOption.WaitInvoke, i, i); + if (rs != i + i) + { + Console.WriteLine("调用结果不一致"); + } + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + } + + public static void StartGetBytesClient(int count) + { + TcpTouchRpcClient client = new TcpTouchRpcClient(); + client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("TouchRpc")); + client.Connect(); + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 1; i < count; i++) + { + var rs = client.Invoke("GetBytes", InvokeOption.WaitInvoke, i);//测试10k数据 + if (rs.Length != i) + { + Console.WriteLine("调用结果不一致"); + } + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + } + + public static void StartBigStringClient(int count) + { + TcpTouchRpcClient client = new TcpTouchRpcClient(); + client.Setup(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .SetVerifyToken("TouchRpc")); + client.Connect(); + + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + for (int i = 0; i < count; i++) + { + var rs = client.Invoke("GetBigString", InvokeOption.WaitInvoke); + if (i % 1000 == 0) + { + Console.WriteLine(i); + } + } + }); + Console.WriteLine(timeSpan); + } + } +} diff --git a/src/TouchSocket.AspNetCore/Core/Common/AspNetCoreContainer.cs b/src/TouchSocket.AspNetCore/Core/Common/AspNetCoreContainer.cs new file mode 100644 index 000000000..053273780 --- /dev/null +++ b/src/TouchSocket.AspNetCore/Core/Common/AspNetCoreContainer.cs @@ -0,0 +1,155 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Core.AspNetCore +{ + /// + /// AspNetCoreContainer + /// + public class AspNetCoreContainer : IContainer + { + private readonly IServiceCollection m_services; + + /// + /// 初始化一个IServiceCollection的容器。 + /// + /// + public AspNetCoreContainer(IServiceCollection services) + { + services.AddSingleton(this); + m_services = services; + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator GetEnumerator() + { + return m_services.ToList().Select(s => + { + DependencyDescriptor descriptor = new DependencyDescriptor(s.ServiceType, s.ImplementationType, (Lifetime)((int)s.Lifetime)); + descriptor.ToInstance = s.ImplementationInstance; + return descriptor; + }).GetEnumerator(); + } + + /// + /// + /// + /// + /// + /// + public bool IsRegistered(Type fromType, string key = "") + { + if (fromType.IsGenericType) + { + fromType = fromType.GetGenericTypeDefinition(); + } + var array = m_services.ToArray(); + foreach (var item in array) + { + if (item.ServiceType == fromType) + { + return true; + } + } + return false; + } + + /// + /// + /// + /// + /// + public void Register(DependencyDescriptor descriptor, string key = "") + { + if (!key.IsNullOrEmpty()) + { + throw new NotSupportedException($"{GetType().Name}不支持包含Key的多实现注入"); + } + if (IsRegistered(descriptor.FromType)) + { + this.Unregister(descriptor.FromType); + } + switch (descriptor.Lifetime) + { + case Lifetime.Singleton: + if (descriptor.ToInstance != null) + { + m_services.AddSingleton(descriptor.FromType, descriptor.ToInstance); + } + else + { + m_services.AddSingleton(descriptor.FromType, descriptor.ToType); + } + break; + + case Lifetime.Transient: + default: + m_services.AddTransient(descriptor.FromType, descriptor.ToType); + break; + } + } + + /// + /// + /// + /// + /// + /// + /// + public object Resolve(Type fromType, object[] ps = null, string key = "") + { + if (fromType == typeof(IContainer)) + { + return this; + } + if (fromType == typeof(IServiceProvider)) + { + return m_services.BuildServiceProvider(); + } + ServiceProvider provider = m_services.BuildServiceProvider(); + + return provider.GetService(fromType); + } + + /// + /// + /// + /// + /// + public void Unregister(DependencyDescriptor descriptor, string key = "") + { + var array = m_services.ToArray(); + foreach (var item in array) + { + if (item.ServiceType == descriptor.FromType) + { + m_services.Remove(item); + return; + } + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Core/Config/AspNetCoreConfigExtension.cs b/src/TouchSocket.AspNetCore/Core/Config/AspNetCoreConfigExtension.cs new file mode 100644 index 000000000..332252e81 --- /dev/null +++ b/src/TouchSocket.AspNetCore/Core/Config/AspNetCoreConfigExtension.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using Microsoft.Extensions.DependencyInjection; +using TouchSocket.Core.AspNetCore; + +namespace TouchSocket.Core +{ + /// + /// AspNetCoreConfigExtension + /// + public static class AspNetCoreConfigExtension + { + /// + /// 使用作为容器。 + /// + /// + /// + /// + public static TouchSocketConfig UseAspNetCoreContainer(this TouchSocketConfig config, IServiceCollection services) + { + config.SetContainer(new AspNetCoreContainer(services)); + return config; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Http/Extensions/HttpServiceCollectionExtensions.cs b/src/TouchSocket.AspNetCore/Http/Extensions/HttpServiceCollectionExtensions.cs new file mode 100644 index 000000000..e2b346fb7 --- /dev/null +++ b/src/TouchSocket.AspNetCore/Http/Extensions/HttpServiceCollectionExtensions.cs @@ -0,0 +1,86 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// HttpServiceCollectionExtensions + /// + public static class HttpServiceCollectionExtensions + { + #region HttpService + + /// + /// 添加HttpService服务。 + /// + /// 注册服务的接口 + /// + /// 实例化的服务器 + /// + public static IHttpService AddHttpService(this IServiceCollection service, ITcpService tcpService) where ServiceInterface : IHttpService + { + tcpService.Config.Container.RegisterSingleton(tcpService); + return (ServiceInterface)tcpService; + } + + /// + /// 添加HttpService服务。 + /// + /// 注册服务的接口 + /// + /// 设置配置相关信息 + /// + public static IHttpService AddHttpService(this IServiceCollection service, Action configAction) where ServiceInterface : IHttpService + { + var config = new TouchSocketConfig() + .UseAspNetCoreContainer(service); + configAction?.Invoke(config); + IHttpService tcpService = new HttpService(); + tcpService.Setup(config) + .Start(); + + return AddHttpService(service, tcpService); + } + + /// + /// 以作为注入接口,添加HttpService服务。 + /// + /// + /// 设置配置相关信息 + /// + public static IHttpService AddHttpService(this IServiceCollection service, Action configAction) + { + return AddHttpService(service, configAction); + } + + /// + /// 以作为注入接口,添加HttpService服务。 + /// + /// + /// 监听端口 + /// + public static IHttpService AddHttpService(this IServiceCollection service, int port) + { + return AddHttpService(service, config => + { + config.SetListenIPHosts(new IPHost[] { new IPHost(port) }); + }); + } + + #endregion HttpService + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/LICENSE.txt b/src/TouchSocket.AspNetCore/LICENSE.txt new file mode 100644 index 000000000..b09cd7856 --- /dev/null +++ b/src/TouchSocket.AspNetCore/LICENSE.txt @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Common/WSTouchRpcUtility.cs b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Common/WSTouchRpcUtility.cs new file mode 100644 index 000000000..4369f8f82 --- /dev/null +++ b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Common/WSTouchRpcUtility.cs @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc.AspNetCore +{ + internal class WSTouchRpcUtility + { + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Components/WSTouchRpcService.cs b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Components/WSTouchRpcService.cs new file mode 100644 index 000000000..4b9ab04b9 --- /dev/null +++ b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Components/WSTouchRpcService.cs @@ -0,0 +1,870 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc.AspNetCore +{ + /// + /// WSTouchRpcService + /// + public class WSTouchRpcService : DisposableObject, IWSTouchRpcService + { + #region SocketClient + + private readonly ConcurrentDictionary m_tokenDic = new ConcurrentDictionary(); + + /// + /// 数量 + /// + public int Count => m_tokenDic.Count; + + /// + /// 获取SocketClient + /// + /// + /// + public WSTouchRpcSocketClient this[string id] + { + get + { + WSTouchRpcSocketClient t; + TryGetSocketClient(id, out t); + return t; + } + } + + /// + /// 获取所有的客户端 + /// + /// + public IEnumerable GetClients() + { + return m_tokenDic.Values; + } + + /// + /// 获取ID集合 + /// + /// + public string[] GetIDs() + { + return m_tokenDic.Keys.ToArray(); + } + + /// + /// 根据ID判断SocketClient是否存在 + /// + /// + /// + public bool SocketClientExist(string id) + { + if (string.IsNullOrEmpty(id)) + { + return false; + } + + if (m_tokenDic.ContainsKey(id)) + { + return true; + } + return false; + } + + /// + /// 尝试获取实例 + /// + /// + /// + /// + public bool TryGetSocketClient(string id, out WSTouchRpcSocketClient socketClient) + { + if (string.IsNullOrEmpty(id)) + { + socketClient = null; + return false; + } + + return m_tokenDic.TryGetValue(id, out socketClient); + } + + internal bool TryAdd(string id, WSTouchRpcSocketClient socketClient) + { + return m_tokenDic.TryAdd(id, socketClient); + } + + internal bool TryRemove(string id, out WSTouchRpcSocketClient socketClient) + { + if (string.IsNullOrEmpty(id)) + { + socketClient = null; + return false; + } + return m_tokenDic.TryRemove(id, out socketClient); + } + + #endregion SocketClient + + private readonly ActionMap m_actionMap; + private readonly RpcActorGroup m_rpcActorGroup; + private long m_idCount; + private RpcStore m_rpcStore; + + /// + /// 创建一个基于WS的Touch服务器。 + /// + /// + public WSTouchRpcService(TouchSocketConfig config) + { + m_actionMap = new ActionMap(); + Config = config; + UsePlugin = config.IsUsePlugin; + PluginsManager = config.PluginsManager; + VerifyToken = config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + if (config.GetValue(TouchSocketConfigExtension.GetDefaultNewIDProperty) is Func fun) + { + GetDefaultNewID = fun; + } + else + { + GetDefaultNewID = () => { return Interlocked.Increment(ref m_idCount).ToString(); }; + } + + m_rpcActorGroup = new RpcActorGroup + { + Config = Config, + OnClose = OnRpcServiceClose, + OnFileTransfered = OnRpcServiceFileTransfered, + GetInvokeMethod = GetInvokeMethod, + OnFileTransfering = OnRpcServiceFileTransfering, + OnFindRpcActor = OnRpcServiceFindRpcActor, + OnRouting = OnRpcServiceRouting, + OnHandshaked = OnRpcServiceHandshaked, + OnHandshaking = OnRpcServiceHandshaking, + OnReceived = OnRpcServiceReceived, + OnStreamTransfered = OnRpcServiceStreamTransfered, + OnStreamTransfering = OnRpcServiceStreamTransfering, + OutputSend = RpcServiceOutputSend + }; + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + } + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + /// + /// + public TouchSocketConfig Config { get; private set; } + + /// + /// + /// + public IContainer Container { get; private set; } + + /// + /// 获取默认新ID。 + /// + public Func GetDefaultNewID { get; private set; } + + /// + /// + /// + public IPluginsManager PluginsManager { get; private set; } + + /// + /// + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// + /// + public bool UsePlugin { get; private set; } + + /// + /// + /// + public string VerifyToken { get; private set; } + + #region 通道 + + /// + /// + /// + /// + /// + public Channel CreateChannel(string targetId) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.CreateChannel(); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + /// + /// + /// + /// + /// + public Channel CreateChannel(string targetId, int id) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.CreateChannel(id); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion 通道 + + #region Rpc + + /// + /// + /// + /// + /// + /// + /// + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + /// 反向调用客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + /// 反向调用客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + /// 返回值 + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + /// 反向调用客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + /// 反向调用客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + /// 返回值 + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.Ping(timeout); + } + return false; + } + + #endregion Rpc + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActorGroup.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + + #region File + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.PullFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.PullFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.PushFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.PushFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion File + + /// + public void ResetID(string oldID, string newID) + { + if (string.IsNullOrEmpty(oldID)) + { + throw new ArgumentException($"“{nameof(oldID)}”不能为 null 或空。", nameof(oldID)); + } + + if (string.IsNullOrEmpty(newID)) + { + throw new ArgumentException($"“{nameof(newID)}”不能为 null 或空。", nameof(newID)); + } + + if (oldID == newID) + { + return; + } + if (m_tokenDic.TryGetValue(oldID, out WSTouchRpcSocketClient socketClient)) + { + socketClient.ResetID(newID); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(oldID)); + } + } + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + client.Close(arg2); + } + + private void OnRpcServiceFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), client, e)) + { + return; + } + OnFileTransfered(client, e); + } + + private void OnRpcServiceFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), client, e)) + { + return; + } + OnFileTransfering(client, e); + } + + private RpcActor OnRpcServiceFindRpcActor(string id) + { + if (TryGetSocketClient(id, out WSTouchRpcSocketClient client)) + { + return client.RpcActor; + } + return null; + } + + private void OnRpcServiceRouting(RpcActor actor, PackageRouterEventArgs e) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), client, e)) + { + return; + } + OnRouting(client, e); + } + + + private void OnRpcServiceHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), client, e)) + { + return; + } + OnHandshaked(client, e); + } + + private void OnRpcServiceHandshaking(RpcActor actor, VerifyOptionEventArgs e) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (e.Token == VerifyToken) + { + e.IsPermitOperation = true; + } + else + { + e.Message = "Token不受理"; + } + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaking), client, e)) + { + return; + } + OnHandshaking(client, e); + } + + private void OnRpcServiceReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), client, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(client, protocol, byteBlock); + } + + private void OnRpcServiceResetID(bool b, RpcActor actor, WaitSetID arg2) + { + ResetID(arg2.OldID, arg2.NewID); + } + + private void OnRpcServiceStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), client, e)) + { + return; + } + OnStreamTransfered(client, e); + } + + private void OnRpcServiceStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), client, e)) + { + return; + } + OnStreamTransfering(client, e); + } + + private void PrivateDisconnected(WSTouchRpcSocketClient client, DisconnectEventArgs e) + { + if (TryRemove(client.ID, out _)) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnDisconnected), client, e)) + { + return; + } + OnDisconnected(client, e); + } + } + + private void RpcServiceOutputSend(RpcActor actor, ArraySegment[] arg3) + { + WSTouchRpcSocketClient client = (WSTouchRpcSocketClient)actor.Caller; + if (!client.CanSend) + { + return; + } + client.RpcActorSend(arg3); + } + + #endregion 内部委托绑定 + + /// + /// 从WebSocket获取新客户端。 + /// + /// + /// + public async Task SwitchClientAsync(System.Net.WebSockets.WebSocket webSocket) + { + string id = GetDefaultNewID(); + WSTouchRpcSocketClient client = new WSTouchRpcSocketClient(); + if (!TryAdd(id, client)) + { + throw new Exception("ID重复"); + } + client.m_service = this; + client.m_usePlugin = UsePlugin; + CheckService(); + + client.SetRpcActor(m_rpcActorGroup.CreateRpcActor(client)); + client.RpcActor.ID = id; + client.m_internalDisconnected = PrivateDisconnected; + await client.Start(Config, webSocket); + } + + private void CheckService() + { + if (m_rpcActorGroup == null) + { + throw new Exception($"{nameof(RpcActorGroup)}未在{nameof(RpcStore)}中注册为解析器。"); + } + } + + #region 事件 + + /// + /// 客户端断开。 + /// + /// + /// + protected virtual void OnDisconnected(WSTouchRpcSocketClient client, DisconnectEventArgs e) + { + } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + protected virtual void OnFileTransfered(WSTouchRpcSocketClient client, FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + protected virtual void OnFileTransfering(WSTouchRpcSocketClient client, FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + /// + protected virtual void OnHandshaked(WSTouchRpcSocketClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在需要转发路由包时。 + /// + /// + /// + protected virtual void OnRouting(WSTouchRpcSocketClient client, PackageRouterEventArgs e) + { + + } + + /// + /// 在验证Token时 + /// + /// 客户端 + /// 参数 + protected virtual void OnHandshaking(WSTouchRpcSocketClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 接收到协议数据。 + /// + /// + /// + /// + protected virtual void OnReceived(WSTouchRpcSocketClient client, short protocol, ByteBlock byteBlock) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfered(WSTouchRpcSocketClient client, StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfering(WSTouchRpcSocketClient client, StreamOperationEventArgs e) + { + } + + #endregion 事件 + + #region 小文件 + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.PullSmallFile(path, metadata, timeout, token); + } + else + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.PullSmallFileAsync(path, metadata, timeout, token); + } + else + { + return Task.FromResult(new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + else + { + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out WSTouchRpcSocketClient client)) + { + return client.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + else + { + return Task.FromResult(new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + #endregion + + #region 发送 + + /// + public void Send(string id, short protocol, byte[] buffer, int offset, int length) + { + if (TryGetSocketClient(id, out WSTouchRpcSocketClient client)) + { + client.Send(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + public Task SendAsync(string id, short protocol, byte[] buffer, int offset, int length) + { + if (TryGetSocketClient(id, out WSTouchRpcSocketClient client)) + { + return client.SendAsync(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + #endregion 发送 + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Components/WSTouchRpcSocketClient.cs b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Components/WSTouchRpcSocketClient.cs new file mode 100644 index 000000000..7ca4d57bd --- /dev/null +++ b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Components/WSTouchRpcSocketClient.cs @@ -0,0 +1,495 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc.AspNetCore +{ + /// + /// WSTouchRpcSocketClient + /// + public class WSTouchRpcSocketClient : DisposableObject, IRpcActor, IPluginObject, ISenderBase + { + internal string m_id; + internal DisconnectEventHandler m_internalDisconnected; + internal WSTouchRpcService m_service; + internal bool m_usePlugin; + private readonly byte[] m_buffer = new byte[1024 * 64]; + private WebSocket m_client; + private RpcActor m_rpcActor; + + /// + public bool CanSend => m_client.State == WebSocketState.Open; + + /// + /// 配置 + /// + public TouchSocketConfig Config { get; private set; } + + /// + public IContainer Container => Config?.Container; + + /// + public string ID => m_rpcActor.ID; + + /// + public bool IsHandshaked => m_rpcActor.IsHandshaked; + + /// + public ILog Logger => m_rpcActor.Logger; + + /// + public IPluginsManager PluginsManager => Config?.PluginsManager; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + /// RpcActor + /// + public RpcActor RpcActor { get => m_rpcActor; } + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get => m_rpcActor.TryCanInvoke; set => m_rpcActor.TryCanInvoke = value; } + + /// + /// 是否已启动插件 + /// + public bool UsePlugin => m_usePlugin; + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + /// 关闭通信 + /// + /// + public void Close(string msg) + { + BreakOut(msg, true); + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public void ResetID(string newId) + { + if (string.IsNullOrEmpty(newId)) + { + throw new ArgumentException($"“{nameof(newId)}”不能为 null 或空。", nameof(newId)); + } + + if (m_id == newId) + { + return; + } + + m_rpcActor.ResetID(newId); + DirectResetID(newId); + } + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + internal async void RpcActorSend(ArraySegment[] transferBytes) + { + using ByteBlock byteBlock = new ByteBlock(); + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + await m_client.SendAsync(byteBlock.Buffer, System.Net.WebSockets.WebSocketMessageType.Binary, true, CancellationToken.None); + } + + internal void SetRpcActor(RpcActor rpcActor) + { + m_rpcActor = rpcActor; + m_rpcActor.OnResetID = ThisOnResetID; + } + + internal Task Start(TouchSocketConfig config, System.Net.WebSockets.WebSocket webSocket) + { + Config = config; + m_client = webSocket; + return BeginReceive(); + } + + /// + /// 直接重置Id。 + /// + /// + /// + /// + protected void DirectResetID(string newId) + { + string oldId = m_id; + if (m_service.TryRemove(m_id, out var socketClient)) + { + socketClient.m_id = newId; + if (m_service.TryAdd(m_id, socketClient)) + { + if (m_usePlugin) + { + IDChangedEventArgs e = new IDChangedEventArgs(oldId, newId); + PluginsManager.Raise(nameof(ITcpPlugin.OnIDChanged), socketClient, e); + } + return; + } + else + { + socketClient.m_id = oldId; + if (m_service.TryAdd(socketClient.m_id, socketClient)) + { + throw new Exception("ID重复"); + } + else + { + socketClient.Close("修改新ID时操作失败,且回退旧ID时也失败。"); + } + } + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(oldId)); + } + } + + /// + protected override void Dispose(bool disposing) + { + if (DisposedValue) + { + return; + } + base.Dispose(disposing); + BreakOut($"{nameof(Dispose)}断开链接", true); + } + + private async Task BeginReceive() + { + ByteBlock byteBlock = null; + try + { + while (true) + { + var result = await m_client.ReceiveAsync(m_buffer, default); + if (result.Count == 0) + { + byteBlock.SafeDispose(); + break; + } + if (byteBlock == null) + { + byteBlock = new ByteBlock(); + } + byteBlock.Write(m_buffer, 0, result.Count); + if (result.EndOfMessage) + { + try + { + m_rpcActor.InputReceivedData(byteBlock); + } + catch + { + } + finally + { + byteBlock.SafeDispose(); + byteBlock = null; + } + } + } + + BreakOut("远程终端主动关闭", false); + } + catch (Exception ex) + { + BreakOut(ex.Message, false); + } + } + + private void BreakOut(string msg, bool manual) + { + lock (this) + { + if (DisposedValue) + { + return; + } + Dispose(); + m_client.SafeDispose(); + m_rpcActor.SafeDispose(); + m_internalDisconnected?.Invoke(this, new DisconnectEventArgs(manual, msg)); + } + } + + private RpcActor FindRpcActor(string id) + { + if (m_service.TryGetSocketClient(id, out WSTouchRpcSocketClient socketClient)) + { + return socketClient.m_rpcActor; + } + return null; + } + + private void ThisOnResetID(bool first, RpcActor rpcActor, WaitSetID waitSetID) + { + DirectResetID(waitSetID.NewID); + } + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Extensions/ApplicationBuilderExtensions.cs b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Extensions/ApplicationBuilderExtensions.cs new file mode 100644 index 000000000..4a7c90b1b --- /dev/null +++ b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Extensions/ApplicationBuilderExtensions.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.TouchRpc.AspNetCore; + +namespace Microsoft.AspNetCore.Builder +{ + /// + /// ApplicationBuilderExtensions + /// + public static class ApplicationBuilderExtensions + { + /// + /// 使用基于WebSocket的TouchRpc。 + /// 启用该功能时,请先启用WebSocket。 + /// + /// + /// + /// + public static IApplicationBuilder UseWSTouchRpc(this IApplicationBuilder builder, string url = "wstouchrpc") + { + return builder.UseMiddleware(url); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Extensions/TouchRpcServiceCollectionExtensions.cs b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Extensions/TouchRpcServiceCollectionExtensions.cs new file mode 100644 index 000000000..ddf21fabd --- /dev/null +++ b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Extensions/TouchRpcServiceCollectionExtensions.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Rpc.TouchRpc.AspNetCore; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// ServiceCollectionExtensions + /// + public static class TouchRpcServiceCollectionExtensions + { + /// + /// 添加WSTouchRpc服务。 + /// + /// + /// + /// + public static IWSTouchRpcService AddWSTouchRpc(this IServiceCollection service, TouchSocketConfig config) + { + WSTouchRpcService rpcService = new WSTouchRpcService(config); + service.AddSingleton(rpcService); + return rpcService; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Interfaces/IWSTouchRpcService.cs b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Interfaces/IWSTouchRpcService.cs new file mode 100644 index 000000000..2b07689b5 --- /dev/null +++ b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Interfaces/IWSTouchRpcService.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc.AspNetCore +{ + /// + /// WSTouchRpcService服务器接口 + /// + public interface IWSTouchRpcService : ITouchRpcService, IPluginObject + { + /// + /// 配置项 + /// + TouchSocketConfig Config { get; } + + /// + /// 连接验证口令 + /// + string VerifyToken { get; } + + /// + /// 转换客户端 + /// + /// + /// + Task SwitchClientAsync(System.Net.WebSockets.WebSocket webSocket); + + /// + /// 重置ID + /// + /// + /// + void ResetID(string oldID, string newID); + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Middlewares/WSTouchRpcMiddleware.cs b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Middlewares/WSTouchRpcMiddleware.cs new file mode 100644 index 000000000..8edca778b --- /dev/null +++ b/src/TouchSocket.AspNetCore/Rpc/TouchRpc/Middlewares/WSTouchRpcMiddleware.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; +namespace TouchSocket.Rpc.TouchRpc.AspNetCore +{ + /// + /// WSTouchRpc中间件 + /// + public class WSTouchRpcMiddleware + { + private readonly RequestDelegate m_next; + private readonly IWSTouchRpcService m_rpcService; + private string m_url = "/wstouchrpc"; + private readonly ILogger m_logger; + + /// + /// 实例化一个中间件 + /// + /// + /// + /// + /// + public WSTouchRpcMiddleware(string m_url, RequestDelegate next, IWSTouchRpcService rpcService, ILoggerFactory loggerFactory) + { + Url = m_url; + m_next = next ?? throw new ArgumentNullException(nameof(next)); + m_rpcService = rpcService; + m_logger = loggerFactory.CreateLogger(); + } + + /// + /// Url + /// + public string Url { get => m_url; set => m_url = string.IsNullOrEmpty(value) ? "/wstouchrpc" : value; } + + /// + /// + /// + /// + /// + public async Task Invoke(HttpContext context) + { + if (context.Request.Path.Equals(Url, StringComparison.CurrentCultureIgnoreCase)) + { + if (context.WebSockets.IsWebSocketRequest) + { + var webSocket = await context.WebSockets.AcceptWebSocketAsync(); + try + { + await m_rpcService.SwitchClientAsync(webSocket); + } + catch (Exception ex) + { + m_logger.LogError(ex.Message); + } + } + else + { + context.Response.StatusCode = 400; + } + return Task.CompletedTask; + } + else + { + return m_next(context); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket.AspNetCore/Sockets/Extensions/SocketsServiceCollectionExtensions.cs b/src/TouchSocket.AspNetCore/Sockets/Extensions/SocketsServiceCollectionExtensions.cs new file mode 100644 index 000000000..fbd99c1d3 --- /dev/null +++ b/src/TouchSocket.AspNetCore/Sockets/Extensions/SocketsServiceCollectionExtensions.cs @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// SocketsServiceCollectionExtensions + /// + public static class SocketsServiceCollectionExtensions + { + #region TcpService + /// + /// 添加TcpService服务。 + /// + /// 注册服务的接口 + /// + /// 实例化的服务器 + /// + public static ITcpService AddTcpService(this IServiceCollection service, ITcpService tcpService) where ServiceInterface : ITcpService + { + tcpService.Config.Container.RegisterSingleton(tcpService); + return (ServiceInterface)tcpService; + } + + /// + /// 添加TcpService服务。 + /// + /// 注册服务的接口 + /// + /// 设置配置相关信息 + /// + public static ITcpService AddTcpService(this IServiceCollection service, Action configAction) where ServiceInterface : ITcpService + { + var config = new TouchSocketConfig() + .UseAspNetCoreContainer(service); + configAction?.Invoke(config); + ITcpService tcpService = new TcpService(); + tcpService.Setup(config) + .Start(); + + return AddTcpService(service, tcpService); + } + + /// + /// 以作为注入接口,添加TcpService服务。 + /// + /// + /// 设置配置相关信息 + /// + public static ITcpService AddTcpService(this IServiceCollection service, Action configAction) + { + return AddTcpService(service, configAction); + } + + /// + /// 以作为注入接口,添加TcpService服务。 + /// + /// + /// 监听端口 + /// + public static ITcpService AddTcpService(this IServiceCollection service, int port) + { + return AddTcpService(service, config => + { + config.SetListenIPHosts(new IPHost[] { new IPHost(port) }); + }); + } + + #endregion TcpService + } +} diff --git a/src/TouchSocket.AspNetCore/TouchSocket.AspNetCore.csproj b/src/TouchSocket.AspNetCore/TouchSocket.AspNetCore.csproj new file mode 100644 index 000000000..10a4deb75 --- /dev/null +++ b/src/TouchSocket.AspNetCore/TouchSocket.AspNetCore.csproj @@ -0,0 +1,74 @@ + + + + netcoreapp3.1;net7.0 + logo.ico + true + D:\MyStore\13_Doc\Keys\TouchSocket.snk + 1.2.0 + 8.0 + 若汝棋茗 + Copyright © 2022 若汝棋茗 + rpc,http,https,websocket,webapi + 这是一个适用于AspNetCore的、轻量级的、支持插件的综合网络通信库。基础通信功能包含Tcp、Udp、Ssl、Rpc、Http等。其中http服务器支持WebSocket、静态网页、XmlRpc、WebApi、JsonRpc等扩展插件。和自定义协议的TouchRpc,支持Ssl加密、异步调用、权限管理、错误状态返回、服务回调、分布式调用等。在空载函数执行时,10万次调用仅3.8秒,在不返回状态时,仅0.9秒。 + +AspNetCore - AspNetCore is a lightweight, plug-in - enabled comprehensive network communication library. Basic communication functions include Tcp, Udp, Ssl, Rpc, and Http. HTTP server supports WebSocket, static web page, XmlRpc, WebApi, JsonRpc and other extension plug-ins. And custom protocol TouchRpc, support Ssl encryption, asynchronous call, permission management, error status return, service callback, distributed call, etc. It takes 3.8 seconds for 100,000 calls when the no-load function is executing, and 0.9 seconds when the state is not returned. + +API:https://www.yuque.com/rrqm/touchsocket/index + https://gitee.com/dotnetchina/TouchSocket.Sockets + + true + logo.png + 若汝棋茗 + true + LICENSE.txt + + + + embedded + true + true + + + + bin\Debug\net7.0\TouchSocket.AspNetCore.xml + + true + + + + bin\Release\net7.0\TouchSocket.AspNetCore.xml + + true + + + + bin\Debug\netcoreapp3.1\TouchSocket.AspNetCore.xml + + true + + + + bin\Release\netcoreapp3.1\TouchSocket.AspNetCore.xml + + true + + + + True + + + + True + + + + + + + + + + + + diff --git a/src/TouchSocket.AspNetCore/logo.ico b/src/TouchSocket.AspNetCore/logo.ico new file mode 100644 index 000000000..7b33dcf65 Binary files /dev/null and b/src/TouchSocket.AspNetCore/logo.ico differ diff --git a/src/TouchSocket.AspNetCore/logo.png b/src/TouchSocket.AspNetCore/logo.png new file mode 100644 index 000000000..d4199b5c3 Binary files /dev/null and b/src/TouchSocket.AspNetCore/logo.png differ diff --git a/src/TouchSocket/Core/ByteManager/ByteBlock.cs b/src/TouchSocket/Core/ByteManager/ByteBlock.cs new file mode 100644 index 000000000..b1ad560c2 --- /dev/null +++ b/src/TouchSocket/Core/ByteManager/ByteBlock.cs @@ -0,0 +1,1285 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 字节块流 + /// + [DebuggerDisplay("Len={Len},Pos={Pos},Capacity={Capacity}")] + public sealed class ByteBlock : Stream, IByteBlock + { + private static float m_ratio = 1.5f; + private readonly bool m_needDis; + private byte[] m_buffer; + private int m_dis = 1; + private bool m_holding; + private long m_length; + private long m_position; + private bool m_using; + + /// + /// 构造函数 + /// + /// + /// + public ByteBlock(int byteSize = 1024 * 64, bool equalSize = false) + { + m_needDis = true; + m_buffer = BytePool.Default.GetByteCore(byteSize, equalSize); + m_using = true; + } + + /// + /// 实例化一个已知内存的对象。且该内存不会被回收。 + /// + /// + public ByteBlock(byte[] bytes) + { + m_buffer = bytes ?? throw new ArgumentNullException(nameof(bytes)); + m_length = bytes.Length; + m_using = true; + } + + /// + /// 扩容增长比,默认为1.5, + /// min:1.5 + /// + public static float Ratio + { + get => m_ratio; + set + { + if (value < 1.5) + { + value = 1.5f; + } + m_ratio = value; + } + } + + /// + /// 字节实例 + /// + public byte[] Buffer => m_buffer; + + /// + /// 仅当内存块可用,且>0时为True。 + /// + public override bool CanRead => m_using && CanReadLen > 0; + + /// + /// 还能读取的长度,计算为的差值。 + /// + public int CanReadLen => Len - Pos; + + /// + /// 还能读取的长度,计算为的差值。 + /// + public long CanReadLength => m_length - m_position; + + /// + /// 支持查找 + /// + public override bool CanSeek => m_using; + + /// + /// 可写入 + /// + public override bool CanWrite => m_using; + + /// + /// 容量 + /// + public int Capacity => m_buffer.Length; + + /// + /// 空闲长度,准确掌握该值,可以避免内存扩展,计算为的差值。 + /// + public int FreeLength => Capacity - Pos; + + /// + /// 表示持续性持有,为True时,Dispose将调用无效。 + /// + public bool Holding => m_holding; + + /// + /// Int真实长度 + /// + public int Len => (int)m_length; + + /// + /// 真实长度 + /// + public override long Length => m_length; + + /// + /// int型流位置 + /// + public int Pos + { + get => (int)m_position; + set => m_position = value; + } + + /// + /// 流位置 + /// + public override long Position + { + get => m_position; + set => m_position = value; + } + + /// + /// 使用状态 + /// + public bool Using => m_using; + + /// + /// 直接完全释放,游离该对象,然后等待GC + /// + public void AbsoluteDispose() + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + Dis(); + } + } + + /// + /// 清空所有内存数据 + /// + /// 内存块已释放 + public void Clear() + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + Array.Clear(m_buffer, 0, m_buffer.Length); + } + + /// + /// 无实际效果 + /// + public override void Flush() + { + } + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + int len = m_length - m_position > length ? length : CanReadLen; + Array.Copy(m_buffer, m_position, buffer, offset, len); + m_position += len; + return len; + } + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + public int Read(byte[] buffer) + { + return Read(buffer, 0, buffer.Length); + } + + /// + /// 读取数据,然后递增Pos + /// + + /// + /// + /// + public int Read(out byte[] buffer, int length) + { + buffer = new byte[length]; + return Read(buffer, 0, buffer.Length); + } + + /// + /// 从当前流位置读取一个值 + /// + public override int ReadByte() + { + byte value = m_buffer[m_position]; + m_position++; + return value; + } + + /// + /// 将内存块初始化到刚申请的状态。 + /// 仅仅重置属性。 + /// + /// 内存块已释放 + public void Reset() + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + m_position = 0; + m_length = 0; + } + + /// + /// 设置流位置 + /// + /// + /// + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + switch (origin) + { + case SeekOrigin.Begin: + m_position = offset; + break; + + case SeekOrigin.Current: + m_position += offset; + break; + + case SeekOrigin.End: + m_position = m_length + offset; + break; + } + return m_position; + } + + /// + /// 移动游标 + /// + /// + /// + public ByteBlock Seek(int position) + { + Position = position; + return this; + } + + /// + /// 设置游标到末位 + /// + /// + public ByteBlock SeekToEnd() + { + Position = Length; + return this; + } + + /// + /// 设置游标到首位 + /// + /// + public ByteBlock SeekToStart() + { + Position = 0; + return this; + } + + /// + /// 重新设置容量 + /// + /// 新尺寸 + /// 是否保留元数据 + /// + public void SetCapacity(int size, bool retainedData = false) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + byte[] bytes = new byte[size]; + + if (retainedData) + { + Array.Copy(m_buffer, 0, bytes, 0, m_buffer.Length); + } + if (m_needDis) + { + BytePool.Default.Recycle(m_buffer); + } + m_buffer = bytes; + } + + /// + /// 设置持续持有属性,当为True时,调用Dispose会失效,表示该对象将长期持有,直至设置为False。 + /// 当为False时,会自动调用Dispose。 + /// + /// + /// + public void SetHolding(bool holding) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + m_holding = holding; + if (!holding) + { + Dispose(); + } + } + + /// + /// 设置实际长度 + /// + /// + /// + public override void SetLength(long value) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (value > m_buffer.Length) + { + throw new Exception("设置值超出容量"); + } + m_length = value; + } + + /// + /// 从指定位置转化到指定长度的有效内存 + /// + /// + /// + /// + public byte[] ToArray(int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + byte[] buffer = new byte[length]; + Array.Copy(m_buffer, offset, buffer, 0, buffer.Length); + return buffer; + } + + /// + /// 转换为有效内存 + /// + /// + public byte[] ToArray() + { + return ToArray(0, Len); + } + + /// + /// 从指定位置转化到有效内存 + /// + + /// + /// + /// + public byte[] ToArray(int offset) + { + return ToArray(offset, Len - offset); + } + + /// + /// 转换为UTF-8字符 + /// + /// + public override string ToString() + { + return ToString(0, Len); + } + + /// + /// 转换为UTF-8字符 + /// + /// 偏移量 + /// 长度 + /// + public string ToString(int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + return Encoding.UTF8.GetString(m_buffer, offset, length); + } + + /// + /// 转换为UTF-8字符 + /// + /// 偏移量 + /// + public string ToString(int offset) + { + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + return Encoding.UTF8.GetString(m_buffer, offset, Len - offset); + } + + /// + /// 写入 + /// + /// + /// + /// + /// + public override void Write(byte[] buffer, int offset, int count) + { + if (count == 0) + { + return; + } + if (!m_using) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (m_buffer.Length - m_position < count) + { + int need = m_buffer.Length + count - ((int)(m_buffer.Length - m_position)); + int lend = m_buffer.Length; + while (need > lend) + { + lend = (int)(lend * m_ratio); + } + SetCapacity(lend, true); + } + Array.Copy(buffer, offset, m_buffer, m_position, count); + m_position += count; + m_length = Math.Max(m_position, m_length); + } + + /// + /// + /// + /// + /// + public void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// + /// + /// + protected override sealed void Dispose(bool disposing) + { + if (m_holding) + { + return; + } + + if (m_needDis) + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + GC.SuppressFinalize(this); + BytePool.Default.Recycle(m_buffer); + Dis(); + } + } + + base.Dispose(disposing); + } + + private void Dis() + { + m_holding = false; + m_using = false; + m_position = 0; + m_length = 0; + m_buffer = null; + } + + #region BytesPackage + + /// + /// 从当前流位置读取一个独立的数组包 + /// + public byte[] ReadBytesPackage() + { + byte status = (byte)ReadByte(); + if (status == 0) + { + return null; + } + int length = ReadInt32(); + byte[] data = new byte[length]; + Array.Copy(Buffer, Pos, data, 0, length); + Pos += length; + return data; + } + + /// + /// 尝试获取数据包信息,方便从Buffer操作数据 + /// + /// + /// + /// + public bool TryReadBytesPackageInfo(out int pos, out int len) + { + byte status = (byte)ReadByte(); + if (status == 0) + { + pos = 0; + len = 0; + return false; + } + len = ReadInt32(); + pos = Pos; + return true; + } + + /// + /// 写入一个独立的数组包,值可以为null。 + /// + /// + /// + /// + public ByteBlock WriteBytesPackage(byte[] value, int offset, int length) + { + if (value == null) + { + Write((byte)0); + } + else + { + Write((byte)1); + Write(length); + Write(value, offset, length); + } + return this; + } + + /// + /// 写入一个独立的数组包。值可以为null。 + /// + /// + public ByteBlock WriteBytesPackage(byte[] value) + { + if (value == null) + { + return WriteBytesPackage(value, 0, 0); + } + return WriteBytesPackage(value, 0, value.Length); + } + + #endregion BytesPackage + + #region Int32 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public int ReadInt32(bool? bigEndian = null) + { + int value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt32(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt32(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt32(Buffer, Pos); break; + } + m_position += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(int value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int32 + + #region Int16 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public short ReadInt16(bool? bigEndian = null) + { + short value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt16(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt16(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt16(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(short value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int16 + + #region Int64 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public long ReadInt64(bool? bigEndian = null) + { + long value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt64(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt64(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(long value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int64 + + #region Boolean + + /// + /// 从当前流位置读取一个值 + /// + public bool ReadBoolean() + { + bool value = TouchSocketBitConverter.Default.ToBoolean(Buffer, Pos); + Pos += 1; + return value; + } + + /// + /// 写入值 + /// + /// + public ByteBlock Write(bool value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value)); + return this; + } + + #endregion Boolean + + #region Byte + + /// + /// 写入值 + /// + /// + /// + public ByteBlock Write(byte value) + { + Write(new byte[] { value }, 0, 1); + return this; + } + + #endregion Byte + + #region String + + /// + /// 从当前流位置读取一个值 + /// + public string ReadString() + { + int len = this.ReadInt32(); + if (len < 0) + { + return null; + } + else + { + string str = Encoding.UTF8.GetString(Buffer, Pos, len); + Pos += len; + return str; + } + } + + /// + /// 写入值。值可以为null,或者空。 + /// 注意:该操作不具备通用性,读取时必须使用ReadString。或者得先做出判断,由默认端序的int32值标识,具体如下: + /// + /// 小于0,表示字符串为null + /// 等于0,表示字符串为"" + /// 大于0,表示字符串在utf-8编码下的字节长度。 + /// + /// + /// + public ByteBlock Write(string value) + { + if (value == null) + { + Write(-1); + } + else + { + byte[] buffer = Encoding.UTF8.GetBytes(value); + Write(buffer.Length); + Write(buffer); + } + return this; + } + + /// + /// 写入值。值必须为有效值。可通用解析。 + /// + /// + /// + public ByteBlock WriteString(string value, Encoding encoding = null) + { + Write((encoding ?? Encoding.UTF8).GetBytes(value)); + return this; + } + + #endregion String + + #region Char + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public char ReadChar(bool? bigEndian = null) + { + char value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToChar(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToChar(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToChar(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(char value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Char + + #region Double + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public double ReadDouble(bool? bigEndian = null) + { + double value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToDouble(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToDouble(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToDouble(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(double value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Double + + #region Float + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public float ReadFloat(bool? bigEndian = null) + { + float value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToSingle(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToSingle(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToSingle(Buffer, Pos); break; + } + Pos += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(float value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Float + + #region UInt16 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ushort ReadUInt16(bool? bigEndian = null) + { + ushort value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt16(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt16(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt16(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(ushort value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt16 + + #region UInt32 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public uint ReadUInt32(bool? bigEndian = null) + { + uint value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt32(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt32(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt32(Buffer, Pos); break; + } + Pos += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(uint value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt32 + + #region UInt64 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ulong ReadUInt64(bool? bigEndian = null) + { + ulong value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt64(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt64(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt64(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ByteBlock Write(ulong value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt64 + + #region Null + + /// + /// 从当前流位置读取一个标识值,判断是否为null。 + /// + public bool ReadIsNull() + { + var status = ReadByte(); + if (status == 0) + { + return true; + } + else if (status == 1) + { + return false; + } + else + { + throw new Exception("标识既非Null,也非NotNull,可能是流位置发生了错误。"); + } + } + + /// + /// 判断该值是否为Null,然后写入标识值 + /// + public ByteBlock WriteIsNull(T t) where T : class + { + if (t == null) + { + WriteNull(); + } + else + { + WriteNotNull(); + } + return this; + } + + /// + /// 写入一个标识非Null值 + /// + public ByteBlock WriteNotNull() + { + Write((byte)1); + return this; + } + + /// + /// 写入一个标识Null值 + /// + public ByteBlock WriteNull() + { + Write((byte)0); + return this; + } + + #endregion Null + + #region Package + + /// + /// 读取一个指定类型的包 + /// + /// + /// + public TPackage ReadPackage() where TPackage : class, IPackage, new() + { + if (ReadIsNull()) + { + return default; + } + else + { + TPackage package = new TPackage(); + package.Unpackage(this); + return package; + } + } + + /// + /// 以包进行写入。允许null值。 + /// 读取时调用,解包。或者先判断,然后自行解包。 + /// + /// + /// + /// + public ByteBlock WritePackage(TPackage package) where TPackage : class, IPackage + { + WriteIsNull(package); + if (package != null) + { + package.Package(this); + } + + return this; + } + + #endregion Package + + #region DateTime + + /// + /// 从当前流位置读取一个值 + /// + public DateTime ReadDateTime() + { + long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); + Pos += 8; + return DateTime.FromBinary(value); + } + + /// + /// 写入值 + /// + /// + public ByteBlock Write(DateTime value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value.ToBinary())); + return this; + } + + #endregion DateTime + + #region TimeSpan + + /// + /// 从当前流位置读取一个值 + /// + public TimeSpan ReadTimeSpan() + { + long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); + Pos += 8; + return TimeSpan.FromTicks(value); + } + + /// + /// 写入值 + /// + /// + public ByteBlock Write(TimeSpan value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value.Ticks)); + return this; + } + + #endregion TimeSpan + + #region Object + + /// + /// 从当前流位置读取一个泛型值 + /// + /// + /// + /// + public T ReadObject(SerializationType serializationType = SerializationType.FastBinary) + { + int length = ReadInt32(); + + if (length == 0) + { + return default; + } + + T obj; + + switch (serializationType) + { + case SerializationType.FastBinary: + { + obj = SerializeConvert.FastBinaryDeserialize(Buffer, Pos); + } + break; + + case SerializationType.Json: + { + string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length); + obj = SerializeConvert.JsonDeserializeFromString(jsonString); + } + break; + + case SerializationType.Xml: + { + string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length); + obj = SerializeConvert.XmlDeserializeFromString(jsonString); + } + break; + + case SerializationType.SystemBinary: + { + obj = SerializeConvert.BinaryDeserialize(Buffer, Pos, length); + } + break; + + default: + throw new Exception("未定义的序列化类型"); + } + + Pos += length; + return obj; + } + + /// + /// 写入值 + /// + /// + /// + public ByteBlock WriteObject(object value, SerializationType serializationType = SerializationType.FastBinary) + { + if (value == null) + { + Write(0); + return this; + } + byte[] data; + switch (serializationType) + { + case SerializationType.FastBinary: + { + data = SerializeConvert.FastBinarySerialize(value); + } + break; + + case SerializationType.Json: + { + data = SerializeConvert.JsonSerializeToBytes(value); + } + break; + + case SerializationType.Xml: + { + data = Encoding.UTF8.GetBytes(SerializeConvert.XmlSerializeToString(value)); + } + break; + + case SerializationType.SystemBinary: + { + data = SerializeConvert.BinarySerialize(value); + } + break; + + default: + throw new Exception("未定义的序列化类型"); + } + + Write(data.Length); + Write(data); + return this; + } + + #endregion Object + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/ByteManager/ByteBlockExtensions.cs b/src/TouchSocket/Core/ByteManager/ByteBlockExtensions.cs new file mode 100644 index 000000000..991de53c3 --- /dev/null +++ b/src/TouchSocket/Core/ByteManager/ByteBlockExtensions.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// ByteBlock扩展 + /// + public static class ByteBlockExtensions + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/ByteManager/BytePool.cs b/src/TouchSocket/Core/ByteManager/BytePool.cs new file mode 100644 index 000000000..3e213b489 --- /dev/null +++ b/src/TouchSocket/Core/ByteManager/BytePool.cs @@ -0,0 +1,446 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 字节池 + /// + public class BytePool + { + private readonly ConcurrentDictionary bytesDictionary = new ConcurrentDictionary(); + private readonly Timer m_timer; + private long m_fullSize; + private long m_maxSize; + + static BytePool() + { + Default = new BytePool(); + } + + private BytePool() + { + m_timer = new Timer((o) => + { + Clear(); + }, null, 1000 * 60 * 60, 1000 * 60 * 60); + KeyCapacity = 100; + AutoZero = false; + m_maxSize = 1024 * 1024 * 512; + SetBlockSize(1024, 1024 * 1024 * 20); + AddSizeKey(10240); + } + + /// + /// 默认的内存池实例 + /// + public static BytePool Default { get; } + + /// + /// 回收内存时,自动归零 + /// + public bool AutoZero { get; set; } + + /// + /// 表示内存池是否可用。 + /// 当业务太轻量级,且要求超高并发时(千万数量级别),可禁用内存池。 + /// + public bool Disabled { get; set; } + + /// + /// 键容量 + /// + public int KeyCapacity { get; set; } + + /// + /// 单个块最大值 + /// + public int MaxBlockSize { get; private set; } + + /// + /// 允许的内存池最大值 + /// + public long MaxSize + { + get => m_maxSize; + set + { + if (value < 1024) + { + value = 1024; + } + m_maxSize = value; + } + } + + /// + /// 单个块最小值 + /// + public int MinBlockSize { get; private set; } + + /// + /// 添加尺寸键 + /// + /// + /// + public bool AddSizeKey(int byteSize) + { + if (bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize))) + { + return true; + } + return false; + } + + /// + /// 清理 + /// + public void Clear() + { + bytesDictionary.Clear(); + GC.Collect(); + } + + /// + /// 确定是否包含指定尺寸键 + /// + /// + /// + public bool ContainsSizeKey(int byteSize) + { + return bytesDictionary.ContainsKey(byteSize); + } + + /// + /// 获取所以内存键 + /// + /// + public long[] GetAllSizeKeys() + { + return bytesDictionary.Keys.ToArray(); + } + + /// + /// 获取ByteBlock + /// + /// 长度 + /// 要求长度相同 + /// + public ByteBlock GetByteBlock(int byteSize, bool equalSize) + { + return new ByteBlock(byteSize, equalSize); + } + + /// + /// 获取ByteBlock + /// + /// + /// + public ByteBlock GetByteBlock(int byteSize) + { + return new ByteBlock(byteSize, false); + } + + /// + /// 获取内存核心。获取的核心可以不用归还。 + /// 如果要调用归还,切记不要有持久性引用。 + /// + /// + /// + /// + public byte[] GetByteCore(int byteSize, bool equalSize = false) + { + if (Disabled) + { + return new byte[byteSize]; + } + + BytesQueue bytesCollection; + if (equalSize) + { + //等长 + if (bytesDictionary.TryGetValue(byteSize, out bytesCollection)) + { + if (bytesCollection.TryGet(out byte[] bytes)) + { + m_fullSize -= byteSize; + return bytes; + } + } + else + { + CheckKeyCapacity(byteSize); + } + return new byte[byteSize]; + } + else + { + byteSize = HitSize(byteSize); + //搜索已创建集合 + if (bytesDictionary.TryGetValue(byteSize, out bytesCollection)) + { + if (bytesCollection.TryGet(out byte[] bytes)) + { + m_fullSize -= byteSize; + return bytes; + } + } + else + { + CheckKeyCapacity(byteSize); + } + return new byte[byteSize]; + } + } + + /// + /// 获取内存池容量 + /// + /// + public long GetPoolSize() + { + long size = 0; + foreach (var item in bytesDictionary.Values) + { + size += item.FullSize; + } + return size; + } + + /// + /// 获取ValueByteBlock + /// + /// + /// + /// + public ValueByteBlock GetValueByteBlock(int byteSize, bool equalSize) + { + return new ValueByteBlock(byteSize, equalSize); + } + + /// + /// 获取ValueByteBlock + /// + /// + /// + public ValueByteBlock GetValueByteBlock(int byteSize) + { + return new ValueByteBlock(byteSize, false); + } + + /// + /// 回收内存核心。 + /// 注意:回收的内存,必须百分百确定该对象没有再被其他引用。不然这属于危险操作。 + /// + /// + public void Recycle(byte[] bytes) + { + if (Disabled) + { + return; + } + if (bytes == null || bytes.Length > MaxBlockSize || bytes.Length < MinBlockSize) + { + return; + } + if (m_maxSize > m_fullSize) + { + if (bytesDictionary.TryGetValue(bytes.Length, out BytesQueue bytesQueue)) + { + if (AutoZero) + { + Array.Clear(bytes, 0, bytes.Length); + } + m_fullSize += bytes.Length; + bytesQueue.Add(bytes); + } + } + else + { + long size = 0; + foreach (var collection in bytesDictionary.Values) + { + size += collection.FullSize; + } + m_fullSize = size; + } + } + + /// + /// 移除尺寸键 + /// + /// + /// + public bool RemoveSizeKey(int byteSize) + { + if (bytesDictionary.TryRemove(byteSize, out BytesQueue queue)) + { + queue.Clear(); + return true; + } + return false; + } + + /// + /// 设置内存块参数 + /// + /// + /// + public void SetBlockSize(int minBlockSize, int maxBlockSize) + { + this.MaxBlockSize = maxBlockSize; + this.MinBlockSize = minBlockSize; + bytesDictionary.Clear(); + } + + private void CheckKeyCapacity(int byteSize) + { + if (byteSize < MinBlockSize || byteSize > MaxBlockSize) + { + return; + } + if (bytesDictionary.Count < KeyCapacity) + { + bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize)); + } + else + { + List bytesQueues = bytesDictionary.Values.ToList(); + bytesQueues.Sort((x, y) => { return x.m_referenced > y.m_referenced ? -1 : 1; }); + for (int i = (int)(bytesQueues.Count * 0.2); i < bytesQueues.Count; i++) + { + if (bytesDictionary.TryRemove(bytesQueues[i].m_size, out BytesQueue queue)) + { + queue.Clear(); + } + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int HitSize(int num) + { + if (num < MinBlockSize) + { + num = MinBlockSize; + } + + if (num <= 10240)//10k + { + return 10240; + } + else if (num <= 65536)//64k + { + return 65536; + } + else if (num <= 102400)//100k + { + return 102400; + } + else if (num <= 524288) //512k + { + return 524288; + } + else if (num <= 1048576)//1Mb + { + return 1048576; + } + else if (num <= 1048576 * 2)//2Mb + { + return 1048576 * 2; + } + else if (num <= 1048576 * 3)//3Mb + { + return 1048576 * 3; + } + else if (num <= 1048576 * 4)//4Mb + { + return 1048576 * 4; + } + else if (num <= 1048576 * 5)//5Mb + { + return 1048576 * 5; + } + else if (num <= 1048576 * 6)//6Mb + { + return 1048576 * 6; + } + else if (num <= 1048576 * 7)//7Mb + { + return 1048576 * 7; + } + else if (num <= 1048576 * 8)//8Mb + { + return 1048576 * 8; + } + else if (num <= 1048576 * 9)//9Mb + { + return 1048576 * 9; + } + else if (num <= 10485760)//10Mb + { + return 10485760; + } + else if (num <= 1024 * 1024 * 12)//12Mb + { + return 1024 * 1024 * 12; + } + else if (num <= 1024 * 1024 * 15)//15Mb + { + return 1024 * 1024 * 15; + } + else if (num <= 1024 * 1024 * 18)//18Mb + { + return 1024 * 1024 * 18; + } + else if (num <= 1024 * 1024 * 20)//20Mb + { + return 1024 * 1024 * 20; + } + else if (num <= 1024 * 1024 * 30)//30Mb + { + return 1024 * 1024 * 30; + } + else if (num <= 1024 * 1024 * 40)//40Mb + { + return 1024 * 1024 * 40; + } + else if (num <= 1024 * 1024 * 50)//50Mb + { + return 1024 * 1024 * 50; + } + else if (num <= 1024 * 1024 * 100)//100Mb + { + return 1024 * 1024 * 100; + } + else if (num <= 1024 * 1024 * 500)//500Mb + { + return 1024 * 1024 * 500; + } + else if (num <= 1024 * 1024 * 1024)//1Gb + { + return 1024 * 1024 * 1024; + } + else + { + return num; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/ByteManager/BytesQueue.cs b/src/TouchSocket/Core/ByteManager/BytesQueue.cs new file mode 100644 index 000000000..c5f7fbf20 --- /dev/null +++ b/src/TouchSocket/Core/ByteManager/BytesQueue.cs @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; +using System.Diagnostics; + +namespace TouchSocket.Core +{ + /// + /// 字节块集合 + /// + [DebuggerDisplay("Count = {bytesQueue.Count}")] + internal class BytesQueue + { + internal int m_size; + + internal BytesQueue(int size) + { + m_size = size; + } + + /// + /// 占用空间 + /// + public long FullSize => m_size * m_bytesQueue.Count; + + private readonly ConcurrentQueue m_bytesQueue = new ConcurrentQueue(); + + internal long m_referenced; + + /// + /// 获取当前实例中的空闲的Block + /// + /// + public bool TryGet(out byte[] bytes) + { + m_referenced++; + return m_bytesQueue.TryDequeue(out bytes); + } + + /// + /// 向当前集合添加Block + /// + /// + public void Add(byte[] bytes) + { + m_bytesQueue.Enqueue(bytes); + } + + internal void Clear() + { + m_bytesQueue.Clear(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/ByteManager/IByteBlock.cs b/src/TouchSocket/Core/ByteManager/IByteBlock.cs new file mode 100644 index 000000000..4ef3a65ac --- /dev/null +++ b/src/TouchSocket/Core/ByteManager/IByteBlock.cs @@ -0,0 +1,147 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 字节块流 + /// + public interface IByteBlock : IWrite, IDisposable + { + /// + /// 字节实例 + /// + byte[] Buffer { get; } + + /// + /// 仅当内存块可用,且>0时为True。 + /// + bool CanRead { get; } + + /// + /// 剩余的长度,准确掌握该值,可以避免内存扩展,计算为的差值。 + /// + int FreeLength { get; } + + /// + /// 还能读取的长度,计算为的差值。 + /// + int CanReadLen { get; } + + /// + /// 还能读取的长度,计算为的差值。 + /// + long CanReadLength { get; } + + /// + /// 容量 + /// + int Capacity { get; } + + /// + /// 表示持续性持有,为True时,Dispose将调用无效。 + /// + bool Holding { get; } + + /// + /// Int真实长度 + /// + int Len { get; } + + /// + /// 真实长度 + /// + long Length { get; } + + /// + /// int型流位置 + /// + int Pos { get; set; } + + /// + /// 流位置 + /// + long Position { get; set; } + + /// + /// 使用状态 + /// + bool Using { get; } + + /// + /// 直接完全释放,游离该对象,然后等待GC + /// + void AbsoluteDispose(); + + /// + /// 清空所有内存数据 + /// + /// 内存块已释放 + void Clear(); + + /// + /// 将内存块初始化到刚申请的状态。 + /// 仅仅重置属性。 + /// + /// 内存块已释放 + void Reset(); + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + /// + /// + /// + int Read(byte[] buffer, int offset, int length); + + /// + /// 读取一个字节 + /// + /// + int ReadByte(); + + /// + /// 重新设置容量 + /// + /// 新尺寸 + /// 是否保留元数据 + /// + void SetCapacity(int size, bool retainedData = false); + + /// + /// 设置持续持有属性,当为True时,调用Dispose会失效,表示该对象将长期持有,直至设置为False。 + /// 当为False时,会自动调用Dispose。 + /// + /// + /// + void SetHolding(bool holding); + + /// + /// 设置实际长度 + /// + /// + /// + void SetLength(long value); + + /// + /// 从指定位置转化到指定长度的有效内存 + /// + /// + /// + /// + byte[] ToArray(int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/ByteManager/ValueByteBlock.cs b/src/TouchSocket/Core/ByteManager/ValueByteBlock.cs new file mode 100644 index 000000000..5a296759e --- /dev/null +++ b/src/TouchSocket/Core/ByteManager/ValueByteBlock.cs @@ -0,0 +1,1274 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 字节块流 + /// + [DebuggerDisplay("Len={Len},Pos={Pos},Capacity={Capacity}")] + public ref struct ValueByteBlock + { + private long m_length; + private bool m_using; + private static float m_ratio = 1.5f; + private readonly bool m_needDis; + private byte[] m_buffer; + private int m_dis; + private bool m_holding; + private long m_position; + + /// + /// 构造函数 + /// + /// + /// + public ValueByteBlock(int byteSize = 1024 * 64, bool equalSize = false) + { + m_dis = 1; + m_needDis = true; + m_buffer = BytePool.Default.GetByteCore(byteSize, equalSize); + m_using = true; + m_length = 0; + m_holding = false; + m_position = 0; + } + + /// + /// 实例化一个已知内存的对象。且该内存不会被回收。 + /// + /// + public ValueByteBlock(byte[] bytes) + { + m_dis = 0; + m_needDis = false; + m_buffer = bytes ?? throw new ArgumentNullException(nameof(bytes)); + m_length = bytes.Length; + m_using = true; + m_length = 0; + m_holding = false; + m_position = 0; + } + + /// + /// 创建一个来自于内存池的成员。 + /// + /// + /// + /// + public static ValueByteBlock Create(int byteSize = 1024 * 64, bool equalSize = false) + { + return new ValueByteBlock(byteSize, equalSize); + } + + /// + /// 扩容增长比,默认为1.5, + /// min:1.5 + /// + public static float Ratio + { + get => m_ratio; + set + { + if (value < 1.5) + { + value = 1.5f; + } + m_ratio = value; + } + } + + /// + /// 字节实例 + /// + public byte[] Buffer => m_buffer; + + /// + /// 仅当内存块可用,且>0时为True。 + /// + public bool CanRead => m_using && CanReadLen > 0; + + /// + /// 还能读取的长度,计算为的差值。 + /// + public int CanReadLen => Len - Pos; + + /// + /// 还能读取的长度,计算为的差值。 + /// + public long CanReadLength => m_length - m_position; + + /// + /// 支持查找 + /// + public bool CanSeek => m_using; + + /// + /// 可写入 + /// + public bool CanWrite => m_using; + + /// + /// 容量 + /// + public int Capacity => m_buffer.Length; + + /// + /// 空闲长度,准确掌握该值,可以避免内存扩展,计算为的差值。 + /// + public int FreeLength => Capacity - Pos; + + /// + /// 表示持续性持有,为True时,Dispose将调用无效。 + /// + public bool Holding => m_holding; + + /// + /// Int真实长度 + /// + public int Len => (int)m_length; + + /// + /// 真实长度 + /// + public long Length => m_length; + + /// + /// int型流位置 + /// + public int Pos + { + get => (int)m_position; + set => m_position = value; + } + + /// + /// 流位置 + /// + public long Position + { + get => m_position; + set => m_position = value; + } + + /// + /// 使用状态 + /// + public bool Using => m_using; + + /// + /// 直接完全释放,游离该对象,然后等待GC + /// + public void AbsoluteDispose() + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + Dis(); + } + } + + /// + /// 清空所有内存数据 + /// + /// 内存块已释放 + public void Clear() + { + if (!m_using) + { + throw new ObjectDisposedException(nameof(ValueByteBlock)); + } + Array.Clear(m_buffer, 0, m_buffer.Length); + } + + /// + /// + /// + public void Dispose() + { + if (m_holding) + { + return; + } + + if (m_needDis) + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + BytePool.Default.Recycle(m_buffer); + Dis(); + } + } + } + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + /// + /// + /// + public int Read(byte[] buffer, int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException(nameof(ValueByteBlock)); + } + int len = m_length - m_position > length ? length : CanReadLen; + Array.Copy(m_buffer, m_position, buffer, offset, len); + m_position += len; + return len; + } + + /// + /// 读取数据,然后递增Pos + /// + /// + /// + public int Read(byte[] buffer) + { + return Read(buffer, 0, buffer.Length); + } + + /// + /// 读取数据,然后递增Pos + /// + + /// + /// + /// + public int Read(out byte[] buffer, int length) + { + buffer = new byte[length]; + return Read(buffer, 0, buffer.Length); + } + + /// + /// 从当前流位置读取一个值 + /// + public int ReadByte() + { + byte value = m_buffer[m_position]; + m_position++; + return value; + } + + /// + /// 将内存块初始化到刚申请的状态。 + /// 仅仅重置属性。 + /// + /// 内存块已释放 + public void Reset() + { + if (!m_using) + { + throw new ObjectDisposedException(nameof(ValueByteBlock)); + } + m_position = 0; + m_length = 0; + } + + /// + /// 设置流位置 + /// + /// + /// + /// + /// + public long Seek(long offset, SeekOrigin origin) + { + if (!m_using) + { + throw new ObjectDisposedException(nameof(ValueByteBlock)); + } + switch (origin) + { + case SeekOrigin.Begin: + m_position = offset; + break; + + case SeekOrigin.Current: + m_position += offset; + break; + + case SeekOrigin.End: + m_position = m_length + offset; + break; + } + return m_position; + } + + /// + /// 移动游标 + /// + /// + /// + public ValueByteBlock Seek(int position) + { + Position = position; + return this; + } + + /// + /// 设置游标到末位 + /// + /// + public ValueByteBlock SeekToEnd() + { + Position = Length; + return this; + } + + /// + /// 设置游标到首位 + /// + /// + public ValueByteBlock SeekToStart() + { + Position = 0; + return this; + } + /// + /// 重新设置容量 + /// + /// 新尺寸 + /// 是否保留元数据 + /// + public void SetCapacity(int size, bool retainedData = false) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + byte[] bytes = new byte[size]; + + if (retainedData) + { + Array.Copy(m_buffer, 0, bytes, 0, m_buffer.Length); + } + if (m_needDis) + { + BytePool.Default.Recycle(m_buffer); + } + m_buffer = bytes; + } + + /// + /// 设置持续持有属性,当为True时,调用Dispose会失效,表示该对象将长期持有,直至设置为False。 + /// 当为False时,会自动调用Dispose。 + /// + /// + /// + public void SetHolding(bool holding) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + m_holding = holding; + if (!holding) + { + Dispose(); + } + } + + /// + /// 设置实际长度 + /// + /// + /// + public void SetLength(long value) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + if (value > m_buffer.Length) + { + throw new Exception("设置值超出容量"); + } + m_length = value; + } + + /// + /// 从指定位置转化到指定长度的有效内存 + /// + /// + /// + /// + public byte[] ToArray(int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + byte[] buffer = new byte[length]; + Array.Copy(m_buffer, offset, buffer, 0, buffer.Length); + return buffer; + } + + /// + /// 转换为有效内存 + /// + /// + public byte[] ToArray() + { + return ToArray(0, Len); + } + + /// + /// 从指定位置转化到有效内存 + /// + + /// + /// + /// + public byte[] ToArray(int offset) + { + return ToArray(offset, Len - offset); + } + + /// + /// 转换为UTF-8字符 + /// + /// + public override string ToString() + { + return ToString(0, Len); + } + + /// + /// 转换为UTF-8字符 + /// + /// 偏移量 + /// 长度 + /// + public string ToString(int offset, int length) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + return Encoding.UTF8.GetString(m_buffer, offset, length); + } + + /// + /// 转换为UTF-8字符 + /// + /// 偏移量 + /// + public string ToString(int offset) + { + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + return Encoding.UTF8.GetString(m_buffer, offset, Len - offset); + } + + /// + /// 写入 + /// + /// + /// + /// + /// + public void Write(byte[] buffer, int offset, int count) + { + if (count == 0) + { + return; + } + if (!m_using) + { + throw new ObjectDisposedException("ValueByteBlock"); + } + if (m_buffer.Length - m_position < count) + { + int need = m_buffer.Length + count - ((int)(m_buffer.Length - m_position)); + int lend = m_buffer.Length; + while (need > lend) + { + lend = (int)(lend * m_ratio); + } + SetCapacity(lend, true); + } + Array.Copy(buffer, offset, m_buffer, m_position, count); + m_position += count; + m_length = Math.Max(m_position, m_length); + } + + /// + /// + /// + /// + /// + public void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// + /// + /// + private void Dispose(bool disposing) + { + if (m_holding) + { + return; + } + + if (m_needDis) + { + if (Interlocked.Decrement(ref m_dis) == 0) + { + BytePool.Default.Recycle(m_buffer); + Dis(); + } + } + } + + private void Dis() + { + m_holding = false; + m_using = false; + m_position = 0; + m_length = 0; + m_buffer = null; + } + + #region BytesPackage + + /// + /// 从当前流位置读取一个独立的数组包 + /// + public byte[] ReadBytesPackage() + { + byte status = (byte)ReadByte(); + if (status == 0) + { + return null; + } + int length = ReadInt32(); + byte[] data = new byte[length]; + Array.Copy(Buffer, Pos, data, 0, length); + Pos += length; + return data; + } + + /// + /// 尝试获取数据包信息,方便从Buffer操作数据 + /// + /// + /// + /// + public bool TryReadBytesPackageInfo(out int pos, out int len) + { + byte status = (byte)ReadByte(); + if (status == 0) + { + pos = 0; + len = 0; + return false; + } + len = ReadInt32(); + pos = Pos; + return true; + } + + /// + /// 写入一个独立的数组包,值可以为null。 + /// + /// + /// + /// + public ValueByteBlock WriteBytesPackage(byte[] value, int offset, int length) + { + if (value == null) + { + Write((byte)0); + } + else + { + Write((byte)1); + Write(length); + Write(value, offset, length); + } + return this; + } + + /// + /// 写入一个独立的数组包。值可以为null。 + /// + /// + public ValueByteBlock WriteBytesPackage(byte[] value) + { + if (value == null) + { + return WriteBytesPackage(value, 0, 0); + } + return WriteBytesPackage(value, 0, value.Length); + } + + #endregion BytesPackage + + #region Int32 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public int ReadInt32(bool? bigEndian = null) + { + int value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt32(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt32(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt32(Buffer, Pos); break; + } + m_position += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(int value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int32 + + #region Int16 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public short ReadInt16(bool? bigEndian = null) + { + short value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt16(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt16(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt16(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(short value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int16 + + #region Int64 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public long ReadInt64(bool? bigEndian = null) + { + long value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToInt64(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToInt64(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(long value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Int64 + + #region Boolean + + /// + /// 从当前流位置读取一个值 + /// + public bool ReadBoolean() + { + bool value = TouchSocketBitConverter.Default.ToBoolean(Buffer, Pos); + Pos += 1; + return value; + } + + /// + /// 写入值 + /// + /// + public ValueByteBlock Write(bool value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value)); + return this; + } + + #endregion Boolean + + #region Byte + + /// + /// 写入值 + /// + /// + /// + public ValueByteBlock Write(byte value) + { + Write(new byte[] { value }, 0, 1); + return this; + } + + #endregion Byte + + #region String + + /// + /// 从当前流位置读取一个值 + /// + public string ReadString() + { + int len = this.ReadInt32(); + if (len < 0) + { + return null; + } + else + { + string str = Encoding.UTF8.GetString(Buffer, Pos, len); + Pos += len; + return str; + } + } + + /// + /// 写入值。值可以为null,或者空。 + /// 注意:该操作不具备通用性,读取时必须使用ReadString。或者得先做出判断,由默认端序的int32值标识,具体如下: + /// + /// 小于0,表示字符串为null + /// 等于0,表示字符串为"" + /// 大于0,表示字符串在utf-8编码下的字节长度。 + /// + /// + /// + public ValueByteBlock Write(string value) + { + if (value == null) + { + Write(-1); + } + else + { + byte[] buffer = Encoding.UTF8.GetBytes(value); + Write(buffer.Length); + Write(buffer); + } + return this; + } + + /// + /// 写入值。值必须为有效值。可通用解析。 + /// + /// + /// + public ValueByteBlock WriteString(string value, Encoding encoding = null) + { + Write((encoding ?? Encoding.UTF8).GetBytes(value)); + return this; + } + + #endregion String + + #region Char + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public char ReadChar(bool? bigEndian = null) + { + char value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToChar(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToChar(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToChar(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(char value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Char + + #region Double + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public double ReadDouble(bool? bigEndian = null) + { + double value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToDouble(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToDouble(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToDouble(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(double value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Double + + #region Float + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public float ReadFloat(bool? bigEndian = null) + { + float value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToSingle(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToSingle(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToSingle(Buffer, Pos); break; + } + Pos += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(float value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion Float + + #region UInt16 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ushort ReadUInt16(bool? bigEndian = null) + { + ushort value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt16(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt16(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt16(Buffer, Pos); break; + } + Pos += 2; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(ushort value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt16 + + #region UInt32 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public uint ReadUInt32(bool? bigEndian = null) + { + uint value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt32(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt32(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt32(Buffer, Pos); break; + } + Pos += 4; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(uint value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt32 + + #region UInt64 + + /// + /// 从当前流位置读取一个值 + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ulong ReadUInt64(bool? bigEndian = null) + { + ulong value; + switch (bigEndian) + { + case true: value = TouchSocketBitConverter.BigEndian.ToUInt64(Buffer, Pos); break; + case false: value = TouchSocketBitConverter.LittleEndian.ToUInt64(Buffer, Pos); break; + default: value = TouchSocketBitConverter.Default.ToUInt64(Buffer, Pos); break; + } + Pos += 8; + return value; + } + + /// + /// 写入值 + /// + /// + /// 是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。 + public ValueByteBlock Write(ulong value, bool? bigEndian = null) + { + switch (bigEndian) + { + case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break; + case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break; + default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break; + } + return this; + } + + #endregion UInt64 + + #region Null + + /// + /// 从当前流位置读取一个标识值,判断是否为null。 + /// + public bool ReadIsNull() + { + var status = ReadByte(); + if (status == 0) + { + return true; + } + else if (status == 1) + { + return false; + } + else + { + throw new Exception("标识既非Null,也非NotNull,可能是流位置发生了错误。"); + } + } + + /// + /// 判断该值是否为Null,然后写入标识值 + /// + public ValueByteBlock WriteIsNull(T t) where T : class + { + if (t == null) + { + WriteNull(); + } + else + { + WriteNotNull(); + } + return this; + } + + /// + /// 写入一个标识非Null值 + /// + public ValueByteBlock WriteNotNull() + { + Write((byte)1); + return this; + } + + /// + /// 写入一个标识Null值 + /// + public ValueByteBlock WriteNull() + { + Write((byte)0); + return this; + } + + #endregion Null + + + #region DateTime + + /// + /// 从当前流位置读取一个值 + /// + public DateTime ReadDateTime() + { + long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); + Pos += 8; + return DateTime.FromBinary(value); + } + + /// + /// 写入值 + /// + /// + public ValueByteBlock Write(DateTime value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value.ToBinary())); + return this; + } + + #endregion DateTime + + #region TimeSpan + + /// + /// 从当前流位置读取一个值 + /// + public TimeSpan ReadTimeSpan() + { + long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); + Pos += 8; + return TimeSpan.FromTicks(value); + } + + /// + /// 写入值 + /// + /// + public ValueByteBlock Write(TimeSpan value) + { + Write(TouchSocketBitConverter.Default.GetBytes(value.Ticks)); + return this; + } + + #endregion TimeSpan + + #region Object + + /// + /// 从当前流位置读取一个泛型值 + /// + /// + /// + /// + public T ReadObject(SerializationType serializationType = SerializationType.FastBinary) + { + int length = ReadInt32(); + + if (length == 0) + { + return default; + } + + T obj; + + switch (serializationType) + { + case SerializationType.FastBinary: + { + obj = SerializeConvert.FastBinaryDeserialize(Buffer, Pos); + } + break; + + case SerializationType.Json: + { + string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length); + obj = SerializeConvert.JsonDeserializeFromString(jsonString); + } + break; + + case SerializationType.Xml: + { + string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length); + obj = SerializeConvert.XmlDeserializeFromString(jsonString); + } + break; + + case SerializationType.SystemBinary: + { + obj = SerializeConvert.BinaryDeserialize(Buffer, Pos, length); + } + break; + + default: + throw new Exception("未定义的序列化类型"); + } + + Pos += length; + return obj; + } + + /// + /// 写入值 + /// + /// + /// + public ValueByteBlock WriteObject(object value, SerializationType serializationType = SerializationType.FastBinary) + { + if (value == null) + { + Write(0); + return this; + } + byte[] data; + switch (serializationType) + { + case SerializationType.FastBinary: + { + data = SerializeConvert.FastBinarySerialize(value); + } + break; + + case SerializationType.Json: + { + data = SerializeConvert.JsonSerializeToBytes(value); + } + break; + + case SerializationType.Xml: + { + data = Encoding.UTF8.GetBytes(SerializeConvert.XmlSerializeToString(value)); + } + break; + + case SerializationType.SystemBinary: + { + data = SerializeConvert.BinarySerialize(value); + } + break; + + default: + throw new Exception("未定义的序列化类型"); + } + + Write(data.Length); + Write(data); + return this; + } + + #endregion Object + } +} diff --git a/src/TouchSocket/Core/Caching/CacheEntry.cs b/src/TouchSocket/Core/Caching/CacheEntry.cs new file mode 100644 index 000000000..dcb52beeb --- /dev/null +++ b/src/TouchSocket/Core/Caching/CacheEntry.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 缓存实体 + /// + public class CacheEntry : ICacheEntry + { + /// + /// 缓存实体 + /// + /// + public CacheEntry(TKey key) : this(key, default) + { + } + + /// + /// 缓存实体 + /// + public CacheEntry(TKey key, TValue value) + { + UpdateTime = DateTime.Now; + Duration = TimeSpan.FromSeconds(60); + Key = key; + Value = value; + } + + /// + /// 有效区间。如果想长期有效,请使用 + /// + public TimeSpan Duration { get; set; } + + /// + /// 键 + /// + public TKey Key { get; set; } + + /// + /// 更新时间 + /// + public DateTime UpdateTime { get; set; } + + /// + /// 值 + /// + public TValue Value { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Caching/CacheManagementExtensions.cs b/src/TouchSocket/Core/Caching/CacheManagementExtensions.cs new file mode 100644 index 000000000..123f86ba6 --- /dev/null +++ b/src/TouchSocket/Core/Caching/CacheManagementExtensions.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// CacheExtensions + /// + public static class CacheManagementExtensions + { + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void AddCache(this ICache cacheManagement, TKey key, TValue value, int duration = 60 * 1000) + { + cacheManagement.AddCache(new CacheEntry(key) + { + Value = value, + Duration = TimeSpan.FromMilliseconds(duration) + }); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void SetCache(this ICache cacheManagement, TKey key, TValue value, int duration = 60 * 1000) + { + cacheManagement.SetCache(new CacheEntry(key) + { + Value = value, + Duration = TimeSpan.FromMilliseconds(duration) + }); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Caching/ICache.cs b/src/TouchSocket/Core/Caching/ICache.cs new file mode 100644 index 000000000..8b773f5db --- /dev/null +++ b/src/TouchSocket/Core/Caching/ICache.cs @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 缓存键值 + /// + public interface ICache + { + /// + /// 添加缓存。当缓存存在时,不会添加成功。 + /// + /// 缓存实体 + /// + bool AddCache(ICacheEntry entity); + + /// + /// 添加缓存。当缓存存在时,不会添加成功。 + /// + /// 缓存实体 + /// + Task AddCacheAsync(ICacheEntry entity); + + /// + /// 清空所有缓存 + /// + void ClearCache(); + + /// + /// 清空所有缓存 + /// + /// + Task ClearCacheAsync(); + + /// + /// 判断缓存是否存在,且在生命周期内。 + /// + /// + /// + /// + bool ContainsCache(TKey key); + + /// + /// 判断缓存是否存在,且在生命周期内。 + /// + /// + /// + /// + Task ContainsCacheAsync(TKey key); + + /// + /// 设置缓存,不管缓存存不存在,都会添加。 + /// + /// + /// + /// + bool SetCache(ICacheEntry entity); + + /// + /// 设置缓存,不管缓存存不存在,都会添加。 + /// + /// + /// + /// + Task SetCacheAsync(ICacheEntry entity); + + /// + /// 获取指定键的缓存。 + /// + /// 键 + /// + /// + ICacheEntry GetCache(TKey key); + + /// + /// 获取指定键的缓存。 + /// + /// 键 + /// + /// + Task> GetCacheAsync(TKey key); + + /// + /// 移除指定键的缓存。 + /// + /// 键 + /// + /// + bool RemoveCache(TKey key); + + /// + /// 移除指定键的缓存。 + /// + /// 键 + /// + /// + Task RemoveCacheAsync(TKey key); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Caching/ICacheEntry.cs b/src/TouchSocket/Core/Caching/ICacheEntry.cs new file mode 100644 index 000000000..f59169784 --- /dev/null +++ b/src/TouchSocket/Core/Caching/ICacheEntry.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 缓存实体接口 + /// + public interface ICacheEntry + { + /// + /// 有效区间。如果想长期有效,请使用 + /// + public TimeSpan Duration { get; } + + /// + /// 更新时间 + /// + public DateTime UpdateTime { get; set; } + } + + /// + /// 缓存实体接口 + /// + public interface ICacheEntry : ICacheEntry + { + /// + /// 键 + /// + public TKey Key { get; } + + /// + /// 值 + /// + public TValue Value { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Caching/MemoryCache.cs b/src/TouchSocket/Core/Caching/MemoryCache.cs new file mode 100644 index 000000000..839961298 --- /dev/null +++ b/src/TouchSocket/Core/Caching/MemoryCache.cs @@ -0,0 +1,319 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 一个简单的内存缓存 + /// + public class MemoryCache : IEnumerable>, ICache + { + private readonly ConcurrentDictionary> m_pairs = new ConcurrentDictionary>(); + private readonly Timer m_timer; + + /// + /// 一个简单的内存缓存 + /// + public MemoryCache() + { + m_timer = new Timer((o) => + { + List list = new List(); + foreach (var item in m_pairs) + { + if (DateTime.Now - item.Value.UpdateTime > item.Value.Duration) + { + list.Add(item.Key); + } + } + foreach (var item in list) + { + OnRemove(item, out _); + } + }, null, 0, 60 * 1000); + } + + /// + /// 当每个元素超时被移除时触发。 + /// + public Action> Remove { get; set; } + + /// + /// + /// + /// + public bool AddCache(ICacheEntry entity) + { + return m_pairs.TryAdd(entity.Key, entity); + } + + /// + /// + /// + /// + /// + public Task AddCacheAsync(ICacheEntry entity) + { + return EasyTask.Run(() => + { + return AddCache(entity); + }); + } + + /// + /// 清空所有缓存 + /// + public void ClearCache() + { + m_pairs.Clear(); + } + + /// + /// + /// + /// + public Task ClearCacheAsync() + { + return EasyTask.Run(() => + { + ClearCache(); + }); + } + + /// + /// + /// + /// + /// + public bool ContainsCache(TKey key) + { + if (m_pairs.TryGetValue(key, out ICacheEntry cache)) + { + if (cache.Duration == TimeSpan.Zero) + { + return true; + } + else + { + if (DateTime.Now - cache.UpdateTime > cache.Duration) + { + OnRemove(key, out _); + return false; + } + else + { + return true; + } + } + } + return false; + } + + /// + /// + /// + /// + /// + public Task ContainsCacheAsync(TKey key) + { + return EasyTask.Run(() => + { + return ContainsCache(key); + }); + } + + /// + /// 获取缓存实体。 + /// + /// + /// + public ICacheEntry GetCache(TKey key) + { + ICacheEntry cache; + if (m_pairs.TryGetValue(key, out cache)) + { + if (cache.Duration == TimeSpan.Zero) + { + return cache; + } + else + { + if (DateTime.Now - cache.UpdateTime > cache.Duration) + { + OnRemove(key, out _); + return default; + } + else + { + return cache; + } + } + } + return default; + } + + /// + /// + /// + /// + /// + public Task> GetCacheAsync(TKey key) + { + return EasyTask.Run(() => + { + return GetCache(key); + }); + } + + /// + /// + /// + /// + public IEnumerator> GetEnumerator() + { + return m_pairs.Values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// 移除缓存 + /// + /// + /// + /// + public bool RemoveCache(TKey key, out ICacheEntry entity) + { + return OnRemove(key, out entity); + } + + /// + /// 移除缓存 + /// + /// + /// + public bool RemoveCache(TKey key) + { + return OnRemove(key, out _); + } + + /// + /// + /// + /// + /// + public Task RemoveCacheAsync(TKey key) + { + return EasyTask.Run(() => + { + return RemoveCache(key); + }); + } + + /// + /// + /// + /// + /// + public bool SetCache(ICacheEntry entity) + { + m_pairs.AddOrUpdate(entity.Key, entity, (k, v) => + { + return entity; + }); + return true; + } + + /// + /// + /// + /// + /// + public Task SetCacheAsync(ICacheEntry entity) + { + return EasyTask.Run(() => + { + return SetCache(entity); + }); + } + + /// + /// 获取对应的值。 + /// + /// + /// + /// + /// + public bool TryGetValue(TKey key, out TValue value, bool update = false) + { + if (m_pairs.TryGetValue(key, out ICacheEntry cache)) + { + if (cache.Duration == TimeSpan.Zero) + { + if (update) + { + cache.UpdateTime = DateTime.Now; + } + value = cache.Value; + return true; + } + else + { + if (DateTime.Now - cache.UpdateTime > cache.Duration) + { + RemoveCache(key); + value = default; + return false; + } + else + { + if (update) + { + cache.UpdateTime = DateTime.Now; + } + value = (TValue)cache.Value; + return true; + } + } + } + value = default; + return false; + } + + private bool OnRemove(TKey key, out ICacheEntry cache) + { + if (m_pairs.TryRemove(key, out cache)) + { + try + { + Remove?.Invoke(cache); + return true; + } + catch + { + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs b/src/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs new file mode 100644 index 000000000..6ad3fb12b --- /dev/null +++ b/src/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; + +namespace TouchSocket.Core +{ + /// + /// 安全双向字典 + /// + public class ConcurrentDoublyDictionary + { + private readonly ConcurrentDictionary m_keyToValue; + private readonly ConcurrentDictionary m_valueToKey; + + /// + /// 构造函数 + /// + public ConcurrentDoublyDictionary() + { + m_keyToValue = new ConcurrentDictionary(); + m_valueToKey = new ConcurrentDictionary(); + } + + /// + /// 由键指向值得集合 + /// + public ConcurrentDictionary KeyToValue => m_keyToValue; + + /// + /// 由值指向键的集合 + /// + public ConcurrentDictionary ValueToKey => m_valueToKey; + + /// + /// 尝试将指定的键和值添加到字典中。 + /// + /// + /// + /// + public bool TryAdd(TKey key, TValue value) + { + if (m_keyToValue.TryAdd(key, value)) + { + if (m_valueToKey.TryAdd(value, key)) + { + return true; + } + else + { + m_keyToValue.TryRemove(key, out _); + return false; + } + } + return false; + } + + /// + /// 由键尝试移除 + /// + /// + /// + /// + public bool TryRemoveFromKey(TKey key, out TValue value) + { + if (m_keyToValue.TryRemove(key, out value)) + { + if (m_valueToKey.TryRemove(value, out _)) + { + return true; + } + } + return false; + } + + /// + /// 由值尝试移除 + /// + /// + /// + /// + public bool TryRemoveFromValue(TValue value, out TKey key) + { + if (m_valueToKey.TryRemove(value, out key)) + { + if (m_keyToValue.TryRemove(key, out _)) + { + return true; + } + } + return false; + } + + /// + /// 由键获取到值 + /// + /// + /// + /// + public bool TryGetFromKey(TKey key, out TValue value) + { + return m_keyToValue.TryGetValue(key, out value); + } + + /// + /// 由值获取到键 + /// + /// + /// + /// + public bool TryGetFromValue(TValue value, out TKey key) + { + return m_valueToKey.TryGetValue(value, out key); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs b/src/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs new file mode 100644 index 000000000..7ed58cf0b --- /dev/null +++ b/src/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs @@ -0,0 +1,680 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Core +{ + /// + /// 线程安全的List,其基本操作和List一致。 + /// + /// + public class ConcurrentList : IList + { + private readonly List m_list; + + /// + /// 构造函数 + /// + /// + public ConcurrentList(IEnumerable collection) + { + m_list = new List(collection); + } + + /// + /// 构造函数 + /// + public ConcurrentList() + { + m_list = new List(); + } + + /// + /// 构造函数 + /// + /// + public ConcurrentList(int capacity) + { + m_list = new List(capacity); + } + + /// + /// 元素数量 + /// + public int Count + { + get + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Count; + } + } + } + + /// + /// 是否为只读 + /// + public bool IsReadOnly => false; + + /// + /// 获取索引元素 + /// + /// + /// + public T this[int index] + { + get + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list[index]; + } + } + set + { + lock (((ICollection)m_list).SyncRoot) + { + m_list[index] = value; + } + } + } + + /// + /// 添加元素 + /// + /// + public void Add(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Add(item); + } + } + + /// + /// 清空所有元素 + /// + public void Clear() + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Clear(); + } + } + + /// + /// 是否包含某个元素 + /// + /// + /// + public bool Contains(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Contains(item); + } + } + + /// + /// 复制到 + /// + /// + /// + public void CopyTo(T[] array, int arrayIndex) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.CopyTo(array, arrayIndex); + } + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator GetEnumerator() + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.ToList().GetEnumerator(); + } + } + + /// + /// 返回迭代器组合 + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + lock (((ICollection)m_list).SyncRoot) + { + return GetEnumerator(); + } + } + + /// + /// 索引 + /// + /// + /// + public int IndexOf(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.IndexOf(item); + } + } + + /// + /// 插入 + /// + /// + /// + public void Insert(int index, T item) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Insert(index, item); + } + } + + /// + /// 移除元素 + /// + /// + /// + public bool Remove(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Remove(item); + } + } + + /// + /// 按索引移除 + /// + /// + public void RemoveAt(int index) + { + lock (((ICollection)m_list).SyncRoot) + { + if (index < m_list.Count) + { + m_list.RemoveAt(index); + } + } + } + + /// + /// 获取或设置容量 + /// + public int Capacity + { + get + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Capacity; + } + } + set + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Capacity = value; + } + } + } + + /// + /// + /// + /// + public void AddRange(IEnumerable collection) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.AddRange(collection); + } + } + + /// + /// + /// + /// + /// + public int BinarySearch(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.BinarySearch(item); + } + } + + /// + /// + /// + /// + /// + /// + public int BinarySearch(T item, IComparer comparer) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.BinarySearch(item, comparer); + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + public int BinarySearch(int index, int count, T item, IComparer comparer) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.BinarySearch(index, count, item, comparer); + } + } + + /// + /// + /// + /// + /// + /// + public List ConvertAll(Converter converter) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.ConvertAll(converter); + } + } + + /// + /// + /// + /// + /// + public T Find(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.Find(match); + } + } + + /// + /// + /// + /// + /// + public List FindAll(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindAll(match); + } + } + + /// + /// + /// + /// + /// + /// + /// + public int FindIndex(int startIndex, int count, Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindIndex(startIndex, count, match); + } + } + + /// + /// + /// + /// + /// + /// + public int FindIndex(int startIndex, Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindIndex(startIndex, match); + } + } + + /// + /// + /// + /// + /// + public int FindIndex(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindIndex(match); + } + } + + /// + /// + /// + /// + /// + public T FindLast(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindLast(match); + } + } + + /// + /// + /// + /// + /// + /// + /// + public int FindLastIndex(int startIndex, int count, Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindLastIndex(startIndex, count, match); + } + } + + /// + /// + /// + /// + /// + /// + public int FindLastIndex(int startIndex, Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindLastIndex(startIndex, match); + } + } + + /// + /// + /// + /// + /// + public int FindLastIndex(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.FindLastIndex(match); + } + } + + /// + /// + /// + /// + public void ForEach(Action action) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.ForEach(action); + } + } + + /// + /// + /// + /// + /// + /// + public List GetRange(int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.GetRange(index, count); + } + } + + /// + /// + /// + /// + /// + /// + public int IndexOf(T item, int index) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.IndexOf(item, index); + } + } + + /// + /// + /// + /// + /// + /// + /// + public int IndexOf(T item, int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.IndexOf(item, index, count); + } + } + + /// + /// + /// + /// + /// + public void InsertRange(int index, IEnumerable collection) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.InsertRange(index, collection); + } + } + + /// + /// + /// + /// + /// + public int LastIndexOf(T item) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.IndexOf(item); + } + } + + /// + /// + /// + /// + /// + /// + public int LastIndexOf(T item, int index) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.LastIndexOf(item, index); + } + } + + /// + /// + /// + /// + /// + /// + /// + public int LastIndexOf(T item, int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.LastIndexOf(item, index, count); + } + } + + /// + /// + /// + /// + public void RemoveAll(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.RemoveAll(match); + } + } + + /// + /// + /// + /// + /// + public void RemoveRange(int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.RemoveRange(index, count); + } + } + + /// + /// + /// + public void Reverse() + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Reverse(); + } + } + + /// + /// + /// + /// + /// + public void Reverse(int index, int count) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Reverse(index, count); + } + } + + /// + /// + /// + public void Sort() + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Sort(); + } + } + + /// + /// + /// + /// + public void Sort(Comparison comparison) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Sort(comparison); + } + } + + /// + /// + /// + /// + public void Sort(IComparer comparer) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Sort(comparer); + } + } + + /// + /// + /// + /// + /// + /// + public void Sort(int index, int count, IComparer comparer) + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.Sort(index, count, comparer); + } + } + + /// + /// + /// + /// + public T[] ToArray() + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.ToArray(); + } + } + + /// + /// + /// + public void TrimExcess() + { + lock (((ICollection)m_list).SyncRoot) + { + m_list.TrimExcess(); + } + } + + /// + /// + /// + /// + /// + public bool TrueForAll(Predicate match) + { + lock (((ICollection)m_list).SyncRoot) + { + return m_list.TrueForAll(match); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs b/src/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs new file mode 100644 index 000000000..9bf73c99c --- /dev/null +++ b/src/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs @@ -0,0 +1,194 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; + +namespace TouchSocket.Core +{ + /// + /// 三元组合 + /// + /// + /// + /// + public readonly struct Ternary + { + /// + /// 三元组合 + /// + /// + /// + /// + public Ternary(TKey1 key1, TKey2 key2, TValue value) + { + Key1 = key1; + Key2 = key2; + Value = value; + } + + /// + /// 首键 + /// + public readonly TKey1 Key1 { get; } + + /// + /// 次键 + /// + public readonly TKey2 Key2 { get; } + + /// + /// 值 + /// + public readonly TValue Value { get; } + } + + /// + /// 线程安全的双键字典 + /// + /// + /// + /// + public class ConcurrentMultiDictionary + { + private readonly ConcurrentDictionary> m_key1ToValue = + new ConcurrentDictionary>(); + + private readonly ConcurrentDictionary> m_key2ToValue = + new ConcurrentDictionary>(); + + /// + /// 元素数量。 + /// + public int Count { get => m_key1ToValue.Count; } + + /// + /// 清空所有元素。 + /// + public void Clear() + { + m_key1ToValue.Clear(); + m_key2ToValue.Clear(); + } + + /// + /// 是否包含指定键。 + /// + /// + /// + public bool ContainsKey(TKey2 key) + { + return m_key2ToValue.ContainsKey(key); + } + + /// + /// 是否包含指定键。 + /// + /// + /// + public bool ContainsKey(TKey1 key) + { + return m_key1ToValue.ContainsKey(key); + } + + /// + /// 尝试添加。 + /// + /// + /// + /// + /// + public bool TryAdd(TKey1 key1, TKey2 key2, TValue value) + { + var ternary = new Ternary(key1, key2, value); + if (m_key1ToValue.TryAdd(key1, ternary) && m_key2ToValue.TryAdd(key2, ternary)) + { + return true; + } + else + { + m_key1ToValue.TryRemove(key1, out _); + m_key2ToValue.TryRemove(key2, out _); + return false; + } + } + + /// + /// 由首键删除 + /// + /// + /// + /// + public bool TryRemove(TKey1 key, out TValue value) + { + if (m_key1ToValue.TryRemove(key, out var ternary)) + { + m_key2ToValue.TryRemove(ternary.Key2, out _); + value = ternary.Value; + return true; + } + value = default; + return false; + } + + /// + /// 由次键删除 + /// + /// + /// + /// + public bool TryRemove(TKey2 key, out TValue value) + { + if (m_key2ToValue.TryRemove(key, out var ternary)) + { + m_key1ToValue.TryRemove(ternary.Key1, out _); + value = ternary.Value; + return true; + } + value = default; + return false; + } + + /// + /// 由首键获取值 + /// + /// + /// + /// + public bool TryGetValue(TKey1 key, out TValue value) + { + if (m_key1ToValue.TryGetValue(key, out var ternary)) + { + value = ternary.Value; + return true; + } + value = default; + return false; + } + + /// + /// 由次键获取值 + /// + /// + /// + /// + public bool TryGetValue(TKey2 key, out TValue value) + { + if (m_key2ToValue.TryGetValue(key, out var ternary)) + { + value = ternary.Value; + return true; + } + value = default; + return false; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs b/src/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs new file mode 100644 index 000000000..e86a8bd62 --- /dev/null +++ b/src/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 智能安全队列 + /// + /// + public class IntelligentConcurrentQueue : ConcurrentQueue + { + private int m_count; + + private readonly int m_maxCount; + + /// + /// 构造函数 + /// + /// + public IntelligentConcurrentQueue(int maxCount) + { + m_maxCount = maxCount; + } + + /// + /// 允许的最大长度 + /// + public int MaxCount => m_maxCount; + + /// + /// 长度 + /// + public new int Count => m_count; + + /// + /// 入队 + /// + /// + public new void Enqueue(T item) + { + SpinWait.SpinUntil(Check); + Interlocked.Increment(ref m_count); + base.Enqueue(item); + } + + /// + /// 出队 + /// + /// + /// + public new bool TryDequeue(out T result) + { + if (base.TryDequeue(out result)) + { + Interlocked.Decrement(ref m_count); + return true; + } + return false; + } + + private bool Check() + { + return m_count < m_maxCount; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs b/src/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs new file mode 100644 index 000000000..fdf1a1b2b --- /dev/null +++ b/src/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs @@ -0,0 +1,233 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 队列数据 + /// + public interface IQueueData + { + /// + /// 数据长度 + /// + int Size { get; } + } + + /// + /// 传输字节 + /// + public class QueueDataBytes : IQueueData + { + /// + /// 构造函数 + /// + /// + /// + /// + public QueueDataBytes(byte[] buffer, int offset, int length) + { + Offset = offset; + Length = length; + Buffer = buffer; + Size = length; + } + + /// + /// 从指定内存创建一个新对象,且内存也为新创建。 + /// + /// + /// + /// + /// + public static QueueDataBytes CreateNew(byte[] buffer, int offset, int length) + { + byte[] buf = new byte[length]; + Array.Copy(buffer, offset, buf, 0, length); + return new QueueDataBytes(buf); + } + + /// + /// 构造函数 + /// + /// + public QueueDataBytes(byte[] buffer) : this(buffer, 0, buffer.Length) + { + } + + /// + /// 数据内存 + /// + public byte[] Buffer { get; } + + /// + /// 长度 + /// + public int Length { get; } + + /// + /// 偏移 + /// + public int Offset { get; } + + /// + /// 尺寸 + /// + public int Size { get; } + } + + /// + /// 智能数据安全队列 + /// + /// + public class IntelligentDataQueue : ConcurrentQueue where T : IQueueData + { + private long m_actualSize; + private bool m_free; + private long m_maxSize; + private Action m_onQueueChanged; + private bool m_overflowWait; + + /// + /// 构造函数 + /// + /// + public IntelligentDataQueue(long maxSize) + { + m_free = true; + m_overflowWait = true; + MaxSize = maxSize; + } + + /// + /// 构造函数 + /// + public IntelligentDataQueue() : this(1024 * 1024 * 10) + { + } + + /// + /// 实际尺寸 + /// + public long ActualSize => m_actualSize; + + /// + /// 是否有空位允许入队 + /// + public bool Free => m_free; + + /// + /// 允许的最大长度 + /// + public long MaxSize + { + get => m_maxSize; + set + { + if (value < 1) + { + value = 1; + } + m_maxSize = value; + } + } + + /// + /// 在队列修改时 + /// + public Action OnQueueChanged + { + get => m_onQueueChanged; + set => m_onQueueChanged = value; + } + + /// + /// 溢出等待 + /// + public bool OverflowWait + { + get => m_overflowWait; + set => m_overflowWait = value; + } + + /// + /// 超时时间。默认1000*30ms; + /// + public int Timeout { get; set; } = 1000 * 30; + + /// + /// 清空队列 + /// + public void Clear(Action onClear) + { + while (base.TryDequeue(out T t)) + { + onClear?.Invoke(t); + } + } + + /// + /// 入队 + /// + /// + public new void Enqueue(T item) + { + lock (this) + { + bool free = m_actualSize < m_maxSize; + if (m_free != free) + { + m_free = free; + m_onQueueChanged?.Invoke(m_free); + } + + if (m_overflowWait) + { + SpinWait.SpinUntil(Check, Timeout); + } + + Interlocked.Add(ref m_actualSize, item.Size); + base.Enqueue(item); + } + } + + /// + /// 出队 + /// + /// + /// + public new bool TryDequeue(out T result) + { + if (base.TryDequeue(out result)) + { + Interlocked.Add(ref m_actualSize, -result.Size); + bool free = m_actualSize < m_maxSize; + if (m_free != free) + { + m_free = free; + m_onQueueChanged?.Invoke(m_free); + } + return true; + } + return false; + } + + private bool Check() + { + return m_actualSize < m_maxSize; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs b/src/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs new file mode 100644 index 000000000..8bc3ee24d --- /dev/null +++ b/src/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs @@ -0,0 +1,150 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 触发器队列 + /// + /// + public class TriggerQueue : DisposableObject + { + private readonly ReaderWriterLockSlim m_lockSlim; + private readonly ConcurrentQueue m_queue; + private readonly Timer m_timer; + private volatile bool m_sending; + + /// + /// 触发器队列 + /// + public TriggerQueue() + { + m_lockSlim = new ReaderWriterLockSlim(); + m_queue = new ConcurrentQueue(); + m_timer = new Timer(TimerRun, null, 10, 10); + } + + /// + /// 析构函数 + /// + ~TriggerQueue() + { + Dispose(false); + } + + /// + /// 出队列处理。 + /// + public Action OnDequeue { get; set; } + + /// + /// 发生错误 + /// + public Action OnError { get; set; } + + /// + /// 是否处于发送状态 + /// + public bool Sending + { + get + { + using (new ReadLock(m_lockSlim)) + { + return m_sending; + } + } + + private set + { + using (new WriteLock(m_lockSlim)) + { + m_sending = value; + } + } + } + + /// + /// 发送 + /// + public void Enqueue(T data) + { + m_queue.Enqueue(data); + if (SwitchToRun()) + { + ThreadPool.QueueUserWorkItem(BeginTrigger); + } + } + + /// + /// 释放 + /// + /// + protected override void Dispose(bool disposing) + { + m_timer.SafeDispose(); + m_queue.Clear(); + base.Dispose(disposing); + } + + private void BeginTrigger(object o) + { + while (true) + { + try + { + if (m_queue.TryDequeue(out T data)) + { + OnDequeue?.Invoke(data); + } + else + { + break; + } + } + catch (Exception ex) + { + OnError?.Invoke(ex); + } + } + Sending = false; + } + + private bool SwitchToRun() + { + using (new ReadLock(m_lockSlim)) + { + if (m_sending) + { + return false; + } + else + { + m_sending = true; + return true; + } + } + } + + private void TimerRun(object state) + { + if (SwitchToRun()) + { + BeginTrigger(null); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs b/src/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs new file mode 100644 index 000000000..371bd095f --- /dev/null +++ b/src/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Specialized; +using System.Diagnostics; + +namespace TouchSocket.Core +{ + /// + /// IgnoreCaseNameValueCollection + /// + [DebuggerTypeProxy(typeof(NameValueCollectionDebugView))] + public class IgnoreCaseNameValueCollection : NameValueCollection + { + /// + /// IgnoreCaseNameValueCollection + /// + public IgnoreCaseNameValueCollection() : base(StringComparer.OrdinalIgnoreCase) + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs b/src/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs new file mode 100644 index 000000000..ebfbeb6cb --- /dev/null +++ b/src/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; + +namespace TouchSocket.Core +{ + /// + /// NameValueCollectionDebugView + /// + public class NameValueCollectionDebugView + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly NameValueCollection m_nameValue; + + /// + /// NameValueCollectionDebugView + /// + /// + public NameValueCollectionDebugView(NameValueCollection nameValue) + { + m_nameValue = nameValue; + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + private Dictionary KV + { + get + { + var dic = new Dictionary(); + foreach (var item in m_nameValue.AllKeys) + { + dic.TryAdd(item, m_nameValue[item]); + } + return dic; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/AppConfigBase.cs b/src/TouchSocket/Core/Common/AppConfigBase.cs new file mode 100644 index 000000000..ac83754a4 --- /dev/null +++ b/src/TouchSocket/Core/Common/AppConfigBase.cs @@ -0,0 +1,137 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.IO; + +namespace TouchSocket.Core +{ + /// + /// 运行配置类 + /// + public abstract class AppConfigBase + { + private readonly string m_fullPath; + + /// + /// 构造函数 + /// + /// + public AppConfigBase(string fullPath) + { + if (string.IsNullOrEmpty(fullPath)) + { + throw new ArgumentException($"“{nameof(fullPath)}”不能为 null 或空。", nameof(fullPath)); + } + + m_fullPath = fullPath; + } + + /// + /// 保存配置 + /// + /// + /// + /// + public bool Save(bool overwrite, out string msg) + { + if (overwrite == false && File.Exists(m_fullPath)) + { + msg = null; + return true; + } + try + { + File.WriteAllText(m_fullPath, this.ToJson()); + msg = null; + return true; + } + catch (Exception ex) + { + msg = ex.Message; + return false; + } + } + + /// + /// 加载配置 + /// + /// + /// + public bool Load(out string msg) + { + try + { + if (!File.Exists(m_fullPath)) + { + Save(false, out _); + } + var obj = File.ReadAllText(m_fullPath).FromJson(GetType()); + var ps = GetType().GetProperties(); + + foreach (var item in ps) + { + item.SetValue(this, item.GetValue(obj)); + } + msg = null; + return true; + } + catch (Exception ex) + { + msg = ex.Message; + return false; + } + } + + /// + /// 获取默认配置。 + /// + /// + /// + public static T GetDefault() where T : AppConfigBase, new() + { + Type type = typeof(T); + if (list.TryGetValue(type, out object value)) + { + return (T)value; + } + T _default = ((T)Activator.CreateInstance(typeof(T))); + _default.Load(out _); + list.Add(type, _default); + return _default; + } + + private static readonly Dictionary list = new Dictionary(); + + /// + /// 获取默认配置,每次调用该方法时,都会重新加载配置。 + /// + /// + /// + public static T GetNewDefault() where T : AppConfigBase, new() + { + T _default = ((T)Activator.CreateInstance(typeof(T))); + _default.Load(out _); + if (list.ContainsKey(_default.GetType())) + { + list[_default.GetType()] = _default; + } + else + { + list.Add(_default.GetType(), _default); + } + return _default; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/DateExtensions.cs b/src/TouchSocket/Core/Common/DateExtensions.cs new file mode 100644 index 000000000..139bd563a --- /dev/null +++ b/src/TouchSocket/Core/Common/DateExtensions.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// DateExtensions + /// + public static class DateExtensions + { + private static readonly DateTime m_utc_time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// 将时间转为毫秒级别的短整形 + /// + /// + /// + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ConvertTime(this in DateTime time) + { + return (uint)(Convert.ToInt64(time.Subtract(m_utc_time).TotalMilliseconds) & 0xffffffff); + } + + private static readonly DateTimeOffset m_utc1970 = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + + /// + /// 将时间转为毫秒级别的短整形 + /// + /// + /// + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ConvertTime(this in DateTimeOffset time) + { + return (uint)(Convert.ToInt64(time.Subtract(m_utc1970).TotalMilliseconds) & 0xffffffff); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/DisposableObject.cs b/src/TouchSocket/Core/Common/DisposableObject.cs new file mode 100644 index 000000000..78723a3af --- /dev/null +++ b/src/TouchSocket/Core/Common/DisposableObject.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 具有释放的对象。 + /// 并未实现析构函数相关。 + /// + public class DisposableObject : IDisposable + { + /// + /// 判断是否已释放。 + /// + private volatile bool m_disposedValue; + + /// + /// 标识该对象是否已被释放 + /// + public bool DisposedValue { get => m_disposedValue; } + + /// + /// 调用释放,切换释放状态。 + /// + /// + protected virtual void Dispose(bool disposing) + { + m_disposedValue = true; + } + + /// + /// 释放资源 + /// + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/Enum/EndianType.cs b/src/TouchSocket/Core/Common/Enum/EndianType.cs new file mode 100644 index 000000000..51608bc48 --- /dev/null +++ b/src/TouchSocket/Core/Common/Enum/EndianType.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 大小端类型 + /// + public enum EndianType + { + /// + /// 小端模式 + /// + Little, + + /// + /// 大端模式 + /// + Big + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/Enum/ResultCode.cs b/src/TouchSocket/Core/Common/Enum/ResultCode.cs new file mode 100644 index 000000000..c3ebc13b6 --- /dev/null +++ b/src/TouchSocket/Core/Common/Enum/ResultCode.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 结果类型 + /// + public enum ResultCode + { + /// + /// 默认 + /// + Default, + + /// + /// 错误 + /// + Error, + + /// + /// 异常 + /// + Exception, + + /// + /// 成功 + /// + Success, + + /// + /// 失败 + /// + Fail, + + /// + /// 操作超时 + /// + Overtime, + + /// + /// 操作取消 + /// + Canceled + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/FlowGate.cs b/src/TouchSocket/Core/Common/FlowGate.cs new file mode 100644 index 000000000..04fed7678 --- /dev/null +++ b/src/TouchSocket/Core/Common/FlowGate.cs @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 流量控制 + /// + public class FlowGate + { + private readonly Stopwatch m_stopwatch; + + private long m_timeTick; + + private long m_transferLength; + + /// + /// 构造函数 + /// + public FlowGate() + { + m_stopwatch = new Stopwatch(); + } + + /// + /// 最大值 + /// + public long Maximum { get; set; } = long.MaxValue; + + /// + /// 最长休眠周期。默认为5*1000ms. + /// 当设置为5000时,假如设置的=10,而一次递增了100,则理应会休眠10s,但是会休眠5s。反之,如果设置1,则每秒周期都会清空。 + /// + public int MaximumPeriod { get; set; } = 5000; + + /// + /// 检测等待 + /// + public void AddCheckWait(int increment) + { + if (GetNowTick() - m_timeTick > 0) + { + //时间过了一秒 + m_timeTick = FlowGate.GetNowTick(); + m_transferLength = 0; + m_stopwatch.Restart(); + } + else + { + //在这一秒中 + if (Interlocked.Add(ref m_transferLength, increment) > Maximum) + { + //上传饱和 + m_stopwatch.Stop(); + int sleepTime = 1000 - (int)m_stopwatch.ElapsedMilliseconds <= 0 ? 0 : GetBaseNum() - (int)m_stopwatch.ElapsedMilliseconds; + Thread.Sleep(sleepTime); + } + } + } + + /// + /// 检测等待 + /// + /// + /// + public async Task AddCheckWaitAsync(int increment) + { + if (GetNowTick() - m_timeTick > 0) + { + //时间过了一秒 + m_timeTick = FlowGate.GetNowTick(); + m_transferLength = 0; + m_stopwatch.Restart(); + } + else + { + //在这一秒中 + if (Interlocked.Add(ref m_transferLength, increment) > Maximum) + { + //上传饱和 + m_stopwatch.Stop(); + int sleepTime = 1000 - (int)m_stopwatch.ElapsedMilliseconds <= 0 ? 0 : GetBaseNum() - (int)m_stopwatch.ElapsedMilliseconds; + await Task.Delay(sleepTime); + } + } + } + + private static long GetNowTick() + { + return DateTime.Now.Ticks / 10000000; + } + + private int GetBaseNum() + { + return Math.Min((int)((double)m_transferLength / Maximum * 1000), MaximumPeriod); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/GlobalEnvironment.cs b/src/TouchSocket/Core/Common/GlobalEnvironment.cs new file mode 100644 index 000000000..e62cf1154 --- /dev/null +++ b/src/TouchSocket/Core/Common/GlobalEnvironment.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 全局环境设置 + /// + public static class GlobalEnvironment + { + /// + /// 优化平台 + /// + public static OptimizedPlatforms OptimizedPlatforms { get; set; } = OptimizedPlatforms.None; + } +} diff --git a/src/TouchSocket/Core/Common/IResult.cs b/src/TouchSocket/Core/Common/IResult.cs new file mode 100644 index 000000000..b91f03af6 --- /dev/null +++ b/src/TouchSocket/Core/Common/IResult.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 返回通知接口 + /// + public interface IResult + { + /// + /// 是否成功 + /// + ResultCode ResultCode { get; } + + /// + /// 消息 + /// + string Message { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/IWrite.cs b/src/TouchSocket/Core/Common/IWrite.cs new file mode 100644 index 000000000..d9e3387e2 --- /dev/null +++ b/src/TouchSocket/Core/Common/IWrite.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 规范写端口,提供更多扩展 + /// + public interface IWrite + { + /// + /// 写入 + /// + /// + /// + /// + void Write(byte[] buffer, int offset, int length); + + /// + /// 写入 + /// + /// + void Write(byte[] buffer); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/Locker.cs b/src/TouchSocket/Core/Common/Locker.cs new file mode 100644 index 000000000..a7d454516 --- /dev/null +++ b/src/TouchSocket/Core/Common/Locker.cs @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 读取锁 + /// + public struct ReadLock : IDisposable + { + private readonly ReaderWriterLockSlim m_locks; + + /// + /// 构造函数 + /// + /// + public ReadLock(ReaderWriterLockSlim locks) + { + m_locks = locks; + m_locks.EnterReadLock(); + } + + /// + /// 释放 + /// + public void Dispose() + { + m_locks.ExitReadLock(); + } + } + + /// + /// 写入锁 + /// + public struct WriteLock : IDisposable + { + private readonly ReaderWriterLockSlim m_locks; + + /// + /// 构造函数 + /// + /// + public WriteLock(ReaderWriterLockSlim locks) + { + m_locks = locks; + m_locks.EnterWriteLock(); + } + + /// + /// 释放 + /// + public void Dispose() + { + m_locks.ExitWriteLock(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/Mapper.cs b/src/TouchSocket/Core/Common/Mapper.cs new file mode 100644 index 000000000..c6f03186e --- /dev/null +++ b/src/TouchSocket/Core/Common/Mapper.cs @@ -0,0 +1,159 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 映射数据 + /// + public static class Mapper + { + private static readonly ConcurrentDictionary> m_typeToProperty = new ConcurrentDictionary>(); + + /// + /// 简单映射 + /// + /// + /// + /// + public static TTarget Map(this object source) where TTarget : class, new() + { + return (TTarget)Map(source, typeof(TTarget)); + } + + /// + /// 简单映射 + /// + /// + /// + /// + /// + public static TTarget Map(this TSource source) where TTarget : class, new() + { + return (TTarget)Map(source, typeof(TTarget)); + } + + /// + /// 简单对象映射 + /// + /// + /// + /// + public static object Map(this object source, Type targetType) + { + return Map(source, Activator.CreateInstance(targetType)); + } + + /// + /// 简单对象映射 + /// + /// + /// + /// + public static object Map(this object source, object target) + { + if (source is null) + { + return default; + } + var sourceType = source.GetType(); + if (sourceType.IsPrimitive || sourceType.IsEnum || sourceType == TouchSocket.Core.TouchSocketCoreUtility.stringType) + { + return source; + } + var sourcePairs = m_typeToProperty.GetOrAdd(sourceType, (k) => + { + Dictionary pairs = new Dictionary(); + var ps = k.GetProperties(BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var item in ps) + { + pairs.Add(item.Name, new Property(item)); + } + return pairs; + }); + + var targetPairs = m_typeToProperty.GetOrAdd(target.GetType(), (k) => + { + Dictionary pairs = new Dictionary(); + var ps = k.GetProperties(BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var item in ps) + { + pairs.Add(item.Name, new Property(item)); + } + return pairs; + }); + foreach (var item in targetPairs) + { + if (item.Value.CanWrite) + { + if (sourcePairs.TryGetValue(item.Key, out Property property)) + { + if (property.CanRead) + { + item.Value.SetValue(target, property.GetValue(source)); + } + } + } + } + return target; + } + + /// + /// 映射List + /// + /// + /// + /// + /// + public static IEnumerable MapList(this IEnumerable list) where T : class where T1 : class, new() + { + if (list is null) + { + throw new ArgumentNullException(nameof(list)); + } + + List result = new List(); + foreach (var item in list) + { + result.Add(Map(item)); + } + return result; + } + + /// + /// 映射List + /// + /// + /// + /// + /// + public static IEnumerable MapList(this IEnumerable list) where T1 : class, new() + { + if (list is null) + { + throw new ArgumentNullException(nameof(list)); + } + + List result = new List(); + foreach (var item in list) + { + result.Add(Map(item)); + } + return result; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/Metadata.cs b/src/TouchSocket/Core/Common/Metadata.cs new file mode 100644 index 000000000..83f22190b --- /dev/null +++ b/src/TouchSocket/Core/Common/Metadata.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Specialized; + +namespace TouchSocket.Core +{ + /// + /// 元数据键值对。 + /// + [FastConverter(typeof(MetadataFastBinaryConverter))] + public class Metadata : NameValueCollection, IPackage + { + /// + /// 元数据键值对。 + /// + public Metadata() + { + } + + /// + /// 添加。如果键存在,将被覆盖。 + /// + /// + /// + public new Metadata Add(string name, string value) + { + base.Add(name, value); + return this; + } + + /// + /// 打包 + /// + /// + public void Package(ByteBlock byteBlock) + { + byteBlock.Write(Count); + foreach (var item in AllKeys) + { + byteBlock.Write(item); + byteBlock.Write(this[item]); + } + } + + /// + /// 解包 + /// + /// + public void Unpackage(ByteBlock byteBlock) + { + int count = byteBlock.ReadInt32(); + for (int i = 0; i < count; i++) + { + string key = byteBlock.ReadString(); + string value = byteBlock.ReadString(); + Add(key, value); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs b/src/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs new file mode 100644 index 000000000..622bc1ced --- /dev/null +++ b/src/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// MetadataFastBinaryConverter + /// + internal sealed class MetadataFastBinaryConverter : FastBinaryConverter + { + protected override Metadata Read(byte[] buffer, int offset, int len) + { + ByteBlock byteBlock = new ByteBlock(buffer); + byteBlock.Pos = offset; + Metadata metadata = new Metadata(); + while (byteBlock.Pos < offset + len) + { + metadata.Add(byteBlock.ReadString(), byteBlock.ReadString()); + } + return metadata; + } + + protected override int Write(ByteBlock byteBlock, Metadata obj) + { + int pos = byteBlock.Pos; + foreach (var item in obj.AllKeys) + { + byteBlock.Write(item); + byteBlock.Write(obj[item]); + } + return byteBlock.Pos - pos; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/OptimizedPlatforms.cs b/src/TouchSocket/Core/Common/OptimizedPlatforms.cs new file mode 100644 index 000000000..ae43ab0f6 --- /dev/null +++ b/src/TouchSocket/Core/Common/OptimizedPlatforms.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 优化平台 + /// + [Flags] + public enum OptimizedPlatforms + { + /// + /// 无特殊优化 + /// + None=0, + + /// + /// 针对Unity2020及以下优化。 + /// 一般来说,当在unity2020及以下版本,中执行il2cpp编译时,需要设置该值。 + /// + Unity = 1 + } +} diff --git a/src/TouchSocket/Core/Common/Result.cs b/src/TouchSocket/Core/Common/Result.cs new file mode 100644 index 000000000..d805d994c --- /dev/null +++ b/src/TouchSocket/Core/Common/Result.cs @@ -0,0 +1,268 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using TouchSocket.Resources; + +namespace TouchSocket.Core +{ + /// + /// 结果返回 + /// + public struct Result : IResult + { + /// + /// 成功 + /// + public static readonly Result Success = new Result(ResultCode.Success, "Success"); + + /// + /// 初始状态 + /// + public static readonly Result Default = new Result(ResultCode.Default, "Default"); + + /// + /// 未知失败 + /// + public static readonly Result UnknownFail = new Result(ResultCode.Fail, TouchSocketStatus.UnknownError.GetDescription()); + + /// + /// 超时 + /// + public static readonly Result Overtime = new Result(ResultCode.Overtime, TouchSocketStatus.Overtime.GetDescription()); + + /// + /// 取消 + /// + public static readonly Result Canceled = new Result(ResultCode.Canceled, TouchSocketStatus.Canceled.GetDescription()); + + /// + /// 构造函数 + /// + /// + /// + public Result(ResultCode resultCode, string message) + { + ResultCode = resultCode; + Message = message; + } + + /// + /// 构造函数 + /// + /// + public Result(IResult result) + { + ResultCode = result.ResultCode; + Message = result.Message; + } + + /// + /// 构造函数 + /// + /// + public Result(Exception exception) + { + ResultCode = ResultCode.Exception; + Message = exception.Message; + } + + /// + /// 构造函数 + /// + /// + public Result(ResultCode resultCode) + { + ResultCode = resultCode; + Message = resultCode.GetDescription(); + } + + /// + /// + /// + public ResultCode ResultCode { get; private set; } + + /// + /// + /// + public string Message { get; private set; } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromCanceled(string msg) + { + return new Result(ResultCode.Canceled, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromError(string msg) + { + return new Result(ResultCode.Error, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromException(string msg) + { + return new Result(ResultCode.Exception, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromFail(string msg) + { + return new Result(ResultCode.Fail, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromOvertime(string msg) + { + return new Result(ResultCode.Overtime, msg); + } + + /// + /// 创建来自 + /// + /// + /// + public static Result FromSuccess(string msg) + { + return new Result(ResultCode.Success, msg); + } + + /// + /// ToString + /// + /// + public override string ToString() + { + return $"类型:{ResultCode},信息:{Message}"; + } + } + + /// + /// 结果返回 + /// + public class ResultBase : IResult + { + /// + /// 构造函数 + /// + /// + /// + public ResultBase(ResultCode resultCode, string message) + { + ResultCode = resultCode; + Message = message; + } + + /// + /// 构造函数 + /// + /// + public ResultBase(ResultCode resultCode) + { + ResultCode = resultCode; + Message = resultCode.GetDescription(); + } + + /// + /// 构造函数 + /// + /// + public ResultBase(Result result) + { + ResultCode = result.ResultCode; + Message = result.Message; + } + + /// + /// 构造函数 + /// + public ResultBase() + { + } + + /// + /// + /// + public ResultCode ResultCode { get; protected set; } + + /// + /// + /// + public string Message { get; protected set; } + + /// + /// ToString + /// + /// + public override string ToString() + { + return $"类型:{ResultCode},信息:{Message}"; + } + } + + /// + /// ResultExtensions + /// + public static class ResultExtensions + { + /// + /// 是否成功。 + /// + /// + /// + public static bool IsSuccess(this IResult result) + { + return result.ResultCode == ResultCode.Success; + } + + /// + /// 是否没有成功。 + /// + /// + /// + public static bool NotSuccess(this IResult result) + { + return result.ResultCode != ResultCode.Success; + } + + /// + /// 转换为 + /// + /// + /// + public static Result ToResult(this IResult result) + { + return new Result(result); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/SnowflakeIDGenerator.cs b/src/TouchSocket/Core/Common/SnowflakeIDGenerator.cs new file mode 100644 index 000000000..970028d85 --- /dev/null +++ b/src/TouchSocket/Core/Common/SnowflakeIDGenerator.cs @@ -0,0 +1,129 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 雪花ID生成器(该代码来自网络) + /// + public class SnowflakeIDGenerator + { + private const int SequenceBits = 10; + + /// + /// 一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成 + /// + private const long SequenceMask = -1L ^ -1L << SequenceBits; + + private const int TimestampLeftShift = SequenceBits + WorkerIdBits; + + private const int WorkerIdBits = 4; + + //计数器字节数,10个字节用来保存计数码 + private const int WorkerIdShift = SequenceBits; + + private static long Sequence = 0L; + + //机器ID + private static long WorkerId; + + private readonly long Twepoch = 687888001020L; + + private long m_lastTimestamp = -1L; + + static SnowflakeIDGenerator() + { + } + + //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成 + /// + /// 机器码 + /// + /// + public SnowflakeIDGenerator(long workerId) + { + if (workerId > MaxWorkerId || workerId < 0) + throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0 ", MaxWorkerId)); + SnowflakeIDGenerator.WorkerId = workerId; + Twepoch = DateTime.Now.Ticks - 10000; + } + + /// + /// 最大机器ID + /// + public static long MaxWorkerId { get; private set; } = -1L ^ (-1L << WorkerIdBits); //最大机器ID + + //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳 + //机器码字节数。4个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义) + + //机器码数据左移位数,就是后面计数器占用的位数 + //时间戳左移动位数就是机器码和计数器总字节数 + /// + /// 获取ID + /// + /// + public long NextID() + { + lock (this) + { + long timestamp = timeGen(); + if (m_lastTimestamp == timestamp) + { //同一微妙中生成ID + Sequence = (Sequence + 1) & SequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限 + if (Sequence == 0) + { + //一微妙内产生的ID计数已达上限,等待下一微妙 + timestamp = tillNextMillis(m_lastTimestamp); + } + } + else + { //不同微秒生成ID + Sequence = 0; //计数清0 + } + if (timestamp < m_lastTimestamp) + { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过 + throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", + m_lastTimestamp - timestamp)); + } + m_lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳 + long nextId = (timestamp - Twepoch << TimestampLeftShift) | WorkerId << WorkerIdShift | Sequence; + return nextId; + } + } + + /// + /// 获取下一微秒时间戳 + /// + /// + /// + private long tillNextMillis(long lastTimestamp) + { + long timestamp = timeGen(); + while (timestamp <= lastTimestamp) + { + timestamp = timeGen(); + } + return timestamp; + } + + /// + /// 生成当前时间戳 + /// + /// + private long timeGen() + { + return Environment.TickCount; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/StringResStore.cs b/src/TouchSocket/Core/Common/StringResStore.cs new file mode 100644 index 000000000..e38ae6998 --- /dev/null +++ b/src/TouchSocket/Core/Common/StringResStore.cs @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.ComponentModel; + +namespace TouchSocket.Core +{ + /// + /// 字符串资源字典 + /// + public static class StringResStore + { + private static readonly ConcurrentDictionary m_cache = new ConcurrentDictionary(); + + /// + /// 获取资源字符 + /// + /// + /// + /// + public static string GetDescription(this Enum @enum, params object[] objs) + { + if (m_cache.TryGetValue(@enum, out string str)) + { + if (string.IsNullOrEmpty(str)) + { + return @enum.ToString(); + } + else + { + return str.Format(objs); + } + } + + if (@enum.GetAttribute() is DescriptionAttribute description) + { + string res = description.Description; + m_cache.TryAdd(@enum, res); + if (!string.IsNullOrEmpty(res)) + { + if (objs.Length > 0) + { + return res.Format(objs); + } + else + { + return res; + } + } + } + return @enum.ToString(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/ThrowHelper.cs b/src/TouchSocket/Core/Common/ThrowHelper.cs new file mode 100644 index 000000000..030e783c2 --- /dev/null +++ b/src/TouchSocket/Core/Common/ThrowHelper.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//using System; +//using System.Collections.Concurrent; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Threading.Tasks; + +//namespace TouchSocket.Core +//{ +// /// +// /// 异常助手 +// /// +// public static class ThrowHelper +// { +// private static readonly ConcurrentDictionary> m_pairs = +// new ConcurrentDictionary>(); + +// /// +// /// 添加抛出规则。 +// /// +// /// +// /// +// public static void Add(Enum @enum,Func func) +// { +// if (@enum is null) +// { +// throw new ArgumentNullException(nameof(@enum)); +// } + +// if (func is null) +// { +// throw new ArgumentNullException(nameof(func)); +// } + +// m_pairs.TryRemove(@enum,out _); +// m_pairs.TryAdd(@enum,func); +// } + +// public static Exception Throw(Enum @enum,string msg,Exception exception) +// { +// } + +// } +//} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/TouchSocketBitConverter.cs b/src/TouchSocket/Core/Common/TouchSocketBitConverter.cs new file mode 100644 index 000000000..7814449ea --- /dev/null +++ b/src/TouchSocket/Core/Common/TouchSocketBitConverter.cs @@ -0,0 +1,498 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Runtime.CompilerServices; + +namespace TouchSocket.Core +{ + /// + /// 将基数据类型转换为指定端的一个字节数组, + /// 或将一个字节数组转换为指定端基数据类型。 + /// + public class TouchSocketBitConverter + { + /// + /// 以大端 + /// + public static TouchSocketBitConverter BigEndian; + + /// + /// 以小端 + /// + public static TouchSocketBitConverter LittleEndian; + + static TouchSocketBitConverter() + { + BigEndian = new TouchSocketBitConverter(EndianType.Big); + LittleEndian = new TouchSocketBitConverter(EndianType.Little); + DefaultEndianType = EndianType.Little; + } + + private static TouchSocketBitConverter m_default; + + /// + /// 以默认小端,可通过重新指定默认端。 + /// + public static TouchSocketBitConverter Default => m_default; + + private static EndianType m_defaultEndianType; + + /// + /// 默认大小端切换。 + /// + public static EndianType DefaultEndianType + { + get => m_defaultEndianType; + set + { + m_defaultEndianType = value; + switch (value) + { + case EndianType.Little: + m_default = LittleEndian; + break; + + case EndianType.Big: + m_default = BigEndian; + break; + + default: + break; + } + } + } + + private readonly EndianType endianType; + + /// + /// 构造函数 + /// + /// + public TouchSocketBitConverter(EndianType endianType) + { + this.endianType = endianType; + } + + /// + /// 指定大小端。 + /// + public EndianType EndianType => endianType; + + /// + /// 判断当前系统是否为设置的大小端 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsSameOfSet() + { + return !(BitConverter.IsLittleEndian ^ (endianType == EndianType.Little)); + //return true; + } + + #region ushort + + /// + /// 转换为指定端2字节 + /// + /// + /// + public byte[] GetBytes(ushort value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + return bytes; + } + + /// + /// 转换为指定端模式的2字节转换为UInt16数据。 + /// + /// + /// + /// + public ushort ToUInt16(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToUInt16(buffer, offset); + } + else + { + byte[] bytes = new byte[2]; + Array.Copy(buffer, offset, bytes, 0, 2); + Array.Reverse(bytes); + return BitConverter.ToUInt16(bytes, 0); + } + } + + #endregion ushort + + #region ulong + + /// + /// 转换为指定端8字节 + /// + /// + /// + public byte[] GetBytes(ulong value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的Ulong数据。 + /// + /// + /// + /// + public ulong ToUInt64(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToUInt64(buffer, offset); + } + else + { + byte[] bytes = new byte[8]; + Array.Copy(buffer, offset, bytes, 0, 8); + Array.Reverse(bytes); + return BitConverter.ToUInt64(bytes,0); + } + + } + + #endregion ulong + + #region bool + + /// + /// 转换为指定端1字节 + /// + /// + /// + public byte[] GetBytes(bool value) + { + return BitConverter.GetBytes(value); + } + + /// + /// 转换为指定端模式的bool数据。 + /// + /// + /// + /// + public bool ToBoolean(byte[] buffer, int offset) + { + return BitConverter.ToBoolean(buffer, offset); + } + + #endregion bool + + #region char + + /// + /// 转换为指定端2字节 + /// + /// + /// + public byte[] GetBytes(char value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的Char数据。 + /// + /// + /// + /// + public char ToChar(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToChar(buffer, offset); + } + else + { + byte[] bytes = new byte[2]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToChar(bytes, 0); + } + } + + #endregion char + + #region short + + /// + /// 转换为指定端2字节 + /// + /// + /// + public byte[] GetBytes(short value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的Short数据。 + /// + /// + /// + /// + public short ToInt16(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToInt16(buffer, offset); + } + else + { + byte[] bytes = new byte[2]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToInt16(bytes, 0); + } + + } + + #endregion short + + #region int + + /// + /// 转换为指定端4字节 + /// + /// + /// + public byte[] GetBytes(int value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的int数据。 + /// + /// + /// + /// + public int ToInt32(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToInt32(buffer, offset); + } + else + { + byte[] bytes = new byte[4]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToInt32(bytes, 0); + } + } + + #endregion int + + #region long + + /// + /// 转换为指定端8字节 + /// + /// + /// + public byte[] GetBytes(long value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的long数据。 + /// + /// + /// + /// + public long ToInt64(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToInt64(buffer, offset); + } + else + { + byte[] bytes = new byte[8]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToInt64(bytes, 0); + } + + } + + #endregion long + + #region uint + + /// + /// 转换为指定端4字节 + /// + /// + /// + public byte[] GetBytes(uint value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的Uint数据。 + /// + /// + /// + /// + public uint ToUInt32(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToUInt32(buffer, offset); + } + else + { + byte[] bytes = new byte[4]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToUInt32(bytes, 0); + } + } + + #endregion uint + + #region float + + /// + /// 转换为指定端4字节 + /// + /// + /// + public byte[] GetBytes(float value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的float数据。 + /// + /// + /// + /// + public float ToSingle(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToSingle(buffer, offset); + } + else + { + byte[] bytes = new byte[4]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToSingle(bytes, 0); + } + } + + #endregion float + + #region long + + /// + /// 转换为指定端8字节 + /// + /// + /// + public byte[] GetBytes(double value) + { + byte[] bytes = BitConverter.GetBytes(value); + if (!IsSameOfSet()) + { + Array.Reverse(bytes); + } + + return bytes; + } + + /// + /// 转换为指定端模式的double数据。 + /// + /// + /// + /// + public double ToDouble(byte[] buffer, int offset) + { + if (IsSameOfSet()) + { + return BitConverter.ToDouble(buffer, offset); + } + else + { + byte[] bytes = new byte[8]; + Array.Copy(buffer, offset, bytes, 0, bytes.Length); + Array.Reverse(bytes); + return BitConverter.ToDouble(bytes, 0); + } + } + + #endregion long + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Common/TouchSocketCoreUtility.cs b/src/TouchSocket/Core/Common/TouchSocketCoreUtility.cs new file mode 100644 index 000000000..c5a7dcf51 --- /dev/null +++ b/src/TouchSocket/Core/Common/TouchSocketCoreUtility.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; + +namespace TouchSocket.Core +{ + /// + /// 常量 + /// + public class TouchSocketCoreUtility + { +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 + public static readonly Type stringType = typeof(string); + public static readonly Type byteType = typeof(byte); + public static readonly Type sbyteType = typeof(sbyte); + public static readonly Type shortType = typeof(short); + public static readonly Type objType = typeof(object); + public static readonly Type ushortType = typeof(ushort); + public static readonly Type intType = typeof(int); + public static readonly Type uintType = typeof(uint); + public static readonly Type boolType = typeof(bool); + public static readonly Type charType = typeof(char); + public static readonly Type longType = typeof(long); + public static readonly Type ulongType = typeof(ulong); + public static readonly Type floatType = typeof(float); + public static readonly Type doubleType = typeof(double); + public static readonly Type decimalType = typeof(decimal); + public static readonly Type dateTimeType = typeof(DateTime); + public static readonly Type bytesType = typeof(byte[]); + public static readonly Type dicType = typeof(IDictionary); + public static readonly Type iEnumerableType = typeof(IEnumerable); + public static readonly Type arrayType = typeof(Array); + public static readonly Type listType = typeof(IList); + public static readonly Type nullableType = typeof(Nullable<>); + + public static readonly byte[] ZeroBytes = new byte[0]; +#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Config/TouchSocketConfig.cs b/src/TouchSocket/Core/Config/TouchSocketConfig.cs new file mode 100644 index 000000000..1653c76f6 --- /dev/null +++ b/src/TouchSocket/Core/Config/TouchSocketConfig.cs @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 配置文件基类 + /// + public class TouchSocketConfig : DependencyObject + { + //private bool built; + private IContainer m_container; + + private IPluginsManager m_pluginsManager; + + //ConcurrentQueue> actions = new ConcurrentQueue>(); + + ///// + ///// 添加构建委托,该委托会在时调用。 + ///// + ///// + ///// + //public void AddBuildAction(Delegate action,params object[] ps) + //{ + // actions.Enqueue(Tuple.Create(action,ps)) ; + //} + + ///// + ///// 构建配置 + ///// + //public void Build() + //{ + // if (!built) + // { + // built = true; + // while (actions.TryDequeue(out var action)) + // { + // action.Item1.DynamicInvoke(action.Item2); + // } + // } + //} + + /// + /// 构造函数 + /// + public TouchSocketConfig() + { + SetContainer(new Container()); + } + + /// + /// IOC容器。 + /// + public IContainer Container => m_container; + + /// + /// 使用插件 + /// + public bool IsUsePlugin { get; set; } + + /// + /// 插件管理器 + /// + public IPluginsManager PluginsManager => m_pluginsManager; + + /// + /// 设置注入容器。 + /// + /// + /// + public TouchSocketConfig SetContainer(IContainer value) + { + m_container = value; + if (!value.IsRegistered(typeof(ILog))) + { + m_container.RegisterSingleton(); + } + SetPluginsManager(new PluginsManager(m_container)); + return this; + } + + /// + /// 设置PluginsManager + /// + /// + /// + public TouchSocketConfig SetPluginsManager(IPluginsManager value) + { + m_pluginsManager = value; + m_container.RegisterSingleton(value); + return this; + } + + /// + /// 启用插件 + /// + /// + public TouchSocketConfig UsePlugin() + { + IsUsePlugin = true; + return this; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs b/src/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs new file mode 100644 index 000000000..2c625bb0f --- /dev/null +++ b/src/TouchSocket/Core/Config/TouchSocketCoreConfigExtension.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// TouchSocketCoreConfigExtension + /// + public static class TouchSocketCoreConfigExtension + { + #region 插件 + + /// + /// 配置插件。 + /// + /// + /// + /// + public static TouchSocketConfig ConfigurePlugins(this TouchSocketConfig config, Action action) + { + action?.Invoke(config.PluginsManager); + return config; + } + + #endregion 插件 + + #region 容器 + + /// + /// 配置容器注入。 + /// + /// + /// + /// + public static TouchSocketConfig ConfigureContainer(this TouchSocketConfig config, Action action) + { + action?.Invoke(config.Container); + return config; + } + + #endregion 容器 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Converter/BytesConverter.cs b/src/TouchSocket/Core/Converter/BytesConverter.cs new file mode 100644 index 000000000..815e7d5ee --- /dev/null +++ b/src/TouchSocket/Core/Converter/BytesConverter.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// 字节类转换器 + /// + public class BytesConverter : TouchSocketConverter + { + /// + /// 字节类转换器 + /// + public BytesConverter() + { + Add(new JsonBytesToClassConverter()); + } + } + + /// + /// Json字节转到对应类 + /// + public class JsonBytesToClassConverter : IConverter + { + /// + /// + /// + public int Order { get; set; } + + /// + /// + /// + /// + /// + /// + /// + public bool TryConvertFrom(byte[] source, Type targetType, out object target) + { + try + { + target = SerializeConvert.JsonDeserializeFromBytes(source, targetType); + return true; + } + catch + { + target = default; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public bool TryConvertTo(object target, out byte[] source) + { + try + { + source = SerializeConvert.JsonSerializeToBytes(target); + return true; + } + catch (Exception) + { + source = null; + return false; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Converter/IConverter.cs b/src/TouchSocket/Core/Converter/IConverter.cs new file mode 100644 index 000000000..82f2c5efd --- /dev/null +++ b/src/TouchSocket/Core/Converter/IConverter.cs @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 转换器接口 + /// + public interface IConverter + { + /// + /// 转换器执行顺序 + /// 该属性值越小,越靠前执行。值相等时,按添加先后顺序 + /// 该属性效果,仅在之前设置有效。 + /// + int Order { get; set; } + + /// + /// 尝试将源数据转换目标类型对象 + /// + /// + /// + /// + /// + bool TryConvertFrom(TSource source, Type targetType, out object target); + + /// + /// 尝试将目标类型对象转换源数据 + /// + /// + /// + /// + bool TryConvertTo(object target, out TSource source); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Converter/StringConverter.cs b/src/TouchSocket/Core/Converter/StringConverter.cs new file mode 100644 index 000000000..e1efe5cf2 --- /dev/null +++ b/src/TouchSocket/Core/Converter/StringConverter.cs @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// String类型数据转换器 + /// + public class StringConverter : TouchSocketConverter + { + /// + /// 构造函数 + /// + public StringConverter() + { + Add(new StringToPrimitiveConverter()); + Add(new JsonStringToClassConverter()); + } + } + + /// + /// String值转换为基础类型。 + /// + public class StringToPrimitiveConverter : IConverter + { + /// + /// + /// + public int Order { get; set; } + + /// + /// + /// + /// + /// + /// + /// + public bool TryConvertFrom(string source, Type targetType, out object target) + { + if (targetType.IsPrimitive || targetType == TouchSocketCoreUtility.stringType) + { + return StringExtension.TryParseToType(source, targetType, out target); + } + target = default; + return false; + } + + /// + /// + /// + /// + /// + /// + public bool TryConvertTo(object target, out string source) + { + if (target != null) + { + Type type = target.GetType(); + if (type.IsPrimitive || type == TouchSocketCoreUtility.stringType) + { + source = target.ToString(); + return true; + } + } + + source = null; + return false; + } + } + + /// + /// Json字符串转到对应类 + /// + public class JsonStringToClassConverter : IConverter + { + /// + /// + /// + public int Order { get; set; } + + /// + /// + /// + /// + /// + /// + /// + public bool TryConvertFrom(string source, Type targetType, out object target) + { + try + { + target = source.FromJson(targetType); + return true; + } + catch + { + target = default; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public bool TryConvertTo(object target, out string source) + { + try + { + source = target.ToJson(); + return true; + } + catch (Exception) + { + source = null; + return false; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Converter/TouchSocketConverter.cs b/src/TouchSocket/Core/Converter/TouchSocketConverter.cs new file mode 100644 index 000000000..042925082 --- /dev/null +++ b/src/TouchSocket/Core/Converter/TouchSocketConverter.cs @@ -0,0 +1,129 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// 转换器 + /// + public class TouchSocketConverter + { + private readonly List> m_converters = new List>(); + + /// + /// 添加插件 + /// + /// 插件 + /// + public void Add(IConverter converter) + { + if (converter == null) + { + throw new ArgumentNullException(); + } + foreach (var item in m_converters) + { + if (item.GetType() == converter.GetType()) + { + return; + } + } + + m_converters.Add(converter); + + m_converters.Sort(delegate (IConverter x, IConverter y) + { + if (x.Order == y.Order) return 0; + else if (x.Order > y.Order) return 1; + else return -1; + }); + } + + /// + /// 清除所有转化器 + /// + public void Clear() + { + m_converters.Clear(); + } + + /// + /// 将源数据转换目标类型对象 + /// + /// + /// + /// + public object ConvertFrom(TSource source, Type targetType) + { + object result; + foreach (var item in m_converters) + { + if (item.TryConvertFrom(source, targetType, out result)) + { + return result; + } + } + + throw new Exception($"{source}无法转换为{targetType}类型。"); + } + + /// + /// 将目标类型对象转换源数据 + /// + /// + /// + public TSource ConvertTo(object target) + { + foreach (var item in m_converters) + { + if (item.TryConvertTo(target, out TSource source)) + { + return source; + } + } + + throw new Exception($"{target}无法转换为{typeof(TSource)}类型。"); + } + + /// + /// 移除插件 + /// + /// + public void Remove(IConverter converter) + { + if (converter == null) + { + throw new ArgumentNullException(); + } + m_converters.Remove(converter); + } + + /// + /// 移除插件 + /// + /// + public void Remove(Type type) + { + for (int i = m_converters.Count - 1; i >= 0; i--) + { + IConverter plugin = m_converters[i]; + if (plugin.GetType() == type) + { + m_converters.RemoveAt(i); + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs b/src/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs new file mode 100644 index 000000000..95502823d --- /dev/null +++ b/src/TouchSocket/Core/Data/Compress/GZipDataCompressor.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// GZip压缩算法的压缩机 + /// + public sealed class GZipDataCompressor : IDataCompressor + { + byte[] IDataCompressor.Compress(ArraySegment data) + { + return GZip.Compress(data.Array, data.Offset, data.Count); + } + + byte[] IDataCompressor.Decompress(ArraySegment data) + { + return GZip.Decompress(data.Array, data.Offset, data.Count); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Data/Compress/IDataCompressor.cs b/src/TouchSocket/Core/Data/Compress/IDataCompressor.cs new file mode 100644 index 000000000..16de22f8c --- /dev/null +++ b/src/TouchSocket/Core/Data/Compress/IDataCompressor.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 数据压缩机接口 + /// + public interface IDataCompressor + { + /// + /// 压缩数据 + /// + /// + /// + byte[] Compress(ArraySegment data); + + /// + /// 解压数据 + /// + /// + /// + byte[] Decompress(ArraySegment data); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Data/Crc.cs b/src/TouchSocket/Core/Data/Crc.cs new file mode 100644 index 000000000..7f18dc8d8 --- /dev/null +++ b/src/TouchSocket/Core/Data/Crc.cs @@ -0,0 +1,783 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// Crc相关。 + /// 该代码来源于网络 + /// + public static class Crc + { + /// ********************************************************************** + /// Name: CRC-4/ITU x4+x+1 + /// Poly: 0x03 + /// Init: 0x00 + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc1(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x0C);//0x0C = (reverse 0x03)>>(8-4) + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-5/EPC x5+x3+1 + /// Poly: 0x09 + /// Init: 0x09 + /// Refin: false + /// Refout: false + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc2(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0x48;// Initial value: 0x48 = 0x09<<(8-5) + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80) > 0) + crc = (byte)((crc << 1) ^ 0x48);// 0x48 = 0x09<<(8-5) + else + crc = (byte)(crc << 1); + } + } + return new byte[] { (byte)(crc >> 3) }; + } + + /// ********************************************************************** + /// Name: CRC-5/ITU x5+x4+x2+1 + /// Poly: 0x15 + /// Init: 0x00 + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc3(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x15);// 0x15 = (reverse 0x15)>>(8-5) + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-5/USB x5+x2+1 + /// Poly: 0x05 + /// Init: 0x1F + /// Refin: true + /// Refout: true + /// Xorout: 0x1F + ///************************************************************************* + public static byte[] Crc4(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0x1F;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x14);// 0x14 = (reverse 0x05)>>(8-5) + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { (byte)(crc ^ 0x1F) }; + } + + /// ********************************************************************** + /// Name: CRC-6/ITU x6+x+1 + /// Poly: 0x03 + /// Init: 0x00 + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc5(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x30);// 0x30 = (reverse 0x03)>>(8-6) + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-7/MMC x7+x3+1 + /// Poly: 0x09 + /// Init: 0x00 + /// Refin: false + /// Refout: false + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc6(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80) > 0) + crc = (byte)((crc << 1) ^ 0x12);// 0x12 = 0x09<<(8-7) + else + crc = (byte)(crc << 1); + } + } + return new byte[] { (byte)(crc >> 1) }; + } + + /// ********************************************************************** + /// Name: CRC8 x8+x2+x+1 + /// Poly: 0x07 + /// Init: 0x00 + /// Refin: false + /// Refout: false + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc7(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80) > 0) + crc = (byte)((crc << 1) ^ 0x07); + else + crc = (byte)(crc << 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-8/ITU x8+x2+x+1 + /// Poly: 0x07 + /// Init: 0x00 + /// Refin: false + /// Refout: false + /// Xorout: 0x55 + ///************************************************************************* + public static byte[] Crc8(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80) > 0) + crc = (byte)((crc << 1) ^ 0x07); + else + crc = (byte)(crc << 1); + } + } + return new byte[] { (byte)(crc ^ 0x55) }; + } + + /// ********************************************************************** + /// Name: CRC-8/MAXIM x8+x5+x4+1 + /// Poly: 0x31 + /// Init: 0x00 + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc9(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0x8C);// 0x8C = reverse 0x31 + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-8/ROHC x8+x2+x+1 + /// Poly: 0x07 + /// Init: 0xFF + /// Refin: true + /// Refout: true + /// Xorout: 0x00 + ///************************************************************************* + public static byte[] Crc10(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + byte crc = 0xFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (byte)((crc >> 1) ^ 0xE0);// 0xE0 = reverse 0x07 + else + crc = (byte)(crc >> 1); + } + } + return new byte[] { crc }; + } + + /// Z1协议校验码计算 + private static readonly byte[] table = { 0x00, 0x1C, 0x38, 0x24, 0x70, 0x6C, 0x48, 0x54, 0xE0, 0xFC, + 0xD8, 0xC4, 0x90, 0x8C, 0xA8, 0xB4, 0xDC, 0xC0, 0xE4, 0xF8, + 0xAC, 0xB0, 0x94, 0x88, 0x3C, 0x20, 0x04, 0x18, 0x4C, 0x50, + 0x74, 0x68, 0xA4, 0xB8, 0x9C, 0x80, 0xD4, 0xC8, 0xEC, 0xF0, + 0x44, 0x58, 0x7C, 0x60, 0x34, 0x28, 0x0C, 0x10, 0x78, 0x64, + 0x40, 0x5C, 0x08, 0x14, 0x30, 0x2C, 0x98, 0x84, 0xA0, 0xBC, + 0xE8, 0xF4, 0xD0, 0xCC, 0x54, 0x48, 0x6C, 0x70, 0x24, 0x38, + 0x1C, 0x00, 0xB4, 0xA8, 0x8C, 0x90, 0xC4, 0xD8, 0xFC, 0xE0, + 0x88, 0x94, 0xB0, 0xAC, 0xF8, 0xE4, 0xC0, 0xDC, 0x68, 0x74, + 0x50, 0x4C, 0x18, 0x04, 0x20, 0x3C, 0xF0, 0xEC, 0xC8, 0xD4, + 0x80, 0x9C, 0xB8, 0xA4, 0x10, 0x0C, 0x28, 0x34, 0x60, 0x7C, + 0x58, 0x44, 0x2C, 0x30, 0x14, 0x08, 0x5C, 0x40, 0x64, 0x78, + 0xCC, 0xD0, 0xF4, 0xE8, 0xBC, 0xA0, 0x84, 0x98, 0xA8, 0xB4, + 0x90, 0x8C, 0xD8, 0xC4, 0xE0, 0xFC, 0x48, 0x54, 0x70, 0x6C, + 0x38, 0x24, 0x00, 0x1C, 0x74, 0x68, 0x4C, 0x50, 0x04, 0x18, + 0x3C, 0x20, 0x94, 0x88, 0xAC, 0xB0, 0xE4, 0xF8, 0xDC, 0xC0, + 0x0C, 0x10, 0x34, 0x28, 0x7C, 0x60, 0x44, 0x58, 0xEC, 0xF0, + 0xD4, 0xC8, 0x9C, 0x80, 0xA4, 0xB8, 0xD0, 0xCC, 0xE8, 0xF4, + 0xA0, 0xBC, 0x98, 0x84, 0x30, 0x2C, 0x08, 0x14, 0x40, 0x5C, + 0x78, 0x64, 0xFC, 0xE0, 0xC4, 0xD8, 0x8C, 0x90, 0xB4, 0xA8, + 0x1C, 0x00, 0x24, 0x38, 0x6C, 0x70, 0x54, 0x48, 0x20, 0x3C, + 0x18, 0x04, 0x50, 0x4C, 0x68, 0x74, 0xC0, 0xDC, 0xF8, 0xE4, + 0xB0, 0xAC, 0x88, 0x94, 0x58, 0x44, 0x60, 0x7C, 0x28, 0x34, + 0x10, 0x0C, 0xB8, 0xA4, 0x80, 0x9C, 0xC8, 0xD4, 0xF0, 0xEC, + 0x84, 0x98, 0xBC, 0xA0, 0xF4, 0xE8, 0xCC, 0xD0, 0x64, 0x78, + 0x5C, 0x40, 0x14, 0x08, 0x2C, 0x30 + }; + + /// + /// Crc11 + /// + /// + /// + /// + /// + public static byte[] Crc11(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + int i; + byte crc = 0x00; + int tableIndex; + for (i = start; i < length; i++) + { + tableIndex = crc ^ (buffer[i] & 0xFF); + crc = table[tableIndex]; + } + return new byte[] { crc }; + } + + /// ********************************************************************** + /// Name: CRC-12 x16+x12+x5+1 + /// Poly: 0x80 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc12(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + short iQ = 0, iR = 0; + for (int i = start; i < length; i++) + { + // 多项式除法 + // 如果该位为1 + if ((buffer[i] & (0x80 >> iR)) > 0) + { + // 则在余数尾部添1否则添0 + crc |= 0x01; + } + // 如果12位除数中的最高位为1,则够除 + if (crc >= 0x1000) + { + crc ^= 0x180D; + } + crc <<= 1; + iR++; + if (8 == iR) + { + iR = 0; + iQ++; + } + } + // 对后面添加的12个0做处理 + for (int i = 0; i < 12; i++) + { + if (crc >= 0x1000) + { + crc ^= 0x180D; + } + crc <<= 1; + } + crc >>= 1; + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/CCITT x16+x12+x5+1 + /// Poly: 0x1021 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc13(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0x8408);// 0x8408 = reverse 0x1021 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/CCITT FALSE x16+x12+x5+1 + /// Poly: 0x1021 + /// Init: 0xFFFF + /// Refin: false + /// Refout: false + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc14(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= (ushort)(buffer[i] << 8); + for (int j = 0; j < 8; j++) + { + if ((crc & 0x8000) > 0) + crc = (ushort)((crc << 1) ^ 0x1021); + else + crc = (ushort)(crc << 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/DNP x16+x13+x12+x11+x10+x8+x6+x5+x2+1 + /// Poly: 0x3D65 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFF + ///************************************************************************* + public static byte[] Crc15(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA6BC);// 0xA6BC = reverse 0x3D65 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes((ushort)~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/IBM x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc16(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/MAXIM x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0x0000 + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFF + ///************************************************************************* + public static byte[] Crc17(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes((ushort)~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/MODBUS x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0xFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc18(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/USB x16+x15+x2+1 + /// Poly: 0x8005 + /// Init: 0xFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFF + ///************************************************************************* + public static byte[] Crc19(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes((ushort)~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/X25 x16+x12+x5+1 + /// Poly: 0x1021 + /// Init: 0xFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFF + ///************************************************************************* + public static byte[] Crc20(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0xFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (ushort)((crc >> 1) ^ 0x8408);// 0x8408 = reverse 0x1021 + else + crc = (ushort)(crc >> 1); + } + } + byte[] ret = BitConverter.GetBytes((ushort)~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC-16/XMODEM x16+x12+x5+1 + /// Poly: 0x1021 + /// Init: 0x0000 + /// Refin: false + /// Refout: false + /// Xorout: 0x0000 + ///************************************************************************* + public static byte[] Crc21(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + ushort crc = 0;// Initial value + for (int i = start; i < length; i++) + { + crc ^= (ushort)(buffer[i] << 8); + for (int j = 0; j < 8; j++) + { + if ((crc & 0x8000) > 0) + crc = (ushort)((crc << 1) ^ 0x1021); + else + crc = (ushort)(crc << 1); + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 + /// Poly: 0x04C11DB7 + /// Init: 0xFFFFFFFF + /// Refin: true + /// Refout: true + /// Xorout: 0xFFFFFFFF + ///************************************************************************* + public static byte[] Crc22(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + uint crc = 0xFFFFFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= buffer[i]; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) > 0) + crc = (crc >> 1) ^ 0xEDB88320;// 0xEDB88320= reverse 0x04C11DB7 + else + crc = crc >> 1; + } + } + byte[] ret = BitConverter.GetBytes(~crc); + Array.Reverse(ret); + return ret; + } + + /// ********************************************************************** + /// Name: CRC32/MPEG-2 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 + /// Poly: 0x04C11DB7 + /// Init: 0xFFFFFFFF + /// Refin: false + /// Refout: false + /// Xorout: 0x00000000 + ///************************************************************************* + public static byte[] Crc23(byte[] buffer, int start = 0, int len = 0) + { + if (buffer == null || buffer.Length == 0) return null; + if (start < 0) return null; + if (len == 0) len = buffer.Length - start; + int length = start + len; + if (length > buffer.Length) return null; + uint crc = 0xFFFFFFFF;// Initial value + for (int i = start; i < length; i++) + { + crc ^= (uint)(buffer[i] << 24); + for (int j = 0; j < 8; j++) + { + if ((crc & 0x80000000) > 0) + crc = (crc << 1) ^ 0x04C11DB7; + else + crc = crc << 1; + } + } + byte[] ret = BitConverter.GetBytes(crc); + Array.Reverse(ret); + return ret; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Data/GZip.cs b/src/TouchSocket/Core/Data/GZip.cs new file mode 100644 index 000000000..f9a34c584 --- /dev/null +++ b/src/TouchSocket/Core/Data/GZip.cs @@ -0,0 +1,142 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; +using System.IO.Compression; + +namespace TouchSocket.Core +{ + /// + /// Gzip操作类 + /// + public static class GZip + { + /// + /// 压缩数据 + /// + /// + /// + /// + /// + /// + public static void Compress(ByteBlock byteBlock, byte[] buffer, int offset, int length) + { + using (GZipStream gZipStream = new GZipStream(byteBlock, CompressionMode.Compress, true)) + { + gZipStream.Write(buffer, offset, length); + gZipStream.Close(); + } + } + + /// + /// 压缩数据 + /// + /// + /// + /// + public static void Compress(ByteBlock byteBlock, byte[] buffer) + { + Compress(byteBlock, buffer, 0, buffer.Length); + } + + /// + /// 压缩数据 + /// + /// + /// + /// + /// + public static byte[] Compress(byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length)) + { + Compress(byteBlock, buffer, offset, length); + return byteBlock.ToArray(); + } + } + + /// + /// 压缩数据 + /// + /// + /// + public static byte[] Compress(byte[] buffer) + { + return Compress(buffer, 0, buffer.Length); + } + + /// + /// 解压数据 + /// + /// + /// + /// + /// + /// + public static void Decompress(ByteBlock byteBlock, byte[] data, int offset, int length) + { + using (GZipStream gZipStream = new GZipStream(new MemoryStream(data, offset, length), CompressionMode.Decompress)) + { + byte[] bytes = BytePool.Default.GetByteCore(1024 * 64); + try + { + int r; + while ((r = gZipStream.Read(bytes, 0, bytes.Length)) != 0) + { + byteBlock.Write(bytes, 0, r); + } + gZipStream.Close(); + } + finally + { + BytePool.Default.Recycle(bytes); + } + } + } + + /// + /// 解压数据 + /// + /// + /// + public static void Decompress(ByteBlock byteBlock, byte[] data) + { + Decompress(byteBlock, data, 0, data.Length); + } + + /// + /// 解压数据 + /// + /// + /// + /// + /// + public static byte[] Decompress(byte[] data, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length)) + { + Decompress(byteBlock, data, offset, length); + return byteBlock.ToArray(); + } + } + + /// + /// 解压数据 + /// + /// + /// + public static byte[] Decompress(byte[] data) + { + return Decompress(data, 0, data.Length); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Data/MD5.cs b/src/TouchSocket/Core/Data/MD5.cs new file mode 100644 index 000000000..c5e7f4f9d --- /dev/null +++ b/src/TouchSocket/Core/Data/MD5.cs @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// MD5相关操作类 + /// + public static class MD5 + { + /// + /// 从字符串获取MD5值 + /// + /// + /// + public static string GetMD5Hash(string str) + { + StringBuilder sb = new StringBuilder(); + using (var md5 = System.Security.Cryptography.MD5.Create()) + { + byte[] data = md5.ComputeHash(Encoding.UTF8.GetBytes(str)); + int length = data.Length; + for (int i = 0; i < length; i++) + sb.Append(data[i].ToString("X2")); + } + return sb.ToString(); + } + + /// + /// 从字节获取MD5值 + /// + /// + /// + /// + /// + public static string GetMD5Hash(byte[] buffer, int offset, int length) + { + StringBuilder sb = new StringBuilder(); + using (var md5 = System.Security.Cryptography.MD5.Create()) + { + byte[] data = md5.ComputeHash(buffer, offset, length); + int count = data.Length; + for (int i = 0; i < count; i++) + sb.Append(data[i].ToString("X2")); + } + return sb.ToString(); + } + + /// + /// 从字节获取MD5值 + /// + /// + /// + public static string GetMD5Hash(byte[] buffer) + { + return GetMD5Hash(buffer, 0, buffer.Length); + } + + /// + /// 验证MD5值。 + /// + /// + /// + /// + public static bool VerifyMD5Hash(string str, string hash) + { + string hashOfInput = GetMD5Hash(str); + if (hashOfInput.CompareTo(hash) == 0) + return true; + else + return false; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Data/Security/DataSecurity.cs b/src/TouchSocket/Core/Data/Security/DataSecurity.cs new file mode 100644 index 000000000..c09011ae2 --- /dev/null +++ b/src/TouchSocket/Core/Data/Security/DataSecurity.cs @@ -0,0 +1,161 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// 数据安全加密 + /// + public static class DataSecurity + { + /// + /// 自定义加密密钥。 + /// + private static byte[] Keys { get; set; } = { 0x12, 0x34, 4, 0x78, 0x90, 255, 0xCD, 0xEF };//自定义密匙 + + /// + /// 使用3DES加密 + /// + /// 待加密字节 + /// 加密口令(长度为8) + /// + public static byte[] EncryptDES(byte[] data, string encryptKey) + { + if (encryptKey.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(encryptKey)); + } + if (encryptKey.Length < 8) + { + throw new Exception("密钥长度不足8位。"); + } + byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); + using (var des = DES.Create()) + { + using (MemoryStream mStream = new MemoryStream()) + { + using (CryptoStream cStream = new CryptoStream(mStream, des.CreateEncryptor(rgbKey, Keys), CryptoStreamMode.Write)) + { + cStream.Write(data, 0, data.Length); + cStream.FlushFinalBlock(); + return mStream.ToArray(); + } + } + } + } + + /// + /// 使用3DES解密 + /// + /// 待解密字节 + /// 解密口令(长度为8) + /// + public static byte[] DecryptDES(byte[] data, string encryptKey) + { + if (encryptKey.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(encryptKey)); + } + if (encryptKey.Length < 8) + { + throw new Exception("密钥长度不足8位。"); + } + byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey); + using (var des = DES.Create()) + { + using (MemoryStream mStream = new MemoryStream()) + { + using (CryptoStream cStream = new CryptoStream(mStream, des.CreateDecryptor(rgbKey, Keys), CryptoStreamMode.Write)) + { + cStream.Write(data, 0, data.Length); + cStream.FlushFinalBlock(); + return mStream.ToArray(); + } + } + } + } + + /// + /// 使用3DES流数据加密。 + /// 注意:数据会从开始 + /// + /// + /// + /// 加密口令(长度为8) + /// + public static void StreamEncryptDES(Stream inStream, Stream outStream, string encryptKey) + { + if (encryptKey.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(encryptKey)); + } + if (encryptKey.Length < 8) + { + throw new Exception("密钥长度不足8位。"); + } + byte[] rgbKeys = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); + byte[] byteIn = new byte[1024 * 64]; + long readLen = 0; + long totalLen = inStream.Length - inStream.Position; + using (var des = DES.Create()) + { + CryptoStream encStream = new CryptoStream(new WrapStream(outStream), des.CreateEncryptor(rgbKeys, Keys), CryptoStreamMode.Write); + while (readLen < totalLen) + { + int r = inStream.Read(byteIn, 0, byteIn.Length); + encStream.Write(byteIn, 0, r); + readLen += r; + } + encStream.Close(); + } + } + + /// + /// 使用3DES流数据解密 + /// 注意:数据会从开始 + /// + /// + /// + /// 解密口令(长度为8) + public static void StreamDecryptDES(Stream inStream, Stream outStream, string encryptKey) + { + if (encryptKey.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(encryptKey)); + } + if (encryptKey.Length < 8) + { + throw new Exception("密钥长度不足8位。"); + } + byte[] rgbKeys = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); + byte[] byteIn = new byte[1024 * 64]; + long readLen = 0; + long totalLen = inStream.Length - inStream.Position; + using (DES des = DES.Create()) + { + CryptoStream encStream = new CryptoStream(new WrapStream(outStream), des.CreateDecryptor(rgbKeys, Keys), CryptoStreamMode.Write); + while (readLen < totalLen) + { + int r = inStream.Read(byteIn, 0, byteIn.Length); + encStream.Write(byteIn, 0, r); + readLen = readLen + r; + } + encStream.Close(); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Data/Swap.cs b/src/TouchSocket/Core/Data/Swap.cs new file mode 100644 index 000000000..e9cc58374 --- /dev/null +++ b/src/TouchSocket/Core/Data/Swap.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 交换类。功能类似:a=1,b=2,交换后a=2,b=1。 + /// + public static class Swap + { + /// + /// 执行交换 + /// + /// + /// + /// + public static void Execute(ref T x, ref T y) + { +#if NET45_OR_GREATER + T temp = x; + x = y; + y = temp; +#else + (y, x) = (x, y); +#endif + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Data/XML/XmlTool.cs b/src/TouchSocket/Core/Data/XML/XmlTool.cs new file mode 100644 index 000000000..764fa650f --- /dev/null +++ b/src/TouchSocket/Core/Data/XML/XmlTool.cs @@ -0,0 +1,721 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; + +namespace TouchSocket.Core +{ + /// + /// xml主类 + /// + public class XmlTool + { + /// + /// 构造函数 + /// + /// 文件路径,包含文件名 + public XmlTool(string path) + { + this.path = path; + } + + private readonly string path = null; + + #region 存储 + + /// + /// 单节点,单属性储存 + /// + /// 节点名 + /// 属性名 + /// 属性值 + public void AttributeStorage(string NodeName, string Attribute_name, string Attribute_value) + { + if (File.Exists(path)) + {//存在Xml的文件 + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + bool N = false;//节点判断变量 + foreach (XmlNode item in nodeList) + {//判断是否存在该节点 + if (item.Name == NodeName) + { + N = true; + break; + } + } + if (N == false) + {//不存在节点,属性,建立节点,属性 + XmlElement PointName = xml.CreateElement(NodeName); + PointName.SetAttribute(Attribute_name, Attribute_value); + root.AppendChild(PointName); + } + else + {//存在属性进行赋值 + XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName); + PointName.Attributes[Attribute_name].Value = Attribute_value; + } + xml.Save(path); + } + else + { + XmlDocument xml = new XmlDocument(); + XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement root = xml.CreateElement("Root"); + xml.AppendChild(root);//根元素 + + XmlElement PointName = xml.CreateElement(NodeName); + PointName.SetAttribute(Attribute_name, Attribute_value); + root.AppendChild(PointName); + xml.Save(path); + } + } + + /// + /// 单节点,多属性存储 + /// + /// 节点名 + /// 属性集合 + /// 属性值集合 + public void AttributeStorage(string NodeName, string[] Attribute_name, string[] Attribute_value) + { + if (Attribute_name.Length != Attribute_value.Length) + { + Console.WriteLine("属性名数量和属性值数量不一致,无法储存"); + return; + } + if (File.Exists(path)) + {//存在Xml的文件 + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + bool N = false;//节点变量 + foreach (XmlNode item in nodeList) + {//判断是否存在该节点 + if (item.Name == NodeName) + { + N = true; + break; + } + } + if (N == false) + {//不存在节点,属性,建立节点,属性 + XmlElement PointName = xml.CreateElement(NodeName); + for (int i = 0; i < Attribute_name.Length; i++) + { + PointName.SetAttribute(Attribute_name[i], Attribute_value[i]); + root.AppendChild(PointName); + } + } + else + {//存在属性进行赋值 + XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName); + for (int i = 0; i < Attribute_name.Length; i++) + { + PointName.Attributes[Attribute_name[i]].Value = Attribute_value[i]; + } + } + xml.Save(path); + } + else + { + XmlDocument xml = new XmlDocument(); + XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement root = xml.CreateElement("Root"); + xml.AppendChild(root);//根元素 + + XmlElement PointName = xml.CreateElement(NodeName); + for (int i = 0; i < Attribute_name.Length; i++) + { + PointName.SetAttribute(Attribute_name[i], Attribute_value[i]); + root.AppendChild(PointName); + } + xml.Save(path); + } + } + + /// + /// 单节点,单属性多集合存储 + /// + /// 节点集合 + /// 属性名集合 + /// 属性值集合 + public void AttributeStorage(string[] NodeName, string[] Attribute_name, string[] Attribute_value) + { + if ((Attribute_name.Length != Attribute_value.Length) && NodeName.Length != Attribute_name.Length) + { + Console.WriteLine("属性名数量和属性值数量不一致,无法储存"); + return; + } + if (File.Exists(path)) + {//存在Xml的文件 + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + for (int i = 0; i < NodeName.Length; i++) + { + bool N = false;//节点变量 + foreach (XmlNode item in nodeList) + {//判断是否存在该节点 + if (item.Name == NodeName[i]) + { + N = true; + break; + } + } + if (N == false) + {//不存在节点,属性,建立节点,属性 + XmlElement PointName = xml.CreateElement(NodeName[i]); + + PointName.SetAttribute(Attribute_name[i], Attribute_value[i]); + root.AppendChild(PointName); + } + else + {//存在属性进行赋值 + XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName); + + PointName.Attributes[Attribute_name[i]].Value = Attribute_value[i]; + } + xml.Save(path); + } + } + else + { + XmlDocument xml = new XmlDocument(); + XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement root = xml.CreateElement("Root"); + xml.AppendChild(root);//根元素 + for (int i = 0; i < NodeName.Length; i++) + { + XmlElement PointName = xml.CreateElement(NodeName[i]); + PointName.SetAttribute(Attribute_name[i], Attribute_value[i]); + root.AppendChild(PointName); + + xml.Save(path); + } + } + } + + /// + /// 多节点,多属性,多集合存储 + /// + /// 节点集合 + /// 属性集合 + /// 每个节点的属性数量 + /// 属性值集合 + public void AttributeStorage(string[] NodeName, string[] Attribute_name, int AttributeNumber, params string[][] Attribute_value) + { + if (File.Exists(path)) + { + //存在Xml的文件 + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + for (int i = 0; i < NodeName.Length; i++) + { + bool N = false;//节点变量 + foreach (XmlNode item in nodeList) + {//判断是否存在该节点 + if (item.Name == NodeName[i]) + { + N = true; + break; + } + } + if (N == false) + {//不存在节点,属性,建立节点,属性 + XmlElement PointName = xml.CreateElement(NodeName[i]); + for (int j = 0; j < AttributeNumber; j++) + { + PointName.SetAttribute(Attribute_name[j], Attribute_value[j][i]); + } + + root.AppendChild(PointName); + } + else + {//存在属性进行赋值 + XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName[i]); + + for (int j = 0; j < AttributeNumber; j++) + { + PointName.Attributes[Attribute_name[j]].Value = Attribute_value[j][i]; + } + } + } + xml.Save(path); + } + else + { + XmlDocument xml = new XmlDocument(); + XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement root = xml.CreateElement("Root"); + xml.AppendChild(root);//根元素 + for (int i = 0; i < NodeName.Length; i++) + { + XmlElement PointName = xml.CreateElement(NodeName[i]); + for (int j = 0; j < AttributeNumber; j++) + { + PointName.SetAttribute(Attribute_name[j], Attribute_value[j][i]); + } + root.AppendChild(PointName); + + xml.Save(path); + } + } + } + + /// + /// 节点值存储 + /// + /// 节点名 + /// 文本 + public void NodeStorage(string NodeName, string Text) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + bool n = false; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + item.InnerText = Text; + n = true; + break; + } + } + if (n == false) + { + XmlElement other = xml.CreateElement(NodeName); + other.InnerText = Text; + root.AppendChild(other); + } + xml.Save(path); + } + else + { + XmlDocument doc = new XmlDocument(); + XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "UTF-8", null); + XmlElement Root = doc.CreateElement("Root"); + doc.AppendChild(Root);//根元素 + + XmlElement Node = doc.CreateElement(NodeName); + Node.InnerText = Text; + Root.AppendChild(Node); + + doc.Save(path); + } + } + + #endregion 存储 + + #region + + /// + /// 通过节点取值 + /// + /// 节点名 + /// 取值失败返回null + public string SearchNode(string NodeName) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + return item.InnerText; + } + } + } + return null; + } + + /// + /// 查找数字 + /// + /// 节点名 + /// 属性名 + /// 取值失败返回0 + public int SearchNumber(string NodeName, string Attribute_name) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + if (item.Attributes[Attribute_name] != null) + { + return Convert.ToInt32(item.Attributes[Attribute_name].Value); + } + } + } + } + return 0; + } + + /// + /// 查找属性值 + /// + /// 节点名 + /// 属性名 + /// 取值失败返回null + public string SearchWords(string NodeName, string Attribute_name) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + if (item.Attributes[Attribute_name] != null) + { + return item.Attributes[Attribute_name].Value; + } + } + } + } + return null; + } + + /// + /// 查找布尔值 + /// + /// 节点名 + /// 属性值 + /// 返回查找结果,查询失败返回false + public bool SearchBoolean(string NodeName, string Attribute_name) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + if (item.Attributes[Attribute_name] != null) + { + try + { + return Convert.ToBoolean(item.Attributes[Attribute_name].Value); + } + catch + { + return false; + } + } + } + } + } + return false; + } + + /// + /// 查找属性值集合 + /// + /// 节点名集合 + /// 属性名集合 + /// 文件不在返回null,单个属性不在返回“空” + public string[] SearchWords(string[] NodeName, string[] Attribute_name) + { + if (File.Exists(path)) + { + string[] s = new string[NodeName.Length]; + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + for (int i = 0; i < NodeName.Length; i++) + { + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName[i]) + { + if (item.Attributes[Attribute_name[i]] != null) + { + s[i] = item.Attributes[Attribute_name[i]].Value; + } + else + { + s[i] = ""; + } + } + } + } + return s; + } + return null; + } + + /// + /// 通过确切属性值,属性名,查找其他属性值 + /// + /// 已知属性名 + /// 已知属性值 + /// 待查属性名 + /// 待查属性值 + public string[] SearchWords(string Attribute_name1, string Attribute_value, string Attribute_name2) + { + List values = new List(); + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Attributes[Attribute_name1] != null) + { + if (item.Attributes[Attribute_name1].Value == Attribute_value) + { + if (item.Attributes[Attribute_name2] != null) + { + values.Add(item.Attributes[Attribute_name2].Value); + } + } + } + } + } + return values.ToArray(); + } + + /// + /// 查找节点的所有属性值 + /// + /// 节点 名 + /// 返回查找键值对,查询失败返回null + public Dictionary SearchAllAttributes(string NodeName) + { + Dictionary Attributes = new Dictionary(); + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + XmlAttributeCollection attributeCollection = item.Attributes; + if (attributeCollection != null) + { + foreach (XmlAttribute attribute in attributeCollection) + { + Attributes.Add(attribute.Name, attribute.Value); + } + } + return Attributes; + } + } + } + return null; + } + + /// + /// 通过确切属性值,属性名,查找其他属性的布尔值 + /// + /// 已知属性名 + /// 已知属性值 + /// 待查属性名 + /// 待查布尔值,失败返回false + public bool SearchBoolean(string Attribute_name1, string Attribute_value, string Attribute_name2) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Attributes[Attribute_name1].Value == Attribute_value) + { + if (item.Attributes[Attribute_name2] != null) + { + try + { + return Convert.ToBoolean(item.Attributes[Attribute_name2].Value); + } + catch + { + return false; + } + } + } + } + } + return false; + } + + #endregion + + /// + /// 按节点名移除节点 + /// + /// 节点名 + /// 是否移除成功 + public bool RemoveNode(string NodeName) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + root.RemoveChild(item); + xml.Save(path); + return true; + } + } + } + return false; + } + + /// + /// 按确切的属性名,属性值删除节点 + /// + /// 属性名 + /// 属性值 + /// 是否移除成功 + public bool RemoveNode(string Attribute_name, string Attribute_value) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Attributes[Attribute_name] != null) + { + if (item.Attributes[Attribute_name].Value == Attribute_value) + { + root.RemoveChild(item); + xml.Save(path); + return true; + } + } + } + } + return false; + } + + /// + /// 如果节点中有日期属性,把日期之前的节点都删除 + /// + /// 属性名 + /// 截止时间 + /// 是否删除成功 + public bool RemoveNode(string Attribute_name, DateTime dateTime) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + for (int i = 0; i < nodeList.Count; i++) + { + if (nodeList[i].Attributes[Attribute_name] != null) + { + DateTime dt = Convert.ToDateTime(nodeList[i].Attributes[Attribute_name].Value); + if (DateTime.Compare(dt, dateTime) < 0) + { + root.RemoveChild(nodeList[i]); + } + } + } + xml.Save(path); + + return true; + } + return false; + } + + /// + /// 判断节点是否存在 + /// + /// 节点名 + /// 返回结果 + public bool NodeExist(string NodeName) + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + XmlNodeList nodeList = root.ChildNodes; + foreach (XmlNode item in nodeList) + { + if (item.Name == NodeName) + { + return true; + } + } + } + return false; + } + + /// + /// 删除所有节点,不包含子节点 + /// + /// 返回删除是否成功 + public bool RemoveAllNode() + { + if (File.Exists(path)) + { + XmlDocument xml = new XmlDocument(); + xml.Load(path); + XmlElement root = xml.DocumentElement; + root.RemoveAll(); + xml.Save(path); + + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs b/src/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs new file mode 100644 index 000000000..86f9f677c --- /dev/null +++ b/src/TouchSocket/Core/Dependency/Attribute/DataValidationAttribute.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 依赖属性数据验证 + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class DataValidationAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs b/src/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs new file mode 100644 index 000000000..a2dc57d06 --- /dev/null +++ b/src/TouchSocket/Core/Dependency/Attribute/DependencyInjectionAttribute.cs @@ -0,0 +1,153 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 指定依赖类型。 + /// + [AttributeUsage(AttributeTargets.Class)] + public class DependencyTypeAttribute : Attribute + { + /// + /// 初始化一个依赖类型。当确定某个类型仅以某种特定方式注入时,可以过滤不必要的注入操作,以提高效率。 + /// + /// 可以叠加位域 + public DependencyTypeAttribute(DependencyType type) + { + Type = type; + } + + /// + /// 支持类型。 + /// + public DependencyType Type { get; } + } + + /// + /// 依赖注入类型。 + /// + public enum DependencyType + { + /// + /// 构造函数 + /// + Constructor = 1, + + /// + /// 属性 + /// + Property = 2, + + /// + /// 方法 + /// + Method = 4 + } + + /// + /// 指定依赖类型,构造函数,可用于构造函数,属性,方法。 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Property | AttributeTargets.Method)] + public class DependencyInjectAttribute : Attribute + { + /// + /// 初始化一个依赖注入对象。并且指定构造参数。 + /// 当创建时也指定参数时,会覆盖该设定。 + /// + /// + public DependencyInjectAttribute(params object[] ps) + { + Ps = ps; + } + + /// + /// 构造函数 + /// + /// + public DependencyInjectAttribute(bool resolveNullIfNoRegistered) + { + ResolveNullIfNoRegistered = resolveNullIfNoRegistered; + } + + /// + /// 构造参数 + /// + public object[] Ps { get; } + + /// + /// 如果没有注册则返回为空 + /// + public bool ResolveNullIfNoRegistered { get; set; } + } + + /// + /// 参数,属性指定性注入。 + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] + public class DependencyParamterInjectAttribute : DependencyInjectAttribute + { + /// + /// 参数,属性指定性注入。 + /// + /// + /// + public DependencyParamterInjectAttribute(string key, params object[] ps) : base(ps) + { + Key = key; + } + + /// + /// 类型,参数,属性指定性注入。 + /// + /// + /// + /// + public DependencyParamterInjectAttribute(Type type, string key, params object[] ps) : base(ps) + { + Key = key; + Type = type; + } + + /// + /// 类型,参数,属性指定性注入。 + /// + /// + /// + public DependencyParamterInjectAttribute(Type type, params object[] ps) : base(ps) + { + Key = string.Empty; + Type = type; + } + + /// + /// 注入类型 + /// + public Type Type { get; } + + /// + /// 构造函数 + /// + /// + public DependencyParamterInjectAttribute(bool resolveNullIfNoRegistered) + { + ResolveNullIfNoRegistered = resolveNullIfNoRegistered; + } + + /// + /// 指定键。 + /// + public string Key { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/Container.cs b/src/TouchSocket/Core/Dependency/Container.cs new file mode 100644 index 000000000..1ab4368c8 --- /dev/null +++ b/src/TouchSocket/Core/Dependency/Container.cs @@ -0,0 +1,371 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// IOC容器 + /// + public class Container : IContainer + { + private readonly ConcurrentDictionary m_registrations = new ConcurrentDictionary(); + + /// + /// 初始化一个IOC容器 + /// + public Container() + { + this.RegisterSingleton(this); + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator GetEnumerator() + { + return m_registrations.Values.ToList().GetEnumerator(); + } + + /// + /// + /// + /// + /// + /// + public bool IsRegistered(Type fromType, string key = "") + { + return m_registrations.ContainsKey($"{fromType.FullName}{key}"); + } + + /// + /// + /// + /// + /// + public void Register(DependencyDescriptor descriptor, string key = "") + { + string k = $"{descriptor.FromType.FullName}{key}"; + m_registrations.AddOrUpdate(k, descriptor, (k, v) => { return descriptor; }); + } + + /// + /// + /// + /// + /// + /// + /// + public object Resolve(Type fromType, object[] ps = null, string key = "") + { + if (fromType == typeof(IContainerProvider)) + { + return GetScopedContainer(); + } + string k; + DependencyDescriptor descriptor; + if (fromType.IsGenericType) + { + Type type = fromType.GetGenericTypeDefinition(); + k = $"{type.FullName}{key}"; + if (m_registrations.TryGetValue(k, out descriptor)) + { + if (descriptor.ImplementationFactory != null) + { + return descriptor.ImplementationFactory.Invoke(this); + } + if (descriptor.Lifetime == Lifetime.Singleton) + { + if (descriptor.ToInstance != null) + { + return descriptor.ToInstance; + } + lock (descriptor) + { + if (descriptor.ToInstance != null) + { + return descriptor.ToInstance; + } + if (descriptor.ToType.IsGenericType) + { + return descriptor.ToInstance = Create(descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps); + } + else + { + return descriptor.ToInstance = Create(descriptor.ToType, ps); + } + } + } + if (descriptor.ToType.IsGenericType) + { + return Create(descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps); + } + else + { + return Create(descriptor.ToType, ps); + } + } + } + k = $"{fromType.FullName}{key}"; + if (m_registrations.TryGetValue(k, out descriptor)) + { + if (descriptor.ImplementationFactory != null) + { + return descriptor.ImplementationFactory.Invoke(this); + } + if (descriptor.Lifetime == Lifetime.Singleton) + { + if (descriptor.ToInstance != null) + { + return descriptor.ToInstance; + } + lock (descriptor) + { + if (descriptor.ToInstance != null) + { + return descriptor.ToInstance; + } + return descriptor.ToInstance = Create(descriptor.ToType, ps); + } + } + return Create(descriptor.ToType, ps); + } + else if (fromType.IsPrimitive || fromType == typeof(string)) + { + return default; + } + else if (fromType.IsClass && !fromType.IsAbstract) + { + if (fromType.GetCustomAttribute() is DependencyInjectAttribute attribute) + { + if (attribute.ResolveNullIfNoRegistered && !IsRegistered(fromType, key)) + { + return default; + } + } + return Create(fromType, ps); + } + else + { + return default; + } + } + + /// + /// + /// + /// + /// + public void Unregister(DependencyDescriptor descriptor, string key = "") + { + string k = $"{descriptor.FromType.FullName}{key}"; + m_registrations.TryRemove(k, out _); + } + + /// + /// + /// + /// + /// + /// + private object Create(Type toType, object[] ops) + { + ConstructorInfo ctor = toType.GetConstructors().FirstOrDefault(x => x.IsDefined(typeof(DependencyInjectAttribute), true)); + if (ctor is null) + { + //如果没有被特性标记,那就取构造函数参数最多的作为注入目标 + if (toType.GetConstructors().Length == 0) + { + throw new Exception($"没有找到类型{toType.FullName}的公共构造函数。"); + } + ctor = toType.GetConstructors().OrderByDescending(x => x.GetParameters().Length).First(); + } + else + { + if (ops == null) + { + ops = ctor.GetCustomAttribute().Ps; + } + } + + DependencyTypeAttribute dependencyTypeAttribute = null; + if (toType.IsDefined(typeof(DependencyTypeAttribute), true)) + { + dependencyTypeAttribute = toType.GetCustomAttribute(); + } + + var parameters = ctor.GetParameters(); + object[] ps = new object[parameters.Length]; + + if (dependencyTypeAttribute == null || dependencyTypeAttribute.Type.HasFlag(DependencyType.Constructor)) + { + for (int i = 0; i < parameters.Length; i++) + { + if (ops != null && ops.Length - 1 >= i) + { + ps[i] = ops[i]; + } + else + { + if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string)) + { + if (parameters[i].HasDefaultValue) + { + ps[i] = parameters[i].DefaultValue; + } + else + { + ps[i] = default; + } + } + else + { + if (parameters[i].IsDefined(typeof(DependencyParamterInjectAttribute), true)) + { + DependencyParamterInjectAttribute attribute = parameters[i].GetCustomAttribute(); + Type type = attribute.Type == null ? parameters[i].ParameterType : attribute.Type; + + if (attribute.ResolveNullIfNoRegistered && !IsRegistered(type, attribute.Key)) + { + ps[i] = default; + } + else + { + ps[i] = Resolve(type, attribute.Ps, attribute.Key); + } + } + else + { + ps[i] = Resolve(parameters[i].ParameterType, null); + } + } + } + } + } + object instance = Activator.CreateInstance(toType, ps); + + if (dependencyTypeAttribute == null || dependencyTypeAttribute.Type.HasFlag(DependencyType.Property)) + { + var propetys = toType.GetProperties().Where(x => x.IsDefined(typeof(DependencyInjectAttribute), true)); + foreach (var item in propetys) + { + if (item.CanWrite) + { + object obj; + if (item.IsDefined(typeof(DependencyParamterInjectAttribute), true)) + { + DependencyParamterInjectAttribute attribute = item.GetCustomAttribute(); + Type type = attribute.Type == null ? item.PropertyType : attribute.Type; + if (attribute.ResolveNullIfNoRegistered && !IsRegistered(type, attribute.Key)) + { + obj = null; + } + else + { + obj = Resolve(type, attribute.Ps, attribute.Key); + } + } + else + { + obj = Resolve(item.PropertyType, null); + } + item.SetValue(instance, obj); + } + } + } + + if (dependencyTypeAttribute == null || dependencyTypeAttribute.Type.HasFlag(DependencyType.Method)) + { + var methods = toType.GetMethods().Where(x => x.IsDefined(typeof(DependencyInjectAttribute), true)).ToList(); + foreach (var item in methods) + { + parameters = item.GetParameters(); + ops = item.GetCustomAttribute().Ps; + ps = new object[parameters.Length]; + for (int i = 0; i < ps.Length; i++) + { + if (ops != null && ops.Length - 1 >= i) + { + ps[i] = ops[i]; + } + else + { + if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string)) + { + if (parameters[i].HasDefaultValue) + { + ps[i] = parameters[i].DefaultValue; + } + else + { + ps[i] = default; + } + } + else + { + if (parameters[i].IsDefined(typeof(DependencyParamterInjectAttribute), true)) + { + DependencyParamterInjectAttribute attribute = parameters[i].GetCustomAttribute(); + Type type = attribute.Type == null ? parameters[i].ParameterType : attribute.Type; + + if (attribute.ResolveNullIfNoRegistered && !IsRegistered(type, attribute.Key)) + { + ps[i] = default; + } + else + { + ps[i] = Resolve(type, attribute.Ps, attribute.Key); + } + } + else + { + ps[i] = Resolve(parameters[i].ParameterType, null); + } + } + } + } + item.Invoke(instance, ps); + } + } + return instance; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + private IContainerProvider GetScopedContainer() + { + Container container = new Container(); + foreach (var item in m_registrations) + { + if (item.Value.Lifetime == Lifetime.Scoped) + { + container.m_registrations.AddOrUpdate(item.Key, new DependencyDescriptor(item.Value.FromType, item.Value.ToType, Lifetime.Singleton), (k, v) => { return v; }); + } + else + { + container.m_registrations.AddOrUpdate(item.Key, item.Value, (k, v) => { return v; }); + } + } + return new ContainerProvider(container); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/ContainerExtension.cs b/src/TouchSocket/Core/Dependency/ContainerExtension.cs new file mode 100644 index 000000000..f0bd34414 --- /dev/null +++ b/src/TouchSocket/Core/Dependency/ContainerExtension.cs @@ -0,0 +1,360 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// IContainerExtensions + /// + public static class ContainerExtension + { + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, TTo instance) + where TFrom : class + where TTo : class, TFrom + { + RegisterSingleton(container, typeof(TFrom), instance); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, object instance) + { + if (instance is null) + { + throw new ArgumentNullException(nameof(instance)); + } + + RegisterSingleton(container, instance.GetType(), instance); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, string key, TTo instance) + where TFrom : class + where TTo : class, TFrom + { + RegisterSingleton(container, typeof(TFrom), instance, key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, Type fromType, object instance, string key = "") + { + container.Register(new DependencyDescriptor(fromType, instance), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, object instance, string key = "") + { + container.Register(new DependencyDescriptor(typeof(TFrom), instance), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, object instance, string key = "") + { + container.Register(new DependencyDescriptor(instance.GetType(), instance), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, string key = "") + { + container.Register(new DependencyDescriptor(typeof(TFrom), typeof(TFrom), Lifetime.Singleton), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, Type fromType, Type toType, string key = "") + { + container.Register(new DependencyDescriptor(fromType, toType, Lifetime.Singleton), key); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container) + where TFrom : class + where TTO : class, TFrom + { + RegisterSingleton(container, typeof(TFrom), typeof(TTO)); + return container; + } + + /// + /// 注册单例 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterSingleton(this IContainer container, string key) + where TFrom : class + where TTO : class, TFrom + { + RegisterSingleton(container, typeof(TFrom), typeof(TTO), key); + return container; + } + + #region Transient + + /// + /// 注册临时映射 + /// + /// + /// + /// + /// + public static IContainer RegisterTransient(this IContainer container) + where TFrom : class + where TTO : class, TFrom + { + RegisterTransient(container, typeof(TFrom), typeof(TTO)); + return container; + } + + /// + /// 注册临时映射 + /// + /// + /// + /// + public static IContainer RegisterTransient(this IContainer container) + where TFrom : class + { + RegisterTransient(container, typeof(TFrom), typeof(TFrom)); + return container; + } + + /// + /// 注册临时映射 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterTransient(this IContainer container, string key) + where TFrom : class + where TTO : class, TFrom + { + RegisterTransient(container, typeof(TFrom), typeof(TTO), key); + return container; + } + + /// + /// 注册临时映射 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterTransient(this IContainer container, Type fromType, Type toType, string key = "") + { + container.Register(new DependencyDescriptor(fromType, toType, Lifetime.Transient), key); + return container; + } + + #endregion Transient + + #region Scoped + + /// + /// 注册区域映射 + /// + /// + /// + /// + /// + public static IContainer RegisterScoped(this IContainer container) + where TFrom : class + where TTO : class, TFrom + { + RegisterScoped(container, typeof(TFrom), typeof(TTO)); + return container; + } + + /// + /// 注册区域映射 + /// + /// + /// + /// + public static IContainer RegisterScoped(this IContainer container) + where TFrom : class + { + RegisterScoped(container, typeof(TFrom), typeof(TFrom)); + return container; + } + + /// + /// 注册区域映射 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterScoped(this IContainer container, string key) + where TFrom : class + where TTO : class, TFrom + { + RegisterScoped(container, typeof(TFrom), typeof(TTO), key); + return container; + } + + /// + /// 注册区域映射 + /// + /// + /// + /// + /// + /// + public static IContainer RegisterScoped(this IContainer container, Type fromType, Type toType, string key = "") + { + container.Register(new DependencyDescriptor(fromType, toType, Lifetime.Scoped), key); + return container; + } + + #endregion Scoped + + /// + /// 创建类型对应的实例 + /// + /// + /// + /// + /// + /// + public static T Resolve(this IContainerProvider container, object[] ps, string key = "") + { + return (T)container.Resolve(typeof(T), ps, key); + } + + /// + /// 创建类型对应的实例 + /// + /// + /// + /// + public static T Resolve(this IContainerProvider container) + { + return Resolve(container, null); + } + + /// + /// 创建类型对应的实例 + /// + /// + /// + /// + /// + public static T Resolve(this IContainerProvider container, string key) + { + return Resolve(container, null, key); + } + + #region Unregister + + /// + /// 移除注册信息 + /// + /// + /// + /// + /// + public static IContainer Unregister(this IContainer container, Type fromType, string key = "") + { + container.Unregister(new DependencyDescriptor(fromType), key); + return container; + } + + /// + /// 移除注册信息 + /// + /// + /// + /// + public static IContainer Unregister(this IContainer container, string key = "") + { + container.Unregister(new DependencyDescriptor(typeof(TFrom)), key); + return container; + } + + #endregion Unregister + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/ContainerProvider.cs b/src/TouchSocket/Core/Dependency/ContainerProvider.cs new file mode 100644 index 000000000..2f86e9721 --- /dev/null +++ b/src/TouchSocket/Core/Dependency/ContainerProvider.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + internal class ContainerProvider : IContainerProvider + { + private readonly Container m_container; + + public ContainerProvider(Container container) + { + m_container = container; + } + + public bool IsRegistered(Type fromType, string key = "") + { + return m_container.IsRegistered(fromType, key); + } + + public object Resolve(Type fromType, object[] ps = null, string key = "") + { + return m_container.Resolve(fromType, ps, key); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/DependencyDescriptor.cs b/src/TouchSocket/Core/Dependency/DependencyDescriptor.cs new file mode 100644 index 000000000..5ca012ece --- /dev/null +++ b/src/TouchSocket/Core/Dependency/DependencyDescriptor.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 注入依赖对象 + /// + public class DependencyDescriptor + { + /// + /// 初始化一个单例实例。 + /// + /// + /// + public DependencyDescriptor(Type fromType, object instance) + { + FromType = fromType; + ToInstance = instance; + Lifetime = Lifetime.Singleton; + ToType = instance.GetType(); + } + + /// + /// 初始化一个完整的服务注册 + /// + /// + /// + /// + public DependencyDescriptor(Type fromType, Type toType, Lifetime lifetime) + { + FromType = fromType; + Lifetime = lifetime; + ToType = toType; + } + + /// + /// 初始化一个简单的的服务描述 + /// + /// + public DependencyDescriptor(Type fromType) + { + FromType = fromType; + } + + /// + /// 实例化工厂委托 + /// + public Func ImplementationFactory { get; set; } + + /// + /// 实例类型 + /// + public Type ToType { get; } + + /// + /// 实例 + /// + public object ToInstance { get; set; } + + /// + /// 生命周期 + /// + public Lifetime Lifetime { get; } + + /// + /// 注册类型 + /// + public Type FromType { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/DependencyObject.cs b/src/TouchSocket/Core/Dependency/DependencyObject.cs new file mode 100644 index 000000000..af93d058e --- /dev/null +++ b/src/TouchSocket/Core/Dependency/DependencyObject.cs @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; + +namespace TouchSocket.Core +{ + /// + /// 依赖对象接口 + /// + public interface IDependencyObject : IDisposable + { + /// + /// 获取依赖注入的值 + /// + /// + /// + /// + public TValue GetValue(IDependencyProperty dp); + + /// + /// 是否有值。 + /// + /// + /// + public bool HasValue(IDependencyProperty dp); + + /// + /// 重置属性值。 + /// + /// + /// + /// + public DependencyObject RemoveValue(IDependencyProperty dp); + + /// + /// 设置依赖注入的值 + /// + /// + /// + public DependencyObject SetValue(IDependencyProperty dp, TValue value); + } + + /// + /// 依赖项对象. + /// 线程安全。 + /// + public class DependencyObject : DisposableObject, IDependencyObject, System.IDisposable + { + [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly ConcurrentDictionary m_dp; + + /// + /// 构造函数 + /// + public DependencyObject() + { + m_dp = new ConcurrentDictionary(); + } + + /// + /// 获取依赖注入的值 + /// + /// + /// + public TValue GetValue(IDependencyProperty dp) + { + if (m_dp.TryGetValue(dp, out object value)) + { + return (TValue)value; + } + else + { + return dp.DefauleValue; + } + } + + /// + /// + /// + /// + /// + public bool HasValue(IDependencyProperty dp) + { + return m_dp.ContainsKey(dp); + } + + /// + /// 移除设定值。 + /// + /// + /// + /// + public DependencyObject RemoveValue(IDependencyProperty dp) + { + m_dp.TryRemove(dp, out _); + return this; + } + + /// + /// 设置依赖注入的值 + /// + /// + /// + public DependencyObject SetValue(IDependencyProperty dp, TValue value) + { + m_dp.AddOrUpdate(dp, value, (k, v) => v); + return this; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_dp.Clear(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/DependencyProperty.cs b/src/TouchSocket/Core/Dependency/DependencyProperty.cs new file mode 100644 index 000000000..779a80194 --- /dev/null +++ b/src/TouchSocket/Core/Dependency/DependencyProperty.cs @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Diagnostics; + +namespace TouchSocket.Core +{ + /// + /// IDependencyProperty + /// + /// + public interface IDependencyProperty + { + /// + /// 默认值 + /// + TValue DefauleValue { get; } + + /// + /// 属性名称 + /// + string Name { get; } + + /// + /// 所属类型 + /// + Type Owner { get; } + } + + /// + /// 依赖项属性 + /// + [DebuggerDisplay("Name={Name},Type={ValueType}")] + public class DependencyProperty : IDependencyProperty + { + /// + /// 属性名称 + /// + protected string m_name; + + /// + /// 所属类型 + /// + protected Type m_owner; + + private TValue m_value; + + /// + /// 依赖项属性 + /// + protected DependencyProperty() + { + } + + /// + /// + /// + public TValue DefauleValue => m_value; + + /// + /// + /// + public string Name => m_name; + + /// + /// + /// + public Type Owner => m_owner; + + /// + /// 注册依赖项属性。 + /// 依赖属性的默认值,可能会应用于所有的 + /// + /// + /// + /// 依赖项属性值,一般该值应该是值类型,因为它可能会被用于多个依赖对象。 + /// + public static DependencyProperty Register(string propertyName, Type owner, TValue value) + { + DependencyProperty dp = new DependencyProperty + { + m_name = propertyName, + m_owner = owner, + m_value = value + }; + return dp; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/IContainer.cs b/src/TouchSocket/Core/Dependency/IContainer.cs new file mode 100644 index 000000000..ec7d29013 --- /dev/null +++ b/src/TouchSocket/Core/Dependency/IContainer.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// 注入容器接口 + /// + public interface IContainer : IContainerProvider, IEnumerable + { + /// + /// 添加类型描述符。 + /// + /// + /// + void Register(DependencyDescriptor descriptor, string key = ""); + + /// + /// 移除注册信息。 + /// + /// + /// + /// + void Unregister(DependencyDescriptor descriptor, string key = ""); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/IContainerProvider.cs b/src/TouchSocket/Core/Dependency/IContainerProvider.cs new file mode 100644 index 000000000..5b8a7e699 --- /dev/null +++ b/src/TouchSocket/Core/Dependency/IContainerProvider.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 具有区域效应的容器。 + /// + public interface IContainerProvider + { + /// + /// 创建目标类型的对应实例。 + /// + /// + /// + /// + /// + object Resolve(Type fromType, object[] ps = null, string key = ""); + + /// + /// 判断某类型是否已经注册 + /// + /// + /// + /// + bool IsRegistered(Type fromType, string key = ""); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Dependency/Lifetime.cs b/src/TouchSocket/Core/Dependency/Lifetime.cs new file mode 100644 index 000000000..8f7e195bf --- /dev/null +++ b/src/TouchSocket/Core/Dependency/Lifetime.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 注入项的生命周期。 + /// + public enum Lifetime + { + /// + /// 单例对象 + /// + Singleton, + + /// + /// 以接口为区域实例单例。 + /// + Scoped, + + /// + /// 瞬时对象 + /// + Transient + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Diagnostics/TimeMeasurer.cs b/src/TouchSocket/Core/Diagnostics/TimeMeasurer.cs new file mode 100644 index 000000000..1dbcf0d86 --- /dev/null +++ b/src/TouchSocket/Core/Diagnostics/TimeMeasurer.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Diagnostics; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 时间测量器 + /// + public class TimeMeasurer + { + /// + /// 开始运行 + /// + /// + /// + public static TimeSpan Run(Action action) + { + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + action?.Invoke(); + stopwatch.Stop(); + return stopwatch.Elapsed; + } + + /// + /// 异步执行 + /// + /// + /// + public static Task RunAsync(Action action) + { + return EasyTask.Run(() => { return Run(action); }); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Event/TouchSocketEventArgs.cs b/src/TouchSocket/Core/Event/TouchSocketEventArgs.cs new file mode 100644 index 000000000..ed0c07621 --- /dev/null +++ b/src/TouchSocket/Core/Event/TouchSocketEventArgs.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// TouchSocketEventArgs + /// + public class TouchSocketEventArgs : EventArgs + { + /// + /// 是否允许操作 + /// + public bool IsPermitOperation { get; set; } + + /// + /// 是否已处理 + /// + public bool Handled { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Exceptions/MessageNotFoundException.cs b/src/TouchSocket/Core/Exceptions/MessageNotFoundException.cs new file mode 100644 index 000000000..706510274 --- /dev/null +++ b/src/TouchSocket/Core/Exceptions/MessageNotFoundException.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 未找到消息异常类 + /// + [Serializable] + public class MessageNotFoundException : Exception + { + /// + ///构造函数 + /// + /// + public MessageNotFoundException(string mes) : base(mes) + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Exceptions/MessageRegisteredException.cs b/src/TouchSocket/Core/Exceptions/MessageRegisteredException.cs new file mode 100644 index 000000000..5619106da --- /dev/null +++ b/src/TouchSocket/Core/Exceptions/MessageRegisteredException.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 消息已注册 + /// + [Serializable] + public class MessageRegisteredException : Exception + { + /// + ///构造函数 + /// + /// + public MessageRegisteredException(string mes) : base(mes) + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Extensions/BytesExtension.cs b/src/TouchSocket/Core/Extensions/BytesExtension.cs new file mode 100644 index 000000000..4a3ba10ab --- /dev/null +++ b/src/TouchSocket/Core/Extensions/BytesExtension.cs @@ -0,0 +1,138 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// BytesExtension + /// + public static class BytesExtension + { + #region 字节数组扩展 + + /// + /// 转Base64。 + /// + /// + /// + public static string ToBase64(this byte[] data) + { + return Convert.ToBase64String(data); + } + + /// + /// 索引包含数组。 + /// + /// 例如:在{0,1,2,3,1,2,3}中搜索{1,2},则会返回list:[2,5],均为最后索引的位置。 + /// + /// + /// + /// + /// + /// + /// + public static List IndexOfInclude(this byte[] srcByteArray, int offset, int length, byte[] subByteArray) + { + int subByteArrayLen = subByteArray.Length; + List indexes = new List(); + if (length < subByteArrayLen) + { + return indexes; + } + int hitLength = 0; + for (int i = offset; i < length; i++) + { + if (srcByteArray[i] == subByteArray[hitLength]) + { + hitLength++; + } + else + { + hitLength = 0; + } + + if (hitLength == subByteArray.Length) + { + hitLength = 0; + indexes.Add(i); + } + } + + return indexes; + } + + /// + /// 索引第一个包含数组的索引位置,例如:在{0,1,2,3,1,2,3}中索引{2,3},则返回3。 + /// 如果目标数组为null或长度为0,则直接返回offset的值 + /// + /// + /// + /// + /// + /// + public static int IndexOfFirst(this byte[] srcByteArray, int offset, int length, byte[] subByteArray) + { + if (length < subByteArray.Length) + { + return -1; + } + if (subByteArray == null || subByteArray.Length == 0) + { + return offset; + } + int hitLength = 0; + for (int i = offset; i < length + offset; i++) + { + if (srcByteArray[i] == subByteArray[hitLength]) + { + hitLength++; + } + else + { + hitLength = 0; + } + + if (hitLength == subByteArray.Length) + { + return i; + } + } + + return -1; + } + + /// + /// 字节数组转16进制字符 + /// + /// + /// + /// + /// + /// + public static string ByBytesToHexString(this byte[] buffer, int offset, int length, string splite = default) + { + if (string.IsNullOrEmpty(splite)) + { + return BitConverter.ToString(buffer, offset, length).Replace("-", string.Empty); + } + else + { + return BitConverter.ToString(buffer, offset, length).Replace("-", splite); + } + } + + #endregion 字节数组扩展 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Extensions/DictionaryExtension.cs b/src/TouchSocket/Core/Extensions/DictionaryExtension.cs new file mode 100644 index 000000000..e680ec97a --- /dev/null +++ b/src/TouchSocket/Core/Extensions/DictionaryExtension.cs @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// DictionaryExtension + /// + public static class DictionaryExtension + { + #region 字典扩展 + + /// + /// 移除满足条件的项目。 + /// + /// + /// + /// + /// + /// + public static int Remove(this ConcurrentDictionary pairs, Func, bool> func) + { + List list = new List(); + foreach (var item in pairs) + { + if (func?.Invoke(item) == true) + { + list.Add(item.Key); + } + } + + int count = 0; + foreach (var item in list) + { + if (pairs.TryRemove(item, out _)) + { + count++; + } + } + return count; + } + +#if NET45_OR_GREATER || NETSTANDARD2_0_OR_GREATER + + /// + /// 尝试添加 + /// + /// + /// + /// + /// + /// + /// + public static bool TryAdd(this Dictionary dictionary, Tkey tkey, TValue value) + { + if (dictionary.ContainsKey(tkey)) + { + return false; + } + dictionary.Add(tkey, value); + return true; + } + +#endif + + /// + /// 尝试添加 + /// + /// + /// + /// + /// + /// + /// + public static void AddOrUpdate(this Dictionary dictionary, Tkey tkey, TValue value) + { + if (dictionary.ContainsKey(tkey)) + { + dictionary[tkey] = value; + } + else + { + dictionary.Add(tkey, value); + } + } + + /// + /// 获取值。如果键不存在,则返回默认值。 + /// + /// + /// + /// + /// + /// + public static TValue GetValue(this Dictionary dictionary, Tkey tkey) + { + if (dictionary.TryGetValue(tkey, out TValue value)) + { + return value; + } + else + { + return default; + } + } + + #endregion 字典扩展 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Extensions/RangeExtension.cs b/src/TouchSocket/Core/Extensions/RangeExtension.cs new file mode 100644 index 000000000..e24681702 --- /dev/null +++ b/src/TouchSocket/Core/Extensions/RangeExtension.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ +#if NETCOREAPP3_1_OR_GREATER + /// + /// RangeExtension + /// + public static class RangeExtension + { + /// + /// 枚举扩展 + /// + /// + /// + public static CustomIntEnumerator GetEnumerator(this Range range) + { + return new CustomIntEnumerator(range); + } + } + + /// + /// CustomIntEnumerator + /// + public ref struct CustomIntEnumerator + { + private int m_current; + private readonly int m_end; + + /// + /// CustomIntEnumerator + /// + /// + public CustomIntEnumerator(Range range) + { + if (range.End.IsFromEnd) + { + throw new NotSupportedException("不支持无限枚举。"); + } + m_current = range.Start.Value - 1; + m_end = range.End.Value; + } + + /// + /// Current + /// + public int Current => m_current; + + /// + /// MoveNext + /// + /// + public bool MoveNext() + { + m_current++; + return m_current <= m_end; + } + } +#endif +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Extensions/StringExtension.cs b/src/TouchSocket/Core/Extensions/StringExtension.cs new file mode 100644 index 000000000..4cc3bb49a --- /dev/null +++ b/src/TouchSocket/Core/Extensions/StringExtension.cs @@ -0,0 +1,349 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace TouchSocket.Core +{ + /// + /// StringExtension + /// + public static class StringExtension + { + /// + /// IsNullOrEmpty + /// + /// + /// + public static bool IsNullOrEmpty(this string str) + { + return string.IsNullOrEmpty(str); + } + + /// + /// IsNullOrWhiteSpace + /// + /// + /// + public static bool IsNullOrWhiteSpace(this string str) + { + return string.IsNullOrWhiteSpace(str); + } + + /// + /// 当不为null,且不为空。 + /// + /// + /// + public static bool HasValue(this string str) + { + return !string.IsNullOrWhiteSpace(str); + } + + /// + /// 将字符串格式化成指定的数据类型 + /// + /// + /// + /// + /// + /// + public static bool TryParseToType(string str, Type type, out object value, char[] splits = default) + { + if (string.IsNullOrEmpty(str)) + { + value = default; + return true; + } + + if (type == null) + { + value = str; + return true; + } + if (type.IsArray) + { + Type elementType = type.GetElementType(); + string[] strs; + if (splits == null) + { + strs = str.Split(new char[] { ' ', ';', '-', '/' }); + } + else + { + strs = str.Split(splits); + } + + Array array = Array.CreateInstance(elementType, strs.Length); + for (int i = 0, c = strs.Length; i < c; ++i) + { + object o; + if (ConvertSimpleType(strs[i], elementType, out o)) + { + array.SetValue(o, i); + } + else + { + value = default; + return false; + } + } + value = array; + return true; + } + return ConvertSimpleType(str, type, out value); + } + + private static bool ConvertSimpleType(string value, Type destinationType, out object returnValue) + { + if ((value == null) || destinationType.IsInstanceOfType(value)) + { + returnValue = value; + return true; + } + + if (string.IsNullOrEmpty(value)) + { + returnValue = default; + return true; + } + TypeConverter converter = TypeDescriptor.GetConverter(destinationType); + bool flag = converter.CanConvertFrom(value.GetType()); + if (!flag) + { + converter = TypeDescriptor.GetConverter(value.GetType()); + } + if (!flag && !converter.CanConvertTo(destinationType)) + { + returnValue = default; + return false; + } + try + { + returnValue = flag ? converter.ConvertFrom(null, null, value) : converter.ConvertTo(null, null, value, destinationType); + } + catch + { + returnValue = default; + return false; + } + return true; + } + + /// + /// 判断字符串compare 在 input字符串中出现的次数 + /// + /// 源字符串 + /// 用于比较的字符串 + /// 字符串compare 在 input字符串中出现的次数 + public static int HitStringCount(this string input, string compare) + { + int index = input.IndexOf(compare); + if (index != -1) + { + return 1 + HitStringCount(input.Substring(index + compare.Length), compare); + } + else + { + return 0; + } + } + + /// + /// 将字符转换为对应的基础类型类型。 + /// + /// + /// 目标类型必须为基础类型 + /// + public static object ParseToType(this string value, Type destinationType) + { + object returnValue; + if ((value == null) || destinationType.IsInstanceOfType(value)) + { + return value; + } + string str = value; + if ((str != null) && (str.Length == 0)) + { + return null; + } + TypeConverter converter = TypeDescriptor.GetConverter(destinationType); + bool flag = converter.CanConvertFrom(value.GetType()); + if (!flag) + { + converter = TypeDescriptor.GetConverter(value.GetType()); + } + if (!flag && !converter.CanConvertTo(destinationType)) + { + throw new InvalidOperationException("无法转换成类型:" + value.ToString() + "==>" + destinationType); + } + try + { + returnValue = flag ? converter.ConvertFrom(null, null, value) : converter.ConvertTo(null, null, value, destinationType); + } + catch (Exception e) + { + throw new InvalidOperationException(" 类型转换出错:" + value.ToString() + "==>" + destinationType, e); + } + return returnValue; + } + + /// + /// 只按第一个匹配项分割 + /// + /// + /// + /// + public static string[] SplitFirst(this string str, char split) + { + List s = new List(); + int index = str.IndexOf(split); + if (index > 0) + { + s.Add(str.Substring(0, index).Trim()); + s.Add(str.Substring(index + 1, str.Length - index - 1).Trim()); + } + + return s.ToArray(); + } + + /// + /// 按字符串分割 + /// + /// + /// + /// + public static string[] Split(this string str, string pattern) + { + return Regex.Split(str, pattern); + } + + /// + /// 只按最后一个匹配项分割 + /// + /// + /// + /// + public static string[] SplitLast(this string str, char split) + { + List s = new List(); + int index = str.LastIndexOf(split); + if (index > 0) + { + s.Add(str.Substring(0, index).Trim()); + s.Add(str.Substring(index + 1, str.Length - index - 1).Trim()); + } + + return s.ToArray(); + } + + /// + /// 按格式填充 + /// + /// + /// + /// + public static string Format(this string str, params object[] ps) + { + if (ps == null || ps.Length == 0) + { + return str; + } + try + { + return string.Format(str, ps); + } + catch + { + return str; + } + } + + /// + /// 转换为SHA1。 + /// + /// + /// + /// + public static byte[] ToSha1(this string value, Encoding encoding) + { + using (SHA1 sha1 = SHA1.Create()) + { + return sha1.ComputeHash(encoding.GetBytes(value)); + } + } + + /// + /// 转换为UTF-8数据,效果等于 + /// + /// + /// + public static byte[] ToUTF8Bytes(this string value) + { + return Encoding.UTF8.GetBytes(value); + } + + /// + /// 将16进制的字符转换为数组。 + /// + /// + /// + /// + public static byte[] ByHexStringToBytes(this string hexString, string splite = default) + { + if (!string.IsNullOrEmpty(splite)) + { + hexString = hexString.Replace(splite, string.Empty); + } + + if ((hexString.Length % 2) != 0) + { + hexString += " "; + } + byte[] returnBytes = new byte[hexString.Length / 2]; + for (int i = 0; i < returnBytes.Length; i++) + { + returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); + } + return returnBytes; + } + + /// + /// 将16进制的字符转换为int32。 + /// + /// + /// + public static int ByHexStringToInt32(this string hexString) + { + if (string.IsNullOrEmpty(hexString)) + { + return default; + } + return int.Parse(hexString, System.Globalization.NumberStyles.HexNumber); + } + + /// + /// 从Base64转到数组。 + /// + /// + /// + public static byte[] ByBase64ToBytes(this string value) + { + return Convert.FromBase64String(value); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Extensions/SystemExtensions.cs b/src/TouchSocket/Core/Extensions/SystemExtensions.cs new file mode 100644 index 000000000..89e8a7d84 --- /dev/null +++ b/src/TouchSocket/Core/Extensions/SystemExtensions.cs @@ -0,0 +1,172 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Globalization; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 为System提供扩展。 + /// + public static class SystemExtensions + { + #region 其他 + + /// + /// 安全性释放(不用判断对象是否为空)。不会抛出任何异常。 + /// + /// + /// + public static void SafeDispose(this IDisposable dis) + { + if (dis == default) + { + return; + } + try + { + dis.Dispose(); + } + catch + { + } + } + + #endregion 其他 + + /// + /// 获取自定义attribute + /// + /// + /// + /// + public static T GetAttribute(this Enum enumObj) where T : Attribute + { + Type type = enumObj.GetType(); + Attribute attr = null; + string enumName = Enum.GetName(type, enumObj); //获取对应的枚举名 + FieldInfo field = type.GetField(enumName); + attr = field.GetCustomAttribute(typeof(T), false); + return (T)attr; + } + + /// + /// 格林尼治标准时间 + /// + /// + /// + /// + public static string ToGMTString(this DateTime dt, string v) + { + return dt.ToString("r", CultureInfo.InvariantCulture); + } + +#if !NETCOREAPP3_1_OR_GREATER + + /// + /// 清除所有成员 + /// + /// + /// + public static void Clear(this ConcurrentQueue queue) + { + while (queue.TryDequeue(out _)) + { + } + } + +#endif + + /// + /// 清除所有成员 + /// + /// + /// + /// + public static void Clear(this ConcurrentQueue queue, Action action) + { + while (queue.TryDequeue(out T t)) + { + action?.Invoke(t); + } + } + + /// + /// 获取字节中的指定Bit的值 + /// + /// 字节 + /// Bit的索引值(0-7) + /// + public static int GetBit(this byte @this, short index) + { + byte x; + switch (index) + { + case 0: { x = 0x01; } break; + case 1: { x = 0x02; } break; + case 2: { x = 0x04; } break; + case 3: { x = 0x08; } break; + case 4: { x = 0x10; } break; + case 5: { x = 0x20; } break; + case 6: { x = 0x40; } break; + case 7: { x = 0x80; } break; + default: { return 0; } + } + return (@this & x) == x ? 1 : 0; + } + + /// + /// 设置字节中的指定Bit的值 + /// + /// 字节 + /// Bit的索引值(0-7) + /// Bit值(0,1) + /// + public static byte SetBit(this byte @this, short index, int bitvalue) + { + var _byte = @this; + if (bitvalue == 1) + { + switch (index) + { + case 0: { return _byte |= 0x01; } + case 1: { return _byte |= 0x02; } + case 2: { return _byte |= 0x04; } + case 3: { return _byte |= 0x08; } + case 4: { return _byte |= 0x10; } + case 5: { return _byte |= 0x20; } + case 6: { return _byte |= 0x40; } + case 7: { return _byte |= 0x80; } + default: { return _byte; } + } + } + else + { + switch (index) + { + case 0: { return _byte &= 0xFE; } + case 1: { return _byte &= 0xFD; } + case 2: { return _byte &= 0xFB; } + case 3: { return _byte &= 0xF7; } + case 4: { return _byte &= 0xEF; } + case 5: { return _byte &= 0xDF; } + case 6: { return _byte &= 0xBF; } + case 7: { return _byte &= 0x7F; } + default: { return _byte; } + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Extensions/SystemNetExtension.cs b/src/TouchSocket/Core/Extensions/SystemNetExtension.cs new file mode 100644 index 000000000..a9b65ada0 --- /dev/null +++ b/src/TouchSocket/Core/Extensions/SystemNetExtension.cs @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Net; + +namespace TouchSocket.Core +{ + /// + /// 其他扩展 + /// + public static class SystemNetExtension + { + /// + /// 从中获得IP地址。 + /// + /// + /// + public static string GetIP(this EndPoint endPoint) + { + int r = endPoint.ToString().LastIndexOf(":"); + return endPoint.ToString().Substring(0, r); + } + + /// + /// 从中获得Port。 + /// + /// + /// + public static int GetPort(this EndPoint endPoint) + { + int r = endPoint.ToString().LastIndexOf(":"); + return Convert.ToInt32(endPoint.ToString().Substring(r + 1, endPoint.ToString().Length - (r + 1))); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Extensions/TaskExtension.cs b/src/TouchSocket/Core/Extensions/TaskExtension.cs new file mode 100644 index 000000000..225fe3c71 --- /dev/null +++ b/src/TouchSocket/Core/Extensions/TaskExtension.cs @@ -0,0 +1,21 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// TaskExtension + /// + public static class TaskExtension + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Extensions/TupleExtension.cs b/src/TouchSocket/Core/Extensions/TupleExtension.cs new file mode 100644 index 000000000..1b691f05e --- /dev/null +++ b/src/TouchSocket/Core/Extensions/TupleExtension.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 元组扩展 + /// + public static class TupleExtension + { + /// + /// 获取元组的名称列表。 + /// + /// + /// + public static IEnumerable GetTupleElementNames(this ParameterInfo parameter) + { + return ((dynamic)parameter.GetCustomAttribute(Type.GetType("System.Runtime.CompilerServices.TupleElementNamesAttribute")))?.TransformNames; + } + } +} diff --git a/src/TouchSocket/Core/Extensions/TypeExtension.cs b/src/TouchSocket/Core/Extensions/TypeExtension.cs new file mode 100644 index 000000000..9e704c58c --- /dev/null +++ b/src/TouchSocket/Core/Extensions/TypeExtension.cs @@ -0,0 +1,102 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// TypeExtension + /// + public static class TypeExtension + { + #region Type扩展 + + /// + /// 获取类型 + /// + /// + /// + public static Type GetRefOutType(this Type type) + { + if (type.IsByRef) + { + return type.GetElementType(); + } + else + { + return type; + } + } + + /// + /// 获取默认值 + /// + /// + /// + public static object GetDefault(this Type targetType) + { + return targetType.IsValueType ? Activator.CreateInstance(targetType) : null; + } + + /// + /// 判断是否为静态类。 + /// + /// + /// + public static bool IsStatic(this Type targetType) + { + return targetType.IsAbstract && targetType.IsSealed; + } + + /// + /// 判断为结构体 + /// + /// + /// + public static bool IsStruct(this Type targetType) + { + if (!targetType.IsPrimitive && !targetType.IsClass && !targetType.IsEnum && targetType.IsValueType) + { + return true; + } + return false; + } + + /// + /// 判断该类型是否为可空类型 + /// + /// + /// + public static bool IsNullableType(this Type theType) + { + return (theType.IsGenericType && theType. + GetGenericTypeDefinition().Equals + (TouchSocketCoreUtility.nullableType)); + } + + /// + /// 判断该类型是否为值元组类型 + /// + /// + /// + public static bool IsValueTuple(this Type theType) + { + return theType.IsValueType && + theType.IsGenericType && + theType.FullName.StartsWith("System.ValueTuple"); + } + + #endregion Type扩展 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/BlockReadStream.cs b/src/TouchSocket/Core/IO/BlockReadStream.cs new file mode 100644 index 000000000..7fb6f037d --- /dev/null +++ b/src/TouchSocket/Core/IO/BlockReadStream.cs @@ -0,0 +1,215 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 阻塞式单项读取流。 + /// + public abstract class BlockReadStream : Stream, IWrite + { + private readonly AutoResetEvent m_inputEvent; + private readonly AutoResetEvent m_readEvent; + private byte[] m_buffer; + private bool m_dis; + private volatile int m_length; + private volatile int m_offset; + + /// + /// 构造函数 + /// + public BlockReadStream() + { + m_readEvent = new AutoResetEvent(false); + m_inputEvent = new AutoResetEvent(false); + ReadTimeout = 5000; + } + + /// + /// + /// + /// + public virtual void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// 还剩余的未读取的长度 + /// + public int CanReadLen + { + get + { + if (m_dis) + { + return 0; + } + return m_length - m_offset; + } + } + + /// + /// 不可使用 + /// + public override bool CanSeek => false; + + /// + /// 不可使用 + /// + public override long Length => throw new NotImplementedException(); + + /// + /// 不可使用 + /// + public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + /// + /// + /// + public override int ReadTimeout { get; set; } + + /// + /// 阻塞读取。 + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + if (!CanRead) + { + throw new Exception("该流不允许读取。"); + } + int r; + if (m_length > 0) + { + if (m_length > count) + { + //按count读取 + Array.Copy(m_buffer, m_offset, buffer, offset, count); + m_length -= count; + m_offset += count; + r = count; + } + else + { + //会读完本次 + Array.Copy(m_buffer, m_offset, buffer, offset, m_length); + r = m_length; + Reset(); + } + } + else + { + //无数据,须等待 + if (m_readEvent.WaitOne(ReadTimeout)) + { + if (m_length == 0) + { + Reset(); + r = 0; + } + else if (m_length > count) + { + //按count读取 + Array.Copy(m_buffer, m_offset, buffer, offset, count); + m_length -= count; + m_offset += count; + r = count; + } + else + { + //会读完本次 + Array.Copy(m_buffer, m_offset, buffer, offset, m_length); + r = m_length; + Reset(); + } + } + else + { + throw new TimeoutException(); + } + } + return r; + } + + /// + /// 不可使用 + /// + /// + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + /// + /// 不可使用 + /// + /// + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (m_dis) + { + return; + } + m_dis = true; + Reset(); + m_readEvent.SafeDispose(); + m_inputEvent.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// 传输输入. + /// 必须以length为0结束。读取端会超时。 + /// + /// + /// + /// + /// + protected bool Input(byte[] buffer, int offset, int length) + { + m_inputEvent.Reset(); + m_buffer = buffer; + m_offset = offset; + m_length = length; + m_readEvent.Set(); + return m_inputEvent.WaitOne(ReadTimeout); + } + + private void Reset() + { + m_buffer = null; + m_offset = 0; + m_length = 0; + m_readEvent.Reset(); + m_inputEvent.Set(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/BlockReader.cs b/src/TouchSocket/Core/IO/BlockReader.cs new file mode 100644 index 000000000..616f27b0f --- /dev/null +++ b/src/TouchSocket/Core/IO/BlockReader.cs @@ -0,0 +1,205 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 阻塞式读取。 + /// + public abstract class BlockReader : DisposableObject + { + private byte[] m_buffer; + private readonly AutoResetEvent m_inputEvent; + private volatile int m_offset; + private readonly AutoResetEvent m_readEvent; + private volatile int m_surLength; + + /// + /// 构造函数 + /// + public BlockReader() + { + m_readEvent = new AutoResetEvent(false); + m_inputEvent = new AutoResetEvent(false); + ReadTimeout = 5000; + } + + /// + /// 可读 + /// + public abstract bool CanRead { get; } + + /// + /// + /// + public int ReadTimeout { get; set; } + + /// + /// 阻塞读取,但不会移动游标。 + /// + /// + /// + /// + /// + public virtual int PeekRead(byte[] buffer, int offset, int count) + { + return PrivateRead(true, buffer, offset, count); + } + + /// + /// 阻塞读取。 + /// + /// + /// + /// + /// + public virtual int Read(byte[] buffer, int offset, int count) + { + return PrivateRead(false, buffer, offset, count); + } + + private int PrivateRead(bool peek, byte[] buffer, int offset, int count) + { + if (!CanRead) + { + throw new Exception("该流不允许读取。"); + } + int r; + if (m_surLength > 0) + { + if (m_surLength > count) + { + //按count读取 + Array.Copy(m_buffer, m_offset, buffer, offset, count); + if (!peek) + { + m_surLength -= count; + m_offset += count; + } + r = count; + } + else + { + //会读完本次 + Array.Copy(m_buffer, m_offset, buffer, offset, m_surLength); + r = m_surLength; + if (!peek) + { + Reset(); + } + } + } + else + { + //无数据,须等待 + if (m_readEvent.WaitOne(ReadTimeout)) + { + if (m_surLength == 0) + { + Reset(); + r = 0; + } + else if (m_surLength > count) + { + //按count读取 + Array.Copy(m_buffer, m_offset, buffer, offset, count); + if (!peek) + { + m_surLength -= count; + m_offset += count; + } + r = count; + } + else + { + //会读完本次 + Array.Copy(m_buffer, m_offset, buffer, offset, m_surLength); + r = m_surLength; + if (!peek) + { + Reset(); + } + } + } + else + { + throw new TimeoutException(); + } + } + return r; + } + + /// + /// 传输输入. + /// 当以length为0结束。 + /// 否则读取端会超时。 + /// + /// + /// + /// + /// + protected bool Input(byte[] buffer, int offset, int length) + { + //if (this.disposedValue) + //{ + // return false; + //} + m_inputEvent.Reset(); + m_buffer = buffer; + m_offset = offset; + m_surLength = length; + m_readEvent.Set(); + return m_inputEvent.WaitOne(ReadTimeout); + } + + /// + /// 输入完成 + /// + protected bool InputComplate() + { + return Input(new byte[0], 0, 0); + } + + private void Reset() + { + m_buffer = null; + m_offset = 0; + m_surLength = 0; + m_readEvent.Reset(); + m_inputEvent.Set(); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + Reset(); + m_readEvent.SafeDispose(); + m_inputEvent.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// 析构函数 + /// + ~BlockReader() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/ConsoleAction.cs b/src/TouchSocket/Core/IO/ConsoleAction.cs new file mode 100644 index 000000000..72b7612a3 --- /dev/null +++ b/src/TouchSocket/Core/IO/ConsoleAction.cs @@ -0,0 +1,159 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Core +{ + /// + /// 控制台行为 + /// + public class ConsoleAction + { + private readonly string helpOrder; + + /// + /// 构造函数 + /// + /// 帮助信息指令,如:"h|help|?" + public ConsoleAction(string helpOrder = "h|help|?") + { + this.helpOrder = helpOrder; + + Add(helpOrder, "帮助信息", ShowAll); + + string title = $@" + + _______ _ _____ _ _ + |__ __| | | / ____| | | | | + | | ___ _ _ ___ | |__ | (___ ___ ___ | | __ ___ | |_ + | | / _ \ | | | | / __|| '_ \ \___ \ / _ \ / __|| |/ // _ \| __| + | || (_) || |_| || (__ | | | | ____) || (_) || (__ | <| __/| |_ + |_| \___/ \__,_| \___||_| |_||_____/ \___/ \___||_|\_\\___| \__| + + ------------------------------------------------------------------- + Author : 若汝棋茗 + Version : {System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()} + Gitee : https://gitee.com/rrqm_home + Github : https://github.com/rrqm + API : https://www.yuque.com/rrqm/touchsocket/index + ------------------------------------------------------------------- +"; + Console.WriteLine(title); + } + + /// + /// 显示所有注册指令 + /// + public void ShowAll() + { + int max = actions.Values.Max(a => a.FullOrder.Length) + 8; + + List s = new List(); + foreach (var item in actions) + { + if (!s.Contains(item.Value.FullOrder.ToLower())) + { + s.Add(item.Value.FullOrder.ToLower()); + Console.Write($"[{item.Value.FullOrder}]"); + for (int i = 0; i < max - item.Value.FullOrder.Length; i++) + { + Console.Write("-"); + } + Console.WriteLine(item.Value.Description); + } + } + } + + /// + /// 帮助信息指令 + /// + public string HelpOrder => helpOrder; + + private readonly Dictionary actions = new Dictionary(); + + /// + /// 添加 + /// + /// 指令,多个指令用“|”分割 + /// 描述 + /// + public void Add(string order, string description, Action action) + { + string[] orders = order.ToLower().Split('|'); + foreach (var item in orders) + { + actions.Add(item, new VAction(description, order, action)); + } + } + + /// + /// 执行异常 + /// + public event Action OnException; + + /// + /// 执行,返回值仅表示是否有这个指令,异常获取请使用 + /// + /// + /// + public bool Run(string order) + { + if (actions.TryGetValue(order.ToLower(), out VAction vAction)) + { + try + { + vAction.Action.Invoke(); + } + catch (Exception ex) + { + OnException?.Invoke(ex); + } + return true; + } + else + { + return false; + } + } + } + + internal struct VAction + { + private readonly Action action; + + public Action Action => action; + + private readonly string fullOrder; + + public string FullOrder => fullOrder; + + private readonly string description; + + /// + /// 构造函数 + /// + /// + /// + /// + public VAction(string description, string fullOrder, Action action) + { + this.fullOrder = fullOrder; + this.action = action ?? throw new ArgumentNullException(nameof(action)); + this.description = description ?? throw new ArgumentNullException(nameof(description)); + } + + public string Description => description; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/DirectoryUtility.cs b/src/TouchSocket/Core/IO/DirectoryUtility.cs new file mode 100644 index 000000000..a9837352d --- /dev/null +++ b/src/TouchSocket/Core/IO/DirectoryUtility.cs @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; +using System.Linq; + +namespace TouchSocket.Core +{ + /// + /// DirectoryUtility + /// + public static class DirectoryUtility + { + /// + /// 复制文件夹及文件 + /// + /// 原文件路径 + /// 目标文件路径 + /// + public static void CopyDirectory(string sourceFolder, string destFolder) + { + //如果目标路径不存在,则创建目标路径 + if (!Directory.Exists(destFolder)) + { + Directory.CreateDirectory(destFolder); + } + //得到原文件根目录下的所有文件 + string[] files = Directory.GetFiles(sourceFolder); + foreach (string file in files) + { + string name = Path.GetFileName(file); + string dest = Path.Combine(destFolder, name); + File.Copy(file, dest);//复制文件 + } + //得到原文件根目录下的所有文件夹 + string[] folders = Directory.GetDirectories(sourceFolder); + foreach (string folder in folders) + { + string name = Path.GetFileName(folder); + string dest = Path.Combine(destFolder, name); + CopyDirectory(folder, dest);//构建目标路径,递归复制文件 + } + } + + /// + /// 获取文件夹下的一级文件夹目录名称,不含子文件夹。 + /// + /// + public static string[] GetDirectories(string sourceFolder) + { + return Directory.GetDirectories(sourceFolder) + .Select(s => Path.GetFileName(s)) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/FileIO/FilePool.cs b/src/TouchSocket/Core/IO/FileIO/FilePool.cs new file mode 100644 index 000000000..501e9c88a --- /dev/null +++ b/src/TouchSocket/Core/IO/FileIO/FilePool.cs @@ -0,0 +1,334 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using TouchSocket.Resources; + +namespace TouchSocket.Core +{ + /// + /// 文件池。 + /// + public static class FilePool + { + private static readonly object m_locker = new object(); + + private static readonly ConcurrentDictionary m_pathStorage = new ConcurrentDictionary(); + + private static readonly Timer m_timer; + + static FilePool() + { + m_timer = new Timer(OnTimer, null, 60000, 60000); + } + + /// + /// 获取所有的路径。 + /// + /// + public static string[] GetAllPaths() + { + return m_pathStorage.Keys.ToArray(); + } + + /// + /// 加载文件为读取流 + /// + /// + /// + /// + /// + public static FileStorage GetFileStorageForRead(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new System.ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); + } + return GetFileStorageForRead(new FileInfo(path)); + } + + /// + /// 加载文件为读取流 + /// + /// + /// + /// + public static FileStorage GetFileStorageForRead(FileInfo fileInfo) + { + if (m_pathStorage.TryGetValue(fileInfo.FullName, out FileStorage storage)) + { + if (storage.FileAccess != FileAccess.Read) + { + throw new Exception("该路径的文件已经被加载为仅写入模式。"); + } + Interlocked.Increment(ref storage.m_reference); + return storage; + } + lock (m_locker) + { + if (m_pathStorage.TryGetValue(fileInfo.FullName, out storage)) + { + return storage; + } + FileStorage fileStorage = new FileStorage(fileInfo, FileAccess.Read); + m_pathStorage.TryAdd(fileInfo.FullName, fileStorage); + return fileStorage; + } + } + + /// + /// 加载文件为写流 + /// + /// + /// + /// + /// + public static FileStorage GetFileStorageForWrite(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); + } + return GetFileStorageForWrite(new FileInfo(path)); + } + + /// + /// 加载文件为写流 + /// + /// + /// + /// + /// + public static FileStorage GetFileStorageForWrite(FileInfo fileInfo) + { + if (m_pathStorage.TryGetValue(fileInfo.FullName, out FileStorage storage)) + { + if (storage.FileAccess != FileAccess.Write) + { + throw new Exception("该路径的文件已经被加载为仅读取模式。"); + } + Interlocked.Increment(ref storage.m_reference); + return storage; + } + lock (m_locker) + { + if (m_pathStorage.TryGetValue(fileInfo.FullName, out storage)) + { + return storage; + } + FileStorage fileStorage = new FileStorage(fileInfo, FileAccess.Write); + m_pathStorage.TryAdd(fileInfo.FullName, fileStorage); + return fileStorage; + } + } + + /// + /// 获取一个可读可写的Stream对象。 + /// + /// + /// + /// + /// + public static FileStorageStream GetFileStorageStream(string path) + { + return new FileStorageStream(GetFileStorageForWrite(path)); + } + + /// + /// 获取一个可读可写的Stream对象。 + /// + /// + /// + /// + /// + public static FileStorageStream GetFileStorageStream(FileInfo fileInfo) + { + return new FileStorageStream(GetFileStorageForWrite(fileInfo)); + } + + /// + /// 获取一个文件读取访问器 + /// + /// + /// + /// + /// + public static FileStorageReader GetReader(string path) + { + return new FileStorageReader(GetFileStorageForRead(path)); + } + + /// + /// 获取一个文件读取访问器 + /// + /// + /// + /// + /// + public static FileStorageReader GetReader(FileInfo fileInfo) + { + return new FileStorageReader(GetFileStorageForRead(fileInfo)); + } + + /// + /// 获取引用次数。 + /// + /// 必须是全路径。 + /// + /// + /// + public static int GetReferenceCount(string path) + { + if (string.IsNullOrEmpty(path)) + { + return 0; + } + if (m_pathStorage.TryGetValue(path, out FileStorage fileStorage)) + { + return fileStorage.m_reference; + } + return 0; + } + + /// + /// 获取一个文件写入访问器 + /// + /// 路径 + /// + /// + /// + public static FileStorageWriter GetWriter(string path) + { + return new FileStorageWriter(GetFileStorageForWrite(path)); + } + + /// + /// 获取一个文件写入访问器 + /// + /// + /// + /// + /// + public static FileStorageWriter GetWriter(FileInfo fileInfo) + { + return new FileStorageWriter(GetFileStorageForWrite(fileInfo)); + } + + /// + /// 加载文件为缓存读取流 + /// + /// + /// + /// + /// + public static void LoadFileForCacheRead(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new System.ArgumentException($"“{nameof(path)}”不能为 null 或空。", nameof(path)); + } + + path = Path.GetFullPath(path); + if (m_pathStorage.TryGetValue(path, out FileStorage storage)) + { + if (storage.FileAccess != FileAccess.Read || !storage.Cache) + { + throw new Exception("该路径的文件已经被加载为其他模式。"); + } + return; + } + if (FileStorage.TryCreateCacheFileStorage(path, out FileStorage fileStorage, out string msg)) + { + m_pathStorage.TryAdd(path, fileStorage); + } + else + { + throw new Exception(msg); + } + } + + /// + /// 减少引用次数,并尝试释放流。 + /// + /// + /// 延迟释放时间。当设置为0时,立即释放,单位毫秒。 + /// + /// + /// + public static Result TryReleaseFile(string path, int delayTime = 0) + { + if (string.IsNullOrEmpty(path)) + { + return new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(path))); + } + path = Path.GetFullPath(path); + if (m_pathStorage.TryGetValue(path, out FileStorage fileStorage)) + { + Interlocked.Decrement(ref fileStorage.m_reference); + if (fileStorage.m_reference <= 0) + { + if (delayTime > 0) + { + EasyTask.DelayRun(delayTime, path, (p) => + { + if (GetReferenceCount(p) == 0) + { + if (m_pathStorage.TryRemove((string)p, out fileStorage)) + { + fileStorage.Dispose(); + } + } + }); + return new Result(ResultCode.Success, $"如果在{delayTime}ms后引用仍然为0的话,即被释放。"); + } + else + { + if (m_pathStorage.TryRemove(path, out fileStorage)) + { + fileStorage.Dispose(); + } + return new Result(ResultCode.Success, "流成功释放。"); + } + } + else + { + return new Result(ResultCode.Error, TouchSocketStatus.StreamReferencing.GetDescription(path, fileStorage.m_reference)); + } + } + else + { + return new Result(ResultCode.Success, TouchSocketStatus.StreamNotFind.GetDescription(path)); + } + } + + private static void OnTimer(object state) + { + List keys = new List(); + foreach (var item in m_pathStorage) + { + if (DateTime.Now - item.Value.AccessTime > item.Value.AccessTimeout) + { + keys.Add(item.Key); + } + } + foreach (var item in keys) + { + TryReleaseFile(item); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/FileIO/FileStorage.cs b/src/TouchSocket/Core/IO/FileIO/FileStorage.cs new file mode 100644 index 000000000..bf651dfbd --- /dev/null +++ b/src/TouchSocket/Core/IO/FileIO/FileStorage.cs @@ -0,0 +1,229 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using TouchSocket.Resources; + +namespace TouchSocket.Core +{ + /// + /// 文件存储器。在该存储器中,读写线程安全。 + /// + public class FileStorage + { + internal volatile int m_reference; + private readonly ReaderWriterLockSlim m_lockSlim; + private bool m_disposedValue; + private byte[] m_fileData; + + /// + /// 初始化一个文件存储器。在该存储器中,读写线程安全。 + /// + internal FileStorage(FileInfo fileInfo, FileAccess fileAccess) : this() + { + FileAccess = fileAccess; + FileInfo = fileInfo; + Path = fileInfo.FullName; + m_reference = 0; + FileStream = fileAccess == FileAccess.Read ? fileInfo.OpenRead() : fileInfo.OpenWrite(); + m_lockSlim = new ReaderWriterLockSlim(); + } + + private FileStorage() + { + AccessTime = DateTime.Now; + AccessTimeout = TimeSpan.FromSeconds(60); + } + + /// + /// 最后访问时间。 + /// + public DateTime AccessTime { get; private set; } + + /// + /// 访问超时时间。默认10s + /// + public TimeSpan AccessTimeout { get; set; } + + /// + /// 是否为缓存型。为false时,意味着该文件句柄正在被该程序占用。 + /// + public bool Cache { get; private set; } + + /// + /// 访问属性 + /// + public FileAccess FileAccess { get; private set; } + + /// + /// 文件信息 + /// + public FileInfo FileInfo { get; private set; } + + /// + /// 文件流。 + /// 一般情况下,请不要直接访问该对象。否则有可能会产生不可预测的错误。 + /// + public FileStream FileStream { get; private set; } + + /// + /// 文件长度 + /// + public long Length => FileStream.Length; + + /// + /// 文件路径 + /// + public string Path { get; private set; } + + /// + /// 引用次数。 + /// + public int Reference => m_reference; + + /// + /// 创建一个只读的、已经缓存的文件信息。该操作不会占用文件句柄。 + /// + /// + /// + /// + /// + public static bool TryCreateCacheFileStorage(string path, out FileStorage fileStorage, out string msg) + { + path = System.IO.Path.GetFullPath(path); + if (!File.Exists(path)) + { + fileStorage = null; + msg = TouchSocketStatus.FileNotExists.GetDescription(path); + return false; + } + try + { + fileStorage = new FileStorage() + { + Cache = true, + FileAccess = FileAccess.Read, + FileInfo = new FileInfo(path), + Path = path, + m_reference = 0, + m_fileData = File.ReadAllBytes(path) + }; + msg = null; + return true; + } + catch (Exception ex) + { + fileStorage = null; + msg = ex.Message; + return false; + } + } + + /// + /// 写入时清空缓存区 + /// + public void Flush() + { + AccessTime = DateTime.Now; + FileStream.Flush(); + } + + /// + /// 从指定位置,读取数据到缓存区。线程安全。 + /// + /// + /// + /// + /// + /// + public int Read(long stratPos, byte[] buffer, int offset, int length) + { + AccessTime = DateTime.Now; + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + if (m_disposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (FileAccess == FileAccess.Write) + { + throw new Exception("该流不允许读取。"); + } + if (Cache) + { + int r = (int)Math.Min(m_fileData.Length - stratPos, length); + Array.Copy(m_fileData, stratPos, buffer, offset, r); + return r; + } + else + { + FileStream.Position = stratPos; + return FileStream.Read(buffer, offset, length); + } + } + } + + /// + /// 减少引用次数,并尝试释放流。 + /// + /// 延迟释放时间。当设置为0时,立即释放,单位毫秒。 + /// + /// + /// + public Result TryReleaseFile(int delayTime = 0) + { + return FilePool.TryReleaseFile(Path, delayTime); + } + + /// + /// 从指定位置,写入数据到存储区。线程安全。 + /// + /// + /// + /// + /// + public void Write(long stratPos, byte[] buffer, int offset, int length) + { + AccessTime = DateTime.Now; + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + if (m_disposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (FileAccess == FileAccess.Read) + { + throw new Exception("该流不允许写入。"); + } + FileStream.Position = stratPos; + FileStream.Write(buffer, offset, length); + FileStream.Flush(); + } + } + + internal void Dispose() + { + if (m_disposedValue) + { + return; + } + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + m_disposedValue = true; + FileStream.SafeDispose(); + m_fileData = null; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/FileIO/FileStorageReader.cs b/src/TouchSocket/Core/IO/FileIO/FileStorageReader.cs new file mode 100644 index 000000000..49cf786f3 --- /dev/null +++ b/src/TouchSocket/Core/IO/FileIO/FileStorageReader.cs @@ -0,0 +1,91 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 文件读取器 + /// + public class FileStorageReader : DisposableObject + { + private FileStorage m_fileStorage; + + private long m_position; + + /// + /// 构造函数 + /// + /// + public FileStorageReader(FileStorage fileStorage) + { + m_fileStorage = fileStorage ?? throw new System.ArgumentNullException(nameof(fileStorage)); + } + + /// + /// 析构函数 + /// + ~FileStorageReader() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + + /// + /// 文件存储器 + /// + public FileStorage FileStorage => m_fileStorage; + + /// + /// 游标位置 + /// + public int Pos + { + get => (int)m_position; + set => m_position = value; + } + + /// + /// 游标位置 + /// + public long Position + { + get => m_position; + set => m_position = value; + } + + /// + /// 读取数据到缓存区 + /// + /// + /// + /// + /// + public int Read(byte[] buffer, int offset, int length) + { + int r = m_fileStorage.Read(m_position, buffer, offset, length); + m_position += r; + return r; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + FilePool.TryReleaseFile(m_fileStorage.Path); + m_fileStorage = null; + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/FileIO/FileStorageStream.cs b/src/TouchSocket/Core/IO/FileIO/FileStorageStream.cs new file mode 100644 index 000000000..9f35a8ac1 --- /dev/null +++ b/src/TouchSocket/Core/IO/FileIO/FileStorageStream.cs @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; + +namespace TouchSocket.Core +{ + /// + /// FileStorageStream。非线程安全。 + /// + public class FileStorageStream : Stream + { + private readonly FileStorage m_fileStorage; + private long m_position; + + /// + /// 构造函数 + /// + /// + public FileStorageStream(FileStorage fileStorage) + { + m_fileStorage = fileStorage ?? throw new System.ArgumentNullException(nameof(fileStorage)); + } + + /// + /// 析构函数 + /// + ~FileStorageStream() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + + /// + /// + /// + public override bool CanRead => m_fileStorage.FileStream.CanRead; + + /// + /// + /// + public override bool CanSeek => m_fileStorage.FileStream.CanSeek; + + /// + /// + /// + public override bool CanWrite => m_fileStorage.FileStream.CanWrite; + + /// + /// 文件存储器 + /// + public FileStorage FileStorage => m_fileStorage; + + /// + /// + /// + public override long Length => m_fileStorage.FileStream.Length; + + /// + /// + /// + public override long Position { get => m_position; set => m_position = value; } + + /// + /// + /// + public override void Flush() + { + m_fileStorage.Flush(); + } + + /// + /// + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + int r = m_fileStorage.Read(m_position, buffer, offset, count); + m_position += r; + return r; + } + + /// + /// + /// + /// + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + m_position = offset; + break; + + case SeekOrigin.Current: + m_position += offset; + break; + + case SeekOrigin.End: + m_position = Length + offset; + break; + } + return m_position; + } + + /// + /// + /// + /// + public override void SetLength(long value) + { + m_fileStorage.FileStream.SetLength(value); + } + + /// + /// + /// + /// + /// + /// + public override void Write(byte[] buffer, int offset, int count) + { + m_fileStorage.Write(m_position, buffer, offset, count); + m_position += count; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + FilePool.TryReleaseFile(m_fileStorage.Path); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs b/src/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs new file mode 100644 index 000000000..5d9d993cd --- /dev/null +++ b/src/TouchSocket/Core/IO/FileIO/FileStorageWriter.cs @@ -0,0 +1,106 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 文件写入器。 + /// + public class FileStorageWriter : DisposableObject, IWrite + { + private readonly FileStorage m_fileStorage; + private long m_position; + + /// + /// 构造函数 + /// + /// + public FileStorageWriter(FileStorage fileStorage) + { + m_fileStorage = fileStorage ?? throw new System.ArgumentNullException(nameof(fileStorage)); + } + + /// + /// + /// + /// + public virtual void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// 析构函数 + /// + ~FileStorageWriter() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + + /// + /// 文件存储器 + /// + public FileStorage FileStorage => m_fileStorage; + + /// + /// 游标位置 + /// + public int Pos + { + get => (int)m_position; + set => m_position = value; + } + + /// + /// 游标位置 + /// + public long Position + { + get => m_position; + set => m_position = value; + } + + /// + /// 移动Pos到流末尾 + /// + /// + public long SeekToEnd() + { + return Position = FileStorage.Length; + } + + /// + /// 读取数据到缓存区 + /// + /// + /// + /// + /// + public void Write(byte[] buffer, int offset, int length) + { + m_fileStorage.Write(m_position, buffer, offset, length); + m_position += length; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + FilePool.TryReleaseFile(m_fileStorage.Path); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/FileUtility.cs b/src/TouchSocket/Core/IO/FileUtility.cs new file mode 100644 index 000000000..fcc8278ba --- /dev/null +++ b/src/TouchSocket/Core/IO/FileUtility.cs @@ -0,0 +1,312 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security.Cryptography; + +namespace TouchSocket.Core +{ + /// + /// 文件操作 + /// + public static class FileUtility + { + /// + /// 获取不重复文件名。 + /// 例如:New.txt已存在时,会返回New(1).txt + /// + /// + /// + public static string GetDuplicateFileName(string fileName) + { + if (!File.Exists(fileName)) + { + return fileName; + } + + int index = 0; + while (true) + { + index++; + string newPath = Path.Combine(Path.GetDirectoryName(fileName), $"{Path.GetFileNameWithoutExtension(fileName)}({index}){Path.GetExtension(fileName)}"); + if (!File.Exists(newPath)) + { + return newPath; + } + } + } + + /// + /// 获取不重复文件夹名称. + /// 例如:NewDir已存在时,会返回NewDir(1) + /// + /// + /// + public static string GetDuplicateDirectoryName(string dirName) + { + if (!Directory.Exists(dirName)) + { + return dirName; + } + + int index = 0; + while (true) + { + index++; + string newPath = Path.Combine(Path.GetDirectoryName(dirName), $"{Path.GetFileNameWithoutExtension(dirName)}({index})"); + if (!System.IO.Directory.Exists(newPath)) + { + return newPath; + } + } + } + + /// + /// 转化为文件大小的字符串,类似10B,10Kb,10Mb,10Gb。 + /// + /// + /// + public static string ToFileLengthString(long length) + { + if (length < 1024) + { + return $"{length}B"; + } + else if (length < 1024 * 1024) + { + return $"{(length / 1024.0).ToString("0.00")}Kb"; + } + else if (length < 1024 * 1024 * 1024) + { + return $"{(length / (1024.0 * 1024)).ToString("0.00")}Mb"; + } + else + { + return $"{(length / (1024.0 * 1024 * 1024)).ToString("0.00")}Gb"; + } + } + + /// + /// 获取文件MD5 + /// + /// + /// + public static string GetFileMD5(string path) + { + using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + return GetStreamMD5(fileStream); + } + } + + /// + /// 获取流MD5 + /// + /// + /// + public static string GetStreamMD5(Stream fileStream) + { + using (HashAlgorithm hash = System.Security.Cryptography.MD5.Create()) + { + return GetStreamHash(fileStream, hash); + } + } + + /// + /// 获得文件Hash值 + /// + /// 文件路径 + /// + public static string GetFileHash256(string filePath) + { + try + { + HashAlgorithm hash = SHA256.Create(); + using (FileStream fileStream = File.OpenRead(filePath)) + { + byte[] HashValue = hash.ComputeHash(fileStream); + return BitConverter.ToString(HashValue).Replace("-", ""); + } + } + catch + { + return null; + } + } + + /// + /// 获得流Hash值 + /// + /// + /// + public static string GetStreamHash256(Stream stream) + { + try + { + HashAlgorithm hash = SHA256.Create(); + byte[] HashValue = hash.ComputeHash(stream); + return BitConverter.ToString(HashValue).Replace("-", ""); + } + catch + { + return null; + } + } + + /// + /// 获得文件Hash值 + /// + /// 文件路径 + /// + /// + public static string GetFileHash(string filePath, HashAlgorithm hash) + { + try + { + using (FileStream fileStream = File.OpenRead(filePath)) + { + byte[] HashValue = hash.ComputeHash(fileStream); + return BitConverter.ToString(HashValue).Replace("-", ""); + } + } + catch + { + return null; + } + } + + /// + /// 获得流Hash值 + /// + /// + /// + /// + public static string GetStreamHash(Stream stream, HashAlgorithm hash) + { + try + { + byte[] HashValue = hash.ComputeHash(stream); + return BitConverter.ToString(HashValue).Replace("-", ""); + } + catch + { + return null; + } + } + + /// + /// 获取仅当前文件夹中包含的文件名称,不含全路径。 + /// + /// + /// + public static string[] GetIncludeFileNames(string dirPath) + { + return Directory.GetFiles(dirPath).Select(s => Path.GetFileName(s)).ToArray(); + } + + /// + /// 获取相对路径。 + /// + /// + /// + /// + /// + public static string GetRelativePath(string relativeTo, string path) + { + if (string.IsNullOrEmpty(relativeTo)) throw new ArgumentNullException(nameof(relativeTo)); + if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path)); + + var fromUri = new Uri(relativeTo); + var toUri = new Uri(path); + + if (fromUri.Scheme != toUri.Scheme) + { + // 不是同一种路径,无法转换成相对路径。 + return path; + } + + if (fromUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase) + && !relativeTo.EndsWith("/", StringComparison.OrdinalIgnoreCase) + && !relativeTo.EndsWith("\\", StringComparison.OrdinalIgnoreCase)) + { + // 如果是文件系统,则视来源路径为文件夹。 + fromUri = new Uri(relativeTo + Path.DirectorySeparatorChar); + } + + var relativeUri = fromUri.MakeRelativeUri(toUri); + var relativePath = Uri.UnescapeDataString(relativeUri.ToString()); + + if (toUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase)) + { + relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + } + + return relativePath; + } + + /// + /// 删除路径文件 + /// + /// + public static void Delete(string path) + { + if (File.Exists(path)) + { + File.SetAttributes(path, FileAttributes.Normal); + File.Delete(path); + } + } + +# if NET45_OR_GREATER + + [DllImport("kernel32.dll")] + private static extern IntPtr _lopen(string lpPathName, int iReadWrite); + + [DllImport("kernel32.dll")] + private static extern bool CloseHandle(IntPtr hObject); + + private const int OF_READWRITE = 2; + + private const int OF_SHARE_DENY_NONE = 0x40; + + private static readonly IntPtr HFILE_ERROR = new IntPtr(-1); + + /// + /// 判断文件是否被已打开 + /// + /// + /// + public static bool FileIsOpen(string fileFullName) + { + if (!File.Exists(fileFullName)) + { + return false; + } + + IntPtr handle = _lopen(fileFullName, OF_READWRITE | OF_SHARE_DENY_NONE); + + if (handle == HFILE_ERROR) + { + return true; + } + + CloseHandle(handle); + + return false; + } + +#endif + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/IO/WrapStream.cs b/src/TouchSocket/Core/IO/WrapStream.cs new file mode 100644 index 000000000..6199a28c5 --- /dev/null +++ b/src/TouchSocket/Core/IO/WrapStream.cs @@ -0,0 +1,124 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; + +namespace TouchSocket.Core +{ + /// + /// 包装的流。为避免该流释放时,内部流也会被释放的问题 + /// + public class WrapStream : Stream + { + private readonly Stream m_stream; + + /// + /// 包装的流。为避免该流释放时,内部流也会被释放的问题 + /// + /// + public WrapStream(Stream stream) + { + m_stream = stream; + } + + /// + /// + /// + public override bool CanRead => m_stream.CanRead; + + /// + /// + /// + public override bool CanSeek => m_stream.CanSeek; + + /// + /// + /// + public override bool CanWrite => m_stream.CanWrite; + + /// + /// + /// + public override long Length => m_stream.Length; + + /// + /// + /// + public override long Position { get => m_stream.Position; set => m_stream.Position = value; } + + /// + /// + /// + public override void Flush() + { + m_stream.Flush(); + } + + /// + /// + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + return m_stream.Read(buffer, offset, count); + } + + /// + /// + /// + /// + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + return m_stream.Seek(offset, origin); + } + + /// + /// + /// + /// + public override void SetLength(long value) + { + m_stream.SetLength(value); + } + + /// + /// + /// + /// + /// + /// + public override void Write(byte[] buffer, int offset, int count) + { + m_stream.Write(buffer, offset, count); + } + + /// + /// 没有关闭效果 + /// + public override void Close() + { + } + + /// + /// 没有释放效果 + /// + /// + protected override void Dispose(bool disposing) + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/ConsoleLogger.cs b/src/TouchSocket/Core/Logger/ConsoleLogger.cs new file mode 100644 index 000000000..a39ff7eed --- /dev/null +++ b/src/TouchSocket/Core/Logger/ConsoleLogger.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 控制台日志记录器 + /// + public class ConsoleLogger : LoggerBase + { + static ConsoleLogger() + { + Default = new ConsoleLogger(); + } + private readonly ConsoleColor m_consoleBackgroundColor; + + private readonly ConsoleColor m_consoleForegroundColor; + + /// + /// 初始化一个日志记录器 + /// + public ConsoleLogger() + { + m_consoleForegroundColor = Console.ForegroundColor; + m_consoleBackgroundColor = Console.BackgroundColor; + } + + /// + /// 默认的实例 + /// + public static ConsoleLogger Default { get; } + + /// + /// + /// + /// + /// + /// + /// + protected override void WriteLog(LogType logType, object source, string message, Exception exception) + { + lock (typeof(ConsoleLogger)) + { + Console.Write(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")); + Console.Write(" | "); + switch (logType) + { + case LogType.Warning: + Console.ForegroundColor = ConsoleColor.Yellow; + break; + + case LogType.Error: + Console.ForegroundColor = ConsoleColor.Red; + break; + + case LogType.Info: + default: + Console.ForegroundColor = m_consoleForegroundColor; + break; + } + Console.Write(logType.ToString()); + Console.ForegroundColor = m_consoleForegroundColor; + Console.Write(" | "); + Console.Write(message); + + if (exception != null) + { + Console.Write(" | "); + Console.Write($"【异常消息】:{exception.Message}"); + Console.Write($"【堆栈】:{(exception == null ? "未知" : exception.StackTrace)}"); + } + Console.WriteLine(); + + Console.ForegroundColor = m_consoleForegroundColor; + Console.BackgroundColor = m_consoleBackgroundColor; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/EasyLogger.cs b/src/TouchSocket/Core/Logger/EasyLogger.cs new file mode 100644 index 000000000..7be80a12c --- /dev/null +++ b/src/TouchSocket/Core/Logger/EasyLogger.cs @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// 快捷日志 + /// + public class EasyLogger : LoggerBase + { + private readonly Action m_action; + private readonly Action m_action1; + + /// + /// 构造函数 + /// + /// 参数依次为:日志类型,触发源,消息,异常 + public EasyLogger(Action action) + { + m_action = action; + } + + /// + /// 构造函数 + /// + /// 参数为日志消息输出。 + public EasyLogger(Action action) + { + m_action1 = action; + } + + /// + /// + /// + /// + /// + /// + /// + protected override void WriteLog(LogType logType, object source, string message, Exception exception) + { + try + { + if (m_action != null) + { + m_action.Invoke(logType, source, message, exception); + return; + } + if (m_action1 != null) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")); + stringBuilder.Append(" | "); + stringBuilder.Append(logType.ToString()); + stringBuilder.Append(" | "); + stringBuilder.Append(message); + + if (exception != null) + { + stringBuilder.Append(" | "); + stringBuilder.Append($"【异常消息】:{exception.Message}"); + stringBuilder.Append($"【堆栈】:{(exception == null ? "未知" : exception.StackTrace)}"); + } + stringBuilder.AppendLine(); + m_action1.Invoke(stringBuilder.ToString()); + return; + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/FileLogger.cs b/src/TouchSocket/Core/Logger/FileLogger.cs new file mode 100644 index 000000000..231aec7a9 --- /dev/null +++ b/src/TouchSocket/Core/Logger/FileLogger.cs @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// 文件日志记录器 + /// 会在指定目录下,生成logs文件夹,然后按[yyyy-MM-dd].log的形式,每日生成日志 + /// + public class FileLogger : LoggerBase + { + private static string m_rootPath; + + /// + /// 构造函数 + /// + /// 日志根目录 + public FileLogger(string rootPath = null) + { + lock (typeof(FileLogger)) + { + rootPath ??= AppDomain.CurrentDomain.BaseDirectory; + + if (m_rootPath.IsNullOrEmpty()) + { + m_rootPath = Path.Combine(rootPath, "logs"); + } + else if (m_rootPath != Path.Combine(rootPath, "logs")) + { + throw new Exception($"{GetType().Name}无法指向不同的根路径。"); + } + } + } + + /// + /// + /// + /// + /// + /// + /// + protected override void WriteLog(LogType logType, object source, string message, Exception exception) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")); + stringBuilder.Append(" | "); + stringBuilder.Append(logType.ToString()); + stringBuilder.Append(" | "); + stringBuilder.Append(message); + + if (exception != null) + { + stringBuilder.Append(" | "); + stringBuilder.Append($"【异常消息】:{exception.Message}"); + stringBuilder.Append($"【堆栈】:{(exception == null ? "未知" : exception.StackTrace)}"); + } + stringBuilder.AppendLine(); + + Print(stringBuilder.ToString()); + } + + private static FileStorageWriter m_writer; + + private void Print(string logString) + { + try + { + lock (typeof(FileLogger)) + { + string dir = Path.Combine(m_rootPath, DateTime.Now.ToString("[yyyy-MM-dd]")); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + if (m_writer == null) + { + int count = 0; + string path = null; + while (true) + { + path = Path.Combine(dir, $"{count:0000}" + ".log"); + if (!File.Exists(path)) + { + m_writer = FilePool.GetWriter(path); + break; + } + count++; + } + } + m_writer.Write(Encoding.UTF8.GetBytes(logString)); + if (m_writer.FileStorage.Length > 1024 * 1024) + { + m_writer.SafeDispose(); + m_writer = null; + } + } + } + catch + { + m_writer.SafeDispose(); + m_writer = null; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/ILog.cs b/src/TouchSocket/Core/Logger/ILog.cs new file mode 100644 index 000000000..b7c08867c --- /dev/null +++ b/src/TouchSocket/Core/Logger/ILog.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// 日志接口 + /// + public interface ILog + { + /// + /// 日志输出类型。 + /// 当的类型,在该设置之内时,才会真正输出日志。 + /// + LogType LogType { get; set; } + + /// + /// 日志记录 + /// + /// + /// + /// + /// + void Log(LogType logType, object source, string message, Exception exception); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/LogType.cs b/src/TouchSocket/Core/Logger/LogType.cs new file mode 100644 index 000000000..a9d22fc96 --- /dev/null +++ b/src/TouchSocket/Core/Logger/LogType.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 日志类型。 + /// + public enum LogType + { + /// + /// 不使用日志类输出 + /// + None = 0, + + /// + /// 更为详细的步骤型日志输出 + /// + Trace = 1, + + /// + /// 调试信息日志 + /// + Debug = 2, + + /// + /// 消息类日志输出 + /// + Info = 4, + + /// + /// 警告类日志输出 + /// + Warning = 8, + + /// + /// 错误类日志输出 + /// + Error = 16, + + /// + /// 不可控中断类日输出 + /// + Critical = 32 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/LoggerBase.cs b/src/TouchSocket/Core/Logger/LoggerBase.cs new file mode 100644 index 000000000..9ee66d29b --- /dev/null +++ b/src/TouchSocket/Core/Logger/LoggerBase.cs @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 日志基类 + /// + public abstract class LoggerBase : ILog + { + /// + /// 全部的日志类型 + /// + public const LogType All = LogType.None | LogType.Trace | LogType.Debug | LogType.Info | LogType.Warning | LogType.Error | LogType.Critical; + + /// + /// 日志基类 + /// + protected LoggerBase() + { + LogType = All; + } + + /// + /// + /// + public LogType LogType { get; set; } + + /// + /// + /// + /// + /// + /// + /// + public void Log(LogType logType, object source, string message, Exception exception) + { + if (LogType.HasFlag(logType)) + { + WriteLog(logType, source, message, exception); + } + } + + /// + /// 筛选日志后输出 + /// + /// + /// + /// + /// + protected abstract void WriteLog(LogType logType, object source, string message, Exception exception); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/LoggerContainerExtension.cs b/src/TouchSocket/Core/Logger/LoggerContainerExtension.cs new file mode 100644 index 000000000..4a836d6e7 --- /dev/null +++ b/src/TouchSocket/Core/Logger/LoggerContainerExtension.cs @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Core +{ + /// + /// LoggerContainerExtension + /// + public static class LoggerContainerExtension + { + /// + /// 设置日志。 + /// + /// + /// + /// + public static IContainer SetLogger(this IContainer container) + where TLogger : class, ILog + { + container.RegisterTransient(); + return container; + } + + /// + /// 设置单例日志。 + /// + /// + /// + /// + public static IContainer SetSingletonLogger(this IContainer container) where TLogger : class, ILog + { + container.RegisterSingleton(); + return container; + } + + /// + /// 设置实例日志。 + /// + /// + /// + /// + /// + public static IContainer SetSingletonLogger(this IContainer container, TLogger logger) where TLogger : class, ILog + { + container.RegisterSingleton(logger); + return container; + } + + /// + /// 添加控制台日志到日志组。 + /// + /// + /// + public static IContainer AddConsoleLogger(this IContainer container) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(new ConsoleLogger()); + return container; + } + + /// + /// 添加委托日志到日志组。 + /// + /// + /// + /// + public static IContainer AddEasyLogger(this IContainer container, Action action) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(new EasyLogger(action)); + return container; + } + + /// + /// 添加委托日志到日志组。 + /// + /// + /// + /// + public static IContainer AddEasyLogger(this IContainer container, Action action) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(new EasyLogger(action)); + return container; + } + + /// + /// 添加文件日志到日志组。 + /// + /// + /// + /// + public static IContainer AddFileLogger(this IContainer container, string rootPath = null) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(new FileLogger(rootPath)); + return container; + } + + /// + /// 添加日志到日志组。 + /// + /// + /// + /// + public static IContainer AddLogger(this IContainer container, ILog logger) + { + LoggerGroup loggerGroup = (LoggerGroup)container.Resolve(); + loggerGroup.AddLogger(logger); + return container; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/LoggerExtensions.cs b/src/TouchSocket/Core/Logger/LoggerExtensions.cs new file mode 100644 index 000000000..5b47e5fae --- /dev/null +++ b/src/TouchSocket/Core/Logger/LoggerExtensions.cs @@ -0,0 +1,274 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// + /// + public static class LoggerExtensions + { + #region LoggerGroup日志 + + /// + /// 指定在中的特定日志类型中输出中断日志 + /// + /// + /// + public static void Critical(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Critical, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出调试日志 + /// + /// + /// + public static void Debug(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Debug, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出错误日志 + /// + /// + /// + public static void Error(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Error, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出错误日志 + /// + /// + /// + /// + public static void Error(this ILog logger, object source, string msg) where TLog : ILog + { + logger.Log(LogType.Error, source, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出异常日志 + /// + /// + /// + public static void Exception(this ILog logger, Exception ex) where TLog : ILog + { + logger.Log(LogType.Error, null, ex.Message, ex); + } + + /// + /// 指定在中的特定日志类型中输出异常日志 + /// + /// + /// + /// + public static void Exception(this ILog logger, object source, Exception ex) where TLog : ILog + { + logger.Log(LogType.Error, source, ex.Message, ex); + } + + /// + /// 指定在中的特定日志类型中输出消息日志 + /// + /// + /// + public static void Info(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Info, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出消息日志 + /// + /// + /// + /// + public static void Info(this ILog logger, object source, string msg) where TLog : ILog + { + logger.Log(LogType.Info, source, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出日志 + /// + /// + /// + /// + /// + /// + public static void Log(this ILog logger, LogType logType, object source, string message, Exception exception) where TLog : ILog + { + if (logger is LoggerGroup loggerGroup) + { + loggerGroup.Log(logType, source, message, exception); + } + } + + /// + /// 指定在中的特定日志类型中输出详细日志 + /// + /// + /// + public static void Trace(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Trace, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出警示日志 + /// + /// + /// + public static void Warning(this ILog logger, string msg) where TLog : ILog + { + logger.Log(LogType.Warning, null, msg, null); + } + + /// + /// 指定在中的特定日志类型中输出警示日志 + /// + /// + /// + /// + public static void Warning(this ILog logger, object source, string msg) where TLog : ILog + { + logger.Log(LogType.Warning, source, msg, null); + } + + #endregion LoggerGroup日志 + + #region 日志 + + /// + /// 输出中断日志 + /// + /// + /// + public static void Critical(this ILog logger, string msg) + { + logger.Log(LogType.Critical, null, msg, null); + } + + /// + /// 输出调试日志 + /// + /// + /// + public static void Debug(this ILog logger, string msg) + { + logger.Log(LogType.Debug, null, msg, null); + } + + /// + /// 输出错误日志 + /// + /// + /// + public static void Error(this ILog logger, string msg) + { + logger.Log(LogType.Error, null, msg, null); + } + + /// + /// 输出错误日志 + /// + /// + /// + /// + public static void Error(this ILog logger, object source, string msg) + { + logger.Log(LogType.Error, source, msg, null); + } + + /// + /// 输出异常日志 + /// + /// + /// + public static void Exception(this ILog logger, Exception ex) + { + logger.Log(LogType.Error, null, ex.Message, ex); + } + + /// + /// 输出异常日志 + /// + /// + /// + /// + public static void Exception(this ILog logger, object source, Exception ex) + { + logger.Log(LogType.Error, source, ex.Message, ex); + } + + /// + /// 输出消息日志 + /// + /// + /// + public static void Info(this ILog logger, string msg) + { + logger.Log(LogType.Info, null, msg, null); + } + + /// + /// 输出消息日志 + /// + /// + /// + /// + public static void Info(this ILog logger, object source, string msg) + { + logger.Log(LogType.Info, source, msg, null); + } + + /// + /// 输出详细日志 + /// + /// + /// + public static void Trace(this ILog logger, string msg) + { + logger.Log(LogType.Trace, null, msg, null); + } + + /// + /// 输出警示日志 + /// + /// + /// + public static void Warning(this ILog logger, string msg) + { + logger.Log(LogType.Warning, null, msg, null); + } + + /// + /// 输出警示日志 + /// + /// + /// + /// + public static void Warning(this ILog logger, object source, string msg) + { + logger.Log(LogType.Warning, source, msg, null); + } + + #endregion 日志 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Logger/LoggerGroup.cs b/src/TouchSocket/Core/Logger/LoggerGroup.cs new file mode 100644 index 000000000..f3745f3f6 --- /dev/null +++ b/src/TouchSocket/Core/Logger/LoggerGroup.cs @@ -0,0 +1,252 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Core +{ + /// + /// 一组日志记录器 + /// + public class LoggerGroup : LoggerBase + { + private readonly Dictionary m_logs = new Dictionary(); + + /// + /// 一组日志记录器 + /// + /// + public LoggerGroup(params ILog[] logs) + { + if (logs is null) + { + throw new ArgumentNullException(nameof(logs)); + } + foreach (var log in logs) + { + this.AddLogger(log); + } + } + + /// + /// 一组日志记录器 + /// + [DependencyInject] + public LoggerGroup() + { + } + + /// + /// 组内的日志记录器 + /// + public ILog[] Logs => m_logs.Values.ToArray(); + + /// + /// 添加日志组件 + /// + /// + /// + public void AddLogger(string key, ILog logger) + { + m_logs.Add(key, logger); + } + + /// + /// 添加日志组件 + /// + /// + public void AddLogger(ILog logger) + { + m_logs.Add(logger.GetType().FullName, logger); + } + + /// + /// 指定输出中的特定类型的日志 + /// + /// + /// + /// + /// + public void Log(LogType logType, object source, string message, Exception exception) where TLog : ILog + { + try + { + for (int i = 0; i < m_logs.Count; i++) + { + ILog log = Logs[i]; + if (log.GetType() == typeof(TLog)) + { + log.Log(logType, source, message, exception); + } + } + } + catch + { + } + } + + /// + /// 移除日志 + /// + /// + public bool RemoveLogger(ILog logger) + { + return this.RemoveLogger(logger.GetType().FullName); + } + + /// + /// 移除日志 + /// + public bool RemoveLogger(Type loggerType) + { + return this.RemoveLogger(loggerType.FullName); + } + + /// + /// 移除对应键的日志 + /// + /// + /// + public bool RemoveLogger(string key) + { + return m_logs.Remove(key); + } + + /// + /// + /// + /// + /// + /// + /// + protected override void WriteLog(LogType logType, object source, string message, Exception exception) + { + try + { + for (int i = 0; i < m_logs.Count; i++) + { + Logs[i].Log(logType, source, message, exception); + } + } + catch + { + } + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2) : base(log1, log2) + { + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + where TLog3 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2, TLog3 log3) : base(log1, log2, log3) + { + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + where TLog3 : ILog + where TLog4 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2, TLog3 log3, TLog4 log4) : base(log1, log2, log3, log4) + { + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + where TLog3 : ILog + where TLog4 : ILog + where TLog5 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2, TLog3 log3, TLog4 log4, TLog5 log5) : base(log1, log2, log3, log4, log5) + { + } + } + + /// + /// 一组日志记录器 + /// + /// + /// + /// + /// + /// + /// + public class LoggerGroup : LoggerGroup + where TLog1 : ILog + where TLog2 : ILog + where TLog3 : ILog + where TLog4 : ILog + where TLog5 : ILog + where TLog6 : ILog + { + /// + /// 一组日志记录器 + /// + public LoggerGroup(TLog1 log1, TLog2 log2, TLog3 log3, TLog4 log4, TLog5 log5, TLog6 log6) : base(log1, log2, log3, log4, log5, log6) + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Packages_/IPackage.cs b/src/TouchSocket/Core/Packages_/IPackage.cs new file mode 100644 index 000000000..22a9973a3 --- /dev/null +++ b/src/TouchSocket/Core/Packages_/IPackage.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 包接口规范 + /// + public interface IPackage + { + /// + /// 打包。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + void Package(ByteBlock byteBlock); + + /// + /// 解包。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + void Unpackage(ByteBlock byteBlock); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Packages_/MsgRouterPackage.cs b/src/TouchSocket/Core/Packages_/MsgRouterPackage.cs new file mode 100644 index 000000000..439f76e73 --- /dev/null +++ b/src/TouchSocket/Core/Packages_/MsgRouterPackage.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 可承载消息的路由包 + /// + public class MsgRouterPackage : RouterPackage + { + /// + /// 消息 + /// + public string Message { get; set; } + + /// + public override void PackageBody(ByteBlock byteBlock) + { + byteBlock.Write(Message); + } + + /// + public override void UnpackageBody(ByteBlock byteBlock) + { + this.Message = byteBlock.ReadString(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Packages_/PackageBase.cs b/src/TouchSocket/Core/Packages_/PackageBase.cs new file mode 100644 index 000000000..7f13d89aa --- /dev/null +++ b/src/TouchSocket/Core/Packages_/PackageBase.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// PackageBase包结构数据。 + /// + public abstract class PackageBase : IPackage + { + /// + public abstract void Package(ByteBlock byteBlock); + + /// + public abstract void Unpackage(ByteBlock byteBlock); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Packages_/PackageExtensions.cs b/src/TouchSocket/Core/Packages_/PackageExtensions.cs new file mode 100644 index 000000000..7dbe20252 --- /dev/null +++ b/src/TouchSocket/Core/Packages_/PackageExtensions.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// PackageExtensions + /// + public static class PackageExtensions + { + /// + /// 打包为字节 + /// + /// + /// + public static byte[] PackageAsBytes(this PackageBase packageBase) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + packageBase.Package(byteBlock); + return byteBlock.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Packages_/RouterPackage.cs b/src/TouchSocket/Core/Packages_/RouterPackage.cs new file mode 100644 index 000000000..914d31ea2 --- /dev/null +++ b/src/TouchSocket/Core/Packages_/RouterPackage.cs @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 具有目标id和源id的路由包 + /// + public class RouterPackage : PackageBase + { + /// + /// 标识是否路由 + /// + public bool Route { get; set; } + + /// + /// 源Id + /// + public string SourceId { get; set; } + + /// + /// 目标Id + /// + public string TargetId { get; set; } + + /// + /// 打包所有的路由包信息。顺序为:先调用,然后 + /// + /// + public override sealed void Package(ByteBlock byteBlock) + { + PackageRouter(byteBlock); + PackageBody(byteBlock); + } + + /// + /// 打包数据体。一般不需要单独调用该方法。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + public virtual void PackageBody(ByteBlock byteBlock) + { + } + + /// + /// 打包路由。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + public virtual void PackageRouter(ByteBlock byteBlock) + { + byteBlock.Write(Route); + byteBlock.Write(SourceId); + byteBlock.Write(TargetId); + } + + /// + /// 转换目标和源的id。 + /// + public void SwitchId() + { + string value = SourceId; + SourceId = TargetId; + TargetId = value; + } + + /// + public override sealed void Unpackage(ByteBlock byteBlock) + { + UnpackageRouter(byteBlock); + UnpackageBody(byteBlock); + } + + /// + /// 解包数据体。一般不需要单独调用该方法。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + public virtual void UnpackageBody(ByteBlock byteBlock) + { + } + + /// + /// 只解包路由部分。一般不需要单独调用该方法。 + /// 重写的话,约定基类方法必须先执行 + /// + /// + public virtual void UnpackageRouter(ByteBlock byteBlock) + { + Route = byteBlock.ReadBoolean(); + SourceId = byteBlock.ReadString(); + TargetId = byteBlock.ReadString(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Packages_/WaitPackage.cs b/src/TouchSocket/Core/Packages_/WaitPackage.cs new file mode 100644 index 000000000..0902eedb8 --- /dev/null +++ b/src/TouchSocket/Core/Packages_/WaitPackage.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// WaitPackage + /// + public class WaitPackage : PackageBase, IWaitResult + { + /// + /// + /// + public string Message { get; set; } + + /// + /// + /// + public long Sign { get; set; } + + /// + /// + /// + public byte Status { get; set; } + + /// + public override void Package(ByteBlock byteBlock) + { + byteBlock.Write(Sign); + byteBlock.Write(Status); + byteBlock.Write(Message); + } + + /// + public override void Unpackage(ByteBlock byteBlock) + { + Sign = byteBlock.ReadInt64(); + Status = (byte)byteBlock.ReadByte(); + Message = byteBlock.ReadString(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Packages_/WaitRouterPackage.cs b/src/TouchSocket/Core/Packages_/WaitRouterPackage.cs new file mode 100644 index 000000000..d6ee51098 --- /dev/null +++ b/src/TouchSocket/Core/Packages_/WaitRouterPackage.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 可等待的路由包。 + /// + public class WaitRouterPackage : MsgRouterPackage, IWaitResult + { + /// + public long Sign { get; set; } + + /// + public byte Status { get; set; } + + /// + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(Sign); + byteBlock.Write(Status); + } + + /// + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + Sign = byteBlock.ReadInt64(); + Status = (byte)byteBlock.ReadByte(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs b/src/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs new file mode 100644 index 000000000..3903ccf1d --- /dev/null +++ b/src/TouchSocket/Core/Plugins/AsyncRaiserAttribute.cs @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 标识该接口应当还会触发异步接口。 + /// 异步接口方法的返回值应该为Task,且必须以Async结尾。 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public sealed class AsyncRaiserAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Plugins/IPlugin.cs b/src/TouchSocket/Core/Plugins/IPlugin.cs new file mode 100644 index 000000000..ed9e72332 --- /dev/null +++ b/src/TouchSocket/Core/Plugins/IPlugin.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 插件接口 + /// + public interface IPlugin : IDisposable + { + /// + /// 插件执行顺序 + /// 该属性值越大,越靠前执行。值相等时,按添加先后顺序 + /// 该属性效果,仅在之前设置有效。 + /// + int Order { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Plugins/IPluginObject.cs b/src/TouchSocket/Core/Plugins/IPluginObject.cs new file mode 100644 index 000000000..570356b63 --- /dev/null +++ b/src/TouchSocket/Core/Plugins/IPluginObject.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 具有插件功能的对象 + /// + public interface IPluginObject + { + /// + /// 内置IOC容器 + /// + IContainer Container { get; } + + /// + /// 插件管理器 + /// + IPluginsManager PluginsManager { get; } + + /// + /// 是否已启用插件 + /// + bool UsePlugin { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Plugins/IPluginsManager.cs b/src/TouchSocket/Core/Plugins/IPluginsManager.cs new file mode 100644 index 000000000..44ecd18ec --- /dev/null +++ b/src/TouchSocket/Core/Plugins/IPluginsManager.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; + +namespace TouchSocket.Core +{ + /// + /// 插件管理器接口 + /// + public interface IPluginsManager : IEnumerable + { + /// + /// 标识该插件是否可用。当不可用时,仅可以添加和删除插件,但不会触发插件 + /// + bool Enable { get; set; } + + /// + /// 内置IOC容器 + /// + IContainer Container { get; } + + /// + /// 添加插件 + /// + /// 插件 + /// + void Add(IPlugin plugin); + + /// + /// 移除插件 + /// + /// + void Remove(IPlugin plugin); + + /// + /// 移除插件 + /// + /// + void Remove(Type type); + + /// + /// 清除所有插件 + /// + void Clear(); + + /// + /// 触发对应方法 + /// + /// 接口类型 + /// 触发名称 + /// + /// + bool Raise(string name, object sender, TouchSocketEventArgs e) where TPlugin : IPlugin; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Plugins/PlguinObjectExtension.cs b/src/TouchSocket/Core/Plugins/PlguinObjectExtension.cs new file mode 100644 index 000000000..80e5fb303 --- /dev/null +++ b/src/TouchSocket/Core/Plugins/PlguinObjectExtension.cs @@ -0,0 +1,75 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// PlguinObjectExtension + /// + public static class PlguinObjectExtension + { + /// + /// 添加插件 + /// + /// 插件类型 + /// 插件类型实例 + public static TPlugin AddPlugin(this IPluginObject plguinObject) where TPlugin : class, IPlugin + { + plguinObject.Container.RegisterSingleton(); + var obj = plguinObject.Container.Resolve(); + AddPlugin(plguinObject, obj); + return obj; + } + + /// + /// 添加插件 + /// + /// + /// 插件 + /// + public static void AddPlugin(this IPluginObject plguinObject, IPlugin plugin) + { + plguinObject.Container.RegisterSingleton(plugin); + plguinObject.PluginsManager.Add(plugin); + } + + /// + /// 清空插件 + /// + public static void ClearPlugins(this IPluginObject plguinObject) + { + plguinObject.PluginsManager.Clear(); + } + + /// + /// 移除插件 + /// + /// + /// + public static void RemovePlugin(this IPluginObject plguinObject, IPlugin plugin) + { + plguinObject.PluginsManager.Remove(plugin); + } + + /// + /// 移除插件 + /// + /// + /// + public static void RemovePlugin(this IPluginObject plguinObject) where T : IPlugin + { + plguinObject.PluginsManager.Remove(typeof(T)); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Plugins/PluginBase.cs b/src/TouchSocket/Core/Plugins/PluginBase.cs new file mode 100644 index 000000000..6a7c8b5cd --- /dev/null +++ b/src/TouchSocket/Core/Plugins/PluginBase.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// PluginBase + /// + public class PluginBase : DisposableObject, IPlugin + { + /// + public int Order { get ; set ; } + } +} diff --git a/src/TouchSocket/Core/Plugins/PluginsManager.cs b/src/TouchSocket/Core/Plugins/PluginsManager.cs new file mode 100644 index 000000000..abf239430 --- /dev/null +++ b/src/TouchSocket/Core/Plugins/PluginsManager.cs @@ -0,0 +1,275 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 表示插件管理器。 + /// + public class PluginsManager : IPluginsManager + { + private readonly Dictionary> m_pluginInfoes = new Dictionary>(); + private readonly List m_plugins = new List(); + + /// + /// 构造函数 + /// + /// + public PluginsManager(IContainer container) + { + Container = container; + } + + /// + /// + /// + public IContainer Container { get; } + + /// + /// + /// + public bool Enable { get; set; } = true; + + /// + /// 添加插件 + /// + /// 插件 + /// + void IPluginsManager.Add(IPlugin plugin) + { + lock (this) + { + if (plugin == null) + { + throw new ArgumentNullException(); + } + if (plugin.GetType().GetCustomAttribute() is SingletonPluginAttribute singletonPlugin) + { + foreach (var item in m_plugins) + { + if (item.PluginType == plugin.GetType()) + { + throw new InvalidOperationException($"插件{plugin.GetType()}不能重复使用。"); + } + } + } + m_plugins.Add(new PluginModel(plugin, plugin.GetType())); + var types = plugin.GetType().GetInterfaces().Where(a => typeof(IPlugin).IsAssignableFrom(a)).ToArray(); + foreach (var type in types) + { + if (!m_pluginInfoes.ContainsKey(type)) + { + Dictionary pairs = new Dictionary(); + var ms = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + foreach (var item in ms) + { + if (item.GetParameters().Length == 2 && typeof(TouchSocketEventArgs).IsAssignableFrom(item.GetParameters()[1].ParameterType)) + { + if (pairs.ContainsKey(item.Name)) + { + throw new Exception("插件的接口方法不允许重载"); + } + PluginMethod pluginMethod = new PluginMethod(type); + if (item.GetCustomAttribute() != null) + { + var asyncMethod = type.GetMethod($"{item.Name}Async", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + if (asyncMethod == null) + { + throw new Exception("当接口标识为异步时,还应当定义其异步方法,以“Async”结尾"); + } + + if (asyncMethod.GetParameters().Length != 2 && typeof(TouchSocketEventArgs).IsAssignableFrom(asyncMethod.GetParameters()[1].ParameterType)) + { + throw new Exception("异步接口方法不符合设定"); + } + if (asyncMethod.ReturnType != typeof(Task)) + { + throw new Exception("异步接口方法返回值必须为Task。"); + } + pluginMethod.MethodAsync=new Method(asyncMethod); + } + pluginMethod.Method = new Method(item); + pairs.Add(item.Name, pluginMethod); + } + } + m_pluginInfoes.Add(type, pairs); + } + } + + m_plugins.Sort(delegate (PluginModel x, PluginModel y) + { + if (x.Plugin.Order == y.Plugin.Order) return 0; + else if (x.Plugin.Order < y.Plugin.Order) return 1; + else return -1; + }); + + Container.RegisterSingleton(plugin); + } + } + + /// + /// 清除所有插件 + /// + void IPluginsManager.Clear() + { + lock (this) + { + foreach (var item in m_plugins) + { + item.Plugin.SafeDispose(); + } + m_plugins.Clear(); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + lock (this) + { + return m_plugins.Select(a => a.Plugin).GetEnumerator(); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + lock (this) + { + return m_plugins.Select(a => a.Plugin).GetEnumerator(); + } + } + + /// + /// 触发对应方法 + /// + /// 接口类型,此处也必须是接口类型 + /// 触发名称 + /// + /// + bool IPluginsManager.Raise(string name, object sender, TouchSocketEventArgs e) + { + if (!Enable) + { + return false; + } + if (m_pluginInfoes.TryGetValue(typeof(TPlugin), out var value)) + { + if (value.TryGetValue(name, out PluginMethod pluginMethod)) + { + for (int i = 0; i < m_plugins.Count; i++) + { + if (e.Handled) + { + return true; + } + if (pluginMethod.Type.IsAssignableFrom(m_plugins[i].PluginType)) + { + try + { + pluginMethod.Method.Invoke(m_plugins[i].Plugin, sender, e); + } + catch (Exception ex) + { + Container.Resolve()?.Exception(ex); + } + + try + { + pluginMethod.MethodAsync?.InvokeAsync(m_plugins[i].Plugin, sender, e); + } + catch (Exception ex) + { + Container.Resolve()?.Exception(ex); + } + } + } + } + } + return false; + } + + /// + /// 移除插件 + /// + /// + void IPluginsManager.Remove(IPlugin plugin) + { + lock (this) + { + if (plugin == null) + { + throw new ArgumentNullException(); + } + foreach (var item in m_plugins) + { + if (plugin == item.Plugin) + { + if (m_plugins.Remove(item)) + { + plugin.SafeDispose(); + return; + } + } + } + } + } + + /// + /// 移除插件 + /// + /// + void IPluginsManager.Remove(Type type) + { + lock (this) + { + for (int i = m_plugins.Count - 1; i >= 0; i--) + { + IPlugin plugin = m_plugins[i].Plugin; + if (plugin.GetType() == type) + { + m_plugins.RemoveAt(i); + plugin.SafeDispose(); + } + } + } + } + } + + internal class PluginMethod + { + public PluginMethod(Type type) + { + this.Type = type; + } + public Method Method; + public Method MethodAsync; + public readonly Type Type; + } + + internal class PluginModel + { + public PluginModel(IPlugin plugin, Type pluginType) + { + Plugin = plugin; + PluginType = pluginType; + } + + public IPlugin Plugin; + public Type PluginType; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Plugins/PluginsManagerExtension.cs b/src/TouchSocket/Core/Plugins/PluginsManagerExtension.cs new file mode 100644 index 000000000..074f6d34b --- /dev/null +++ b/src/TouchSocket/Core/Plugins/PluginsManagerExtension.cs @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// PluginsManagerExtension + /// + public static class PluginsManagerExtension + { + /// + /// 添加插件 + /// + /// 插件类型 + /// 插件类型实例 + public static TPlugin Add(this IPluginsManager pluginsManager) where TPlugin : class, IPlugin + { + pluginsManager.Container.RegisterSingleton(); + var obj = pluginsManager.Container.Resolve(); + pluginsManager.Add(obj); + return obj; + } + + /// + /// 添加插件 + /// + /// 插件类型 + /// + /// 创建插件相关构造函数插件 + /// 插件类型实例 + public static TPlugin Add(this IPluginsManager pluginsManager, params object[] ps) where TPlugin : class, IPlugin + { + pluginsManager.Container.RegisterSingleton(); + var obj = pluginsManager.Container.Resolve(ps); + pluginsManager.Add(obj); + return obj; + } + + /// + /// 清空插件 + /// + public static void Clear(this IPluginsManager pluginsManager) + { + pluginsManager.Clear(); + } + + /// + /// 移除插件 + /// + /// + /// + public static void Remove(this IPluginsManager pluginsManager, IPlugin plugin) + { + pluginsManager.Remove(plugin); + } + + /// + /// 移除插件 + /// + /// + /// + public static void Remove(this IPluginsManager pluginsManager) where T : IPlugin + { + pluginsManager.Remove(typeof(T)); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs b/src/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs new file mode 100644 index 000000000..93531688d --- /dev/null +++ b/src/TouchSocket/Core/Plugins/SingletonPluginAttribute.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 标识插件只能注册一次。 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] + public sealed class SingletonPluginAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs b/src/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs new file mode 100644 index 000000000..5b5a59c79 --- /dev/null +++ b/src/TouchSocket/Core/Pool/ObjectPool/IObjectPool.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 对象池接口 + /// + public interface IObjectPool : IDisposable + { + /// + /// 可使用数量 + /// + int FreeSize { get; } + + /// + /// 清空池中对象 + /// + void Clear(); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs b/src/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs new file mode 100644 index 000000000..8a8ef01ec --- /dev/null +++ b/src/TouchSocket/Core/Pool/ObjectPool/IPoolObject.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 对象池单位接口 + /// + public interface IPoolObject + { + /// + /// 是否为新建对象 + /// + bool NewCreate { get; set; } + + /// + /// 初创建对象 + /// + void Create(); + + /// + /// 重新创建对象 + /// + void Recreate(); + + /// + /// 销毁对象 + /// + void Destroy(); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs b/src/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs new file mode 100644 index 000000000..9861f84ba --- /dev/null +++ b/src/TouchSocket/Core/Pool/ObjectPool/ObjectPool.cs @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 对象池 + /// + /// + public class ObjectPool : IObjectPool where T : IPoolObject + { + private readonly ConcurrentQueue m_queue = new ConcurrentQueue(); + + private bool m_autoCreate = true; + + private int m_freeSize; + + /// + /// 构造函数 + /// + /// + public ObjectPool(int capacity) + { + Capacity = capacity; + } + + /// + /// 构造函数 + /// + public ObjectPool() + { + } + + /// + /// 是否自动生成 + /// + public bool AutoCreate + { + get => m_autoCreate; + set => m_autoCreate = value; + } + + /// + /// 对象池容量 + /// + public int Capacity { get; set; } + + /// + /// 可使用(创建)数量 + /// + public int FreeSize => m_freeSize; + + /// + /// 清除池中所有对象 + /// + public void Clear() + { + while (m_queue.TryDequeue(out _)) + { + } + } + + /// + /// 注销对象 + /// + /// + public void DestroyObject(T t) + { + t.Destroy(); + if (m_freeSize < Capacity) + { + Interlocked.Increment(ref m_freeSize); + m_queue.Enqueue(t); + } + } + + /// + /// 释放对象 + /// + public void Dispose() + { + Clear(); + } + + /// + /// 获取所有对象 + /// + /// + public T[] GetAllObject() + { + List ts = new List(); + while (m_queue.TryDequeue(out T t)) + { + ts.Add(t); + } + return ts.ToArray(); + } + + /// + /// 获取对象T + /// + /// + public T GetObject() + { + if (m_queue.TryDequeue(out T t)) + { + t.Recreate(); + t.NewCreate = false; + Interlocked.Decrement(ref m_freeSize); + return t; + } + if (m_autoCreate) + { + t = (T)Activator.CreateInstance(typeof(T)); + t.Create(); + t.NewCreate = true; + } + return t; + } + + /// + /// 预获取 + /// + /// + public T PreviewGetObject() + { + m_queue.TryPeek(out T t); + return t; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs b/src/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs new file mode 100644 index 000000000..b03cd22a0 --- /dev/null +++ b/src/TouchSocket/Core/Reflection/DynamicMethodMemberAccessor.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// DynamicMethodMemberAccessor + /// + public class DynamicMethodMemberAccessor : IMemberAccessor + { + private static ConcurrentDictionary classAccessors = new ConcurrentDictionary(); + + /// + /// 获取属性 + /// + public Func OnGetProperties { get; set; } + + /// + /// 获取字段 + /// + public Func OnGetFieldInfes { get; set; } + + /// + public object GetValue(object instance, string memberName) + { + return FindClassAccessor(instance).GetValue(instance, memberName); + } + + /// + public void SetValue(object instance, string memberName, object newValue) + { + FindClassAccessor(instance).SetValue(instance, memberName, newValue); + } + + private IMemberAccessor FindClassAccessor(object instance) + { + var typekey = instance.GetType(); + if (!classAccessors.TryGetValue(typekey, out IMemberAccessor classAccessor)) + { + MemberAccessor memberAccessor = new MemberAccessor(instance.GetType()); + if (this.OnGetFieldInfes != null) + { + memberAccessor.OnGetFieldInfes = this.OnGetFieldInfes; + } + + if (this.OnGetProperties != null) + { + memberAccessor.OnGetProperties = this.OnGetProperties; + } + memberAccessor.Build(); + classAccessor = memberAccessor; + classAccessors.TryAdd(typekey, classAccessor); + } + return classAccessor; + } + } +} diff --git a/src/TouchSocket/Core/Reflection/ExpressionMapper.cs b/src/TouchSocket/Core/Reflection/ExpressionMapper.cs new file mode 100644 index 000000000..ae9383422 --- /dev/null +++ b/src/TouchSocket/Core/Reflection/ExpressionMapper.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace TouchSocket.Core +{ + /// + /// 表达式复制 + /// + public class ExpressionMapper + { + private static readonly Dictionary m_dic = new Dictionary(); + + /// + /// 字典缓存表达式树 + /// + public static TOut Trans(TIn tIn) + { + string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName); + if (!m_dic.ContainsKey(key)) + { + ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p"); + List memberBindingList = new List(); + foreach (var item in typeof(TOut).GetProperties()) + { + MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name)); + MemberBinding memberBinding = Expression.Bind(item, property); + memberBindingList.Add(memberBinding); + } + foreach (var item in typeof(TOut).GetFields()) + { + MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name)); + MemberBinding memberBinding = Expression.Bind(item, property); + memberBindingList.Add(memberBinding); + } + MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray()); + Expression> lambda = Expression.Lambda>(memberInitExpression, parameterExpression); + Func func = lambda.Compile();//拼装是一次性的 + m_dic[key] = func; + } + return ((Func)m_dic[key]).Invoke(tIn); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Reflection/IMemberAccessor.cs b/src/TouchSocket/Core/Reflection/IMemberAccessor.cs new file mode 100644 index 000000000..a1738da8c --- /dev/null +++ b/src/TouchSocket/Core/Reflection/IMemberAccessor.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 一个成员访问接口 + /// + public interface IMemberAccessor + { + /// + /// 获取指定成员的值 + /// + /// + /// + /// + object GetValue(object instance, string memberName); + + /// + ///设置指定成员的值 + /// + /// + /// + /// + void SetValue(object instance, string memberName, object newValue); + } +} diff --git a/src/TouchSocket/Core/Reflection/Member.cs b/src/TouchSocket/Core/Reflection/Member.cs new file mode 100644 index 000000000..d08aba89b --- /dev/null +++ b/src/TouchSocket/Core/Reflection/Member.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 用于表达式树的成员 + /// + public abstract class Member + { + } +} diff --git a/src/TouchSocket/Core/Reflection/MemberAccessor.cs b/src/TouchSocket/Core/Reflection/MemberAccessor.cs new file mode 100644 index 000000000..deb451397 --- /dev/null +++ b/src/TouchSocket/Core/Reflection/MemberAccessor.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 动态成员访问器 + /// + /// + public class MemberAccessor : MemberAccessor + { + /// + /// 动态成员访问器 + /// + public MemberAccessor() : base(typeof(T)) + { + + } + } + + /// + /// 动态成员访问器 + /// + public class MemberAccessor : IMemberAccessor + { + Func GetValueDelegate; + + Action SetValueDelegate; + + /// + /// 动态成员访问器 + /// + /// + public MemberAccessor(Type type) + { + Type = type; + this.OnGetFieldInfes = (t) => { return t.GetFields(); }; + this.OnGetProperties = (t) => { return t.GetProperties(); }; + } + + private Dictionary dicFieldInfes; + private Dictionary dicProperties; + /// + /// 构建 + /// + public void Build() + { + if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + dicFieldInfes = this.OnGetFieldInfes.Invoke(Type).ToDictionary(a => a.Name); + dicProperties = this.OnGetProperties.Invoke(Type).ToDictionary(a => a.Name); + } + + GetValueDelegate = GenerateGetValue(); + SetValueDelegate = GenerateSetValue(); + } + + /// + /// 获取属性 + /// + public Func OnGetProperties { get; set; } + + /// + /// 获取字段 + /// + public Func OnGetFieldInfes { get; set; } + + /// + /// 所属类型 + /// + public Type Type { get; } + + /// + public object GetValue(object instance, string memberName) + { + return GetValueDelegate(instance, memberName); + } + + /// + public void SetValue(object instance, string memberName, object newValue) + { + SetValueDelegate(instance, memberName, newValue); + } + + private Func GenerateGetValue() + { + if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + return (obj, key) => + { + if (dicFieldInfes.TryGetValue(key, out var value1)) + { + return value1.GetValue(obj); + } + if (dicProperties.TryGetValue(key, out var value2)) + { + return value2.GetValue(obj); + } + return default; + }; + } + + var instance = Expression.Parameter(typeof(object), "instance"); + var memberName = Expression.Parameter(typeof(string), "memberName"); + var nameHash = Expression.Variable(typeof(int), "nameHash"); + var calHash = Expression.Assign(nameHash, Expression.Call(memberName, typeof(object).GetMethod("GetHashCode"))); + var cases = new List(); + foreach (var propertyInfo in this.OnGetFieldInfes.Invoke(Type)) + { + var property = Expression.Field(Expression.Convert(instance, Type), propertyInfo.Name); + var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); + + cases.Add(Expression.SwitchCase(Expression.Convert(property, typeof(object)), propertyHash)); + } + foreach (var propertyInfo in this.OnGetProperties.Invoke(Type)) + { + var property = Expression.Property(Expression.Convert(instance, Type), propertyInfo.Name); + var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); + + cases.Add(Expression.SwitchCase(Expression.Convert(property, typeof(object)), propertyHash)); + } + if (cases.Count == 0) + { + return (a, b) => default; + } + var switchEx = Expression.Switch(nameHash, Expression.Constant(null), cases.ToArray()); + var methodBody = Expression.Block(typeof(object), new[] { nameHash }, calHash, switchEx); + + return Expression.Lambda>(methodBody, instance, memberName).Compile(); + } + + private Action GenerateSetValue() + { + if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + return (obj, key, value) => + { + if (dicFieldInfes.TryGetValue(key, out var value1)) + { + value1.SetValue(obj, value); + } + if (dicProperties.TryGetValue(key, out var value2)) + { + value2.SetValue(obj, value); + } + }; + } + + var instance = Expression.Parameter(typeof(object), "instance"); + var memberName = Expression.Parameter(typeof(string), "memberName"); + var newValue = Expression.Parameter(typeof(object), "newValue"); + var nameHash = Expression.Variable(typeof(int), "nameHash"); + var calHash = Expression.Assign(nameHash, Expression.Call(memberName, typeof(object).GetMethod("GetHashCode"))); + var cases = new List(); + foreach (var propertyInfo in this.OnGetFieldInfes.Invoke(Type)) + { + var property = Expression.Field(Expression.Convert(instance, Type), propertyInfo.Name); + var setValue = Expression.Assign(property, Expression.Convert(newValue, propertyInfo.FieldType)); + var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); + + cases.Add(Expression.SwitchCase(Expression.Convert(setValue, typeof(object)), propertyHash)); + } + foreach (var propertyInfo in this.OnGetProperties(Type)) + { + if (!propertyInfo.CanWrite) + { + continue; + } + var property = Expression.Property(Expression.Convert(instance, Type), propertyInfo.Name); + var setValue = Expression.Assign(property, Expression.Convert(newValue, propertyInfo.PropertyType)); + var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); + + cases.Add(Expression.SwitchCase(Expression.Convert(setValue, typeof(object)), propertyHash)); + } + if (cases.Count == 0) + { + return (a, b, c) => { }; + } + var switchEx = Expression.Switch(nameHash, Expression.Constant(null), cases.ToArray()); + var methodBody = Expression.Block(typeof(object), new[] { nameHash }, calHash, switchEx); + + return Expression.Lambda>(methodBody, instance, memberName, newValue).Compile(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Reflection/MemberGetter.cs b/src/TouchSocket/Core/Reflection/MemberGetter.cs new file mode 100644 index 000000000..e1321d13f --- /dev/null +++ b/src/TouchSocket/Core/Reflection/MemberGetter.cs @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 表示属性的Getter + /// + public class MemberGetter + { + /// + /// get方法委托 + /// + private readonly Func m_getFunc; + + /// + /// 表示属性的Getter + /// + /// 属性 + /// + public MemberGetter(PropertyInfo property) + { + m_getFunc = CreateGetterDelegate(property); + } + + /// + /// 表示类型字段或属性的Getter + /// + /// + public MemberGetter(FieldInfo fieldInfo) + { + m_getFunc = CreateGetterDelegate(fieldInfo); + } + + /// + /// 获取属性的值 + /// + /// 实例 + /// + public object Invoke(object instance) + { + return m_getFunc.Invoke(instance); + } + + private static Func CreateGetterDelegate(PropertyInfo property) + { + var param_instance = Expression.Parameter(typeof(object)); + var body_instance = Expression.Convert(param_instance, property.DeclaringType); + var body_property = Expression.Property(body_instance, property); + var body_return = Expression.Convert(body_property, typeof(object)); + + return Expression.Lambda>(body_return, param_instance).Compile(); + } + + private static Func CreateGetterDelegate(FieldInfo fieldInfo) + { + var param_instance = Expression.Parameter(typeof(object)); + var body_instance = Expression.Convert(param_instance, fieldInfo.DeclaringType); + var body_field = Expression.Field(body_instance, fieldInfo); + var body_return = Expression.Convert(body_field, typeof(object)); + + return Expression.Lambda>(body_return, param_instance).Compile(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Reflection/MemberSetter.cs b/src/TouchSocket/Core/Reflection/MemberSetter.cs new file mode 100644 index 000000000..8dc8faf5b --- /dev/null +++ b/src/TouchSocket/Core/Reflection/MemberSetter.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 表示属性的设置器 + /// + public class MemberSetter + { + /// + /// set方法委托 + /// + private readonly Action setFunc; + + /// + /// 表示属性的Getter + /// + /// 属性 + /// + public MemberSetter(PropertyInfo property) + { + if (property == null) + { + throw new ArgumentNullException(nameof(property)); + } + setFunc = CreateSetterDelegate(property); + } + + /// + /// 设置属性的值 + /// + /// 实例 + /// 值 + /// + public void Invoke(object instance, object value) + { + setFunc.Invoke(instance, value); + } + + private static Action CreateSetterDelegate(PropertyInfo property) + { + var param_instance = Expression.Parameter(typeof(object)); + var param_value = Expression.Parameter(typeof(object)); + + var body_instance = Expression.Convert(param_instance, property.DeclaringType); + var body_value = Expression.Convert(param_value, property.PropertyType); + var body_call = Expression.Call(body_instance, property.GetSetMethod(true), body_value); + + return Expression.Lambda>(body_call, param_instance, param_value).Compile(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Reflection/Method.cs b/src/TouchSocket/Core/Reflection/Method.cs new file mode 100644 index 000000000..25142407c --- /dev/null +++ b/src/TouchSocket/Core/Reflection/Method.cs @@ -0,0 +1,360 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// Task类型 + /// + public enum TaskReturnType + { + /// + /// 没有Task + /// + None, + + /// + /// 仅返回Task + /// + Task, + + /// + /// 返回Task的值 + /// + TaskObject + } + + /// + /// 表示方法 + /// + public class Method + { + private readonly MethodInfo m_info; + + /// + /// 方法执行委托 + /// + private readonly Func m_invoker; + + private readonly bool m_isByRef; + + /// + /// 方法 + /// + /// 方法信息 + public Method(MethodInfo method) + { + m_info = method ?? throw new ArgumentNullException(nameof(method)); + Name = method.Name; + Static = method.IsStatic; + foreach (var item in method.GetParameters()) + { + if (item.ParameterType.IsByRef) + { + m_isByRef = true; + } + } + if (this.m_isByRef||GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + if (method.ReturnType == typeof(Task)) + { + HasReturn = false; + TaskType = TaskReturnType.Task; + } + else if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) + { + HasReturn = true; + ReturnType = method.ReturnType.GetGenericArguments()[0]; + TaskType = TaskReturnType.TaskObject; + } + else if (method.ReturnType == typeof(void)) + { + HasReturn = false; + TaskType = TaskReturnType.None; + } + else + { + HasReturn = true; + TaskType = TaskReturnType.None; + ReturnType = method.ReturnType; + } + } + else + { + m_invoker = CreateInvoker(method); + } + } + + /// + /// 是否具有返回值 + /// + public bool HasReturn { get; private set; } + + /// + /// 方法信息 + /// + public MethodInfo Info => m_info; + + /// + /// 是否有引用类型 + /// + public bool IsByRef => m_isByRef; + + /// + /// 获取方法名 + /// + public string Name { get; protected set; } + + /// + /// 返回值类型。 + /// 当方法为void或task时,为null + /// 当方法为task泛型时,为泛型元素类型 + /// + public Type ReturnType { get; private set; } + + /// + /// 是否为静态函数 + /// + public bool Static { get; private set; } + + /// + /// 返回值的Task类型。 + /// + public TaskReturnType TaskType { get; private set; } + + /// + /// 执行方法。 + /// 当方法为void或task时,会返回null + /// 当方法为task泛型时,会wait后的值 + /// 注意:当调用方为UI主线程时,调用异步方法,则极有可能发生死锁。 + /// + /// 实例 + /// 参数 + /// + public object Invoke(object instance, params object[] parameters) + { + switch (TaskType) + { + case TaskReturnType.None: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + return re; + } + case TaskReturnType.Task: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + Task task = (Task)re; + task.Wait(); + return default; + } + case TaskReturnType.TaskObject: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + Task task = (Task)re; + task.Wait(); + return task.GetType().GetProperty("Result").GetValue(task); + } + default: + return default; + } + } + + /// + /// 异步调用 + /// + /// + /// + /// + public Task InvokeAsync(object instance, params object[] parameters) + { + switch (TaskType) + { + case TaskReturnType.None: + { + throw new Exception("该方法不包含Task。"); + } + case TaskReturnType.Task: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + return (Task)re; + } + case TaskReturnType.TaskObject: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + return (Task)re; + } + default: + return default; + } + } + + /// + /// 调用异步结果 + /// + /// + /// + /// + public async Task InvokeObjectAsync(object instance, params object[] parameters) + { + switch (TaskType) + { + case TaskReturnType.None: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + return re; + } + case TaskReturnType.Task: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + Task task = (Task)re; + await task; + return default; + } + case TaskReturnType.TaskObject: + { + object re; + if (m_isByRef || GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) + { + re = m_info.Invoke(instance, parameters); + } + else + { + re = m_invoker.Invoke(instance, parameters); + } + Task task = (Task)re; + await task; + return task.GetType().GetProperty("Result").GetValue(task); + } + default: + return default; + } + } + + /// + /// 生成方法的调用委托 + /// + /// 方法成员信息 + /// + /// + private Func CreateInvoker(MethodInfo method) + { + var instance = Expression.Parameter(typeof(object), "instance"); + var parameters = Expression.Parameter(typeof(object[]), "parameters"); + + var instanceCast = method.IsStatic ? null : Expression.Convert(instance, method.DeclaringType); + var parametersCast = method.GetParameters().Select((p, i) => + { + var parameter = Expression.ArrayIndex(parameters, Expression.Constant(i)); + return Expression.Convert(parameter, p.ParameterType); + }); + + var body = Expression.Call(instanceCast, method, parametersCast); + + if (method.ReturnType == typeof(Task)) + { + HasReturn = false; + TaskType = TaskReturnType.Task; + var bodyCast = Expression.Convert(body, typeof(object)); + return Expression.Lambda>(bodyCast, instance, parameters).Compile(); + } + else if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) + { + TaskType = TaskReturnType.TaskObject; + HasReturn = true; + ReturnType = method.ReturnType.GetGenericArguments()[0]; + var bodyCast = Expression.Convert(body, typeof(object)); + return Expression.Lambda>(bodyCast, instance, parameters).Compile(); + } + else if (method.ReturnType == typeof(void)) + { + HasReturn = false; + TaskType = TaskReturnType.None; + var action = Expression.Lambda>(body, instance, parameters).Compile(); + return (_instance, _parameters) => + { + action.Invoke(_instance, _parameters); + return null; + }; + } + else + { + HasReturn = true; + TaskType = TaskReturnType.None; + ReturnType = method.ReturnType; + var bodyCast = Expression.Convert(body, typeof(object)); + return Expression.Lambda>(bodyCast, instance, parameters).Compile(); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Reflection/Property.cs b/src/TouchSocket/Core/Reflection/Property.cs new file mode 100644 index 000000000..2ee713395 --- /dev/null +++ b/src/TouchSocket/Core/Reflection/Property.cs @@ -0,0 +1,121 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 表示属性 + /// + public class Property: Member + { + /// + /// 类型属性的Setter缓存 + /// + private static readonly ConcurrentDictionary m_cached = new ConcurrentDictionary(); + + /// + /// 获取器 + /// + private readonly MemberGetter m_geter; + + /// + /// 设置器 + /// + private readonly MemberSetter m_seter; + + /// + /// 属性 + /// + /// 属性信息 + public Property(PropertyInfo property) + { + Name = property.Name; + Info = property; + + if (property.CanRead == true) + { + CanRead = true; + m_geter = new MemberGetter(property); + } + if (property.CanWrite == true) + { + CanWrite = true; + m_seter = new MemberSetter(property); + } + } + + /// + /// 是否可以读取 + /// + public bool CanRead { get; private set; } + + /// + /// 是否可以写入 + /// + public bool CanWrite { get; private set; } + + /// + /// 获取属性信息 + /// + public PropertyInfo Info { get; private set; } + + /// + /// 获取属性名称 + /// + public string Name { get; protected set; } + + /// + /// 从类型的属性获取属性 + /// + /// 类型 + /// + public static Property[] GetProperties(Type type) + { + return m_cached.GetOrAdd(type, t => t.GetProperties().Select(p => new Property(p)).ToArray()); + } + + /// + /// 获取属性的值 + /// + /// 实例 + /// + /// + public object GetValue(object instance) + { + if (m_geter == null) + { + throw new NotSupportedException(); + } + return m_geter.Invoke(instance); + } + + /// + /// 设置属性的值 + /// + /// 实例 + /// 值 + /// + public void SetValue(object instance, object value) + { + if (m_seter == null) + { + throw new NotSupportedException($"{Name}不允许赋值"); + } + m_seter.Invoke(instance, value); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Action/EasyTask.cs b/src/TouchSocket/Core/Run/Action/EasyTask.cs new file mode 100644 index 000000000..822d9d60e --- /dev/null +++ b/src/TouchSocket/Core/Run/Action/EasyTask.cs @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 易用组件 + /// + public class EasyTask + { + static EasyTask() + { + InitCompletedTask(); + } + + private static readonly ConcurrentDictionary timers = new ConcurrentDictionary(); + +#if DEBUG + + /// + /// Timers + /// + public static ConcurrentDictionary Timers => timers; + +#endif + + /// + /// 延迟执行 + /// + /// + /// + public static void DelayRun(TimeSpan delayTimeSpan, Action action) + { + DelayRun(delayTimeSpan.Milliseconds, action); + } + + /// + /// 延迟执行 + /// + /// + /// + /// + public static void DelayRun(TimeSpan delayTimeSpan, T status, Action action) + { + DelayRun(delayTimeSpan.Milliseconds, status, action); + } + + /// + /// 延迟执行 + /// + /// + /// + public static void DelayRun(int delay, Action action) + { + object obj = new object(); + Timer timer = new Timer((o) => + { + if (timers.TryRemove(o, out Timer timer1)) + { + timer1.Dispose(); + } + action?.Invoke(); + }, obj, delay, Timeout.Infinite); + timers.TryAdd(obj, timer); + } + + /// + /// 延迟执行 + /// + /// + /// + /// + public static void DelayRun(int delay, T status, Action action) + { + object obj = new object(); + Timer timer = new Timer((o) => + { + if (timers.TryRemove(o, out Timer timer1)) + { + timer1.Dispose(); + } + action?.Invoke(status); + }, obj, delay, Timeout.Infinite); + timers.TryAdd(obj, timer); + } + + /// + /// Task异步 + /// + /// + /// + public static Task Run(T statu, Action action) + { + return Task.Factory.StartNew(() => + { + action.Invoke(statu); + }); + } + + /// + /// Task异步 + /// + /// + /// + /// + public static Task Run(Func function) + { + return Task.Factory.StartNew(function); + } + + /// + /// Task异步 + /// + /// + /// + public static Task Run(Action action) + { + return Task.Factory.StartNew(action); + } + + /// + /// 已完成的Task + /// + public static Task CompletedTask { get; private set; } + + private static void InitCompletedTask() + { +#if NET45_OR_GREATER + Task task = new Task(() => { }); + task.Start(); + task.Wait(); + CompletedTask = task; +#else + CompletedTask = Task.CompletedTask; +#endif + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Action/LoopAction.cs b/src/TouchSocket/Core/Run/Action/LoopAction.cs new file mode 100644 index 000000000..8bda09cb3 --- /dev/null +++ b/src/TouchSocket/Core/Run/Action/LoopAction.cs @@ -0,0 +1,259 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 循环动作 + /// + public class LoopAction : EasyTask, IDisposable + { + /// + /// 析构函数 + /// + ~LoopAction() + { + Dispose(); + } + + private int executedCount; + + private readonly TimeSpan m_interval; + + private readonly int m_loopCount; + + private readonly EventWaitHandle m_waitHandle; + + private LoopAction(int count, TimeSpan interval, Action action) + { + m_loopCount = count; + this.action = action; + m_interval = interval; + m_waitHandle = new AutoResetEvent(false); + } + + /// + /// 创建可循环操作体 + /// + /// 循环次数,设为-1时一直循环 + /// 每次循环间隔 + /// 执行委托 + /// + public static LoopAction CreateLoopAction(int count, TimeSpan interval, Action action) + { + return new LoopAction(count, interval, action); + } + + /// + /// 创建可循环操作体 + /// + /// 循环次数,设为-1时一直循环 + /// 每次循环间隔,毫秒 + /// 执行委托 + /// + public static LoopAction CreateLoopAction(int count, int intervalMS, Action action) + { + return new LoopAction(count, TimeSpan.FromMilliseconds(intervalMS), action); + } + + /// + /// 创建可循环操作体 + /// + /// 循环次数,设为-1时一直循环 + /// 执行委托 + /// + public static LoopAction CreateLoopAction(int count, Action action) + { + return CreateLoopAction(count, TimeSpan.Zero, action); + } + + /// + /// 创建可循环操作体 + /// + /// 每次循环间隔 + /// 执行委托 + /// + public static LoopAction CreateLoopAction(TimeSpan interval, Action action) + { + return CreateLoopAction(-1, interval, action); + } + + /// + /// 创建可循环操作体 + /// + /// 执行委托 + /// + public static LoopAction CreateLoopAction(Action action) + { + return CreateLoopAction(-1, TimeSpan.Zero, action); + } + + /// + /// 已执行次数 + /// + public int ExecutedCount => executedCount; + + /// + /// 执行间隔 + /// + public TimeSpan Interval => m_interval; + + /// + /// 循环次数 + /// + public int LoopCount => m_loopCount; + + private readonly Action action; + + /// + /// 执行委托 + /// + public Action ExecuteAction => action; + + private RunStatus runStatus; + + /// + /// 是否在运行 + /// + public RunStatus RunStatus => runStatus; + + /// + /// 运行 + /// + public void Run() + { + if (runStatus == RunStatus.None) + { + runStatus = RunStatus.Running; + if (m_loopCount >= 0) + { + for (int i = 0; i < m_loopCount; i++) + { + if (runStatus == RunStatus.Disposed) + { + return; + } + action.Invoke(this); + executedCount++; + if (runStatus == RunStatus.Paused) + { + m_waitHandle.WaitOne(); + } + m_waitHandle.WaitOne(m_interval); + } + } + else + { + while (true) + { + if (runStatus == RunStatus.Disposed) + { + return; + } + action.Invoke(this); + executedCount++; + if (runStatus == RunStatus.Paused) + { + m_waitHandle.WaitOne(); + } + m_waitHandle.WaitOne(m_interval); + } + } + runStatus = RunStatus.Completed; + } + } + + /// + /// 重新运行 + /// + public void Rerun() + { + if (runStatus == RunStatus.Disposed) + { + throw new Exception("无法利用已释放的资源"); + } + runStatus = RunStatus.None; + Run(); + } + + /// + /// 以异步重新运行 + /// + /// + public Task RerunAsync() + { + if (runStatus == RunStatus.Disposed) + { + throw new Exception("无法利用已释放的资源"); + } + runStatus = RunStatus.None; + return RunAsync(); + } + + /// + /// 以异步运行 + /// + /// + public Task RunAsync() + { + return EasyTask.Run(() => + { + Run(); + }); + } + + /// + /// 暂停 + /// + public void Pause() + { + if (runStatus == RunStatus.Running) + { + m_waitHandle.Reset(); + runStatus = RunStatus.Paused; + } + } + + /// + /// 回复 + /// + public void Resume() + { + if (runStatus == RunStatus.Paused) + { + runStatus = RunStatus.Running; + m_waitHandle.Set(); + } + } + + /// + /// 释放资源 + /// + public void Dispose() + { + if (runStatus == RunStatus.Disposed) + { + return; + } + if (runStatus == RunStatus.Completed) + { + m_waitHandle.Dispose(); + } + runStatus = RunStatus.Disposed; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Action/RunStatus.cs b/src/TouchSocket/Core/Run/Action/RunStatus.cs new file mode 100644 index 000000000..8fba5fc6d --- /dev/null +++ b/src/TouchSocket/Core/Run/Action/RunStatus.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 运行状态 + /// + public enum RunStatus : byte + { + /// + /// None + /// + None, + + /// + /// Running + /// + Running, + + /// + /// Completed + /// + Completed, + + /// + /// Pause + /// + Paused, + + /// + /// Disposed + /// + Disposed + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Message/AppMessageAttribute.cs b/src/TouchSocket/Core/Run/Message/AppMessageAttribute.cs new file mode 100644 index 000000000..e45f4374f --- /dev/null +++ b/src/TouchSocket/Core/Run/Message/AppMessageAttribute.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 注册为消息 + /// + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)] + public sealed class AppMessageAttribute : Attribute + { + /// + /// 构造函数 + /// + public AppMessageAttribute() + { + } + + /// + /// 构造函数 + /// + /// + public AppMessageAttribute(string token) + { + Token = token; + } + + /// + /// 标识 + /// + public string Token { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Message/AppMessenger.cs b/src/TouchSocket/Core/Run/Message/AppMessenger.cs new file mode 100644 index 000000000..75f130352 --- /dev/null +++ b/src/TouchSocket/Core/Run/Message/AppMessenger.cs @@ -0,0 +1,269 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Resources; + +namespace TouchSocket.Core +{ + /// + /// 消息通知类。内部全为弱引用。 + /// + public class AppMessenger + { + private static AppMessenger m_instance; + private readonly ReaderWriterLockSlim m_lockSlim = new ReaderWriterLockSlim(); + private readonly Dictionary> m_tokenAndInstance = new Dictionary>(); + + /// + /// 默认单例实例 + /// + public static AppMessenger Default + { + get + { + if (m_instance != null) + { + return m_instance; + } + lock (typeof(AppMessenger)) + { + if (m_instance != null) + { + return m_instance; + } + m_instance = new AppMessenger(); + return m_instance; + } + } + } + + /// + /// 允许多广播注册 + /// + public bool AllowMultiple { get; set; } + + /// + /// 添加 + /// + /// + /// + /// + public void Add(string token, MessageInstance messageInstance) + { + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + if (m_tokenAndInstance.ContainsKey(token)) + { + if (!AllowMultiple) + { + throw new MessageRegisteredException(TouchSocketStatus.TokenExisted.GetDescription(token)); + } + m_tokenAndInstance[token].Add(messageInstance); + } + else + { + m_tokenAndInstance.Add(token, new List() + { + messageInstance + }); + } + } + } + + /// + /// 判断能否触发该消息,意味着该消息是否已经注册。 + /// + /// + /// + public bool CanSendMessage(string token) + { + using (ReadLock readLock = new ReadLock(m_lockSlim)) + { + return m_tokenAndInstance.ContainsKey(token); + } + } + + /// + /// 清除所有消息 + /// + public void Clear() + { + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + m_tokenAndInstance.Clear(); + } + } + + /// + /// 获取所有消息 + /// + /// + public string[] GetAllMessage() + { + using (ReadLock readLock = new ReadLock(m_lockSlim)) + { + return m_tokenAndInstance.Keys.ToArray(); + } + } + + /// + /// 移除 + /// + /// + public void Remove(string token) + { + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + m_tokenAndInstance.Remove(token); + } + } + + /// + /// 按对象移除 + /// + /// + public void Remove(IMessageObject messageObject) + { + using (WriteLock writeLock = new WriteLock(m_lockSlim)) + { + List key = new List(); + + foreach (var item in m_tokenAndInstance.Keys) + { + foreach (var item2 in m_tokenAndInstance[item].ToArray()) + { + if (messageObject == item2.MessageObject) + { + m_tokenAndInstance[item].Remove(item2); + if (m_tokenAndInstance[item].Count == 0) + { + key.Add(item); + } + } + } + } + + foreach (var item in key) + { + m_tokenAndInstance.Remove(item); + } + } + } + + /// + /// 发送消息 + /// + /// + /// + /// + public Task SendAsync(string token, params object[] parameters) + { + return EasyTask.Run(() => + { + using (ReadLock readLock = new ReadLock(m_lockSlim)) + { + if (m_tokenAndInstance.TryGetValue(token, out List list)) + { + List clear = new List(); + + foreach (var item in list) + { + if (!item.Static && !item.WeakReference.TryGetTarget(out _)) + { + clear.Add(item); + continue; + } + try + { + item.Invoke(item.MessageObject, parameters); + } + catch + { + } + } + + foreach (var item in clear) + { + list.Remove(item); + } + } + else + { + throw new MessageNotFoundException(TouchSocketStatus.MessageNotFound.GetDescription(token)); + } + } + }); + } + + /// + /// 发送消息,当多播时,只返回最后一个返回值 + /// + /// 返回值类型 + /// + /// + /// + /// + public Task SendAsync(string token, params object[] parameters) + { + return EasyTask.Run(() => + { + using (ReadLock readLock = new ReadLock(m_lockSlim)) + { + if (m_tokenAndInstance.TryGetValue(token, out List list)) + { + T result = default; + List clear = new List(); + for (int i = 0; i < list.Count; i++) + { + var item = list[i]; + if (!item.Static && !item.WeakReference.TryGetTarget(out _)) + { + clear.Add(item); + continue; + } + + try + { + if (i == list.Count - 1) + { + result = (T)item.Invoke(item.MessageObject, parameters); + } + else + { + item.Invoke(item.MessageObject, parameters); + } + } + catch + { + } + } + + foreach (var item in clear) + { + list.Remove(item); + } + return result; + } + else + { + throw new MessageNotFoundException(TouchSocketStatus.MessageNotFound.GetDescription(token)); + } + } + }); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs b/src/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs new file mode 100644 index 000000000..e704258ac --- /dev/null +++ b/src/TouchSocket/Core/Run/Message/AppMessengerExtensions.cs @@ -0,0 +1,321 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// AppMessengerExtensions + /// + public static class AppMessengerExtensions + { + /// + /// 注册类的静态消息 + /// + /// + public static void Register(this AppMessenger appMessenger) where T : IMessageObject + { + Type type = typeof(T); + Register(appMessenger, type); + } + + /// + /// 注册类的静态消息 + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Type type) + { + MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Default); + foreach (var method in methods) + { + IEnumerable attributes = method.GetCustomAttributes(); + foreach (var attribute in attributes) + { + if (attribute is AppMessageAttribute att) + { + if (string.IsNullOrEmpty(att.Token)) + { + Register(appMessenger, null, method.Name, method); + } + else + { + Register(appMessenger, null, att.Token, method); + } + } + } + } + } + + /// + /// 注册消息 + /// + /// + /// + public static void Register(this AppMessenger appMessenger, IMessageObject messageObject) + { + MethodInfo[] methods = messageObject.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Default); + foreach (var method in methods) + { + IEnumerable attributes = method.GetCustomAttributes(); + foreach (var attribute in attributes) + { + if (attribute is AppMessageAttribute att) + { + if (string.IsNullOrEmpty(att.Token)) + { + Register(appMessenger, messageObject, method.Name, method); + } + else + { + Register(appMessenger, messageObject, att.Token, method); + } + } + } + } + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, IMessageObject messageObject, string token, MethodInfo methodInfo) + { + appMessenger.Add(token, new MessageInstance(methodInfo, messageObject)); + } + + /// + /// 注册消息 + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Action action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + public static void Register(this AppMessenger appMessenger, Func action, string token = default) + { + RegisterDelegate(appMessenger, token, action); + } + + /// + /// 卸载消息 + /// + /// + /// + public static void Unregister(this AppMessenger appMessenger, IMessageObject messageObject) + { + appMessenger.Remove(messageObject); + } + + /// + /// 移除注册 + /// + /// + /// + /// + public static void Unregister(this AppMessenger appMessenger, string token) + { + if (token is null) + { + throw new ArgumentNullException(nameof(token)); + } + appMessenger.Remove(token); + } + + private static void RegisterDelegate(this AppMessenger appMessenger, string token, Delegate dele) + { + IEnumerable attributes = dele.Method.GetCustomAttributes(); + foreach (var attribute in attributes) + { + if (attribute is AppMessageAttribute att) + { + if (token.IsNullOrEmpty()) + { + if (string.IsNullOrEmpty(att.Token)) + { + token = dele.Method.Name; + } + else + { + token = att.Token; + } + } + + appMessenger.Add(token, new MessageInstance(dele.Method, dele.Target)); + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Message/IMessageObject.cs b/src/TouchSocket/Core/Run/Message/IMessageObject.cs new file mode 100644 index 000000000..d66bfe8a0 --- /dev/null +++ b/src/TouchSocket/Core/Run/Message/IMessageObject.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 限定消息的接口 + /// + public interface IMessageObject + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Message/MessageInstance.cs b/src/TouchSocket/Core/Run/Message/MessageInstance.cs new file mode 100644 index 000000000..b89301cbf --- /dev/null +++ b/src/TouchSocket/Core/Run/Message/MessageInstance.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// MessageInstance + /// + public class MessageInstance : Method + { + private readonly WeakReference weakReference; + + /// + /// MessageInstance + /// + /// + /// + public MessageInstance(MethodInfo method, object messageObject) : base(method) + { + weakReference = new WeakReference(messageObject); + } + + /// + /// 承载消息的实体 + /// + public object MessageObject + { + get + { + weakReference.TryGetTarget(out var target); + return target; + } + } + + /// + /// 弱引用。 + /// + public WeakReference WeakReference => weakReference; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/Timers/SingleTimer.cs b/src/TouchSocket/Core/Run/Timers/SingleTimer.cs new file mode 100644 index 000000000..4ec575d0a --- /dev/null +++ b/src/TouchSocket/Core/Run/Timers/SingleTimer.cs @@ -0,0 +1,175 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 不可重入的Timer + /// + public class SingleTimer : DisposableObject + { + private readonly Action m_action1; + private readonly Action m_action2; + private readonly object m_state; + private readonly Timer m_timer; + private readonly Action m_action3; + private int m_signal = 1; + + /// + /// 是否暂停执行。 + /// + public bool Pause { get; set; } + + /// + /// 自启动以来执行的次数。 + /// + public long Count { get; private set; } + + /// + /// 不可重入的Timer + /// + /// + /// + public SingleTimer(int period, Action action) + { + m_timer = new Timer(OnTimer, null, 0, period); + m_action3 = action; + m_state = null; + } + + /// + /// 不可重入的Timer + /// + /// + /// + public SingleTimer(TimeSpan period, Action action) + { + m_timer = new Timer(OnTimer, null, TimeSpan.Zero, period); + m_action3 = action; + m_state = null; + } + + /// + /// 不可重入的Timer + /// + /// + /// + public SingleTimer(int period, Action action) + { + m_timer = new Timer(OnTimer, null, 0, period); + m_action1 = action; + m_state = null; + } + + /// + /// 不可重入的Timer + /// + /// + /// + public SingleTimer(int period, Action action) + { + m_timer = new Timer(OnTimer, null, 0, period); + m_action2 = action; + m_state = null; + } + + /// + /// 不可重入的Timer + /// + /// + /// + /// + public SingleTimer(object state, TimeSpan period, Action action) + { + m_timer = new Timer(OnTimer, state, TimeSpan.Zero, period); + m_action1 = action; + m_state = state; + } + + /// + /// 不可重入的Timer + /// + /// + /// + /// + public SingleTimer(object state, TimeSpan period, Action action) + { + m_timer = new Timer(OnTimer, state, TimeSpan.Zero, period); + m_action2 = action; + m_state = state; + } + + /// + /// 不可重入的Timer + /// + /// + /// + /// + public SingleTimer(object state, int period, Action action) + { + m_timer = new Timer(OnTimer, state, 0, period); + m_action1 = action; + m_state = state; + } + + /// + /// 不可重入的Timer + /// + /// + /// + /// + public SingleTimer(object state, int period, Action action) + { + m_timer = new Timer(OnTimer, state, 0, period); + m_action2 = action; + m_state = state; + } + + private void OnTimer(object state) + { + if (Pause) + { + return; + } + if (Interlocked.Decrement(ref m_signal) == 0) + { + try + { + Count++; + m_action1?.Invoke(this); + m_action2?.Invoke(this, m_state); + m_action3?.Invoke(); + } + catch + { + } + finally + { + m_signal = 1; + } + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_timer.SafeDispose(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/WaitPool/IWaitResult.cs b/src/TouchSocket/Core/Run/WaitPool/IWaitResult.cs new file mode 100644 index 000000000..78e77bdce --- /dev/null +++ b/src/TouchSocket/Core/Run/WaitPool/IWaitResult.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 等待返回类 + /// + public interface IWaitResult + { + /// + /// 消息 + /// + string Message { get; set; } + + /// + /// 标记 + /// + long Sign { get; set; } + + /// + /// 状态 + /// + byte Status { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs b/src/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs new file mode 100644 index 000000000..c2798d07f --- /dev/null +++ b/src/TouchSocket/Core/Run/WaitPool/ValueWaitResult.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// ValueWaitResult + /// + [Serializable] + public struct ValueWaitResult : IWaitResult + { + /// + /// 消息 + /// + public string Message { get; set; } + + /// + /// 标记号 + /// + public long Sign { get; set; } + + /// + /// 状态 + /// + public byte Status { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/WaitPool/WaitData.cs b/src/TouchSocket/Core/Run/WaitPool/WaitData.cs new file mode 100644 index 000000000..a01341015 --- /dev/null +++ b/src/TouchSocket/Core/Run/WaitPool/WaitData.cs @@ -0,0 +1,216 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 等待数据对象 + /// + /// + public class WaitData : DisposableObject + { + private readonly AutoResetEvent m_waitHandle; + private WaitDataStatus m_status; + private T m_waitResult; + + /// + /// 构造函数 + /// + public WaitData() + { + m_waitHandle = new AutoResetEvent(false); + } + + /// + /// 延迟模式 + /// + public bool DelayModel { get; set; } + + /// + /// 状态 + /// + public WaitDataStatus Status => m_status; + + /// + /// 等待数据结果 + /// + public T WaitResult => m_waitResult; + + /// + /// 取消任务 + /// + public void Cancel() + { + m_status = WaitDataStatus.Canceled; + if (!DelayModel) + { + m_waitHandle.Set(); + } + } + + /// + /// Reset。 + /// 设置为null。然后重置状态为,waitHandle.Reset() + /// + public bool Reset() + { + m_status = WaitDataStatus.Default; + m_waitResult = default; + if (!DelayModel) + { + return m_waitHandle.Reset(); + } + return true; + } + + /// + /// 使等待的线程继续执行 + /// + public bool Set() + { + m_status = WaitDataStatus.SetRunning; + if (!DelayModel) + { + return m_waitHandle.Set(); + } + return true; + } + + /// + /// 使等待的线程继续执行 + /// + /// 等待结果 + public bool Set(T waitResult) + { + m_waitResult = waitResult; + m_status = WaitDataStatus.SetRunning; + if (!DelayModel) + { + return m_waitHandle.Set(); + } + return true; + } + + /// + /// 加载取消令箭 + /// + /// + public void SetCancellationToken(CancellationToken cancellationToken) + { + if (cancellationToken.CanBeCanceled) + { + cancellationToken.Register(Cancel); + } + } + + /// + /// 载入结果 + /// + public void SetResult(T result) + { + m_waitResult = result; + } + + /// + /// 等待指定时间 + /// + /// + public WaitDataStatus Wait(TimeSpan timeSpan) + { + return this.Wait((int)timeSpan.TotalMilliseconds); + } + + /// + /// 等待指定毫秒 + /// + /// + public WaitDataStatus Wait(int millisecond) + { + if (DelayModel) + { + for (int i = 0; i < millisecond / 10.0; i++) + { + if (m_status != WaitDataStatus.Default) + { + return m_status; + } + Task.Delay(10).GetAwaiter().GetResult(); + } + m_status = WaitDataStatus.Overtime; + return m_status; + } + else + { + if (!m_waitHandle.WaitOne(millisecond)) + { + m_status = WaitDataStatus.Overtime; + } + return m_status; + } + } + + /// + /// 等待指定时间 + /// + /// + /// + public Task WaitAsync(TimeSpan timeSpan) + { + return this.WaitAsync((int)timeSpan.TotalMilliseconds); + } + + /// + /// 等待指定毫秒 + /// + /// + public async Task WaitAsync(int millisecond) + { + if (DelayModel) + { + for (int i = 0; i < millisecond / 10.0; i++) + { + if (m_status != WaitDataStatus.Default) + { + return m_status; + } + await Task.Delay(10); + } + m_status = WaitDataStatus.Overtime; + return m_status; + } + else + { + if (!m_waitHandle.WaitOne(millisecond)) + { + m_status = WaitDataStatus.Overtime; + } + return m_status; + } + } + + /// + /// 释放 + /// + /// + protected override void Dispose(bool disposing) + { + m_status = WaitDataStatus.Disposed; + m_waitResult = default; + m_waitHandle.SafeDispose(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs b/src/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs new file mode 100644 index 000000000..49aef1ed1 --- /dev/null +++ b/src/TouchSocket/Core/Run/WaitPool/WaitDataStatus.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// 等待数据状态 + /// + public enum WaitDataStatus : byte + { + /// + /// 默认 + /// + Default, + + /// + /// 收到信号运行 + /// + SetRunning, + + /// + /// 超时 + /// + Overtime, + + /// + /// 已取消 + /// + Canceled, + + /// + /// 已释放 + /// + Disposed + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs b/src/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs new file mode 100644 index 000000000..3631cc035 --- /dev/null +++ b/src/TouchSocket/Core/Run/WaitPool/WaitHandlePool.cs @@ -0,0 +1,191 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace TouchSocket.Core +{ + /// + /// 等待处理数据 + /// + /// + public class WaitHandlePool : IDisposable where T : IWaitResult + { + private readonly ConcurrentDictionary> m_waitDic; + private readonly ConcurrentQueue> m_waitQueue; + + /// + /// 构造函数 + /// + public WaitHandlePool() + { + m_waitDic = new ConcurrentDictionary>(); + m_waitQueue = new ConcurrentQueue>(); + } + + /// + /// 销毁 + /// + /// + public void Destroy(WaitData waitData) + { + if (waitData.DisposedValue) + { + throw new ObjectDisposedException(nameof(waitData)); + } + if (m_waitDic.TryRemove(waitData.WaitResult.Sign, out _)) + { + waitData.Reset(); + m_waitQueue.Enqueue(waitData); + } + } + + /// + /// 释放 + /// + public void Dispose() + { + foreach (var item in m_waitDic.Values) + { + item.Dispose(); + } + foreach (var item in m_waitQueue) + { + item.Dispose(); + } + m_waitDic.Clear(); + + m_waitQueue.Clear(); + } + + /// + /// 取消全部 + /// + public void CancelAll() + { + foreach (var item in m_waitDic.Values) + { + item.Cancel(); + } + } + + /// + /// 延迟模式 + /// + public bool DelayModel { get; set; } = false; + + private long m_waitCount; + private long m_waitReverseCount; + + /// + /// 获取一个可等待对象 + /// + /// + /// 设置为false时,不会生成sign + /// + public WaitData GetWaitData(T result, bool autoSign = true) + { + if (m_waitQueue.TryDequeue(out var waitData)) + { + if (autoSign) + { + result.Sign = Interlocked.Increment(ref m_waitCount); + } + waitData.SetResult(result); + m_waitDic.TryAdd(result.Sign, waitData); + return waitData; + } + + waitData = new WaitData(); + waitData.DelayModel = DelayModel; + if (autoSign) + { + result.Sign = Interlocked.Increment(ref m_waitCount); + } + waitData.SetResult(result); + m_waitDic.TryAdd(result.Sign, waitData); + return waitData; + } + + /// + /// 获取一个Sign为负数的可等待对象 + /// + /// + /// 设置为false时,不会生成sign + /// + public WaitData GetReverseWaitData(T result, bool autoSign = true) + { + if (m_waitQueue.TryDequeue(out var waitData)) + { + if (autoSign) + { + result.Sign = Interlocked.Decrement(ref m_waitReverseCount); + } + waitData.SetResult(result); + m_waitDic.TryAdd(result.Sign, waitData); + return waitData; + } + + waitData = new WaitData(); + waitData.DelayModel = DelayModel; + if (autoSign) + { + result.Sign = Interlocked.Decrement(ref m_waitReverseCount); + } + waitData.SetResult(result); + m_waitDic.TryAdd(result.Sign, waitData); + return waitData; + } + + /// + /// 让等待对象恢复运行 + /// + /// + public void SetRun(long sign) + { + WaitData waitData; + if (m_waitDic.TryGetValue(sign, out waitData)) + { + waitData.Set(); + } + } + + /// + /// 让等待对象恢复运行 + /// + /// + /// + public void SetRun(long sign, T waitResult) + { + WaitData waitData; + if (m_waitDic.TryGetValue(sign, out waitData)) + { + waitData.Set(waitResult); + } + } + + /// + /// 让等待对象恢复运行 + /// + /// + public void SetRun(T waitResult) + { + if (m_waitDic.TryGetValue(waitResult.Sign, out WaitData waitData)) + { + waitData.Set(waitResult); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Run/WaitPool/WaitResult.cs b/src/TouchSocket/Core/Run/WaitPool/WaitResult.cs new file mode 100644 index 000000000..f6787b49c --- /dev/null +++ b/src/TouchSocket/Core/Run/WaitPool/WaitResult.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 等待返回类 + /// + [Serializable] + public class WaitResult : IWaitResult + { + /// + /// 消息 + /// + public string Message { get; set; } + + /// + /// 标记号 + /// + public long Sign { get; set; } + + /// + /// 状态 + /// + public byte Status { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs b/src/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs new file mode 100644 index 000000000..4c3572be0 --- /dev/null +++ b/src/TouchSocket/Core/Serialization/Attributes/FastConverterAttribute.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// FastConverterAttribute + /// + public class FastConverterAttribute : Attribute + { + /// + /// FastConverterAttribute + /// + /// + public FastConverterAttribute(Type type) + { + Type = type; + } + + /// + /// 转化器类型。 + /// + public Type Type { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs b/src/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs new file mode 100644 index 000000000..5a9b7092a --- /dev/null +++ b/src/TouchSocket/Core/Serialization/Attributes/FastNonSerializedAttribute.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Core +{ + /// + /// 忽略的Fast序列化 + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class FastNonSerializedAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs b/src/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs new file mode 100644 index 000000000..c3b79e777 --- /dev/null +++ b/src/TouchSocket/Core/Serialization/Attributes/FastSerializedAttribute.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TouchSocket.Core +{ + /// + /// 强制Fast序列化。一般当某个属性为只读时,使用该特性。 + /// + [AttributeUsage(AttributeTargets.Property)] + public class FastSerializedAttribute: Attribute + { + } +} diff --git a/src/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs b/src/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs new file mode 100644 index 000000000..fccc26a46 --- /dev/null +++ b/src/TouchSocket/Core/Serialization/FastBinary/FastBinaryFormatter.cs @@ -0,0 +1,669 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// 快速二进制序列化。 + /// + public static class FastBinaryFormatter + { + private static readonly ConcurrentDictionary m_instanceCache = new ConcurrentDictionary(); + + /// + /// 添加转换器。 + /// + public static void AddFastBinaryConverter() where TConverter : IFastBinaryConverter, new() + { + AddFastBinaryConverter(typeof(TType), (IFastBinaryConverter)Activator.CreateInstance(typeof(TConverter))); + } + + /// + /// 添加转换器。 + /// + /// + /// + public static void AddFastBinaryConverter(IFastBinaryConverter converter) + { + AddFastBinaryConverter(typeof(TType), converter); + } + + /// + /// 添加转换器。 + /// + /// + /// + public static void AddFastBinaryConverter(Type type, IFastBinaryConverter converter) + { + m_instanceCache.AddOrUpdate(type, new SerializObject(type) { Converter = converter }, (k, v) => v); + } + + #region Serialize + + /// + /// 序列化对象 + /// + /// 流 + /// 对象 + public static void Serialize(ByteBlock byteBlock, T graph) + { + byteBlock.Position = 1; + SerializeObject(byteBlock, graph); + byteBlock.Buffer[0] = 1; + byteBlock.SetLength(byteBlock.Position); + } + + private static int SerializeClass(ByteBlock stream, T obj, Type type) + { + int len = 0; + if (obj != null) + { + SerializObject serializObject = GetOrAddInstance(type); + + for (int i = 0; i < serializObject.MemberInfos.Length; i++) + { + MemberInfo memberInfo = serializObject.MemberInfos[i]; + byte[] propertyBytes = Encoding.UTF8.GetBytes(memberInfo.Name); + if (propertyBytes.Length > byte.MaxValue) + { + throw new Exception($"属性名:{memberInfo.Name}超长"); + } + stream.Write((byte)propertyBytes.Length); + stream.Write(propertyBytes, 0, propertyBytes.Length); + len += propertyBytes.Length + 1; + //len += SerializeObject(stream, property.GetValue(obj)); + len += SerializeObject(stream, serializObject.MemberAccessor.GetValue(obj, memberInfo.Name)); + } + //foreach (PropertyInfo property in serializObject.Properties) + //{ + //} + + //foreach (FieldInfo fieldInfo in serializObject.FieldInfos) + //{ + // byte[] propertyBytes = Encoding.UTF8.GetBytes(fieldInfo.Name); + // if (propertyBytes.Length > byte.MaxValue) + // { + // throw new Exception($"属性名:{fieldInfo.Name}超长"); + // } + // byte lenBytes = (byte)propertyBytes.Length; + // stream.Write(lenBytes); + // stream.Write(propertyBytes, 0, propertyBytes.Length); + // len += propertyBytes.Length + 1; + // len += SerializeObject(stream, fieldInfo.GetValue(obj)); + //} + } + return len; + } + + private static int SerializeDictionary(ByteBlock stream, IEnumerable param) + { + int len = 0; + if (param != null) + { + long oldPosition = stream.Position; + stream.Position += 4; + len += 4; + uint paramLen = 0; + + foreach (dynamic item in param) + { + len += SerializeObject(stream, item.Key); + len += SerializeObject(stream, item.Value); + paramLen++; + } + long newPosition = stream.Position; + stream.Position = oldPosition; + stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen)); + stream.Position = newPosition; + } + return len; + } + + private static int SerializeIListOrArray(ByteBlock stream, IEnumerable param) + { + int len = 0; + if (param != null) + { + long oldPosition = stream.Position; + stream.Position += 4; + len += 4; + uint paramLen = 0; + + foreach (object item in param) + { + paramLen++; + len += SerializeObject(stream, item); + } + long newPosition = stream.Position; + stream.Position = oldPosition; + stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen)); + stream.Position = newPosition; + } + return len; + } + + private static int SerializeObject(ByteBlock byteBlock, T graph) + { + int len = 0; + byte[] data = null; + + long startPosition = byteBlock.Position; + long endPosition; + if (graph != null) + { + Type type = graph.GetType(); + if (type.IsPrimitive) + { + switch (graph) + { + case byte value: + { + data = new byte[] { value }; + break; + } + case sbyte value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case bool value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case short value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case ushort value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case int value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case uint value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case long value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case ulong value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case float value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case double value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + case char value: + { + data = TouchSocketBitConverter.Default.GetBytes(value); + break; + } + default: + { + throw new Exception("未知基础类型"); + } + } + } + else + { + switch (graph) + { + case string value: + { + data = Encoding.UTF8.GetBytes(value); + break; + } + case DateTime value: + { + data = TouchSocketBitConverter.Default.GetBytes(value.Ticks); + break; + } + case Enum _: + { + var enumValType = Enum.GetUnderlyingType(type); + + if (enumValType == TouchSocketCoreUtility.byteType) + { + data = new byte[] { Convert.ToByte(graph) }; + } + else if (enumValType == TouchSocketCoreUtility.shortType) + { + data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt16(graph)); + } + else if (enumValType == TouchSocketCoreUtility.intType) + { + data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt32(graph)); + } + else + { + data = TouchSocketBitConverter.Default.GetBytes(Convert.ToInt64(graph)); + } + break; + } + case byte[] value: + { + data = value; + break; + } + default: + { + byteBlock.Position += 4; + var serializeObj = GetOrAddInstance(type); + if (serializeObj.Converter != null) + { + len += serializeObj.Converter.Write(byteBlock, graph); + } + else + { + switch (serializeObj.InstanceType) + { + case InstanceType.List: + len += SerializeIListOrArray(byteBlock, (IEnumerable)graph); + break; + + case InstanceType.Array: + len += SerializeIListOrArray(byteBlock, (IEnumerable)graph); + break; + + case InstanceType.Dictionary: + len += SerializeDictionary(byteBlock, (IEnumerable)graph); + break; + + default: + case InstanceType.Class: + len += SerializeClass(byteBlock, graph, type); + break; + } + } + break; + } + } + } + + if (data != null) + { + len = data.Length; + endPosition = len + startPosition + 4; + } + else + { + endPosition = byteBlock.Position; + } + } + else + { + endPosition = startPosition + 4; + } + + byte[] lenBuffer = TouchSocketBitConverter.Default.GetBytes(len); + byteBlock.Position = startPosition; + byteBlock.Write(lenBuffer, 0, lenBuffer.Length); + + if (data != null) + { + byteBlock.Write(data, 0, data.Length); + } + byteBlock.Position = endPosition; + return len + 4; + } + + #endregion Serialize + + #region Deserialize + + /// + /// 反序列化 + /// + /// + /// + /// + /// + public static object Deserialize(byte[] data, int offset, Type type) + { + if (data[offset] != 1) + { + throw new Exception("Fast反序列化数据流解析错误。"); + } + offset += 1; + return Deserialize(type, data, ref offset); + } + + private static object Deserialize(Type type, byte[] datas, ref int offset) + { + bool nullable = type.IsNullableType(); + if (nullable) + { + type = type.GenericTypeArguments[0]; + } + dynamic obj; + int len = TouchSocketBitConverter.Default.ToInt32(datas, offset); + offset += 4; + if (len > 0) + { + if (type == TouchSocketCoreUtility.stringType) + { + obj = Encoding.UTF8.GetString(datas, offset, len); + } + else if (type == TouchSocketCoreUtility.byteType) + { + obj = datas[offset]; + } + else if (type == TouchSocketCoreUtility.sbyteType) + { + obj = (sbyte)(TouchSocketBitConverter.Default.ToInt16(datas, offset)); + } + else if (type == TouchSocketCoreUtility.boolType) + { + obj = (TouchSocketBitConverter.Default.ToBoolean(datas, offset)); + } + else if (type == TouchSocketCoreUtility.shortType) + { + obj = (TouchSocketBitConverter.Default.ToInt16(datas, offset)); + } + else if (type == TouchSocketCoreUtility.ushortType) + { + obj = (TouchSocketBitConverter.Default.ToUInt16(datas, offset)); + } + else if (type == TouchSocketCoreUtility.intType) + { + obj = (TouchSocketBitConverter.Default.ToInt32(datas, offset)); + } + else if (type == TouchSocketCoreUtility.uintType) + { + obj = (TouchSocketBitConverter.Default.ToUInt32(datas, offset)); + } + else if (type == TouchSocketCoreUtility.longType) + { + obj = (TouchSocketBitConverter.Default.ToInt64(datas, offset)); + } + else if (type == TouchSocketCoreUtility.ulongType) + { + obj = (TouchSocketBitConverter.Default.ToUInt64(datas, offset)); + } + else if (type == TouchSocketCoreUtility.floatType) + { + obj = (TouchSocketBitConverter.Default.ToSingle(datas, offset)); + } + else if (type == TouchSocketCoreUtility.doubleType) + { + obj = (TouchSocketBitConverter.Default.ToDouble(datas, offset)); + } + else if (type == TouchSocketCoreUtility.decimalType) + { + obj = (TouchSocketBitConverter.Default.ToDouble(datas, offset)); + } + else if (type == TouchSocketCoreUtility.charType) + { + obj = (TouchSocketBitConverter.Default.ToChar(datas, offset)); + } + else if (type == TouchSocketCoreUtility.dateTimeType) + { + obj = (new DateTime(TouchSocketBitConverter.Default.ToInt64(datas, offset))); + } + else if (type.BaseType == typeof(Enum)) + { + Type enumType = Enum.GetUnderlyingType(type); + + if (enumType == typeof(byte)) + { + obj = Enum.ToObject(type, datas[offset]); + } + else if (enumType == typeof(short)) + { + obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt16(datas, offset)); + } + else if (enumType == typeof(int)) + { + obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt32(datas, offset)); + } + else + { + obj = Enum.ToObject(type, TouchSocketBitConverter.Default.ToInt64(datas, offset)); + } + } + else if (type == TouchSocketCoreUtility.bytesType) + { + byte[] data = new byte[len]; + Buffer.BlockCopy(datas, offset, data, 0, len); + obj = data; + } + else if (type.IsClass || type.IsStruct()) + { + if (m_instanceCache.TryGetValue(type, out var serializObject) && serializObject.Converter != null) + { + obj = serializObject.Converter.Read(datas, offset, len); + } + else + { + obj = DeserializeClass(type, datas, offset, len); + } + } + else + { + throw new Exception("未定义的类型:" + type.ToString()); + } + } + else + { + if (nullable) + { + obj = null; + } + else + { + obj = type.GetDefault(); + } + } + offset += len; + return obj; + } + + private static object DeserializeClass(Type type, byte[] datas, int offset, int length) + { + SerializObject serializObject = GetOrAddInstance(type); + + object instance; + switch (serializObject.InstanceType) + { + case InstanceType.Class: + { + instance = serializObject.GetNewInstance(); + int index = offset; + while (offset - index < length && (length >= 4)) + { + int len = datas[offset]; + string propertyName = Encoding.UTF8.GetString(datas, offset + 1, len); + offset += len + 1; + if (serializObject.IsStruct) + { + if (serializObject.PropertiesDic.ContainsKey(propertyName)) + { + PropertyInfo property = serializObject.PropertiesDic[propertyName]; + object obj = Deserialize(property.PropertyType, datas, ref offset); + property.SetValue(instance, obj); + } + else if (serializObject.FieldInfosDic.ContainsKey(propertyName)) + { + FieldInfo property = serializObject.FieldInfosDic[propertyName]; + object obj = Deserialize(property.FieldType, datas, ref offset); + property.SetValue(instance, obj); + } + else + { + int pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset); + offset += 4; + offset += pLen; + } + } + else + { + if (serializObject.PropertiesDic.TryGetValue(propertyName, out PropertyInfo property)) + { + object obj = Deserialize(property.PropertyType, datas, ref offset); + serializObject.MemberAccessor.SetValue(instance, property.Name, obj); + } + else if (serializObject.FieldInfosDic.TryGetValue(propertyName, out FieldInfo fieldInfo)) + { + object obj = Deserialize(fieldInfo.FieldType, datas, ref offset); + serializObject.MemberAccessor.SetValue(instance, fieldInfo.Name, obj); + } + else + { + int pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset); + offset += 4; + offset += pLen; + } + } + } + break; + } + case InstanceType.List: + { + instance = serializObject.GetNewInstance(); + if (length > 0) + { + uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset); + offset += 4; + for (uint i = 0; i < paramLen; i++) + { + object obj = Deserialize(serializObject.ArgTypes[0], datas, ref offset); + serializObject.AddMethod.Invoke(instance, new object[] { obj }); + } + } + else + { + instance = null; + } + break; + } + case InstanceType.Array: + { + if (length > 0) + { + uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset); + Array array = Array.CreateInstance(serializObject.ArrayType, paramLen); + + offset += 4; + for (uint i = 0; i < paramLen; i++) + { + object obj = Deserialize(serializObject.ArrayType, datas, ref offset); + array.SetValue(obj, i); + } + instance = array; + } + else + { + instance = null; + } + break; + } + case InstanceType.Dictionary: + { + instance = serializObject.GetNewInstance(); + if (length > 0) + { + uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset); + offset += 4; + for (uint i = 0; i < paramLen; i++) + { + object key = Deserialize(serializObject.ArgTypes[0], datas, ref offset); + object value = Deserialize(serializObject.ArgTypes[1], datas, ref offset); + if (key != null) + { + serializObject.AddMethod.Invoke(instance, new object[] { key, value }); + } + } + + //uint paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset); + //offset += 4; + //for (uint i = 0; i < paramLen; i++) + //{ + // offset += 4; + // offset += datas[offset] + 1; + // object key = this.Deserialize(instanceObject.ArgTypes[0], datas, ref offset); + + // offset += datas[offset] + 1; + // object value = this.Deserialize(instanceObject.ArgTypes[1], datas, ref offset); + // if (key != null) + // { + // instanceObject.AddMethod.Invoke(instance, new object[] { key, value }); + // } + //} + } + else + { + instance = null; + } + break; + } + default: + instance = null; + break; + } + + return instance; + } + + #endregion Deserialize + + private static SerializObject GetOrAddInstance(Type type) + { + if (m_instanceCache.TryGetValue(type, out SerializObject instance)) + { + return instance; + } + if (type.IsArray)//数组 + { + SerializObject instanceObject = new SerializObject(type); + m_instanceCache.TryAdd(type, instanceObject); + return instanceObject; + } + else if (type.IsClass || type.IsStruct()) + { + if (type.IsNullableType()) + { + type = type.GetGenericArguments()[0]; + } + + SerializObject instanceObject = new SerializObject(type); + m_instanceCache.TryAdd(type, instanceObject); + return instanceObject; + } + return null; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs b/src/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs new file mode 100644 index 000000000..199dc36dc --- /dev/null +++ b/src/TouchSocket/Core/Serialization/FastBinary/IFastBinaryConverter.cs @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Core +{ + /// + /// FastBinary转换器 + /// + public interface IFastBinaryConverter + { + /// + /// 读取 + /// + /// + /// + /// + /// + public object Read(byte[] buffer, int offset, int len); + + /// + /// 写入 + /// + /// + /// + public int Write(ByteBlock byteBlock, object obj); + } + + /// + /// FastBinary转换器 + /// + /// + public abstract class FastBinaryConverter : IFastBinaryConverter + { + int IFastBinaryConverter.Write(ByteBlock byteBlock, object obj) + { + return Write(byteBlock, (T)obj); + } + + object IFastBinaryConverter.Read(byte[] buffer, int offset, int len) + { + return Read(buffer, offset, len); + } + + /// + /// 写入 + /// + /// + /// + protected abstract int Write(ByteBlock byteBlock, T obj); + + /// + /// 读取 + /// + /// + /// + /// + /// + protected abstract T Read(byte[] buffer, int offset, int len); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs b/src/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs new file mode 100644 index 000000000..7383eea49 --- /dev/null +++ b/src/TouchSocket/Core/Serialization/FastBinary/InstanceType.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + internal enum InstanceType + { + Class, + List, + Array, + Dictionary + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs b/src/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs new file mode 100644 index 000000000..29e080dc3 --- /dev/null +++ b/src/TouchSocket/Core/Serialization/FastBinary/SerializObject.cs @@ -0,0 +1,191 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace TouchSocket.Core +{ + internal class SerializObject + { + private MemberInfo[] m_MemberInfos; + private FieldInfo[] m_fieldInfos; + private PropertyInfo[] m_properties; + public IFastBinaryConverter Converter { get; set; } + public SerializObject(Type type) + { + Type = type; + if (type.IsArray)//数组 + { + this.InstanceType = InstanceType.Array; + this.ArrayType = type.GetElementType(); + } + else if (type.IsClass || type.IsStruct()) + { + if (type.IsNullableType()) + { + type = type.GetGenericArguments()[0]; + } + this.Type = type; + if (TouchSocketCoreUtility.listType.IsAssignableFrom(type)) + { + Type genericType = type; + while (true) + { + if (genericType.IsGenericType) + { + break; + } + genericType = genericType.BaseType; + if (genericType == TouchSocketCoreUtility.objType) + { + break; + } + } + this.ArgTypes = genericType.GetGenericArguments(); + this.AddMethod = new Method(type.GetMethod("Add")); + this.InstanceType = InstanceType.List; + } + else if (TouchSocketCoreUtility.dicType.IsAssignableFrom(type)) + { + Type genericType = type; + while (true) + { + if (genericType.IsGenericType) + { + break; + } + genericType = genericType.BaseType; + if (genericType == TouchSocketCoreUtility.objType) + { + break; + } + } + this.ArgTypes = genericType.GetGenericArguments(); + this.AddMethod = new Method(type.GetMethod("Add")); + this.InstanceType = InstanceType.Dictionary; + } + else + { + this.InstanceType = InstanceType.Class; + MemberAccessor = new MemberAccessor(type) + { + OnGetFieldInfes = GetFieldInfos, + OnGetProperties = GetProperties + }; + MemberAccessor.Build(); + } + if (type.GetCustomAttribute() is FastConverterAttribute attribute) + { + this.Converter = (IFastBinaryConverter)Activator.CreateInstance(attribute.Type); + } + this.PropertiesDic = GetProperties(type).ToDictionary(a => a.Name); + this.FieldInfosDic = GetFieldInfos(type).ToDictionary(a => a.Name); + if (type.IsGenericType) + { + this.ArgTypes = type.GetGenericArguments(); + } + } + this.IsStruct = type.IsStruct(); + } + + public bool IsStruct { get; private set; } + + public Method AddMethod { get; private set; } + + public Type[] ArgTypes { get; private set; } + + public Type ArrayType { get; private set; } + + public FieldInfo[] FieldInfos + { + get + { + m_fieldInfos ??= FieldInfosDic.Values.ToArray(); + return m_fieldInfos; + } + } + + public MemberInfo[] MemberInfos + { + get + { + if (m_MemberInfos == null) + { + List infos = new List(); + infos.AddRange(FieldInfosDic.Values); + infos.AddRange(PropertiesDic.Values); + m_MemberInfos = infos.ToArray(); + } + return m_MemberInfos; + } + } + + public Dictionary FieldInfosDic { get; private set; } + + public InstanceType InstanceType { get; private set; } + + public MemberAccessor MemberAccessor { get; private set; } + + public PropertyInfo[] Properties + { + get + { + m_properties ??= PropertiesDic.Values.ToArray(); + return m_properties; + } + } + + public Dictionary PropertiesDic { get; private set; } + + public Type Type { get; private set; } + + public object GetNewInstance() + { + return Activator.CreateInstance(Type); + } + + private static FieldInfo[] GetFieldInfos(Type type) + { + return type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default) + .Where(p => + { + return !p.IsInitOnly && (!p.IsDefined(typeof(FastNonSerializedAttribute), true)); + }) + .ToArray(); + } + + private static PropertyInfo[] GetProperties(Type type) + { + return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default) + .Where(p => + { + if (p.IsDefined(typeof(FastSerializedAttribute), true)) + { + return true; + } + else + { + return p.CanWrite && + p.CanRead && + (!p.IsDefined(typeof(FastNonSerializedAttribute), true) && + (p.SetMethod.GetParameters().Length == 1) && + (p.GetMethod.GetParameters().Length == 0)); + } + }) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs b/src/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs new file mode 100644 index 000000000..fb59f6111 --- /dev/null +++ b/src/TouchSocket/Core/Serialization/FastBinary/SerializationType.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Core +{ + /// + /// 序列化类型 + /// + public enum SerializationType : byte + { + /// + /// 内置快速二进制 + /// + FastBinary, + + /// + /// Json + /// + Json, + + /// + /// Xml + /// + Xml, + + /// + /// 系统二进制。微软认为这是不安全的,所以谨慎使用。 + /// + SystemBinary + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/Json/JsonFast.cs b/src/TouchSocket/Core/Serialization/Json/JsonFast.cs new file mode 100644 index 000000000..8fb30b4fe --- /dev/null +++ b/src/TouchSocket/Core/Serialization/Json/JsonFast.cs @@ -0,0 +1,881 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.Dynamic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace TouchSocket.Core +{ + /// + /// Json高速转换 + /// 此代码来源:https://gitee.com/majorworld + /// + public static class JsonFastConverter + { + /// + /// 全局时间序列化样式,默认为yyyy-MM-dd HH:mm:ss + /// + public static string TimeFormat = "yyyy-MM-dd HH:mm:ss"; + + /// + /// 将Json字符串转为指定类型 + /// + /// + /// + /// + public static T JsonFrom(string s) where T : class + { + return (T)JsonFrom(s, typeof(T)); + } + + /// + /// 将Json字符串转为指定类型 + /// + /// + /// + /// + /// + public static object JsonFrom(string s, Type t) + { + if (s == null) + throw new NullReferenceException("不能为null"); + StringBuilder sb = new StringBuilder(s.Length); + Dictionary dict = new Dictionary(); + List list = new List(); + int index = 0; + switch (s[0]) + { + case '{': + return s.GetObject(ref index, sb, list).ToObject(t); + + case '[': + var data = s.GetArray(ref index, sb, dict); + if (t == typeof(DataTable)) + return data.ToDataTable();//处理表类型 + if (t.GetGenericArguments().Length < 1) + { + if (t.IsArray) + JsonChange.ChangeArray(t.GetElementType(), data);//处理数组类型 + return JsonChange.ChangeData(t, data);//处理动态类型 + } + if (t.IsList()) + { + return JsonChange.ChangeList(t.GetGenericArguments()[0], data);//处理集合类型 + } + throw new NullReferenceException("类型应该为集合或数组或dynamic"); + default: + throw new NullReferenceException("第一个字符缺失{或["); + } + } + + /// + /// 将Json字符串转为对象
+ /// 重载,当前数据类型速度最快 + ///
+ /// + /// + public static Dictionary JsonFrom(string s) + { + return JsonFrom>(s); + } + + /// + /// 将对象转为Json字符串 + /// + /// + /// + /// 时间序列化样式,默认为yyyy-MM-dd HH:mm:ss + /// + public static string JsonTo(T t, string timeFormat = null) + { + StringBuilder sb = new StringBuilder(); + t.CodeObject(sb, timeFormat ?? TimeFormat); + return sb.ToString(); + } + } + + /// + /// 过滤不需要序列化的字段 + /// + public class JsonFastIgnore : Attribute + { } + + /// + /// 转换为实体类对应的类型 + /// + internal static class JsonChange + { + #region 类型判断 + + internal static bool IsDictionary(this Type type) => (typeof(IDictionary).IsAssignableFrom(type)); + + internal static bool IsList(this Type type) => (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)); + + #endregion 类型判断 + + #region 转换 + + /// + /// 处理数组类型 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ChangeArray(Type type, IList data) + { + var array = Array.CreateInstance(type, data.Count); + for (int i = 0; i < data.Count; i++) + { + array.SetValue(type.ChangeData(data[i]), i); + } + return array; + } + + /// + /// 转换ArrayList类型 + /// https://gitee.com/majorworld + /// + /// + /// + internal static ArrayList ChangeArrayList(object value) + { + ArrayList array = new ArrayList(); + if (value is IList list) + { + foreach (var item in list) + array.Add(item); + } + return array; + } + + /// + /// 转换Color类型 + /// https://gitee.com/majorworld + /// + /// + /// + internal static Color ChangeColor(string s) + { + if (s[0] == '#') + return Color.FromArgb(Convert.ToInt32(s.Substring(1), 16)); + var c = s.Split(','); + if (c.Length == 3) + return Color.FromArgb(int.Parse(c[0]), int.Parse(c[1]), int.Parse(c[2])); + else if (c.Length == 4) + return Color.FromArgb(int.Parse(c[0]), int.Parse(c[1]), int.Parse(c[2]), int.Parse(c[3])); + return Color.FromName(s); + } + + /// + /// 转换为各种数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ChangeData(this Type p, object value) + { + if (value is Dictionary dictionary) + { + return ToObject(dictionary, p);//解析子级实体类的数据 + } + else if (p == typeof(string)) + { + return Convert.ChangeType(value, p); + } + else if (p.IsPrimitive && p != typeof(char)) + { + return Convert.ChangeType(value, p); + } + else if (p == typeof(byte[])) + { + return Convert.FromBase64String(value as string); + } + else if (p == typeof(Color)) + { + return ChangeColor(value as string); + } + else if (p == typeof(Point)) + { + return ChangePoint(value as string); + } + else if (p == typeof(Guid)) + { + return Guid.Parse(value as string); + } + else if (p == typeof(ArrayList)) + { + return ChangeArrayList(value);//处理动态数组类型 + } + else if (value is IList list) + { + if (p.GetGenericArguments().Length < 1) + { + if (p.IsArray) + return ChangeArray(p.GetElementType(), value as IList);//处理数组类型 + List d = new List(); + foreach (var kv in list as dynamic) + { + if (kv is Dictionary dict) + d.Add(dict.ToObject(typeof(object))); + } + return d;//解析dynamic + } + return ChangeList(p.GetGenericArguments()[0], value as List);//处理List类型 + } + return Convert.ChangeType(value, p); + } + + /// + /// 处理字典类型 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ChangeDictionary(Type type, Dictionary dict) + { + //反射创建泛型字典 + var t = typeof(Dictionary<,>).MakeGenericType(new[] { type.GetGenericArguments()[0], type.GetGenericArguments()[1] }); ; + var d = Activator.CreateInstance(t) as IDictionary; + foreach (var item in dict) + d.Add(type.GetGenericArguments()[0].ChangeData(item.Key), type.GetGenericArguments()[1].ChangeData(item.Value)); + return d; + } + + /// + /// 处理集合类型 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ChangeList(Type type, List data) + { + IList list = Activator.CreateInstance(typeof(List<>).MakeGenericType(type)) as IList; + foreach (var item in data) + list.Add(type.ChangeData(item)); + return list; + } + + /// + /// 转换Point类型 + /// https://gitee.com/majorworld + /// + /// + /// + internal static Point ChangePoint(string s) + { + var c = s.Split(','); + return new Point(int.Parse(c[0]), int.Parse(c[1])); + } + + /// + /// List转DataTable + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static DataTable ToDataTable(this List list) + { + DataTable dt = new DataTable(); + for (int i = 0; i < list.Count; i++) + { + Dictionary dict = list[i] as Dictionary; + if (i == 0) + { + foreach (var item in dict) + { + dt.Columns.Add(item.Key, item.Value.GetType()); + } + } + dt.Rows.Add(dict.Values.ToArray()); + } + return dt; + } + + /// + /// 转换为对象 + /// https://gitee.com/majorworld + /// + /// + /// + /// + internal static object ToObject(this Dictionary dict, Type type) + { + //(1/4)返回原始解析数据 + if (type == typeof(Dictionary)) + { + return dict; + } + //(2/4)返回dynamic类型数据 + if (type.UnderlyingSystemType.Name == "Object") + { + dynamic d = new ExpandoObject(); + foreach (var kv in dict) + { + if (kv.Value is Dictionary dictionary) + (d as ICollection>).Add(new KeyValuePair(kv.Key, ToObject(dictionary, typeof(object)))); + else + (d as ICollection>).Add(kv); + } + return d; + } + //(3/4)返回DataSet类型数据 + if (type == typeof(DataSet)) + { + DataSet ds = new DataSet(); + foreach (var item in dict) + { + if (item.Value is List list) + { + var dt = list.ToDataTable(); + dt.TableName = item.Key; + ds.Tables.Add(dt); + } + } + return ds; + } + //(4/4)返回所绑定的实体类数据 + var obj = Activator.CreateInstance(type); + var props = type.GetCacheInfo(); + foreach (var kv in dict) + { + var prop = props.Where(x => string.Equals(x.Name, kv.Key, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + if (prop is null) + { + if (type.IsDictionary()) + { + return ChangeDictionary(type, dict);//解析值是字典的数据(非缓存字段的字典) + } + continue; + } + if (prop.CanWrite) + { + prop.SetValue(obj, prop.PropertyType.ChangeData(kv.Value), null);//递归调用当前方法,解析子级 + } + } + return obj; + } + + private static object Go(string sValue) + { + Type type = typeof(T); + return System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(sValue.ToString()); + } + + #endregion 转换 + } + + /// + /// 解析字符串为对象 + /// + internal static class JsonDecode + { + #region 解析 + + /// + /// 解析集合 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + /// + internal static List GetArray(this string s, ref int index, StringBuilder sb, Dictionary dict) + { + index++; + List list = new List(); + while (index < s.Length) + { + switch (s[index]) + { + case ',': + index++; + break; + + case '"': + list.Add(s.GetString(ref index, sb)); + break; + + case ']': + ++index; + return list; + + case ' ': + case '\r': + case '\n': + case '\t': + case '\f': + case '\b': + ++index; + break; + + default: + list.Add(s.GetData(s[index], ref index, sb, dict, list)); + break; + } + } + return list; + } + + /// + /// 解析对象 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + /// + internal static Dictionary GetObject(this string s, ref int index, StringBuilder sb, List list) + { + index++; + Dictionary dict = new Dictionary(); + string key = string.Empty; + bool iskey = true; + while (index < s.Length) + { + switch (s[index]) + { + case ',': + iskey = true; + key = string.Empty; + index++; + break; + + case ':': + iskey = false; + index++; + break; + + case '}': + ++index; + return dict; + + case '"': + if (iskey) + key = s.GetString(ref index, sb); + else + dict.Add(key, s.GetString(ref index, sb)); + break; + + case ' ': + case '\r': + case '\n': + case '\t': + case '\f': + case '\b': + index++; + break; + + default: + dict.Add(key, s.GetData(s[index], ref index, sb, dict, list)); + break; + } + } + throw new FormatException("解析错误,不完整的Json"); + } + + /// + /// 获取布尔数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + private static bool GetBool(this string s, ref int index, bool state) + { + if (state) + { + if (s[index + 1] == 'r' && s[index + 2] == 'u' && s[index + 3] == 'e') + { + index += 4; + return true; + } + } + else + { + if (s[index + 1] == 'a' && s[index + 2] == 'l' && s[index + 3] == 's' && s[index + 4] == 'e') + { + index += 5; + return false; + } + } + throw new FormatException($"\"{string.Concat(s[index], s[index + 1], s[index + 2], s[index + 3])}\"处Json格式无法解析"); + } + + /// + /// 自动获取数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + /// + /// + /// + private static object GetData(this string s, char c, ref int index, StringBuilder sb, Dictionary dict, List list) + { + switch (c) + { + case 't': + return s.GetBool(ref index, true); + + case 'f': + return s.GetBool(ref index, false); + + case 'n': + return s.GetNull(ref index); + + case '{': + return s.GetObject(ref index, sb, list); + + case '[': + return s.GetArray(ref index, sb, dict); + + default: + return s.GetNumber(ref index, sb); + } + } + + /// + /// 获取空数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + private static object GetNull(this string s, ref int index) + { + if (s[index + 1] == 'u' && s[index + 2] == 'l' && s[index + 3] == 'l') + { + index += 4; + return null; + } + throw new FormatException($"\"{string.Concat(s[index], s[index + 1], s[index + 2], s[index + 3])}\"处Json格式无法解析"); + } + + /// + /// 获取数字数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + private static object GetNumber(this string s, ref int index, StringBuilder sb) + { + sb.Clear(); + for (; index < s.Length; ++index) + { + if (s[index] == ',' || s[index] == '}' || s[index] == ']' || s[index] == ' ' || s[index] == '\n' || s[index] == '\r') + break; + else + sb.Append(s[index]); + } + string code = sb.ToString(); + if (long.TryParse(code, out long x)) + return x; + if (double.TryParse(code, out double y)) + return y; + throw new FormatException($"\"{code}\"处Json格式无法解析"); + } + + /// + /// 获取字符串数据 + /// https://gitee.com/majorworld + /// + /// + /// + /// + /// + private static string GetString(this string s, ref int index, StringBuilder sb) + { + sb.Clear(); + index++; + for (; index < s.Length; ++index) + { + switch (s[index]) + { + case '"': + index++; + return sb.ToString(); + + case '\\': + if (s[index + 1] == '"' || s[index + 1] == '\\') + index++; + sb.Append(s[index]); + break; + + default: + sb.Append(s[index]); + break; + } + } + throw new FormatException($"\"{sb}\"处Json格式无法解析"); + } + + #endregion 解析 + } + + /// + /// 编码对象为字符串 + /// + internal static class JsonEncode + { + /// + /// 缓存数据加速序列化速度,主要是减少不必要的GetCustomAttributes获取特性并过滤字段 + /// + internal static ConcurrentDictionary InfoCache = new ConcurrentDictionary(); + + /// + /// 序列化 + /// + /// + /// + /// + internal static void CodeObject(this object obj, StringBuilder sb, string timeFormat) + { + bool get = true; + switch (obj) + { + case null: + sb.Append("null"); + break; + + case Enum _: + sb.Append($"{Convert.ToInt32(obj)}"); + break; + + case byte[] bytes: + sb.Append($"\"{Convert.ToBase64String(bytes)}\""); + break; + + case Array array: + sb.Append('['); + for (int i = 0; i < array.Length; i++) + { + if (i != 0) + sb.Append(","); + array.GetValue(i).CodeObject(sb, timeFormat); + } + sb.Append(']'); + break; + + case string _: + sb.Append($"\"{obj}\""); + break; + + case char _: + sb.Append($"\"{obj}\""); + break; + + case bool _: + sb.Append($"{obj.ToString().ToLower()}"); + break; + + case DataTable dt: + dt.CodeDataTable(sb, timeFormat); + break; + + case DataSet ds: + sb.Append('{'); + for (int i = 0; i < ds.Tables.Count; i++) + { + if (i != 0) + sb.Append(","); + sb.Append($"\"{ds.Tables[i].TableName}\":"); + ds.Tables[i].CodeDataTable(sb, timeFormat); + } + sb.Append('}'); + break; + + case DateTime time: + sb.AppendFormat($"\"{time.ToString(timeFormat)}\""); + break; + + case Guid id: + sb.AppendFormat($"\"{id}\""); + break; + + case Color color: + if (color.A == 255) + sb.Append($"\"{color.R},{color.G},{color.B}\""); + else + sb.Append($"\"{color.A},{color.R},{color.G},{color.B}\""); + break; + + case Point point: + sb.Append($"\"{point.X},{point.Y}\""); + break; + + case ArrayList list: + sb.Append('['); + for (int i = 0; i < list.Count; i++) + { + if (i != 0) + sb.Append(","); + list[i].CodeObject(sb, timeFormat); + } + sb.Append(']'); + break; + + default: + get = false; + break; + } + if (get) + return; + Type type = obj.GetType(); + //数字 + if (type.IsPrimitive && type != typeof(char)) + { + sb.Append($"{obj}"); + return; + } + //字典 + else if (type.IsDictionary()) + { + sb.Append('{'); + var collection = obj as IDictionary; + var enumerator = collection.GetEnumerator(); + int index = 0; + while (enumerator.MoveNext()) + { + if (index != 0) + sb.Append(","); + sb.Append($"\"{enumerator.Key}\":"); + enumerator.Value.CodeObject(sb, timeFormat); + index++; + } + sb.Append('}'); + return; + } + //集合 + else if (type.IsList()) + { + sb.Append('['); + if (obj is IList list) + { + for (int i = 0; i < list.Count; i++) + { + if (i != 0) + sb.Append(","); + list[i].CodeObject(sb, timeFormat); + } + } + sb.Append(']'); + return; + } + else if (type.UnderlyingSystemType.Name == "ExpandoObject") + { + sb.Append('{'); + bool first = true; + foreach (dynamic item in obj as dynamic) + { + if (!first) + sb.Append(','); + first = false; + object value = item.Value; + sb.Append($"\"{item.Key}\":"); + value.CodeObject(sb, timeFormat); + } + sb.Append('}'); + return; + } + + //对象 + var prop = type.GetCacheInfo(); + if (prop is null) + { + sb.Append("null"); + return; + } + sb.Append('{'); + for (int i = 0; i < prop.Length; i++) + { + PropertyInfo p = prop[i]; + if (i != 0) + sb.Append(","); + var data = p.GetValue(obj, null); + sb.Append($"\"{p.Name}\":"); + data.CodeObject(sb, timeFormat); + } + sb.Append("}"); + } + + /// + /// 尝试获取缓存中的类型,排除忽略的字段 + /// + /// + /// + internal static PropertyInfo[] GetCacheInfo(this Type type) + { + if (InfoCache.TryGetValue(type, out PropertyInfo[] props)) { } + else + { + props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); + List cache = new List(); + foreach (var item in props) + { + if (Attribute.GetCustomAttributes(item, typeof(JsonFastIgnore))?.Length == 0) + cache.Add(item); + } + InfoCache[type] = cache.ToArray(); + props = cache.ToArray(); + } + return props; + } + + /// + /// 序列化DataTable + /// + /// + /// + /// 时间格式化样式,默认为yyyy-MM-dd HH:mm:ss + private static void CodeDataTable(this DataTable dt, StringBuilder sb, string timeFormat) + { + sb.Append('['); + for (int i = 0; i < dt.Rows.Count; i++) + { + if (i != 0) + sb.Append(","); + var item = dt.Rows[i]; + sb.Append('{'); + for (int j = 0; j < dt.Columns.Count; j++) + { + if (j != 0) + sb.Append(","); + var cell = dt.Columns[j]; + sb.Append($"\"{cell}\":"); + item[j].CodeObject(sb, timeFormat); + } + sb.Append('}'); + } + sb.Append(']'); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/Json/JsonNet.cs b/src/TouchSocket/Core/Serialization/Json/JsonNet.cs new file mode 100644 index 000000000..6b019753c --- /dev/null +++ b/src/TouchSocket/Core/Serialization/Json/JsonNet.cs @@ -0,0 +1,147 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq; +using System.Reflection; + +namespace TouchSocket.Core +{ + /// + /// 提供Json.net无引用调用。 + /// 该代码来源:https://www.cnblogs.com/kewei/p/8228343.html + /// + internal static class JsonNet + { + /// + /// Json.Net程序集名称 + /// + private static readonly string jsonNetAssemblyName = "Newtonsoft.Json"; + + /// + /// JsonConvert类名 + /// + private static readonly string jsonNetJsonConvertTypeName = "Newtonsoft.Json.JsonConvert"; + + /// + /// 序列化方法的委托 + /// + private static Func serializeFunc = null; + + /// + /// 反序列化方法的委托 + /// + private static Func deserializeFunc = null; + + /// + /// 获取是否得到支持 + /// + public static bool IsSupported { get; private set; } = false; + + /// + /// Json.net + /// + static JsonNet() + { + AppDomain.CurrentDomain.AssemblyLoad += (s, e) => InitJsonNet(e.LoadedAssembly); + InitJsonNet(AppDomain.CurrentDomain.GetAssemblies()); + } + + /// + /// 序列化对象 + /// + /// 对象 + /// + public static string SerializeObject(object obj) + { + return JsonNet.serializeFunc.Invoke(obj); + } + + /// + /// 反序列化为对象 + /// + /// json文本 + /// 对象类型 + /// + public static object DeserializeObject(string json, Type type) + { + return JsonNet.deserializeFunc.Invoke(json, type); + } + + /// + /// 初始化json.net + /// + /// 查找的程序集 + private static void InitJsonNet(params Assembly[] assemblies) + { + if (JsonNet.IsSupported == true) + { + return; + } + + var jsonNetAssembly = assemblies + .FirstOrDefault(item => item.GetName().Name.Equals(jsonNetAssemblyName, StringComparison.OrdinalIgnoreCase)); + + if (jsonNetAssembly == null) + { + return; + } + + var jsonConvertType = jsonNetAssembly.GetType(jsonNetJsonConvertTypeName, false); + if (jsonConvertType == null) + { + return; + } + + serializeFunc = CreateSerializeObjectFunc(jsonConvertType); + deserializeFunc = CreateDeserializeObjectFunc(jsonConvertType); + JsonNet.IsSupported = serializeFunc != null && deserializeFunc != null; + } + + public static bool InitJsonNet(Type jsonConvertType) + { + serializeFunc = CreateSerializeObjectFunc(jsonConvertType); + deserializeFunc = CreateDeserializeObjectFunc(jsonConvertType); + return JsonNet.IsSupported = serializeFunc != null && deserializeFunc != null; + } + + /// + /// 创建SerializeObject方法的委托 + /// + /// JsonConvert类型 + /// + private static Func CreateSerializeObjectFunc(Type classType) + { + var method = classType.GetMethod("SerializeObject", new[] { typeof(object) }); + if (method == null) + { + return null; + } + return (Func)method.CreateDelegate(typeof(Func)); + } + + /// + /// 创建DeserializeObject方法的委托 + /// + /// JsonConvert类型 + /// + private static Func CreateDeserializeObjectFunc(Type classType) + { + var method = classType.GetMethod("DeserializeObject", new[] { typeof(string), typeof(Type) }); + if (method == null) + { + return null; + } + return (Func)method.CreateDelegate(typeof(Func)); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/Serialization/SerializeConvert.cs b/src/TouchSocket/Core/Serialization/SerializeConvert.cs new file mode 100644 index 000000000..444fafa71 --- /dev/null +++ b/src/TouchSocket/Core/Serialization/SerializeConvert.cs @@ -0,0 +1,523 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Xml.Serialization; + +namespace TouchSocket.Core +{ + /// + /// 高性能序列化器 + /// + public static class SerializeConvert + { +#pragma warning disable SYSLIB0011 // 微软觉得不安全,不推荐使用 + + #region 普通二进制序列化 + + /// + /// 普通二进制序列化对象 + /// + /// 数据对象 + /// + public static byte[] BinarySerialize(object obj) + { + using (MemoryStream serializeStream = new MemoryStream()) + { + BinaryFormatter bf = new BinaryFormatter(); + bf.Serialize(serializeStream, obj); + return serializeStream.ToArray(); + } + } + + /// + /// 二进制序列化对象至文件 + /// + /// 数据对象 + /// 路径 + public static void BinarySerializeToFile(object obj, string path) + { + using (FileStream serializeStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite)) + { + BinaryFormatter bf = new BinaryFormatter(); + bf.Serialize(serializeStream, obj); + serializeStream.Close(); + } + } + + /// + /// 二进制序列化对象 + /// + /// + /// + public static void BinarySerialize(Stream stream, object obj) + { + BinaryFormatter bf = new BinaryFormatter(); + bf.Serialize(stream, obj); + } + + #endregion 普通二进制序列化 + + #region 普通二进制反序列化 + + /// + /// 从Byte[]中反序列化 + /// + /// + /// + /// + /// + /// + /// + public static T BinaryDeserialize(byte[] data, int offset, int length, SerializationBinder binder = null) + { + using (MemoryStream DeserializeStream = new MemoryStream(data, offset, length)) + { + DeserializeStream.Position = 0; + BinaryFormatter bf = new BinaryFormatter(); + if (binder != null) + { + bf.Binder = binder; + } + return (T)bf.Deserialize(DeserializeStream); + } + } + + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + public static object BinaryDeserialize(byte[] data, int offset, int length, SerializationBinder binder = null) + { + using (MemoryStream DeserializeStream = new MemoryStream(data, offset, length)) + { + DeserializeStream.Position = 0; + BinaryFormatter bf = new BinaryFormatter(); + if (binder != null) + { + bf.Binder = binder; + } + return bf.Deserialize(DeserializeStream); + } + } + + /// + /// 从Stream中反序列化 + /// + /// + /// + /// + /// + public static T BinaryDeserialize(Stream stream, SerializationBinder binder = null) + { + BinaryFormatter bf = new BinaryFormatter(); + if (binder != null) + { + bf.Binder = binder; + } + return (T)bf.Deserialize(stream); + } + + /// + /// 将二进制文件数据反序列化为指定类型对象 + /// + /// + /// + /// + public static T BinaryDeserializeFromFile(string path) + { + using (FileStream serializeStream = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + BinaryFormatter bf = new BinaryFormatter(); + return (T)bf.Deserialize(serializeStream); + } + } + + /// + /// 将二进制数据反序列化为指定类型对象 + /// + /// + /// + /// + public static T BinaryDeserialize(byte[] data) + { + return BinaryDeserialize(data, 0, data.Length); + } + + /// + /// 从Byte[]中反序列化 + /// + /// + /// + /// + /// + public static T BinaryDeserialize(byte[] data, SerializationBinder binder = null) + { + return BinaryDeserialize(data, 0, data.Length, binder); + } + + #endregion 普通二进制反序列化 + +#pragma warning restore SYSLIB0011 // 微软觉得不安全,不推荐使用 + + #region Fast二进制序列化 + + /// + /// Fast二进制序列化对象 + /// + /// + /// + /// + public static void FastBinarySerialize(ByteBlock stream, T obj) + { + FastBinaryFormatter.Serialize(stream, obj); + } + + /// + /// Fast二进制序列化对象 + /// + /// + /// + public static byte[] FastBinarySerialize(T obj) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + FastBinarySerialize(byteBlock, obj); + return byteBlock.ToArray(); + } + } + + #endregion Fast二进制序列化 + + #region Fast二进制反序列化 + + /// + /// Fast反序列化 + /// + /// + /// + /// + /// + public static T FastBinaryDeserialize(byte[] data, int offset) + { + return (T)FastBinaryFormatter.Deserialize(data, offset, typeof(T)); + } + + /// + /// Fast反序列化 + /// + /// + /// + /// + /// + public static object FastBinaryDeserialize(byte[] data, int offset, Type type) + { + return FastBinaryFormatter.Deserialize(data, offset, type); + } + + /// + /// 从Byte[]中反序列化 + /// + /// + /// + /// + public static T FastBinaryDeserialize(byte[] data) + { + return FastBinaryDeserialize(data, 0); + } + + #endregion Fast二进制反序列化 + + #region Xml序列化和反序列化 + + /// + /// Xml序列化数据对象 + /// + /// 数据对象 + /// 编码格式 + /// + public static string XmlSerializeToString(object obj, Encoding encoding) + { + return encoding.GetString(XmlSerializeToBytes(obj)); + } + + /// + /// Xml序列化数据对象 + /// + /// 数据对象 + /// + public static string XmlSerializeToString(object obj) + { + return XmlSerializeToString(obj, Encoding.UTF8); + } + + /// + /// Xml序列化数据对象 + /// + /// 数据对象 + /// + public static byte[] XmlSerializeToBytes(object obj) + { + using (MemoryStream fileStream = new MemoryStream()) + { + XmlSerializer xml = new XmlSerializer(obj.GetType()); + xml.Serialize(fileStream, obj); + return fileStream.ToArray(); + } + } + + /// + /// Xml序列化至文件 + /// + /// + /// + public static void XmlSerializeToFile(object obj, string path) + { + using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite)) + { + XmlSerializer xml = new XmlSerializer(obj.GetType()); + xml.Serialize(fileStream, obj); + fileStream.Close(); + } + } + + /// + /// Xml反序列化 + /// + /// 反序列化类型 + /// 数据 + /// + public static T XmlDeserializeFromBytes(byte[] datas) + { + XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); + using (Stream xmlstream = new MemoryStream(datas)) + { + return (T)xmlserializer.Deserialize(xmlstream); + } + } + + /// + /// Xml反序列化 + /// + /// + /// + /// + public static object XmlDeserializeFromBytes(byte[] datas, Type type) + { + XmlSerializer xmlserializer = new XmlSerializer(type); + using (Stream xmlstream = new MemoryStream(datas)) + { + return xmlserializer.Deserialize(xmlstream); + } + } + + /// + /// Xml反序列化 + /// + /// 类型 + /// xml字符串 + /// 编码格式 + /// + public static T XmlDeserializeFromString(string xmlString, Encoding encoding) + { + XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); + using (Stream xmlstream = new MemoryStream(encoding.GetBytes(xmlString))) + { + return (T)xmlserializer.Deserialize(xmlstream); + } + } + + /// + /// Xml反序列化 + /// + /// 类型 + /// xml字符串 + /// + public static T XmlDeserializeFromString(string json) + { + return XmlDeserializeFromString(json, Encoding.UTF8); + } + + /// + /// Xml反序列化 + /// + /// 反序列化类型 + /// 文件路径 + /// + public static T XmlDeserializeFromFile(string path) + { + using (Stream xmlstream = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); + return (T)xmlserializer.Deserialize(xmlstream); + } + } + + #endregion Xml序列化和反序列化 + + #region Json序列化和反序列化 + + /// + /// 首先使用NewtonsoftJson.默认True。 + /// + /// 当设置True时,json序列化会优先使用NewtonsoftJson(需要将dll加载到程序)。 + /// 当设置为FALSE,或者NewtonsoftJson不可用时,netstandard2.0和net45平台将使用。 + /// 其他平台将使用System.Text.Json。 + /// + /// + public static bool NewtonsoftJsonFirst { get; set; } = true; + + /// + /// 判断是否支持NewtonsoftJson + /// + public static bool NewtonsoftJsonIsSupported => JsonNet.IsSupported; + + /// + /// 主动载入NewtonsoftJson。 + /// + /// 传入命名为JsonConvert的类型 + /// + public static bool LoadNewtonsoftJson(Type jsonConvertType) + { + return JsonNet.InitJsonNet(jsonConvertType); + } + + /// + /// 转换为Json + /// + /// + /// + public static string ToJson(this object item) + { + if (NewtonsoftJsonFirst && JsonNet.IsSupported) + { + return JsonNet.SerializeObject(item); + } + +#if NETCOREAPP3_1_OR_GREATER + return System.Text.Json.JsonSerializer.Serialize(item); +#else + return JsonFastConverter.JsonTo(item); +#endif + } + + /// + /// 从字符串到json + /// + /// + /// + /// + public static object FromJson(this string json, Type type) + { + if (NewtonsoftJsonFirst && JsonNet.IsSupported) + { + return JsonNet.DeserializeObject(json, type); + } + +#if NETCOREAPP3_1_OR_GREATER + return System.Text.Json.JsonSerializer.Deserialize(json,type); +#else + return JsonFastConverter.JsonFrom(json, type); +#endif + } + + /// + /// 从字符串到json + /// + /// + /// + /// + public static T FromJson(this string json) + { + return (T)FromJson(json, typeof(T)); + } + + /// + /// Json序列化数据对象 + /// + /// 数据对象 + /// + public static byte[] JsonSerializeToBytes(object obj) + { + return ToJson(obj).ToUTF8Bytes(); + } + + /// + /// Json序列化至文件 + /// + /// + /// + public static void JsonSerializeToFile(object obj, string path) + { + using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite)) + { + var date = JsonSerializeToBytes(obj); + fileStream.Write(date, 0, date.Length); + fileStream.Close(); + } + } + + /// + /// Json反序列化 + /// + /// 反序列化类型 + /// 数据 + /// + public static T JsonDeserializeFromBytes(byte[] datas) + { + return (T)JsonDeserializeFromBytes(datas, typeof(T)); + } + + /// + /// Xml反序列化 + /// + /// + /// + /// + public static object JsonDeserializeFromBytes(byte[] datas, Type type) + { + return FromJson(Encoding.UTF8.GetString(datas), type); + } + + /// + /// Json反序列化 + /// + /// 类型 + /// json字符串 + /// + public static T JsonDeserializeFromString(string json) + { + return FromJson(json); + } + + /// + /// Json反序列化 + /// + /// 反序列化类型 + /// 文件路径 + /// + public static T JsonDeserializeFromFile(string path) + { + return JsonDeserializeFromString(File.ReadAllText(path)); + } + + #endregion Json序列化和反序列化 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Core/代码说明.txt b/src/TouchSocket/Core/代码说明.txt new file mode 100644 index 000000000..8c0373cac --- /dev/null +++ b/src/TouchSocket/Core/代码说明.txt @@ -0,0 +1,10 @@ +该程序代码由三大部分组成,网络来源、开源程序集以及自编代码。若汝棋茗仅享有自编代码版权,且只为自编代码授权。 +其中代码版权说明由于是工具生成,所以会对非自编代码也标注,但是我们会在类注释中说明, +或设置XREF命名空间(XREF命名空间下的所有代码均来自开源社区)表示,所以请读者悉知。 + +例如: +1、SnowflakeIDGenerator类代码,来源于网络,所以已在类注释中说明。 + + +感谢!! +感谢所有第三方代码的开源贡献。 diff --git a/src/TouchSocket/Http/Common/FileCachePool.cs b/src/TouchSocket/Http/Common/FileCachePool.cs new file mode 100644 index 000000000..c47f68f0a --- /dev/null +++ b/src/TouchSocket/Http/Common/FileCachePool.cs @@ -0,0 +1,444 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.Web; +using TouchSocket.Core; + +namespace TouchSocket.Http +{ + /// + /// 静态文件缓存池 + /// + public class FileCachePool : DisposableObject + { + /// + /// 添加委托 + /// + /// + /// + /// + /// + /// + public delegate bool InsertHandler(FileCachePool cache, string key, byte[] value, TimeSpan timeout); + + #region Cache items access + + /// + /// Is the file cache empty? + /// + public bool Empty => entriesByKey.Count == 0; + + /// + /// Get the file cache size + /// + public int Size => entriesByKey.Count; + + /// + /// Add a new cache value with the given timeout into the file cache + /// + /// Key to add + /// Value to add + /// Cache timeout (default is 0 - no timeout) + /// 'true' if the cache value was added, 'false' if the given key was not added + public bool Add(string key, byte[] value, TimeSpan timeout = new TimeSpan()) + { + using (new WriteLock(lockEx)) + { + // Try to find and remove the previous key + entriesByKey.Remove(key); + + // Update the cache entry + entriesByKey.Add(key, new MemCacheEntry(value, timeout)); + + return true; + } + } + + /// + /// Try to find the cache value by the given key + /// + /// Key to find + /// + /// 'true' and cache value if the cache value was found, 'false' if the given key was not found + public bool Find(string key, out byte[] data) + { + using (new ReadLock(lockEx)) + { + // Try to find the given key + if (!entriesByKey.TryGetValue(key, out var cacheValue)) + { + data = null; + return false; + } + data = cacheValue.Value; + return true; + } + } + + /// + /// Remove the cache value with the given key from the file cache + /// + /// Key to remove + /// 'true' if the cache value was removed, 'false' if the given key was not found + public bool Remove(string key) + { + using (new WriteLock(lockEx)) + { + return entriesByKey.Remove(key); + } + } + + #endregion Cache items access + + #region Cache management methods + + /// + /// Insert a new cache path with the given timeout into the file cache + /// + /// Path to insert + /// Cache prefix (default is "/") + /// Cache filter (default is "*.*") + /// Cache timeout (default is 0 - no timeout) + /// Cache insert handler (default is 'return cache.Add(key, value, timeout)') + /// 'true' if the cache path was setup, 'false' if failed to setup the cache path + public bool InsertPath(string path, string prefix = "/", string filter = "*.*", TimeSpan timeout = new TimeSpan(), InsertHandler handler = null) + { + handler ??= (FileCachePool cache, string key, byte[] value, TimeSpan timespan) => cache.Add(key, value, timespan); + + // Try to find and remove the previous path + RemovePathInternal(path); + + using (new WriteLock(lockEx)) + { + // Add the given path to the cache + pathsByKey.Add(path, new FileCacheEntry(this, prefix, path, filter, handler, timeout)); + // Create entries by path map + entriesByPath[path] = new HashSet(); + } + + // Insert the cache path + if (!InsertPathInternal(path, path, prefix, timeout, handler)) + return false; + + return true; + } + + /// + /// Try to find the cache path + /// + /// Path to find + /// 'true' if the cache path was found, 'false' if the given path was not found + public bool FindPath(string path) + { + using (new ReadLock(lockEx)) + { + // Try to find the given key + return pathsByKey.ContainsKey(path); + } + } + + /// + /// Remove the cache path from the file cache + /// + /// Path to remove + /// 'true' if the cache path was removed, 'false' if the given path was not found + public bool RemovePath(string path) + { + return RemovePathInternal(path); + } + + /// + /// Clear the memory cache + /// + public void Clear() + { + using (new WriteLock(lockEx)) + { + // Stop all file system watchers + foreach (var fileCacheEntry in pathsByKey) + fileCacheEntry.Value.StopWatcher(); + + // Clear all cache entries + entriesByKey.Clear(); + entriesByPath.Clear(); + pathsByKey.Clear(); + } + } + + #endregion Cache management methods + + #region Cache implementation + + private readonly ReaderWriterLockSlim lockEx = new ReaderWriterLockSlim(); + private readonly Dictionary entriesByKey = new Dictionary(); + private readonly Dictionary> entriesByPath = new Dictionary>(); + private readonly Dictionary pathsByKey = new Dictionary(); + + private class MemCacheEntry + { + private readonly byte[] _value; + private readonly TimeSpan _timespan; + + public byte[] Value => _value; + public TimeSpan Timespan => _timespan; + + public MemCacheEntry(byte[] value, TimeSpan timespan = new TimeSpan()) + { + _value = value; + _timespan = timespan; + } + + public MemCacheEntry(string value, TimeSpan timespan = new TimeSpan()) + { + _value = Encoding.UTF8.GetBytes(value); + _timespan = timespan; + } + }; + + private class FileCacheEntry + { + private readonly string _prefix; + private readonly string _path; + private readonly InsertHandler _handler; + private readonly TimeSpan _timespan; + private readonly FileSystemWatcher _watcher; + + public FileCacheEntry(FileCachePool cache, string prefix, string path, string filter, InsertHandler handler, TimeSpan timespan) + { + _prefix = prefix; + _path = path; + _handler = handler; + _timespan = timespan; + _watcher = new FileSystemWatcher(); + + // Start the filesystem watcher + StartWatcher(cache, path, filter); + } + + private void StartWatcher(FileCachePool cache, string path, string filter) + { + FileCacheEntry entry = this; + + // Initialize a new filesystem watcher + _watcher.Created += (sender, e) => OnCreated(sender, e, cache, entry); + _watcher.Changed += (sender, e) => OnChanged(sender, e, cache, entry); + _watcher.Deleted += (sender, e) => OnDeleted(sender, e, cache, entry); + _watcher.Renamed += (sender, e) => OnRenamed(sender, e, cache, entry); + _watcher.Path = path; + _watcher.IncludeSubdirectories = true; + _watcher.Filter = filter; + _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite; + _watcher.EnableRaisingEvents = true; + } + + public void StopWatcher() + { + _watcher.Dispose(); + } + + private static bool IsDirectory(string path) + { + try + { + // Skip directory updates + if (File.GetAttributes(path).HasFlag(FileAttributes.Directory)) + return true; + } + catch (Exception) { } + + return false; + } + + private static void OnCreated(object sender, FileSystemEventArgs e, FileCachePool cache, FileCacheEntry entry) + { + var key = e.FullPath.Replace(entry._path, entry._prefix); + var file = e.FullPath; + + // Skip missing files + if (!File.Exists(file)) + return; + // Skip directory updates + if (IsDirectory(file)) + return; + + cache.InsertFileInternal(entry._path, file, key, entry._timespan, entry._handler); + } + + private static void OnChanged(object sender, FileSystemEventArgs e, FileCachePool cache, FileCacheEntry entry) + { + if (e.ChangeType != WatcherChangeTypes.Changed) + return; + + var key = e.FullPath.Replace(entry._path, entry._prefix); + var file = e.FullPath; + + // Skip missing files + if (!File.Exists(file)) + return; + // Skip directory updates + if (IsDirectory(file)) + return; + + cache.InsertFileInternal(entry._path, file, key, entry._timespan, entry._handler); + } + + private static void OnDeleted(object sender, FileSystemEventArgs e, FileCachePool cache, FileCacheEntry entry) + { + var key = e.FullPath.Replace(entry._path, entry._prefix); + var file = e.FullPath; + + cache.RemoveFileInternal(entry._path, key); + } + + private static void OnRenamed(object sender, RenamedEventArgs e, FileCachePool cache, FileCacheEntry entry) + { + var oldKey = e.OldFullPath.Replace(entry._path, entry._prefix); + var oldFile = e.OldFullPath; + var newKey = e.FullPath.Replace(entry._path, entry._prefix); + var newFile = e.FullPath; + + // Skip missing files + if (!File.Exists(newFile)) + return; + // Skip directory updates + if (IsDirectory(newFile)) + return; + + cache.RemoveFileInternal(entry._path, oldKey); + cache.InsertFileInternal(entry._path, newFile, newKey, entry._timespan, entry._handler); + } + }; + + private bool InsertFileInternal(string path, string file, string key, TimeSpan timeout, InsertHandler handler) + { + try + { + key = key.Replace('\\', '/'); + file = file.Replace('\\', '/'); + + // Load the cache file content + var content = File.ReadAllBytes(file); + if (!handler(this, key, content, timeout)) + return false; + + using (new WriteLock(lockEx)) + { + // Update entries by path map + entriesByPath[path].Add(key); + } + + return true; + } + catch (Exception) { return false; } + } + + private bool RemoveFileInternal(string path, string key) + { + try + { + key = key.Replace('\\', '/'); + + using (new WriteLock(lockEx)) + { + // Update entries by path map + entriesByPath[path].Remove(key); + } + + return Remove(key); + } + catch (Exception) { return false; } + } + + private bool InsertPathInternal(string root, string path, string prefix, TimeSpan timeout, InsertHandler handler) + { + try + { + string keyPrefix = (string.IsNullOrEmpty(prefix) || (prefix == "/")) ? "/" : (prefix + "/"); + + // Iterate through all directory entries + foreach (var item in Directory.GetDirectories(path)) + { + string key = keyPrefix + HttpUtility.UrlDecode(Path.GetFileName(item)); + + // Recursively insert sub-directory + if (!InsertPathInternal(root, item, key, timeout, handler)) + return false; + } + + foreach (var item in Directory.GetFiles(path)) + { + string key = keyPrefix + HttpUtility.UrlDecode(Path.GetFileName(item)); + + // Insert file into the cache + if (!InsertFileInternal(root, item, key, timeout, handler)) + return false; + } + + return true; + } + catch (Exception) { return false; } + } + + private bool RemovePathInternal(string path) + { + using (new WriteLock(lockEx)) + { + // Try to find the given path + if (!pathsByKey.TryGetValue(path, out var cacheValue)) + return false; + + // Stop the file system watcher + cacheValue.StopWatcher(); + + // Remove path entries + foreach (var entryKey in entriesByPath[path]) + entriesByKey.Remove(entryKey); + entriesByPath.Remove(path); + + // Remove cache path + pathsByKey.Remove(path); + + return true; + } + } + + #endregion Cache implementation + + #region IDisposable implementation + + /// + /// 释放 + /// + /// + protected override void Dispose(bool disposing) + { + Clear(); + base.Dispose(disposing); + } + + /// + /// 析构函数 + /// + ~FileCachePool() + { + // Simply call Dispose(false). + Dispose(false); + } + + #endregion IDisposable implementation + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/HttpBase.cs b/src/TouchSocket/Http/Common/HttpBase.cs new file mode 100644 index 000000000..454346bea --- /dev/null +++ b/src/TouchSocket/Http/Common/HttpBase.cs @@ -0,0 +1,279 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http基础头部 + /// + public abstract class HttpBase : BlockReader, IRequestInfo + { + /// + /// 服务器版本 + /// + public static readonly string ServerVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + + /// + /// 内容长度 + /// + protected long m_contentLength; + + private static readonly byte[] m_rnrnCode = Encoding.UTF8.GetBytes("\r\n\r\n"); + + private IgnoreCaseNameValueCollection m_headers; + + /// + /// 构造函数 + /// + public HttpBase() + { + ReadTimeout = 1000 * 30; + } + + /// + /// 能否写入。 + /// + public abstract bool CanWrite { get; } + + /// + /// 客户端 + /// + public abstract ITcpClientBase Client { get; } + + /// + /// 内容填充完成 + /// + public bool? ContentComplated { get; protected set; } = null; + + /// + /// int类型,内容长度 + /// + public int ContentLen + { + get => (int)m_contentLength; + set => m_contentLength = value; + } + + /// + /// 内容长度 + /// + public long ContentLength + { + get => m_contentLength; + set => m_contentLength = value; + } + + /// + /// 内容类型 + /// + public string ContentType { get; set; } + + /// + /// 传递标识 + /// + public object Flag { get; set; } + + /// + /// 请求头集合 + /// + public IgnoreCaseNameValueCollection Headers + { + get + { + m_headers ??= new IgnoreCaseNameValueCollection(); + return m_headers; + } + } + + /// + /// 协议名称,默认HTTP + /// + public string Protocols { get; set; } = "HTTP"; + + /// + /// HTTP协议版本,默认1.1 + /// + public string ProtocolVersion { get; set; } = "1.1"; + + /// + /// 请求行 + /// + public string RequestLine { get; private set; } + + /// + /// 获取头值 + /// + /// + /// + public string GetHeader(string fieldName) + { + return GetHeaderByKey(fieldName); + } + + /// + /// 获取头集合的值 + /// + /// + /// + public string GetHeader(HttpHeaders header) + { + var fieldName = header.GetDescription(); + if (fieldName == null) return null; + return Headers.Get(fieldName); + } + + /// + /// + /// + /// + /// + /// + public bool ParsingHeader(ByteBlock byteBlock, int length) + { + int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, length, m_rnrnCode); + if (index > 0) + { + int headerLength = index - byteBlock.Pos; + ReadHeaders(byteBlock.Buffer, byteBlock.Pos, headerLength); + byteBlock.Pos += headerLength; + return true; + } + else + { + return false; + } + } + + /// + /// 从Request中持续读取数据。 + /// + /// + /// + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + return base.Read(buffer, offset, count); + } + + /// + /// 从内存中读取 + /// + /// + /// + /// + public void ReadHeaders(byte[] buffer, int offset, int length) + { + string data = Encoding.UTF8.GetString(buffer, offset, length); + string[] rows = Regex.Split(data, "\r\n"); + + //Request URL & Method & Version + RequestLine = rows[0]; + + //Request Headers + GetRequestHeaders(rows); + long.TryParse(GetHeader(HttpHeaders.ContentLength), out m_contentLength); + LoadHeaderProterties(); + } + + /// + /// 设置一次性内容 + /// + /// + /// + public abstract void SetContent(byte[] content); + + /// + /// 设置请求头 + /// + /// + /// + public HttpBase SetHeaderByKey(string fieldName, string value) + { + if (string.IsNullOrEmpty(fieldName)) return this; + Headers.Add(fieldName, value); + return this; + } + + /// + /// 获取一次性内容。 + /// + /// + public abstract bool TryGetContent(out byte[] content); + + /// + /// 持续写入内容。 + /// + /// + /// + /// + public abstract void WriteContent(byte[] buffer, int offset, int count); + + internal bool InternalInput(byte[] buffer, int offset, int length) + { + return Input(buffer, offset, length); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (!DisposedValue && CanRead) + { + TryGetContent(out _); + } + + base.Dispose(disposing); + } + + /// + /// 读取信息 + /// + protected abstract void LoadHeaderProterties(); + + private string GetHeaderByKey(string fieldName) + { + if (string.IsNullOrEmpty(fieldName)) return null; + return Headers.Get(fieldName); + } + + private void GetRequestHeaders(IEnumerable rows) + { + if (rows == null || rows.Count() <= 0) + { + return; + } + + foreach (var item in rows) + { + string[] kv = item.SplitFirst(':'); + if (kv.Length == 2) + { + string key = kv[0].ToLower(); + Headers.Add(key, kv[1]); + } + } + + ContentType = GetHeader(HttpHeaders.ContentType); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/HttpContext.cs b/src/TouchSocket/Http/Common/HttpContext.cs new file mode 100644 index 000000000..68bb4d0d3 --- /dev/null +++ b/src/TouchSocket/Http/Common/HttpContext.cs @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Http +{ + /// + /// Http上下文 + /// + public class HttpContext + { + private HttpResponse m_response; + + /// + /// 构造函数 + /// + /// + public HttpContext(HttpRequest request) + { + Request = request ?? throw new ArgumentNullException(nameof(request)); + } + + /// + /// 构造函数 + /// + /// + /// + public HttpContext(HttpRequest request, HttpResponse response) + { + Request = request ?? throw new ArgumentNullException(nameof(request)); + m_response = response ?? throw new ArgumentNullException(nameof(response)); + } + + /// + /// Http请求 + /// + public HttpRequest Request { get; } + + /// + /// Http响应 + /// + public HttpResponse Response + { + get + { + lock (this) + { + if (m_response == null) + { + m_response = new HttpResponse(Request.Client, true); + } + return m_response; + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/HttpProxy.cs b/src/TouchSocket/Http/Common/HttpProxy.cs new file mode 100644 index 000000000..9b2714220 --- /dev/null +++ b/src/TouchSocket/Http/Common/HttpProxy.cs @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http代理 + /// + public class HttpProxy + { + /// + /// 不带基本验证的代理 + /// + /// + public HttpProxy(IPHost host) + { + Host = host; + } + + /// + /// 带基本验证的代理 + /// + /// + /// + /// + public HttpProxy(IPHost host, string userName, string passWord) + { + Host = host; + Credential = new NetworkCredential(userName, passWord, $"{host.IP}:{host.Port}"); + } + + /// + /// 验证代理 + /// + public NetworkCredential Credential { get; set; } + + /// + /// 代理的地址 + /// + public IPHost Host { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/HttpRange.cs b/src/TouchSocket/Http/Common/HttpRange.cs new file mode 100644 index 000000000..fa9e54825 --- /dev/null +++ b/src/TouchSocket/Http/Common/HttpRange.cs @@ -0,0 +1,139 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; + +namespace TouchSocket.Http +{ + /// + /// Range: bytes=0-499 表示第 0-499 字节范围的内容 + /// Range: bytes=500-999 表示第 500-999 字节范围的内容 + /// Range: bytes=-500 表示最后 500 字节的内容 + /// Range: bytes=500- 表示从第 500 字节开始到文件结束部分的内容 + /// Range: bytes=0-0,-1 表示第一个和最后一个字节 + /// Range: bytes=500-600,601-999 同时指定几个范围 + /// + public class HttpRange + { + /// + /// 转换获取的集合 + /// + /// + /// + /// + public static HttpRange[] GetRanges(string rangeStr, long size) + { + string[] ranges = rangeStr.Split('='); + if (ranges.Length != 2) + { + return new HttpRange[0]; + } + rangeStr = ranges[1]; + if (string.IsNullOrEmpty(rangeStr)) + { + return new HttpRange[0]; + } + ranges = rangeStr.Split(','); + List httpRanges = new List(); + foreach (var range in ranges) + { + HttpRange httpRange = new HttpRange(); + ranges = range.Split('-'); + if (ranges.Length == 2) + { + if (range.StartsWith("-")) + { + httpRange.Length = Convert.ToInt64(ranges[1]); + httpRange.Start = size - httpRange.Length; + } + else if (range.EndsWith("-")) + { + httpRange.Start = Convert.ToInt64(ranges[0]); + httpRange.Length = size - httpRange.Start; + } + else + { + httpRange.Start = Convert.ToInt64(ranges[0]); + httpRange.Length = Convert.ToInt64(ranges[1]) - httpRange.Start + 1; + } + } + else + { + continue; + } + httpRanges.Add(httpRange); + } + return httpRanges.ToArray(); + } + + /// + /// 转换获取的集合 + /// + /// + /// + /// + public static HttpRange GetRange(string rangeStr, long size) + { + string[] ranges = rangeStr.Split('='); + if (ranges.Length != 2) + { + return null; + } + rangeStr = ranges[1]; + if (string.IsNullOrEmpty(rangeStr)) + { + return null; + } + ranges = rangeStr.Split(','); + foreach (var range in ranges) + { + HttpRange httpRange = new HttpRange(); + ranges = range.Split('-'); + if (ranges.Length == 2) + { + if (range.StartsWith("-")) + { + httpRange.Length = Convert.ToInt64(ranges[1]); + httpRange.Start = size - httpRange.Length; + } + else if (range.EndsWith("-")) + { + httpRange.Start = Convert.ToInt64(ranges[0]); + httpRange.Length = size - httpRange.Start; + } + else + { + httpRange.Start = Convert.ToInt64(ranges[0]); + httpRange.Length = Convert.ToInt64(ranges[1]) - httpRange.Start + 1; + } + } + else + { + continue; + } + return httpRange; + } + return null; + } + + /// + /// 起始位置 + /// + public long Start { get; set; } = -1; + + /// + /// 长度 + /// + public long Length { get; set; } = -1; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/HttpRequest.cs b/src/TouchSocket/Http/Common/HttpRequest.cs new file mode 100644 index 000000000..47871269d --- /dev/null +++ b/src/TouchSocket/Http/Common/HttpRequest.cs @@ -0,0 +1,455 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// HTTP请求定义 + /// + public class HttpRequest : HttpBase + { + private bool m_canRead; + private ITcpClientBase m_client; + private byte[] m_content; + private NameValueCollection m_forms; + private NameValueCollection m_params; + private NameValueCollection m_query; + private string m_relativeURL; + private bool m_sentHeader; + private int m_sentLength; + private string m_uRL; + + /// + /// 构造函数 + /// + /// + /// + public HttpRequest(ITcpClientBase client, bool isServer = false) + { + m_client = client; + if (isServer) + { + m_canRead = true; + CanWrite = false; + } + else + { + m_canRead = false; + CanWrite = true; + } + } + + /// + /// 构造函数 + /// + public HttpRequest() + { + m_canRead = false; + CanWrite = false; + } + + /// + /// + /// + public override bool CanRead => m_canRead; + + /// + /// + /// + public override bool CanWrite { get; } + + /// + /// + /// + public override ITcpClientBase Client => m_client; + + /// + /// 表单数据 + /// + public NameValueCollection Forms + { + get + { + if (ContentType == @"application/x-www-form-urlencoded") + { + m_forms ??= GetParameters(this.GetBody()); + return m_forms; + } + + return m_forms ??= new NameValueCollection(); + } + } + + /// + /// 获取时候保持连接 + /// + public bool KeepAlive + { + get + { + if (ProtocolVersion == "1.0") + { + return false; + } + else + { + if (GetHeader(HttpHeaders.Connection) == "keep-alive") + { + return true; + } + else + { + return false; + } + } + } + } + + /// + /// HTTP请求方式。 + /// + public string Method { get; set; } + + /// + /// Body参数 + /// + public NameValueCollection Params + { + get + { + m_params ??= new NameValueCollection(); + return m_params; + } + } + + /// + /// url参数 + /// + public NameValueCollection Query + { + get + { + m_query ??= new NameValueCollection(); + return m_query; + } + } + + /// + /// 相对路径(不含参数) + /// + public string RelativeURL => m_relativeURL; + + /// + /// Url全地址,包含参数 + /// + public string URL => m_uRL; + + /// + /// 构建响应数据。 + /// 当数据较大时,不建议这样操作,可直接 + /// + /// + public void Build(ByteBlock byteBlock) + { + BuildHeader(byteBlock); + BuildContent(byteBlock); + } + + /// + /// 构建数据为字节数组。 + /// + /// + public byte[] BuildAsBytes() + { + using ByteBlock byteBlock = new ByteBlock(); + Build(byteBlock); + return byteBlock.ToArray(); + } + + /// + /// 设置内容 + /// + /// + public override void SetContent(byte[] content) + { + m_content = content; + ContentLength = content.Length; + ContentComplated = true; + } + + /// + /// 设置Url,必须以“/”开头,可带参数 + /// + /// + /// + /// + public HttpRequest SetUrl(string url, bool justValue = false) + { + if (justValue || url.StartsWith("/")) + { + m_uRL = url; + } + else + { + m_uRL = "/" + url; + } + ParseUrl(); + return this; + } + + /// + /// 输出 + /// + public override string ToString() + { + using (ByteBlock byteBlock = new ByteBlock()) + { + Build(byteBlock); + return byteBlock.ToString(); + } + } + + /// + /// + /// + /// + public override bool TryGetContent(out byte[] content) + { + if (!ContentComplated.HasValue) + { + if (m_contentLength == 0) + { + m_content = new byte[0]; + content = m_content; + ContentComplated = true; + return true; + } + try + { + using MemoryStream block1 = new MemoryStream(); + using ByteBlock block2 = new ByteBlock(); + byte[] buffer = block2.Buffer; + while (true) + { + int r = Read(buffer, 0, buffer.Length); + if (r == 0) + { + break; + } + block1.Write(buffer, 0, r); + } + ContentComplated = true; + m_content = block1.ToArray(); + content = m_content; + return true; + } + catch + { + ContentComplated = false; + content = null; + return false; + } + finally + { + m_canRead = false; + } + } + else if (ContentComplated == true) + { + content = m_content; + return true; + } + else + { + content = null; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public override void WriteContent(byte[] buffer, int offset, int count) + { + if (!CanWrite) + { + throw new NotSupportedException("该对象不支持持续写入内容。"); + } + if (!m_sentHeader) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + BuildHeader(byteBlock); + m_client.DefaultSend(byteBlock); + } + m_sentHeader = true; + } + if (m_sentLength + count <= m_contentLength) + { + m_client.DefaultSend(buffer, offset, count); + m_sentLength += count; + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_client = null; + base.Dispose(disposing); + } + + /// + /// 从内存中读取 + /// + protected override void LoadHeaderProterties() + { + var first = Regex.Split(RequestLine, @"(\s+)").Where(e => e.Trim() != string.Empty).ToArray(); + if (first.Length > 0) Method = first[0].Trim().ToUpper(); + if (first.Length > 1) + { + SetUrl(Uri.UnescapeDataString(first[1])); + } + if (first.Length > 2) + { + string[] ps = first[2].Split('/'); + if (ps.Length == 2) + { + Protocols = ps[0]; + ProtocolVersion = ps[1]; + } + } + } + + private void BuildContent(ByteBlock byteBlock) + { + if (ContentLength > 0) + { + byteBlock.Write(m_content); + } + } + + /// + /// 构建响应头部 + /// + /// + private void BuildHeader(ByteBlock byteBlock) + { + StringBuilder stringBuilder = new StringBuilder(); + + string url = null; + if (!string.IsNullOrEmpty(m_relativeURL)) + { + if (m_query == null) + { + url = m_relativeURL; + } + else + { + StringBuilder urlBuilder = new StringBuilder(); + urlBuilder.Append(m_relativeURL); + urlBuilder.Append("?"); + int i = 0; + foreach (var item in m_query.AllKeys) + { + urlBuilder.Append($"{item}={m_query[item]}"); + if (++i < m_query.Count) + { + urlBuilder.Append("&"); + } + } + url = urlBuilder.ToString(); + } + } + + if (string.IsNullOrEmpty(url)) + { + stringBuilder.Append($"{Method} / HTTP/{ProtocolVersion}\r\n"); + } + else + { + stringBuilder.Append($"{Method} {url} HTTP/{ProtocolVersion}\r\n"); + } + if (ContentLength > 0) + { + this.SetHeader(HttpHeaders.ContentLength, ContentLength.ToString()); + } + foreach (var headerkey in Headers.AllKeys) + { + stringBuilder.Append($"{headerkey}: "); + stringBuilder.Append(Headers[headerkey] + "\r\n"); + } + + stringBuilder.Append("\r\n"); + byteBlock.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString())); + } + + private NameValueCollection GetParameters(string row) + { + if (string.IsNullOrEmpty(row)) + { + return null; + } + string[] kvs = row.Split('&'); + if (kvs == null || kvs.Count() == 0) + { + return null; + } + + NameValueCollection pairs = new NameValueCollection(); + foreach (var item in kvs) + { + string[] kv = item.SplitFirst('='); + if (kv.Length == 2) + { + pairs.Add(kv[0], kv[1]); + } + } + + return pairs; + } + + private void ParseUrl() + { + if (m_uRL.Contains("?")) + { + string[] urls = m_uRL.Split('?'); + if (urls.Length > 0) + { + m_relativeURL = urls[0]; + } + if (urls.Length > 1) + { + m_query = GetParameters(urls[1]); + } + } + else + { + m_relativeURL = m_uRL; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/HttpResponse.cs b/src/TouchSocket/Http/Common/HttpResponse.cs new file mode 100644 index 000000000..40d4986b8 --- /dev/null +++ b/src/TouchSocket/Http/Common/HttpResponse.cs @@ -0,0 +1,405 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http响应 + /// + public class HttpResponse : HttpBase + { + private bool m_canRead; + private bool m_canWrite; + private ITcpClientBase m_client; + private byte[] m_content; + private bool m_responsed; + private bool m_sentHeader; + private long m_sentLength; + + /// + /// 构造函数 + /// + /// + /// + public HttpResponse(ITcpClientBase client, bool isServer = true) + { + m_client = client; + if (isServer) + { + m_canRead = false; + m_canWrite = true; + } + else + { + m_canRead = true; + m_canWrite = false; + } + } + + /// + /// 构造函数 + /// + public HttpResponse() + { + m_canRead = false; + m_canWrite = false; + } + + /// + /// + /// + public override bool CanRead => m_canRead; + + /// + /// + /// + public override bool CanWrite => m_canWrite; + + /// + /// + /// + public override ITcpClientBase Client => m_client; + + /// + /// 关闭会话请求 + /// + public bool CloseConnection + { + get + { + return GetHeader(HttpHeaders.Connection).Equals("close", StringComparison.CurrentCultureIgnoreCase); + } + } + + /// + /// 是否分块 + /// + public bool IsChunk { get; set; } + + /// + /// 是否代理权限验证。 + /// + public bool IsProxyAuthenticationRequired + { + get + { + return StatusCode == "407"; + } + } + + /// + /// 是否重定向 + /// + public bool IsRedirect + { + get + { + return StatusCode == "301" || StatusCode == "302"; + } + } + + /// + /// 是否已经响应数据。 + /// + public bool Responsed => m_responsed; + + /// + /// 状态码,默认200 + /// + public string StatusCode { get; set; } = "200"; + + /// + /// 状态消息,默认Success + /// + public string StatusMessage { get; set; } = "Success"; + + /// + /// 构建数据并回应。 + /// 该方法仅在具有Client实例时有效。 + /// + public void Answer() + { + if (m_responsed) + { + return; + } + using (ByteBlock byteBlock = new ByteBlock()) + { + Build(byteBlock); + if (m_client.CanSend) + { + m_client.DefaultSend(byteBlock); + } + m_responsed = true; + } + } + + /// + /// 构建响应数据。 + /// 当数据较大时,不建议这样操作,可直接 + /// + /// + /// + public void Build(ByteBlock byteBlock, bool responsed = true) + { + if (m_responsed) + { + throw new Exception("该对象已被响应。"); + } + + BuildHeader(byteBlock); + BuildContent(byteBlock); + m_responsed = responsed; + } + + /// + /// 构建数据为字节数组。 + /// + /// + public byte[] BuildAsBytes() + { + using (ByteBlock byteBlock = new ByteBlock()) + { + Build(byteBlock); + return byteBlock.ToArray(); + } + } + + /// + /// 当传输模式是Chunk时,用于结束传输。 + /// + public void Complete() + { + m_canWrite = false; + if (IsChunk) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + byteBlock.Write(Encoding.UTF8.GetBytes($"{0:X}\r\n")); + byteBlock.Write(Encoding.UTF8.GetBytes("\r\n")); + m_client.DefaultSend(byteBlock); + m_responsed = true; + } + } + } + + /// + /// + /// + /// + public override void SetContent(byte[] content) + { + m_content = content; + ContentLength = content.Length; + ContentComplated = true; + } + + /// + /// + /// + /// + public override bool TryGetContent(out byte[] content) + { + if (!ContentComplated.HasValue) + { + if (!IsChunk && m_contentLength == 0) + { + m_content = new byte[0]; + content = m_content; + return true; + } + + try + { + using (ByteBlock block1 = new ByteBlock(1024 * 1024)) + { + using (ByteBlock block2 = new ByteBlock()) + { + byte[] buffer = block2.Buffer; + while (true) + { + int r = Read(buffer, 0, buffer.Length); + if (r == 0) + { + break; + } + block1.Write(buffer, 0, r); + } + ContentComplated = true; + m_content = block1.ToArray(); + content = m_content; + return true; + } + } + } + catch + { + ContentComplated = false; + content = null; + return false; + } + finally + { + m_canRead = false; + } + } + else if (ContentComplated == true) + { + content = m_content; + return true; + } + else + { + content = null; + return false; + } + } + + /// + /// + /// + /// + /// + /// + public override void WriteContent(byte[] buffer, int offset, int count) + { + if (m_responsed) + { + throw new Exception("该对象已被响应。"); + } + + if (!CanWrite) + { + throw new NotSupportedException("该对象不支持持续写入内容。"); + } + + if (!m_sentHeader) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + BuildHeader(byteBlock); + m_client.DefaultSend(byteBlock); + } + m_sentHeader = true; + } + if (IsChunk) + { + using (ByteBlock byteBlock = new ByteBlock(count + 1024)) + { + byteBlock.Write(Encoding.UTF8.GetBytes($"{count.ToString("X")}\r\n")); + byteBlock.Write(buffer, offset, count); + byteBlock.Write(Encoding.UTF8.GetBytes("\r\n")); + m_client.DefaultSend(byteBlock); + m_sentLength += count; + } + } + else + { + if (m_sentLength + count <= m_contentLength) + { + m_client.DefaultSend(buffer, offset, count); + m_sentLength += count; + if (m_sentLength == ContentLength) + { + m_canWrite = false; + m_responsed = true; + } + } + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_client = null; + base.Dispose(disposing); + } + + /// + /// 读取数据 + /// + protected override void LoadHeaderProterties() + { + var first = Regex.Split(RequestLine, @"(\s+)").Where(e => e.Trim() != string.Empty).ToArray(); + if (first.Length > 0) + { + string[] ps = first[0].Split('/'); + if (ps.Length == 2) + { + Protocols = ps[0]; + ProtocolVersion = ps[1]; + } + } + if (first.Length > 1) + { + StatusCode = first[1]; + } + string msg = string.Empty; + for (int i = 2; i < first.Length; i++) + { + msg += first[i] + " "; + } + StatusMessage = msg; + + string transferEncoding = GetHeader(HttpHeaders.TransferEncoding); + if ("chunked".Equals(transferEncoding, StringComparison.OrdinalIgnoreCase)) + { + IsChunk = true; + } + } + + private void BuildContent(ByteBlock byteBlock) + { + if (ContentLength > 0) + { + byteBlock.Write(m_content); + } + } + + /// + /// 构建响应头部 + /// + /// + private void BuildHeader(ByteBlock byteBlock) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"HTTP/{ProtocolVersion} {StatusCode} {StatusMessage}\r\n"); + + if (ContentLength > 0) + { + this.SetHeader(HttpHeaders.ContentLength, ContentLength.ToString()); + } + if (IsChunk) + { + this.SetHeader(HttpHeaders.TransferEncoding, "chunked"); + } + foreach (var headerkey in Headers.AllKeys) + { + stringBuilder.Append($"{headerkey}: "); + stringBuilder.Append(Headers[headerkey] + "\r\n"); + } + + stringBuilder.Append("\r\n"); + byteBlock.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString())); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/HttpTools.cs b/src/TouchSocket/Http/Common/HttpTools.cs new file mode 100644 index 000000000..180503b7f --- /dev/null +++ b/src/TouchSocket/Http/Common/HttpTools.cs @@ -0,0 +1,181 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Http +{ + /// + /// Http工具 + /// + public static class HttpTools + { + /// + /// 从扩展名获取ContentType + /// + /// + /// + public static string GetContentTypeFromExtension(string extension) + { + switch (extension.ToLower()) + { + case ".html": + return "text/html"; + + case ".css": + return "text/css"; + + case ".js": + return "text/javascript"; + + case ".xml": + return "text/xml"; + + case ".gzip": + return "application/gzip"; + + case ".json": + return "application/json"; + + case ".map": + return "application/json"; + + case ".pdf": + return "application/pdf"; + + case ".zip": + return "application/zip"; + + case ".mp3": + return "audio/mpeg"; + + case ".jpg": + return "image/jpeg"; + + case ".gif": + return "image/gif"; + + case ".png": + return "image/png"; + + case ".svg": + return "image/svg+xml"; + + case ".mp4": + return "video/mp4"; + + case ".atom": + return "application/atom+xml"; + + case ".fastsoap": + return "application/fastsoap"; + + case ".ps": + return "application/postscript"; + + case ".soap": + return "application/soap+xml"; + + case ".sql": + return "application/sql"; + + case ".xslt": + return "application/xslt+xml"; + + case ".zlib": + return "application/zlib"; + + case ".aac": + return "audio/aac"; + + case ".ac3": + return "audio/ac3"; + + case ".ogg": + return "audio/ogg"; + + case ".ttf": + return "font/ttf"; + + case ".bmp": + return "image/bmp"; + + case ".jpm": + return "image/jpm"; + + case ".jpx": + return "image/jpx"; + + case ".jrx": + return "image/jrx"; + + case ".tiff": + return "image/tiff"; + + case ".emf": + return "image/emf"; + + case ".wmf": + return "image/wmf"; + + case ".http": + return "message/http"; + + case ".s-http": + return "message/s-http"; + + case ".mesh": + return "model/mesh"; + + case ".vrml": + return "model/vrml"; + + case ".csv": + return "text/csv"; + + case ".plain": + return "text/plain"; + + case ".richtext": + return "text/richtext"; + + case ".rtf": + return "text/rtf"; + + case ".rtx": + return "text/rtx"; + + case ".sgml": + return "text/sgml"; + + case ".strings": + return "text/strings"; + + case ".url": + return "text/uri-list"; + + case ".H264": + return "video/H264"; + + case ".H265": + return "video/H265"; + + case ".mpeg": + return "video/mpeg"; + + case ".raw": + return "video/raw"; + + default: + return "application/octet-stream"; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/MultifileCollection.cs b/src/TouchSocket/Http/Common/MultifileCollection.cs new file mode 100644 index 000000000..e81439b8f --- /dev/null +++ b/src/TouchSocket/Http/Common/MultifileCollection.cs @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Http +{ + /// + /// 多文件集合 + /// + public class MultifileCollection : IEnumerable + { + private readonly HttpRequest m_httpRequest; + + /// + /// 多文件集合 + /// + /// + public MultifileCollection(HttpRequest httpRequest) + { + m_httpRequest = httpRequest; + } + + /// + /// 获取一个迭代器。 + /// + /// + public IEnumerator GetEnumerator() + { + if (m_httpRequest.ContentComplated == null || m_httpRequest.ContentComplated == true) + { + if (m_httpRequest.TryGetContent(out byte[] context)) + { + byte[] boundary = $"--{m_httpRequest.GetBoundary()}".ToUTF8Bytes(); + var indexs = context.IndexOfInclude(0, context.Length, boundary); + if (indexs.Count <= 0) + { + throw new Exception("没有发现由Boundary包裹的数据。"); + } + List files = new List(); + for (int i = 0; i < indexs.Count; i++) + { + if (i + 1 < indexs.Count) + { + InternalFormFile internalFormFile = new InternalFormFile(); + files.Add(internalFormFile); + int index = context.IndexOfFirst(indexs[i] + 3, indexs[i + 1], Encoding.UTF8.GetBytes("\r\n\r\n")); + string line = Encoding.UTF8.GetString(context, indexs[i] + 3, index - indexs[i] - 6); + string[] lines = line.Split(new string[] { ";", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + internalFormFile.DataPair = new NameValueCollection(); + foreach (var item in lines) + { + string[] kv = item.Split(new char[] { ':', '=' }); + if (kv.Length == 2) + { + internalFormFile.DataPair.Add(kv[0].Trim(), kv[1].Replace("\"", String.Empty).Trim()); + } + } + + int length = indexs[i + 1] - (index + 2) - boundary.Length; + byte[] data = new byte[length]; + Array.Copy(context, index + 1, data, 0, length); + //string ssss = Encoding.UTF8.GetString(data); + internalFormFile.Data = data; + } + } + + return files.GetEnumerator(); + } + throw new Exception("管道状态异常"); + } + else + { + throw new Exception("管道状态异常"); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/TouchSocketHttpUtility.cs b/src/TouchSocket/Http/Common/TouchSocketHttpUtility.cs new file mode 100644 index 000000000..8499ca856 --- /dev/null +++ b/src/TouchSocket/Http/Common/TouchSocketHttpUtility.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Http +{ + /// + /// HttpUtility + /// + public static class TouchSocketHttpUtility + { + /// + /// 非缓存上限 + /// + public const int NoCacheMaxSize = 1024 * 1024; + + /// + /// Get关键字 + /// + public const string Get = "GET"; + + /// + /// Post关键字 + /// + public const string Post = "POST"; + + /// + /// Put关键字 + /// + public const string Put = "PUT"; + + /// + /// Delete关键字 + /// + public const string Delete = "DELETE"; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs b/src/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs new file mode 100644 index 000000000..cced4896d --- /dev/null +++ b/src/TouchSocket/Http/Common/WebProxy/AuthenticationChallenge.cs @@ -0,0 +1,161 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TouchSocket.Http +{ + /// + /// 处理代理认证凭证 + /// + internal class AuthenticationChallenge + { + /// + /// 构造 + /// + /// 服务器返回的凭证认证类型 + /// 基本凭证用户名密码 + /// 暂时不知道是什么 + public AuthenticationChallenge(string value, NetworkCredential credential, uint nonceCount = 0) + { + Parse(value, credential); + NonceCount = nonceCount; + } + + /// + /// 暂时不知 + /// + public uint NonceCount { get; set; } + + /// + /// 其实用不用他都一样 + /// + public Dictionary Parameters { get; set; } + + /// + /// 凭证类型 + /// + public AuthenticationType Type { get; set; } + + /// + /// 转换成凭证本文 + /// + /// + /// + public override string ToString() + { + if (Type == AuthenticationType.Basic) + return ToBasicString(); + else + throw new Exception("该凭证类型不支持"); + } + + private void Parse(string value, NetworkCredential credential) + { + var chal = value.Split(new[] { ' ' }, 2); + if (chal.Length != 2) + throw new Exception("该凭证类型不支持"); + + var schm = chal[0].ToLower(); + Parameters = ParseParameters(chal[1]); + + if (Parameters.ContainsKey("username") == false) + Parameters.Add("username", credential.Username); + if (Parameters.ContainsKey("password") == false) + Parameters.Add("password", credential.Password); + + /* + * Basic基本类型貌似只需要用户名密码即可 + * if (this.parameters.ContainsKey("uri") == false) + this.parameters.Add("uri", credential.Domain);*/ + + if (schm == "basic") + { + Type = AuthenticationType.Basic; + } + else + throw new Exception("该凭证类型不支持"); + } + + private Dictionary ParseParameters(string value) + { + var res = new Dictionary(); + IEnumerable values = SplitHeaderValue(value, ','); + foreach (var param in values) + { + var i = param.IndexOf('='); + var name = i > 0 ? param.Substring(0, i).Trim() : null; + var val = i < 0 + ? param.Trim().Trim('"') + : i < param.Length - 1 + ? param.Substring(i + 1).Trim().Trim('"') + : string.Empty; + + res.Add(name, val); + } + return res; + } + + private IEnumerable SplitHeaderValue(string value, params char[] separators) + { + var len = value.Length; + var end = len - 1; + + var buff = new StringBuilder(32); + var escaped = false; + var quoted = false; + + for (var i = 0; i <= end; i++) + { + var c = value[i]; + buff.Append(c); + if (c == '"') + { + if (escaped) + { + escaped = false; + continue; + } + quoted = !quoted; + continue; + } + if (c == '\\') + { + if (i == end) + break; + if (value[i + 1] == '"') + escaped = true; + continue; + } + if (Array.IndexOf(separators, c) > -1) + { + if (quoted) + continue; + buff.Length -= 1; + yield return buff.ToString(); + buff.Length = 0; + continue; + } + } + yield return buff.ToString(); + } + + private string ToBasicString() + { + var userPass = $"{Parameters["username"]}:{Parameters["password"]}"; + var cred = Convert.ToBase64String(Encoding.UTF8.GetBytes(userPass)); + return "Basic " + cred; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs b/src/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs new file mode 100644 index 000000000..b941948a6 --- /dev/null +++ b/src/TouchSocket/Http/Common/WebProxy/AuthenticationType.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Http +{ + /// + /// 代理身份认证类型 + /// + public enum AuthenticationType + { /// + /// 不允许身份认证 + /// + None, + + /// + /// 指定摘要身份验证。 + /// + Digest = 1, + + /// + /// 指定基本身份验证。 + /// + Basic = 8, + + /// + /// 指定匿名身份验证。 + /// + Anonymous = 0x8000 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs b/src/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs new file mode 100644 index 000000000..56ac85754 --- /dev/null +++ b/src/TouchSocket/Http/Common/WebProxy/NetworkCredential.cs @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Http +{ + /// + /// 代理身份认证 + /// + public class NetworkCredential + { + /// + /// 构造 + /// + /// + /// + /// 基本认证应该不需要这个 + /// + /// + /// + public NetworkCredential(string username, string password, string domain, params string[] roles) + { + if (username == null) + throw new ArgumentNullException("username"); + + if (username.Length == 0) + throw new ArgumentException("An empty string.", "username"); + Username = username; + Password = password; + Domain = domain; + Roles = roles; + } + + /// + /// 凭证用户名 + /// + + public string Username { get; } + + /// + /// 凭证密码 + /// + public string Password { get; } + + /// + /// Domain + /// + public string Domain { get; } + + /// + /// Roles + /// + public string[] Roles { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Components/HttpClient.cs b/src/TouchSocket/Http/Components/HttpClient.cs new file mode 100644 index 000000000..cd4db8971 --- /dev/null +++ b/src/TouchSocket/Http/Components/HttpClient.cs @@ -0,0 +1,238 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http客户端 + /// + public class HttpClient : HttpClientBase + { + } + + /// + /// Http客户端基类 + /// + public class HttpClientBase : TcpClientBase, IHttpClient + { + private readonly object m_requestLocker = new object(); + private bool m_getContent; + private readonly WaitData m_waitData; + + /// + /// 构造函数 + /// + public HttpClientBase() + { + m_waitData = new WaitData(); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default) + { + lock (m_requestLocker) + { + m_getContent = false; + using (ByteBlock byteBlock = new ByteBlock()) + { + request.Build(byteBlock); + + m_waitData.Reset(); + m_waitData.SetCancellationToken(token); + + this.DefaultSend(byteBlock); + if (onlyRequest) + { + return default; + } + + switch (m_waitData.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + return m_waitData.WaitResult; + + case WaitDataStatus.Overtime: + throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + return default; + + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default) + { + lock (m_requestLocker) + { + m_getContent = true; + using (ByteBlock byteBlock = new ByteBlock()) + { + request.Build(byteBlock); + + m_waitData.Reset(); + m_waitData.SetCancellationToken(token); + + this.DefaultSend(byteBlock); + if (onlyRequest) + { + return default; + } + + switch (m_waitData.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + return m_waitData.WaitResult; + + case WaitDataStatus.Overtime: + throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + return default; + + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_waitData?.Dispose(); + base.Dispose(disposing); + } + + /// + /// + /// + /// + /// + public override ITcpClient Connect(int timeout = 5000) + { + if (Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy) + { + IPHost proxyHost = httpProxy.Host; + var credential = httpProxy.Credential; + IPHost remoteHost = Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + try + { + Config.SetRemoteIPHost(proxyHost); + base.Connect(timeout); + HttpRequest httpRequest = new HttpRequest(); + httpRequest.InitHeaders() + .SetHost(remoteHost.Host) + .SetUrl(remoteHost.Host, true) + .AsMethod("CONNECT"); + var response = Request(httpRequest, timeout: timeout); + if (response.IsProxyAuthenticationRequired) + { + if (credential is null) + { + throw new Exception("未指定代理的凭据。"); + } + string authHeader = response.GetHeader(HttpHeaders.ProxyAuthenticate); + if (authHeader.IsNullOrEmpty()) + { + throw new Exception("未指定代理身份验证质询。"); + } + + var ares = new AuthenticationChallenge(authHeader, credential); + + httpRequest.SetHeader(HttpHeaders.ProxyAuthorization, ares.ToString()); + if (response.CloseConnection) + { + base.Close("代理要求关闭连接,随后重写连接。"); + base.Connect(timeout); + } + + response = Request(httpRequest, timeout: timeout); + } + + if (response.StatusCode != "200") + { + throw new Exception(response.StatusMessage); + } + } + finally + { + Config.SetRemoteIPHost(remoteHost); + } + } + else + { + base.Connect(timeout); + } + return this; + } + + /// + /// + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + base.HandleReceivedData(byteBlock, requestInfo); + + if (requestInfo is HttpResponse response) + { + if (m_getContent) + { + response.TryGetContent(out _); + } + m_waitData.Set(response); + } + } + + /// + /// + /// + /// + protected override void OnConnecting(ConnectingEventArgs e) + { + Protocol = Protocol.Http; + SetDataHandlingAdapter(new HttpClientDataHandlingAdapter()); + base.OnConnecting(e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Components/HttpService.cs b/src/TouchSocket/Http/Components/HttpService.cs new file mode 100644 index 000000000..c5e483add --- /dev/null +++ b/src/TouchSocket/Http/Components/HttpService.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// HTTP/HTTPS服务器 + /// + public class HttpService : TcpService, IHttpService where TClient : HttpSocketClient + { + } + + /// + /// HTTP/HTTPS服务器 + /// + public class HttpService : HttpService + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Components/HttpSocketClient.cs b/src/TouchSocket/Http/Components/HttpSocketClient.cs new file mode 100644 index 000000000..ad798458e --- /dev/null +++ b/src/TouchSocket/Http/Components/HttpSocketClient.cs @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// http辅助类 + /// + public class HttpSocketClient : SocketClient, IHttpSocketClient + { + /// + /// 构造函数 + /// + public HttpSocketClient() + { + Protocol = Protocol.Http; + } + + /// + /// + /// + /// + protected override void OnConnecting(OperationEventArgs e) + { + SetDataHandlingAdapter(new HttpServerDataHandlingAdapter()); + base.OnConnecting(e); + } + + /// + /// + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (requestInfo is HttpRequest request) + { + OnReceivedHttpRequest(request); + } + } + + /// + /// 当收到到Http请求时。覆盖父类方法将不会触发插件。 + /// + protected virtual void OnReceivedHttpRequest(HttpRequest request) + { + HttpContextEventArgs args = new HttpContextEventArgs(new HttpContext(request)); + + switch (request.Method) + { + case TouchSocketHttpUtility.Get: + { + PluginsManager.Raise("OnGet", this, args); + break; + } + case TouchSocketHttpUtility.Post: + { + PluginsManager.Raise("OnPost", this, args); + break; + } + case TouchSocketHttpUtility.Put: + { + PluginsManager.Raise("OnPut", this, args); + break; + } + case TouchSocketHttpUtility.Delete: + { + PluginsManager.Raise("OnDelete", this, args); + break; + } + default: + PluginsManager.Raise("OnReceivedOtherHttpRequest", this, args); + break; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Config/HttpConfigExtensions.cs b/src/TouchSocket/Http/Config/HttpConfigExtensions.cs new file mode 100644 index 000000000..c85eae979 --- /dev/null +++ b/src/TouchSocket/Http/Config/HttpConfigExtensions.cs @@ -0,0 +1,94 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; +using TouchSocket.Http; + +namespace TouchSocket.Sockets +{ + /// + /// HttpConfigExtensions + /// + public static class HttpConfigExtensions + { + #region 创建 + + /// + /// 构建Http类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithHttpClient(this TouchSocketConfig config) where TClient : IHttpClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建Http类客户端,并连接 + /// + /// + /// + public static HttpClient BuildWithHttpClient(this TouchSocketConfig config) + { + return BuildWithHttpClient(config); + } + + /// + /// 构建Http类服务器,并启动。 + /// + /// + /// + /// + public static TService BuildWithHttpService(this TouchSocketConfig config) where TService : IHttpService + { + TService service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建Http类服务器,并启动。 + /// + /// + /// + public static HttpService BuildWithHttpService(this TouchSocketConfig config) + { + return BuildWithHttpService(config); + } + + #endregion 创建 + + /// + /// Http代理 + /// + public static readonly DependencyProperty HttpProxyProperty = + DependencyProperty.Register("HttpProxy", typeof(HttpConfigExtensions), null); + + /// + ///设置Http代理 + /// + /// + /// + /// + public static TouchSocketConfig SetHttpProxy(this TouchSocketConfig config, HttpProxy value) + { + config.SetValue(HttpProxyProperty, value); + return config; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs b/src/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs new file mode 100644 index 000000000..a931692ef --- /dev/null +++ b/src/TouchSocket/Http/DataAdapter/HttpClientDataHandlingAdapter.cs @@ -0,0 +1,206 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http客户端数据处理适配器 + /// + public class HttpClientDataHandlingAdapter : NormalDataHandlingAdapter + { + /// + /// 缓存数据,如果需要手动释放,请先判断,然后到调用后,再置空; + /// + protected ByteBlock tempByteBlock; + + private static readonly byte[] m_rnCode = Encoding.UTF8.GetBytes("\r\n"); + private HttpResponse m_httpResponse; + + private long m_surLen; + + private Task m_task; + + /// + /// + /// + public override bool CanSplicingSend => false; + + /// + /// + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (tempByteBlock == null) + { + byteBlock.Pos = 0; + Single(byteBlock, false); + } + else + { + tempByteBlock.Write(byteBlock.Buffer, 0, byteBlock.Len); + ByteBlock block = tempByteBlock; + tempByteBlock = null; + block.Pos = 0; + Single(block, true); + } + } + + private void Cache(ByteBlock byteBlock) + { + if (byteBlock.CanReadLen > 0) + { + tempByteBlock = new ByteBlock(); + tempByteBlock.Write(byteBlock.Buffer, byteBlock.Pos, byteBlock.CanReadLen); + if (tempByteBlock.Len > MaxPackageSize) + { + OnError("缓存的数据长度大于设定值的情况下未收到解析信号"); + } + } + } + + private FilterResult ReadChunk(ByteBlock byteBlock) + { + int position = byteBlock.Pos; + int index = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, m_rnCode); + if (index > 0) + { + int headerLength = index - byteBlock.Pos; + string hex = Encoding.ASCII.GetString(byteBlock.Buffer, byteBlock.Pos, headerLength - 1); + int count = hex.ByHexStringToInt32(); + byteBlock.Pos += headerLength + 1; + + if (count >= 0) + { + if (count > byteBlock.CanReadLen) + { + byteBlock.Pos = position; + return FilterResult.Cache; + } + + m_httpResponse.InternalInput(byteBlock.Buffer, byteBlock.Pos, count); + byteBlock.Pos += count; + byteBlock.Pos += 2; + return FilterResult.GoOn; + } + else + { + byteBlock.Pos += 2; + return FilterResult.Success; + } + } + else + { + return FilterResult.Cache; + } + } + + private void Single(ByteBlock byteBlock, bool dis) + { + try + { + while (byteBlock.CanReadLen > 0) + { + if (m_httpResponse == null) + { + m_httpResponse = new HttpResponse(Client, false); + if (m_httpResponse.ParsingHeader(byteBlock, byteBlock.CanReadLen)) + { + byteBlock.Pos++; + if (m_httpResponse.IsChunk || m_httpResponse.ContentLength > byteBlock.CanReadLength) + { + m_surLen = m_httpResponse.ContentLength; + m_task = EasyTask.Run(m_httpResponse, (res) => + { + GoReceived(null, res); + }); + } + else + { + byteBlock.Read(out byte[] buffer, (int)m_httpResponse.ContentLength); + m_httpResponse.SetContent(buffer); + GoReceived(null, m_httpResponse); + m_httpResponse = null; + } + } + else + { + Cache(byteBlock); + m_httpResponse = null; + m_task?.Wait(); + m_task = null; + return; + } + } + if (m_httpResponse != null) + { + if (m_httpResponse.IsChunk) + { + switch (ReadChunk(byteBlock)) + { + case FilterResult.Cache: + Cache(byteBlock); + return; + + case FilterResult.Success: + m_httpResponse = null; + m_task?.Wait(); + m_task = null; + break; + + case FilterResult.GoOn: + default: + break; + } + } + else if (m_surLen > 0) + { + if (byteBlock.CanRead) + { + int len = (int)Math.Min(m_surLen, byteBlock.CanReadLength); + m_httpResponse.InternalInput(byteBlock.Buffer, byteBlock.Pos, len); + m_surLen -= len; + byteBlock.Pos += len; + if (m_surLen == 0) + { + m_httpResponse.InternalInput(null, 0, 0); + m_httpResponse = null; + m_task?.Wait(); + m_task = null; + } + } + } + else + { + m_httpResponse = null; + m_task?.Wait(); + m_task = null; + } + } + } + } + finally + { + if (dis) + { + byteBlock.Dispose(); + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs b/src/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs new file mode 100644 index 000000000..abd57e8b8 --- /dev/null +++ b/src/TouchSocket/Http/DataAdapter/HttpServerDataHandlingAdapter.cs @@ -0,0 +1,146 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http服务器数据处理适配器 + /// + public class HttpServerDataHandlingAdapter : NormalDataHandlingAdapter + { + /// + /// 缓存数据,如果需要手动释放,请先判断,然后到调用后,再置空; + /// + protected ByteBlock tempByteBlock; + + /// + /// + /// + public override bool CanSplicingSend => false; + + /// + /// + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (tempByteBlock == null) + { + byteBlock.Pos = 0; + Single(byteBlock, false); + } + else + { + tempByteBlock.Write(byteBlock.Buffer, 0, byteBlock.Len); + ByteBlock block = tempByteBlock; + tempByteBlock = null; + block.Pos = 0; + Single(block, true); + } + } + + private HttpRequest m_httpRequest; + private Task m_task; + private long m_surLen; + + private void Single(ByteBlock byteBlock, bool dis) + { + try + { + while (byteBlock.CanReadLen > 0) + { + if (m_httpRequest == null) + { + m_httpRequest = new HttpRequest(Client, true); + if (m_httpRequest.ParsingHeader(byteBlock, byteBlock.CanReadLen)) + { + byteBlock.Pos++; + if (m_httpRequest.ContentLength > byteBlock.CanReadLength) + { + m_surLen = m_httpRequest.ContentLength; + + m_task = EasyTask.Run(m_httpRequest, (res) => + { + GoReceived(null, res); + }); + } + else + { + byteBlock.Read(out byte[] buffer, (int)m_httpRequest.ContentLength); + m_httpRequest.SetContent(buffer); + GoReceived(null, m_httpRequest); + m_httpRequest = null; + } + } + else + { + Cache(byteBlock); + m_httpRequest = null; + m_task?.Wait(); + m_task = null; + return; + } + } + + if (m_surLen > 0) + { + if (byteBlock.CanRead) + { + int len = (int)Math.Min(m_surLen, byteBlock.CanReadLength); + m_httpRequest.InternalInput(byteBlock.Buffer, byteBlock.Pos, len); + m_surLen -= len; + byteBlock.Pos += len; + if (m_surLen == 0) + { + m_httpRequest.InternalInput(null, 0, 0); + m_httpRequest = null; + m_task?.Wait(); + m_task = null; + } + } + } + else + { + m_httpRequest = null; + m_task?.Wait(); + m_task = null; + } + } + } + finally + { + if (dis) + { + byteBlock.Dispose(); + } + } + } + + private void Cache(ByteBlock byteBlock) + { + if (byteBlock.CanReadLen > 0) + { + tempByteBlock = new ByteBlock(); + tempByteBlock.Write(byteBlock.Buffer, byteBlock.Pos, byteBlock.CanReadLen); + if (tempByteBlock.Len > MaxPackageSize) + { + OnError("缓存的数据长度大于设定值的情况下未收到解析信号"); + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/DelegateCollection.cs b/src/TouchSocket/Http/DelegateCollection.cs new file mode 100644 index 000000000..3773da02c --- /dev/null +++ b/src/TouchSocket/Http/DelegateCollection.cs @@ -0,0 +1,21 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +/// +/// HTTP上下文事件委托 +/// +/// +/// +/// +public delegate void HttpContextEventHandler(TClient client, HttpContextEventArgs e); \ No newline at end of file diff --git a/src/TouchSocket/Http/Enum/HttpHeaders.cs b/src/TouchSocket/Http/Enum/HttpHeaders.cs new file mode 100644 index 000000000..dfebd8049 --- /dev/null +++ b/src/TouchSocket/Http/Enum/HttpHeaders.cs @@ -0,0 +1,340 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.ComponentModel; + +namespace TouchSocket.Http +{ + /// + /// 请求头枚举 + /// + public enum HttpHeaders : byte + { + /// + /// Cache-Control 标头,指定请求/响应链上所有缓存控制机制必须服从的指令。 + /// + [Description("cache-control")] + CacheControl = 0, + + /// + /// Connection 标头,指定特定连接需要的选项。 + /// + [Description("connection")] + Connection = 1, + + /// + /// Date 标头,指定开始创建请求的日期和时间。 + /// + [Description("date")] + Date = 2, + + /// + /// Keep-Alive 标头,指定用以维护持久性连接的参数。 + /// + [Description("keep-alive")] + KeepAlive = 3, + + /// + /// Pragma 标头,指定可应用于请求/响应链上的任何代理的特定于实现的指令。 + /// + [Description("pragma")] + Pragma = 4, + + /// + /// Trailer 标头,指定标头字段显示在以 chunked 传输编码方式编码的消息的尾部。 + /// + [Description("trailer")] + Trailer = 5, + + /// + /// Transfer-Encoding 标头,指定对消息正文应用的转换的类型(如果有)。 + /// + [Description("transfer-encoding")] + TransferEncoding = 6, + + /// + /// Upgrade 标头,指定客户端支持的附加通信协议。 + /// + [Description("upgrade")] + Upgrade = 7, + + /// + /// Via 标头,指定网关和代理程序要使用的中间协议。 + /// + [Description("via")] + Via = 8, + + /// + /// Warning 标头,指定关于可能未在消息中反映的消息的状态或转换的附加信息。 + /// + [Description("warning")] + Warning = 9, + + /// + /// Allow 标头,指定支持的 HTTP 方法集。 + /// + [Description("allow")] + Allow = 10, + + /// + /// Content-Length 标头,指定伴随正文数据的长度(以字节为单位)。 + /// + [Description("content-length")] + ContentLength = 11, + + /// + /// Content-Type 标头,指定伴随正文数据的 MIME 类型。 + /// + [Description("content-type")] + ContentType = 12, + + /// + /// Content-Encoding 标头,指定已应用于伴随正文数据的编码。 + /// + [Description("content-encoding")] + ContentEncoding = 13, + + /// + /// Content-Langauge 标头,指定伴随正文数据的自然语言。 + /// + [Description("content-langauge")] + ContentLanguage = 14, + + /// + /// Content-Location 标头,指定可从其中获得伴随正文的 URI。 + /// + [Description("content-location")] + ContentLocation = 15, + + /// + /// Content-MD5 标头,指定伴随正文数据的 MD5 摘要,用于提供端到端消息完整性检查。 + /// + [Description("content-md5")] + ContentMd5 = 16, + + /// + /// Content-Range 标头,指定在完整正文中应用伴随部分正文数据的位置。 + /// + [Description("content-range")] + ContentRange = 17, + + /// + /// Expires 标头,指定日期和时间,在此之后伴随的正文数据应视为陈旧的。 + /// + [Description("expires")] + Expires = 18, + + /// + /// Last-Modified 标头,指定上次修改伴随的正文数据的日期和时间。 + /// + [Description("last-modified")] + LastModified = 19, + + /// + /// Accept 标头,指定响应可接受的 MIME 类型。 + /// + [Description("accept")] + Accept = 20, + + /// + /// Accept-Charset 标头,指定响应可接受的字符集。 + /// + [Description("accept-charset")] + AcceptCharset = 21, + + /// + /// Accept-Encoding 标头,指定响应可接受的内容编码。 + /// + [Description("accept-encoding")] + AcceptEncoding = 22, + + /// + /// Accept-Langauge 标头,指定响应首选的自然语言。 + /// + [Description("accept-langauge")] + AcceptLanguage = 23, + + /// + /// Authorization 标头,指定客户端为向服务器验证自身身份而出示的凭据。 + /// + [Description("authorization")] + Authorization = 24, + + /// + /// Cookie 标头,指定向服务器提供的 Cookie 数据。 + /// + [Description("cookie")] + Cookie = 25, + + /// + /// Expect 标头,指定客户端要求的特定服务器行为。 + /// + [Description("expect")] + Expect = 26, + + /// + /// From 标头,指定控制请求用户代理的用户的 Internet 电子邮件地址。 + /// + [Description("from")] + From = 27, + + /// + /// Host 标头,指定所请求资源的主机名和端口号。 + /// + [Description("host")] + Host = 28, + + /// + /// If-Match 标头,指定仅当客户端的指示资源的缓存副本是最新的时,才执行请求的操作。 + /// + [Description("if-match")] + IfMatch = 29, + + /// + /// If-Modified-Since 标头,指定仅当自指示的数据和时间之后修改了请求的资源时,才执行请求的操作。 + /// + [Description("if-modified-since")] + IfModifiedSince = 30, + + /// + /// If-None-Match 标头,指定仅当客户端的指示资源的缓存副本都不是最新的时,才执行请求的操作。 + /// + [Description("if-none-match")] + IfNoneMatch = 31, + + /// + /// If-Range 标头,指定如果客户端的缓存副本是最新的,仅发送指定范围的请求资源。 + /// + [Description("if-range")] + IfRange = 32, + + /// + /// If-Unmodified-Since 标头,指定仅当自指示的日期和时间之后修改了请求的资源时,才执行请求的操作。 + /// + [Description("if-unmodified-since")] + IfUnmodifiedSince = 33, + + /// + /// Max-Forwards 标头,指定一个整数,表示此请求还可转发的次数。 + /// + [Description("max-forwards")] + MaxForwards = 34, + + /// + /// Proxy-Authorization 标头,指定客户端为向代理验证自身身份而出示的凭据。 + /// + [Description("proxy-authorization")] + ProxyAuthorization = 35, + + /// + /// Referer 标头,指定从中获得请求 URI 的资源的 URI。 + /// + [Description("referer")] + Referer = 36, + + /// + /// Range 标头,指定代替整个响应返回的客户端请求的响应的子范围。 + /// + [Description("range")] + Range = 37, + + /// + /// TE 标头,指定响应可接受的传输编码方式。 + /// + [Description("te")] + Te = 38, + + /// + /// Translate 标头,与 WebDAV 功能一起使用的 HTTP 规范的 Microsoft 扩展。 + /// + [Description("translate")] + Translate = 39, + + /// + /// User-Agent 标头,指定有关客户端代理的信息。 + /// + [Description("user-agent")] + UserAgent = 40, + + /// + /// Accept-Ranges 标头,指定服务器接受的范围。 + /// + [Description("accept-ranges")] + AcceptRanges = 41, + + /// + /// Age 标头,指定自起始服务器生成响应以来的时间长度(以秒为单位)。 + /// + [Description("age")] + Age = 42, + + /// + /// Etag 标头,指定请求的变量的当前值。 + /// + [Description("etag")] + ETag = 43, + + /// + /// Location 标头,指定为获取请求的资源而将客户端重定向到的 URI。 + /// + [Description("location")] + Location = 44, + + /// + /// Proxy-Authenticate 标头,指定客户端必须对代理验证其自身。 + /// + [Description("proxy-authenticate")] + ProxyAuthenticate = 45, + + /// + /// Retry-After 标头,指定某个时间(以秒为单位)或日期和时间,在此时间之后客户端可以重试其请求。 + /// + [Description("retry-after")] + RetryAfter = 46, + + /// + /// Server 标头,指定关于起始服务器代理的信息。 + /// + [Description("server")] + Server = 47, + + /// + /// Set-Cookie 标头,指定提供给客户端的 Cookie 数据。 + /// + [Description("set-cookie")] + SetCookie = 48, + + /// + /// Vary 标头,指定用于确定缓存的响应是否为新响应的请求标头。 + /// + [Description("vary")] + Vary = 49, + + /// + /// WWW-Authenticate 标头,指定客户端必须对服务器验证其自身。 + /// + [Description("www-authenticate")] + WwwAuthenticate = 50, + + /// + /// Origin。 + /// + [Description("origin")] + Origin = 51, + + /// + /// Content-Disposition + /// + [Description("content-disposition")] + ContentDisposition = 52 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs b/src/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs new file mode 100644 index 000000000..48d186da5 --- /dev/null +++ b/src/TouchSocket/Http/EventArgs/HttpContextEventArgs.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Http +{ + /// + /// Http请求事件类 + /// + public class HttpContextEventArgs : TouchSocketEventArgs + { + /// + /// Http上下文 + /// + public HttpContext Context { get; } + + /// + /// 构造函数 + /// + /// + public HttpContextEventArgs(HttpContext context) + { + Context = context; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Extensions/HttpExtensions.cs b/src/TouchSocket/Http/Extensions/HttpExtensions.cs new file mode 100644 index 000000000..e5469dae4 --- /dev/null +++ b/src/TouchSocket/Http/Extensions/HttpExtensions.cs @@ -0,0 +1,474 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http扩展辅助 + /// + public static class HttpExtensions + { + /// + /// 根据字符串获取枚举 + /// + /// + /// + /// + /// + public static bool GetEnum(string str, out T result) where T : struct + { + return Enum.TryParse(str, out result); + } + + #region HttpBase + + #region 设置内容 + + /// + /// 从Json + /// + /// + /// + /// + public static T FromJson(this T httpRequest, string value) where T : HttpBase + { + httpRequest.SetContent(Encoding.UTF8.GetBytes(value)); + httpRequest.SetHeader(HttpHeaders.ContentType, "application/json;charset=UTF-8"); + return httpRequest; + } + + /// + /// 从文本 + /// + /// + /// + /// + public static T FromText(this T httpRequest, string value) where T : HttpBase + { + httpRequest.SetContent(Encoding.UTF8.GetBytes(value)); + httpRequest.SetHeader(HttpHeaders.ContentType, "text/plain;charset=UTF-8"); + return httpRequest; + } + + /// + /// 从Xml格式 + /// + /// + /// + /// + public static T FromXML(this T httpRequest, string value) where T : HttpBase + { + httpRequest.SetContent(Encoding.UTF8.GetBytes(value)); + httpRequest.SetHeader(HttpHeaders.ContentType, "application/xml;charset=UTF-8"); + return httpRequest; + } + + #endregion 设置内容 + + /// + /// 获取Body的字符串 + /// + /// + /// + public static string GetBody(this HttpBase httpBase) + { + if (httpBase.TryGetContent(out byte[] data)) + { + return Encoding.UTF8.GetString(data); + } + throw new Exception("获取数据体错误。"); + } + + /// + /// 当数据类型为multipart/form-data时,获取boundary + /// + /// + /// + /// + public static string GetBoundary(this HttpBase httpBase) + { + if (httpBase.ContentType.IsNullOrEmpty()) + { + return string.Empty; + } + string[] strs = httpBase.ContentType.Split(';'); + if (strs.Length == 2) + { + strs = strs[1].Split('='); + if (strs.Length == 2) + { + return strs[1].Trim(); + } + } + return string.Empty; + } + + /// + /// 设置内容 + /// + /// + /// + /// + /// + public static T SetContent(this T httpBase, string content, Encoding encoding = null) where T : HttpBase + { + httpBase.SetContent(Encoding.UTF8.GetBytes(content)); + return httpBase; + } + + /// + /// 设置数据体长度 + /// + /// + /// + public static T SetContentLength(this T httpBase, long value) where T : HttpBase + { + httpBase.ContentLength = value; + return httpBase; + } + + /// + /// 从扩展名设置内容类型,必须以“.”开头 + /// + /// + /// + /// + public static T SetContentTypeByExtension(this T httpBase, string extension) where T : HttpBase + { + string type = HttpTools.GetContentTypeFromExtension(extension); + httpBase.SetHeader(HttpHeaders.ContentType.GetDescription(), type); + httpBase.ContentType = type; + return httpBase; + } + + /// + /// 设置头值 + /// + /// + /// + /// + public static T SetHeader(this T httpBase, HttpHeaders header, string value) where T : HttpBase + { + httpBase.SetHeaderByKey(header.GetDescription(), value); + return httpBase; + } + + /// + /// 设置头值 + /// + /// + /// + /// + public static T SetHeader(this T httpBase, string fieldName, string value) where T : HttpBase + { + httpBase.SetHeaderByKey(fieldName.ToLower(), value); + return httpBase; + } + + /// + /// 写入 + /// + /// + /// + public static T WriteContent(this T httpBase, byte[] buffer) where T : HttpBase + { + httpBase.WriteContent(buffer, 0, buffer.Length); + return httpBase; + } + + #endregion HttpBase + + #region HttpRequest + + /// + /// 获取多文件集合。如果不存在,则返回null。 + /// + /// + /// + /// + public static MultifileCollection GetMultifileCollection(this TRequest request) where TRequest : HttpRequest + { + if (request.GetBoundary().IsNullOrEmpty()) + { + return null; + } + else + { + return new MultifileCollection(request); + } + } + + /// + /// 初始化常规的请求头。 + /// 包含: + /// + /// Connection:keep-alive + /// Pragma:no-cache + /// UserAgent:TouchSocket.Http + /// Accept:*/* + /// AcceptEncoding:deflate, br + /// + /// + /// + /// + public static TRequest InitHeaders(this TRequest request) where TRequest : HttpRequest + { + request.SetHeader(HttpHeaders.Connection, "keep-alive"); + request.SetHeader(HttpHeaders.Pragma, "no-cache"); + request.SetHeader(HttpHeaders.UserAgent, "TouchSocket.Http"); + request.SetHeader(HttpHeaders.Accept, "*/*"); + request.SetHeader(HttpHeaders.AcceptEncoding, "deflate, br"); + return request; + } + + /// + /// 添加Host请求头 + /// + /// + /// + /// + public static TRequest SetHost(this TRequest request, string host) where TRequest : HttpRequest + { + request.SetHeader(HttpHeaders.Host, host); + return request; + } + + /// + /// 对比不包含参数的Url。其中有任意一方为null,则均返回False。 + /// + /// + /// + /// + public static bool UrlEquals(this TRequest httpRequest, string url) where TRequest : HttpRequest + { + if (string.IsNullOrEmpty(httpRequest.RelativeURL) || string.IsNullOrEmpty(url)) + { + return false; + } + if (httpRequest.RelativeURL.Equals(url, StringComparison.CurrentCultureIgnoreCase)) + { + return true; + } + return false; + } + + #region 设置函数 + + /// + /// 作为Delete访问 + /// + /// + /// + public static TRequest AsDelete(this TRequest httpRequest) where TRequest : HttpRequest + { + httpRequest.Method = TouchSocketHttpUtility.Delete; + return httpRequest; + } + + /// + /// 作为Get访问 + /// + /// + /// + public static TRequest AsGet(this TRequest httpRequest) where TRequest : HttpRequest + { + httpRequest.Method = TouchSocketHttpUtility.Get; + return httpRequest; + } + + /// + /// 作为指定函数 + /// + /// + /// + /// + public static TRequest AsMethod(this TRequest request, string method) where TRequest : HttpRequest + { + request.Method = method; + return request; + } + + /// + /// 作为Post访问 + /// + /// + /// + public static TRequest AsPost(this TRequest httpRequest) where TRequest : HttpRequest + { + httpRequest.Method = TouchSocketHttpUtility.Post; + return httpRequest; + } + + /// + /// 作为Put访问 + /// + /// + /// + public static TRequest AsPut(this TRequest httpRequest) where TRequest : HttpRequest + { + httpRequest.Method = TouchSocketHttpUtility.Put; + return httpRequest; + } + + #endregion 设置函数 + + #endregion HttpRequest + + #region HttpResponse + + /// + /// 路径文件没找到 + /// + /// + /// + public static TResponse UrlNotFind(this TResponse response) where TResponse : HttpResponse + { + response.SetContent("

404 -RRQM Not Found

"); + response.StatusCode = "404"; + response.ContentType = "text/html;charset=utf-8"; + return response; + } + + /// + /// 从文件响应。 + /// 当response支持持续写入时,会直接回复响应。并阻塞执行,直到完成。所以在执行该方法之前,请确保已设置完成所有状态字 + /// 当response不支持持续写入时,会填充Content,且不会响应,需要自己执行Build,并发送。 + /// + /// 响应 + /// 请求头,用于尝试续传,为null时则不续传。 + /// 文件路径 + /// 文件名,不设置时会获取路径文件名 + /// 最大速度(仅企业版有效)。 + /// 读取长度。 + /// + /// + /// + public static TResponse FromFile(this TResponse response, string filePath, HttpRequest request, string fileName = null, int maxSpeed = 1024 * 1024 * 10, int bufferLen = 1024 * 64) where TResponse : HttpResponse + { + using (var reader = FilePool.GetReader(filePath)) + { + response.SetContentTypeByExtension(Path.GetExtension(filePath)); + var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName == null ? Path.GetFileName(filePath) : fileName); + response.SetHeader(HttpHeaders.ContentDisposition, contentDisposition) + .SetHeader(HttpHeaders.AcceptRanges, "bytes"); + + if (response.CanWrite) + { + HttpRange httpRange; + string range = request?.GetHeader(HttpHeaders.Range); + if (string.IsNullOrEmpty(range)) + { + response.SetStatus(); + response.ContentLength = reader.FileStorage.FileInfo.Length; + httpRange = new HttpRange() { Start = 0, Length = reader.FileStorage.FileInfo.Length }; + } + else + { + httpRange = HttpRange.GetRange(range, reader.FileStorage.FileInfo.Length); + if (httpRange == null) + { + response.ContentLength = reader.FileStorage.FileInfo.Length; + httpRange = new HttpRange() { Start = 0, Length = reader.FileStorage.FileInfo.Length }; + } + else + { + response.SetContentLength(httpRange.Length) + .SetStatus("206", "Partial Content") + .SetHeader(HttpHeaders.ContentRange, string.Format("bytes {0}-{1}/{2}", httpRange.Start, httpRange.Length + httpRange.Start - 1, reader.FileStorage.FileInfo.Length)); + } + } + reader.Position = httpRange.Start; + long surLen = httpRange.Length; + FlowGate flowGate = new FlowGate(); + flowGate.Maximum = maxSpeed; + + using (ByteBlock block = new ByteBlock(bufferLen)) + { + while (surLen > 0) + { + int r = reader.Read(block.Buffer, 0, (int)Math.Min(bufferLen, surLen)); + if (r == 0) + { + break; + } + flowGate.AddCheckWait(r); + response.WriteContent(block.Buffer, 0, r); + surLen -= r; + } + } + } + else + { + if (reader.FileStorage.FileInfo.Length > 1024 * 1024) + { + throw new OverlengthException("当该对象不支持写入时,仅支持1Mb以内的文件。"); + } + + using (ByteBlock byteBlock = new ByteBlock((int)reader.FileStorage.FileInfo.Length)) + { + using (ByteBlock block = new ByteBlock(bufferLen)) + { + while (true) + { + int r = reader.Read(block.Buffer, 0, bufferLen); + if (r == 0) + { + break; + } + byteBlock.Write(block.Buffer, 0, r); + } + response.SetContent(byteBlock.ToArray()); + } + } + } + } + return response; + } + + /// + /// 设置文件类型。 + /// + /// + /// + /// + public static TResponse SetContentTypeFromFileName(this TResponse response, string fileName) where TResponse : HttpResponse + { + var contentDisposition = "attachment;" + "filename=" + System.Web.HttpUtility.UrlEncode(fileName); + response.SetHeader(HttpHeaders.ContentDisposition, contentDisposition); + return response; + } + + /// + /// 设置状态,并且附带时间戳。 + /// + /// + /// + /// + /// + public static TResponse SetStatus(this TResponse response, string status = "200", string msg = "Success") where TResponse : HttpResponse + { + response.StatusCode = status; + response.StatusMessage = msg; + response.SetHeader(HttpHeaders.Server, $"TouchSocket.Http {HttpBase.ServerVersion}"); + response.SetHeader(HttpHeaders.Date, DateTime.Now.ToGMTString("r")); + return response; + } + + #endregion HttpResponse + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs b/src/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs new file mode 100644 index 000000000..1e681c644 --- /dev/null +++ b/src/TouchSocket/Http/Extensions/HttpPluginsManagerExtension.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Core +{ + /// + /// HttpPluginsManagerExtension + /// + public static class HttpPluginsManagerExtension + { + /// + /// 默认的Http服务。为Http做兜底拦截。该插件应该最后添加。 + /// + /// + /// + public static DefaultHttpServicePlugin UseDefaultHttpServicePlugin(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Interface/HttpPluginInterface.cs b/src/TouchSocket/Http/Interface/HttpPluginInterface.cs new file mode 100644 index 000000000..057b51d5b --- /dev/null +++ b/src/TouchSocket/Http/Interface/HttpPluginInterface.cs @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http接口 + /// + public interface IHttpPlugin : IPlugin + { + /// + /// 在收到Delete时 + /// + /// + /// + [AsyncRaiser] + void OnDelete(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Delete时 + /// + /// + /// + /// + Task OnDeleteAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Get时 + /// + /// + /// + [AsyncRaiser] + void OnGet(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Get时 + /// + /// + /// + /// + Task OnGetAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Post时 + /// + /// + /// + [AsyncRaiser] + void OnPost(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Post时 + /// + /// + /// + /// + Task OnPostAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Put时 + /// + /// + /// + [AsyncRaiser] + void OnPut(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到Put时 + /// + /// + /// + /// + Task OnPutAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到其他Http请求时 + /// + /// + /// + [AsyncRaiser] + void OnReceivedOtherHttpRequest(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 在收到其他Http请求时 + /// + /// + /// + /// + Task OnReceivedOtherHttpRequestAsync(ITcpClientBase client, HttpContextEventArgs e); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Interface/IFormFile.cs b/src/TouchSocket/Http/Interface/IFormFile.cs new file mode 100644 index 000000000..9c8232c5f --- /dev/null +++ b/src/TouchSocket/Http/Interface/IFormFile.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Specialized; + +namespace TouchSocket.Http +{ + /// + /// 表单文件 + /// + public interface IFormFile + { + /// + /// 获取Content-Disposition + /// + string ContentDisposition { get; } + + /// + /// 获取Content-Type + /// + string ContentType { get; } + + /// + /// 实际的数据 + /// + public byte[] Data { get; } + + /// + /// 数据对 + /// + public NameValueCollection DataPair { get; } + + /// + /// 获取file name + /// + string FileName { get; } + + /// + /// 文件长度。在数据接收完成之前,该值为-1; + /// + long Length { get; } + + /// + /// 获取name字段 + /// + string Name { get; } + + ///// + ///// 读取文件数据 //太麻烦先不实现 + ///// + //public int Read(byte[] buffer, int offset, int count); + } + + internal class InternalFormFile : IFormFile + { + public string ContentDisposition => DataPair["Content-Disposition"]; + + public string ContentType => DataPair["Content-Type"]; + + public byte[] Data { get; set; } + public NameValueCollection DataPair { get; set; } + public string FileName => DataPair["filename"]; + public long Length => Data == null ? 0 : Data.Length; + + public string Name => DataPair["name"]; + //public int Read(byte[] buffer, int offset, int count) + //{ + // return this.ReadAction(buffer, offset, count); + //} + + //public Func ReadAction { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Interface/IHttpClient.cs b/src/TouchSocket/Http/Interface/IHttpClient.cs new file mode 100644 index 000000000..481efa70d --- /dev/null +++ b/src/TouchSocket/Http/Interface/IHttpClient.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http终端基础接口 + /// + public interface IHttpClientBase : ITcpClientBase + { + } + + /// + /// Http服务器终端接口 + /// + public interface IHttpSocketClient : IHttpClientBase + { + } + + /// + /// Http终端接口 + /// + public interface IHttpClient : ITcpClient, IHttpClientBase + { + /// + /// 发起请求 + /// + /// 请求体 + /// 仅仅请求,而不等待结果 + /// 等待超时时间 + /// 结束等待令箭 + /// + HttpResponse Request(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default); + + /// + /// 发起请求,并获取数据体 + /// + /// 请求体 + /// 仅仅请求,而不等待结果 + /// 等待超时时间 + /// 结束等待令箭 + /// + public HttpResponse RequestContent(HttpRequest request, bool onlyRequest = false, int timeout = 10 * 1000, CancellationToken token = default); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Interface/IHttpService.cs b/src/TouchSocket/Http/Interface/IHttpService.cs new file mode 100644 index 000000000..14e28e1f0 --- /dev/null +++ b/src/TouchSocket/Http/Interface/IHttpService.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// HttpService接口 + /// + public interface IHttpService : ITcpService + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs b/src/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs new file mode 100644 index 000000000..6608592ce --- /dev/null +++ b/src/TouchSocket/Http/Plugins/DefaultHttpServicePlugin.cs @@ -0,0 +1,117 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// 默认的Http服务。为Http做兜底拦截。该插件应该最后添加。 + /// + public class DefaultHttpServicePlugin : HttpPluginBase + { + /// + /// 默认的Http服务。为Http做兜底拦截。该插件应该最后添加。 + /// + public DefaultHttpServicePlugin() + { + Order = int.MinValue; + } + + /// + /// + /// + /// + /// + /// + protected override void OnLoadingConfig(object sender, ConfigEventArgs e) + { + if (!(sender is IService)) + { + throw new Exception("该插件仅可用于服务器。"); + } + base.OnLoadingConfig(sender, e); + } + + /// + /// + /// + /// + /// + protected override void OnGet(HttpSocketClient client, HttpContextEventArgs e) + { + e.Context.Response.UrlNotFind().Answer(); + base.OnGet(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnPost(HttpSocketClient client, HttpContextEventArgs e) + { + e.Context.Response.UrlNotFind().Answer(); + base.OnPost(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnPut(HttpSocketClient client, HttpContextEventArgs e) + { + e.Context.Response.UrlNotFind().Answer(); + base.OnPut(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnDelete(HttpSocketClient client, HttpContextEventArgs e) + { + e.Context.Response.UrlNotFind().Answer(); + base.OnDelete(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedOtherHttpRequest(HttpSocketClient client, HttpContextEventArgs e) + { + switch (e.Context.Request.Method.ToUpper()) + { + case "OPTIONS": + { + e.Context.Response + .SetStatus() + .SetHeader("Access-Control-Allow-Origin", "*") + .SetHeader("Access-Control-Allow-Headers", "*") + .SetHeader("Allow", "OPTIONS, GET, POST") + .SetHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS") + .Answer(); + break; + } + default: + e.Context.Response.UrlNotFind().Answer(); + break; + } + base.OnReceivedOtherHttpRequest(client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Plugins/HttpPluginBase.cs b/src/TouchSocket/Http/Plugins/HttpPluginBase.cs new file mode 100644 index 000000000..286f1e100 --- /dev/null +++ b/src/TouchSocket/Http/Plugins/HttpPluginBase.cs @@ -0,0 +1,185 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http扩展基类 + /// + public class HttpPluginBase : HttpPluginBase + { + } + + /// + /// Http扩展基类 + /// + public abstract class HttpPluginBase : TcpPluginBase, IHttpPlugin + { + void IHttpPlugin.OnDelete(ITcpClientBase client, HttpContextEventArgs e) + { + OnDelete((TClient)client, e); + } + + Task IHttpPlugin.OnDeleteAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnDeleteAsync((TClient)client, e); + } + + void IHttpPlugin.OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + OnGet((TClient)client, e); + } + + Task IHttpPlugin.OnGetAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnGetAsync((TClient)client, e); + } + + void IHttpPlugin.OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + OnPost((TClient)client, e); + } + + Task IHttpPlugin.OnPostAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnPostAsync((TClient)client, e); + } + + void IHttpPlugin.OnPut(ITcpClientBase client, HttpContextEventArgs e) + { + OnPut((TClient)client, e); + } + + Task IHttpPlugin.OnPutAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnPutAsync((TClient)client, e); + } + + void IHttpPlugin.OnReceivedOtherHttpRequest(ITcpClientBase client, HttpContextEventArgs e) + { + OnReceivedOtherHttpRequest((TClient)client, e); + } + + Task IHttpPlugin.OnReceivedOtherHttpRequestAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnReceivedOtherHttpRequestAsync((TClient)client, e); + } + + #region 虚函数 + + /// + /// + /// + /// + /// + protected virtual void OnDelete(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到Delete时 + /// + /// + /// + /// + protected virtual Task OnDeleteAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// + /// + /// + /// + protected virtual void OnGet(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到Get时 + /// + /// + /// + /// + protected virtual Task OnGetAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// + /// + /// + /// + protected virtual void OnPost(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到Post时 + /// + /// + /// + /// + protected virtual Task OnPostAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// + /// + /// + /// + protected virtual void OnPut(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到Put时 + /// + /// + /// + /// + protected virtual Task OnPutAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// + /// + /// + /// + protected virtual void OnReceivedOtherHttpRequest(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 在收到其他Http请求时 + /// + /// + /// + /// + protected virtual Task OnReceivedOtherHttpRequestAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs b/src/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs new file mode 100644 index 000000000..8224437fd --- /dev/null +++ b/src/TouchSocket/Http/Plugins/HttpStaticPagePlugin.cs @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using TouchSocket.Sockets; + +namespace TouchSocket.Http +{ + /// + /// Http静态内容插件 + /// + public class HttpStaticPagePlugin : HttpPluginBase + { + private readonly FileCachePool fileCache; + + /// + /// 构造函数 + /// + public HttpStaticPagePlugin() + { + fileCache = new FileCachePool(); + } + + /// + /// 静态文件缓存。 + /// + public FileCachePool FileCache => fileCache; + + /// + /// 添加静态 + /// + /// Static content path + /// Cache prefix (default is "/") + /// Cache filter (default is "*.*") + /// Refresh cache timeout (default is 1 hour) + public void AddFolder(string path, string prefix = "/", string filter = "*.*", TimeSpan? timeout = null) + { + timeout ??= TimeSpan.FromHours(1); + + fileCache.InsertPath(path, prefix, filter, timeout.Value, null); + } + + /// + /// Clear static content cache + /// + public void ClearFolder() + { + fileCache.Clear(); + } + + /// + /// Remove static content cache + /// + /// Static content path + public void RemoveFolder(string path) + { + fileCache.RemovePath(path); + } + + /// + /// + /// + /// + /// + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (fileCache.Find(e.Context.Request.RelativeURL, out byte[] data)) + { + e.Context.Response + .SetStatus() + .SetContentTypeByExtension(Path.GetExtension(e.Context.Request.RelativeURL)) + .SetContentLength(data.Length) + .WriteContent(data); + e.Handled = true; + } + base.OnGet(client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs b/src/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs new file mode 100644 index 000000000..14e6b6168 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Common/WSDataFrame.cs @@ -0,0 +1,132 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket数据帧 + /// + public class WSDataFrame : IDisposable, IRequestInfo + { + private bool m_disposedValue; + + /// + /// 是否为最后数据帧。 + /// + public bool FIN { get; set; } + + /// + /// 标识RSV-1。 + /// + public bool RSV1 { get; set; } + + /// + /// 标识RSV-2。 + /// + public bool RSV2 { get; set; } + + /// + /// 标识RSV-3。 + /// + public bool RSV3 { get; set; } + + /// + /// 数据类型 + /// + public WSDataType Opcode { get; set; } + + /// + /// 计算掩码 + /// + public bool Mask { get; set; } + + /// + /// 有效载荷数据长度 + /// + public int PayloadLength { get; set; } + + /// + /// 掩码值 + /// + public byte[] MaskingKey { get; set; } + + /// + /// 有效数据 + /// + public ByteBlock PayloadData { get; set; } + + /// + /// 构建数据 + /// + /// + /// + /// + public bool Build(ByteBlock byteBlock, bool masked) + { + if (PayloadData != null) + { + PayloadLength = PayloadData.Len; + } + else + { + PayloadLength = 0; + } + + if (PayloadData == null) + { + return WSTools.Build(byteBlock, this, new byte[0], 0, 0); + } + return WSTools.Build(byteBlock, this, PayloadData.Buffer, 0, PayloadLength); + } + + /// + /// + /// + /// + protected virtual void Dispose(bool disposing) + { + if (!m_disposedValue) + { + if (disposing) + { + // TODO: 释放托管状态(托管对象) + } + + PayloadData?.Dispose(); + m_disposedValue = true; + } + } + + /// + /// 析构函数 + /// + ~WSDataFrame() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: false); + } + + /// + /// + /// + public void Dispose() + { + // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中 + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Common/WSTools.cs b/src/TouchSocket/Http/WebSockets/Common/WSTools.cs new file mode 100644 index 000000000..50a2881da --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Common/WSTools.cs @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WSTools + /// + public static class WSTools + { + /// + /// 应答。 + /// + public const string acceptMask = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + + /// + /// 构建数据 + /// + /// + /// + /// + /// + /// + /// + public static bool Build(ByteBlock byteBlock, WSDataFrame dataFrame, byte[] buffer, int offset, int length) + { + int payloadLength; + + byte[] extLen; + + if (length < 126) + { + payloadLength = length; + extLen = new byte[0]; + } + else if (length < 65536) + { + payloadLength = 126; + extLen = TouchSocketBitConverter.BigEndian.GetBytes((ushort)length); + } + else + { + payloadLength = 127; + extLen = TouchSocketBitConverter.BigEndian.GetBytes((ulong)length); + } + + int header = dataFrame.FIN ? 1 : 0; + header = (header << 1) + (dataFrame.RSV1 ? 1 : 0); + header = (header << 1) + (dataFrame.RSV2 ? 1 : 0); + header = (header << 1) + (dataFrame.RSV3 ? 1 : 0); + header = (header << 4) + (ushort)dataFrame.Opcode; + + if (dataFrame.Mask) + { + header = (header << 1) + 1; + } + else + { + header = (header << 1) + 0; + } + + header = (header << 7) + payloadLength; + + byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes((ushort)header)); + + if (payloadLength > 125) + { + byteBlock.Write(extLen, 0, extLen.Length); + } + + if (dataFrame.Mask) + { + byteBlock.Write(dataFrame.MaskingKey, 0, 4); + } + + if (payloadLength > 0) + { + if (dataFrame.Mask) + { + if (byteBlock.Capacity < byteBlock.Pos + length) + { + byteBlock.SetCapacity(byteBlock.Pos + length, true); + } + WSTools.DoMask(byteBlock.Buffer, byteBlock.Pos, buffer, offset, length, dataFrame.MaskingKey); + byteBlock.SetLength(byteBlock.Pos + length); + } + else + { + byteBlock.Write(buffer, offset, length); + } + } + return true; + } + + /// + /// 计算Base64值 + /// + /// + /// + public static string CalculateBase64Key(string str) + { + return (str + acceptMask).ToSha1(Encoding.UTF8).ToBase64(); + } + + /// + /// 获取Base64随即字符串。 + /// + /// + public static string CreateBase64Key() + { + var src = new byte[16]; + new Random().NextBytes(src); + return Convert.ToBase64String(src); + } + + /// + /// 掩码运算 + /// + /// + /// + /// + /// + /// + /// + public static void DoMask(byte[] storeBuf, int sOffset, byte[] buffer, int offset, int length, byte[] masks) + { + for (var i = 0; i < length; i++) + { + storeBuf[sOffset + i] = (byte)(buffer[offset + i] ^ masks[i % 4]); + } + } + + /// + /// 获取WS的请求头 + /// + /// + /// + /// + /// + /// + public static HttpRequest GetWSRequest(string host, string url, string version, out string base64Key) + { + HttpRequest request = new HttpRequest + { + Method = "GET", + Protocols = "HTTP", + ProtocolVersion = "1.1" + }; + request.SetUrl(url); + request.SetHeader(HttpHeaders.Host, host); + request.SetHeader(HttpHeaders.Pragma, "no-cache"); + request.SetHeader(HttpHeaders.UserAgent, "TouchSocket.Http.WebSockets"); + request.SetHeader(HttpHeaders.Origin, "RRQM"); + request.SetHeader(HttpHeaders.AcceptEncoding, "deflate, br"); + request.SetHeaderByKey("Connection", "upgrade"); + request.SetHeaderByKey("Upgrade", "websocket"); + request.SetHeaderByKey("Sec-WebSocket-Version", $"{version}"); + base64Key = CreateBase64Key(); + request.SetHeaderByKey("Sec-WebSocket-Key", base64Key); + + return request; + } + + /// + /// 获取响应 + /// + /// + /// + /// + public static bool TryGetResponse(HttpRequest request, HttpResponse response) + { + string upgrade = request.GetHeader(HttpHeaders.Upgrade); + if (string.IsNullOrEmpty(upgrade)) + { + return false; + } + string connection = request.GetHeader(HttpHeaders.Connection); + if (string.IsNullOrEmpty(connection)) + { + return false; + } + string secWebSocketKey = request.GetHeader("sec-websocket-key"); + if (string.IsNullOrEmpty(secWebSocketKey)) + { + return false; + } + + response.StatusCode = "101"; + response.StatusMessage = "switching protocols"; + response.SetHeader(HttpHeaders.Connection, "upgrade"); + response.SetHeader(HttpHeaders.Upgrade, "websocket"); + response.SetHeader("sec-websocket-accept", CalculateBase64Key(secWebSocketKey)); + return true; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs b/src/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs new file mode 100644 index 000000000..5084204a7 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Components/WebSocketClient.cs @@ -0,0 +1,199 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocketClient用户终端简单实现。 + /// + public class WebSocketClient : WebSocketClientBase + { + /// + /// 收到WebSocket数据 + /// + public WSDataFrameEventHandler Received { get; set; } + + /// + /// + /// + /// + protected override void OnHandleWSDataFrame(WSDataFrame dataFrame) + { + Received?.Invoke(this, dataFrame); + base.OnHandleWSDataFrame(dataFrame); + } + } + + /// + /// WebSocket用户终端。 + /// + public class WebSocketClientBase : HttpClientBase, IWebSocketClient + { + /// + /// 请求连接到WebSocket。 + /// + /// + public override ITcpClient Connect(int timeout = 5000) + { + return Connect(default, timeout); + } + + /// + /// + /// + /// + /// + /// + public virtual ITcpClient Connect(CancellationToken token, int timeout = 5000) + { + lock (this) + { + if (!Online) + { + base.Connect(timeout); + } + + string base64Key; + IPHost iPHost = Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + string url = iPHost.IsUri ? iPHost.Uri.PathAndQuery : string.Empty; + HttpRequest request = WSTools.GetWSRequest(RemoteIPHost.ToString(), url, this.GetWebSocketVersion(), out base64Key); + OnHandshaking(new HttpContextEventArgs(new HttpContext(request))); + + var response = Request(request, timeout: timeout, token: token); + if (!response.StatusCode.Trim().Equals("101")) + { + throw new WebSocketConnectException($"协议升级失败,信息:{response.StatusMessage},更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response)); + } + string accept = response.GetHeader("sec-websocket-accept").Trim(); + if (accept.IsNullOrEmpty() || !accept.Equals(WSTools.CalculateBase64Key(base64Key).Trim(), StringComparison.OrdinalIgnoreCase)) + { + MainSocket.SafeDispose(); + throw new WebSocketConnectException($"WS服务器返回的应答码不正确,更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response)); + } + + SetAdapter(new WebSocketDataHandlingAdapter()); + SetValue(WebSocketServerPlugin.HandshakedProperty, true); + response.Flag = true; + OnHandshaked(new HttpContextEventArgs(new HttpContext(request, response))); + return this; + } + } + + /// + /// + /// + /// + /// + /// + public Task ConnectAsync(CancellationToken token, int timeout = 5000) + { + return EasyTask.Run(() => + { + return Connect(token, timeout); + }); + } + + #region 事件 + + /// + /// 表示在即将握手连接时。 + /// + public HttpContextEventHandler Handshaking { get; set; } + + /// + /// 表示完成握手后。 + /// + public HttpContextEventHandler Handshaked { get; set; } + + /// + /// 表示在即将握手连接时。 + /// + /// + protected virtual void OnHandshaking(HttpContextEventArgs e) + { + if (UsePlugin && PluginsManager.Raise("OnHandshaking", this, e)) + { + return; + } + Handshaking?.Invoke(this, e); + } + + /// + /// 表示完成握手后。 + /// + /// + protected virtual void OnHandshaked(HttpContextEventArgs e) + { + if (UsePlugin && PluginsManager.Raise("OnHandshaked", this, e)) + { + return; + } + Handshaked?.Invoke(this, e); + } + + #endregion 事件 + + /// + /// 当收到WS数据时。 + /// + /// + protected virtual void OnHandleWSDataFrame(WSDataFrame dataFrame) + { + if (UsePlugin) + { + PluginsManager.Raise("OnHandleWSDataFrame", this, new WSDataFrameEventArgs(dataFrame)); + } + } + + /// + /// + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (this.GetHandshaked()) + { + WSDataFrame dataFrame = (WSDataFrame)requestInfo; + OnHandleWSDataFrame(dataFrame); + } + else + { + if (requestInfo is HttpResponse response) + { + response.Flag = false; + base.HandleReceivedData(byteBlock, requestInfo); + SpinWait.SpinUntil(() => + { + return (bool)response.Flag; + }, 1000); + } + } + } + + /// + /// + /// + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + SetValue(WebSocketServerPlugin.HandshakedProperty, false); + base.OnDisconnected(e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs b/src/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs new file mode 100644 index 000000000..ac7133367 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Config/WebSocketConfigExtensions.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Http.WebSockets; + +namespace TouchSocket.Sockets +{ + /// + /// WebSocketConfigExtensions + /// + public static class WebSocketConfigExtensions + { + /// + /// 构建WebSocketClient类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithWebSocketClient(this TouchSocketConfig config) where TClient : IWebSocketClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建WebSocketClient类客户端,并连接 + /// + /// + /// + public static WebSocketClient BuildWithWebSocketClient(this TouchSocketConfig config) + { + return BuildWithWebSocketClient(config); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs b/src/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs new file mode 100644 index 000000000..5ad7f787c --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/DataAdapter/WebSocketDataHandlingAdapter.cs @@ -0,0 +1,289 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket适配器 + /// + public class WebSocketDataHandlingAdapter : DataHandlingAdapter + { + private WSDataFrame m_dataFrameTemp; + + /// + /// 数据包剩余长度 + /// + private int m_surPlusLength = 0; + + /// + /// 临时包 + /// + private ByteBlock m_tempByteBlock; + + /// + /// + /// + public override bool CanSplicingSend => false; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// 解码 + /// + /// + /// + /// + /// + /// + public FilterResult DecodingFromBytes(byte[] dataBuffer, ref int offset, int length, out WSDataFrame dataFrame) + { + int index = offset; + dataFrame = new WSDataFrame(); + dataFrame.RSV1 = dataBuffer[offset].GetBit(6) == 1; + dataFrame.RSV2 = dataBuffer[offset].GetBit(5) == 1; + dataFrame.RSV3 = dataBuffer[offset].GetBit(4) == 1; + dataFrame.FIN = (dataBuffer[offset] >> 7) == 1; + dataFrame.Opcode = (WSDataType)(dataBuffer[offset] & 0xf); + dataFrame.Mask = (dataBuffer[++offset] >> 7) == 1; + + int payloadLength = dataBuffer[offset] & 0x7f; + if (payloadLength < 126) + { + offset++; + } + else if (payloadLength == 126) + { + if (length < 4) + { + offset = index; + return FilterResult.Cache; + } + payloadLength = TouchSocketBitConverter.BigEndian.ToUInt16(dataBuffer, ++offset); + offset += 2; + } + else if (payloadLength == 127) + { + if (length < 12) + { + if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(); + } + m_tempByteBlock.Write(dataBuffer, index, length); + offset = index; + return FilterResult.GoOn; + } + payloadLength = (int)TouchSocketBitConverter.BigEndian.ToUInt64(dataBuffer, ++offset); + offset += 8; + } + + dataFrame.PayloadLength = payloadLength; + + if (dataFrame.Mask) + { + if (length < (offset - index) + 4) + { + if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(); + } + m_tempByteBlock.Write(dataBuffer, index, length); + offset = index; + return FilterResult.GoOn; + } + dataFrame.MaskingKey = new byte[4]; + dataFrame.MaskingKey[0] = dataBuffer[offset++]; + dataFrame.MaskingKey[1] = dataBuffer[offset++]; + dataFrame.MaskingKey[2] = dataBuffer[offset++]; + dataFrame.MaskingKey[3] = dataBuffer[offset++]; + } + + ByteBlock byteBlock = new ByteBlock(payloadLength); + dataFrame.PayloadData = byteBlock; + + int surlen = length - (offset - index); + if (payloadLength <= surlen) + { + byteBlock.Write(dataBuffer, offset, payloadLength); + offset += payloadLength; + } + else + { + byteBlock.Write(dataBuffer, offset, surlen); + offset += surlen; + } + + return FilterResult.Success; + } + + /// + /// 当接收到数据时处理数据 + /// + /// 数据流 + protected override void PreviewReceived(ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + + if (m_tempByteBlock != null) + { + m_tempByteBlock.Write(buffer, 0, r); + buffer = m_tempByteBlock.ToArray(); + r = m_tempByteBlock.Pos; + m_tempByteBlock.Dispose(); + m_tempByteBlock = null; + } + + if (m_dataFrameTemp == null) + { + SplitPackage(buffer, 0, r); + } + else + { + if (m_surPlusLength == r) + { + m_dataFrameTemp.PayloadData.Write(buffer, 0, m_surPlusLength); + PreviewHandle(m_dataFrameTemp); + m_dataFrameTemp = null; + m_surPlusLength = 0; + } + else if (m_surPlusLength < r) + { + m_dataFrameTemp.PayloadData.Write(buffer, 0, m_surPlusLength); + PreviewHandle(m_dataFrameTemp); + m_dataFrameTemp = null; + SplitPackage(buffer, m_surPlusLength, r); + } + else + { + m_dataFrameTemp.PayloadData.Write(buffer, 0, r); + m_surPlusLength -= r; + } + } + } + + /// + /// 当发送数据前处理数据 + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + GoSend(buffer, offset, length); + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。 + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + m_tempByteBlock = null; + m_dataFrameTemp = null; + m_surPlusLength = 0; + } + + private void PreviewHandle(WSDataFrame dataFrame) + { + try + { + if (dataFrame.Mask) + { + WSTools.DoMask(dataFrame.PayloadData.Buffer, 0, dataFrame.PayloadData.Buffer, 0, dataFrame.PayloadData.Len, dataFrame.MaskingKey); + } + GoReceived(null, dataFrame); + } + finally + { + dataFrame.Dispose(); + } + } + + /// + /// 分解包 + /// + /// + /// + /// + private void SplitPackage(byte[] dataBuffer, int offset, int length) + { + while (offset < length) + { + if (length - offset < 2) + { + if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(); + } + m_tempByteBlock.Write(dataBuffer, offset, length - offset); + return; + } + + switch (DecodingFromBytes(dataBuffer, ref offset, length - offset, out WSDataFrame dataFrame)) + { + case FilterResult.Cache: + { + if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(); + } + m_tempByteBlock.Write(dataBuffer, offset, length - offset); + return; + } + case FilterResult.Success: + { + if (dataFrame.PayloadLength == dataFrame.PayloadData.Len) + { + PreviewHandle(dataFrame); + } + else + { + m_surPlusLength = dataFrame.PayloadLength - dataFrame.PayloadData.Len; + m_dataFrameTemp = dataFrame; + } + } + break; + + case FilterResult.GoOn: + default: + return; + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/DelegateCollection.cs b/src/TouchSocket/Http/WebSockets/DelegateCollection.cs new file mode 100644 index 000000000..5a8cdbff5 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/DelegateCollection.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Http.WebSockets +{ + /// + /// 收到WebSocket数据 + /// + /// + /// + public delegate void WSDataFrameEventHandler(TClient client, WSDataFrame dataFrame); +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Enum/WSDataType.cs b/src/TouchSocket/Http/WebSockets/Enum/WSDataType.cs new file mode 100644 index 000000000..65a8200b6 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Enum/WSDataType.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket数据类型 + /// + public enum WSDataType : ushort + { + /// + /// 表示一个中间数据包,denotes a continuation frame + /// + Cont = 0, + + /// + /// 表示一个text类型数据包 + /// + Text = 1, + + /// + /// 表示一个binary类型数据包 + /// + Binary = 2, + + /// + /// 表示一个断开连接类型数据包 + /// + Close = 8, + + /// + /// 表示一个ping类型数据包 + /// + Ping = 9, + + /// + /// 表示一个pong类型数据包 + /// + Pong = 10 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs b/src/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs new file mode 100644 index 000000000..0dcd0eec8 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/EventArgs/WSDataFrameEventArgs.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WS数据事件类 + /// + public class WSDataFrameEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + public WSDataFrameEventArgs(WSDataFrame dataFrame) + { + DataFrame = dataFrame; + } + + /// + /// WS数据帧。 + /// + public WSDataFrame DataFrame { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs b/src/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs new file mode 100644 index 000000000..cf3b84cca --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Exceptions/WebSocketConnectException.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket连接异常。 + /// + [Serializable] + public class WebSocketConnectException : Exception + { + /// + ///构造函数 + /// + /// + /// + public WebSocketConnectException(string mes, HttpContext context) : base(mes) + { + Context = context; + } + + /// + /// HttpContext + /// + public HttpContext Context { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs b/src/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs new file mode 100644 index 000000000..488424431 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Extensions/WSClientExtensions.cs @@ -0,0 +1,811 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +using TouchSocket.Core; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// IWSClientBase辅助扩展 + /// + public static class WSClientExtensions + { + /// + /// 是否已经完成握手 + /// + /// + /// + public static bool GetHandshaked(this IHttpClientBase client) + { + return client.GetValue(WebSocketServerPlugin.HandshakedProperty); + } + + /// + /// 获取WebSocket版本号。 + /// + /// + /// + public static string GetWebSocketVersion(this IHttpClientBase client) + { + return client.GetValue(WebSocketServerPlugin.WebSocketVersionProperty); + } + + /// + /// 设置WebSocket版本号。 + /// + public static void SetWebSocketVersion(this IHttpClientBase client, string value) + { + client.SetValue(WebSocketServerPlugin.WebSocketVersionProperty, value); + } + + #region 客户端 + + /// + /// 发送Ping报文。 + /// + /// + /// + public static bool Ping(this HttpClientBase client) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping }); + return true; + } + catch + { + return false; + } + } + + /// + /// 发送Pong报文。 + /// + /// + /// + public static bool Pong(this HttpClientBase client) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong }); + return true; + } + catch + { + return false; + } + } + + /// + /// 发送Close报文。 + /// + /// + /// + /// + public static bool CloseWithWS(this HttpClientBase client, string msg) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg)); + return true; + } + catch + { + return false; + } + } + + #region 同步发送 + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendBinary(buffer, offset, length).BuildRequest(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, ByteBlock byteBlock) + { + SendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, byte[] buffer) + { + SendWithWS(client, buffer, 0, buffer.Length); + } + + /// + /// 采用WebSocket协议,发送文本数据。 + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, string text) + { + using (ByteBlock byteBlock = new ByteBlock(text.Length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendText(text).BuildRequest(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送WS数据。 + /// + /// + /// + public static void SendWithWS(this HttpClientBase client, WSDataFrame dataFrame) + { + using (ByteBlock byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) + { + dataFrame.BuildRequest(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + #endregion 同步发送 + + #region 异步发送 + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendBinary(buffer, offset, length).BuildRequest(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, ByteBlock byteBlock) + { + SendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, byte[] buffer) + { + SendWithWSAsync(client, buffer, 0, buffer.Length); + } + + /// + /// 采用WebSocket协议,发送文本数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, string text) + { + using (ByteBlock byteBlock = new ByteBlock(text.Length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendText(text).BuildRequest(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送WS数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpClientBase client, WSDataFrame dataFrame) + { + using (ByteBlock byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) + { + dataFrame.BuildRequest(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + #endregion 异步发送 + + #region 同步分包发送 + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpClientBase client, byte[] buffer, int offset, int length, int packageSize) + { + lock (client) + { + if (packageSize >= length) + { + SendWithWS(client, buffer, offset, length); + return; + } + int sentLen = 0; + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.SetMaskString("RRQM"); + dataFrame.Mask = true; + dataFrame.FIN = false; + dataFrame.Opcode = WSDataType.Binary; + + int count; + if (length % packageSize == 0) + { + count = length / packageSize; + } + else + { + count = length / packageSize + 1; + } + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + dataFrame.Opcode = WSDataType.Cont; + } + if (i == count - 1)//最后 + { + dataFrame.FIN = true; + } + using (ByteBlock byteBlock = new ByteBlock(packageSize + 1024)) + { + int thisLen = Math.Min(packageSize, length - sentLen); + WSTools.Build(byteBlock, dataFrame, buffer, offset, thisLen); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + sentLen += thisLen; + offset += thisLen; + } + } + } + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpClientBase client, byte[] buffer, int packageSize) + { + SubSendWithWS(client, buffer, 0, buffer.Length, packageSize); + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpClientBase client, ByteBlock byteBlock, int packageSize) + { + SubSendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len, packageSize); + } + + #endregion 同步分包发送 + + #region 异步分包发送 + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpClientBase client, byte[] buffer, int offset, int length, int packageSize) + { + lock (client) + { + if (packageSize >= length) + { + SendWithWSAsync(client, buffer, offset, length); + return; + } + int sentLen = 0; + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.SetMaskString("RRQM"); + dataFrame.Mask = true; + dataFrame.FIN = false; + dataFrame.Opcode = WSDataType.Binary; + + int count; + if (length % packageSize == 0) + { + count = length / packageSize; + } + else + { + count = length / packageSize + 1; + } + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + dataFrame.Opcode = WSDataType.Cont; + } + if (i == count - 1)//最后 + { + dataFrame.FIN = true; + } + using (ByteBlock byteBlock = new ByteBlock(packageSize + 1024)) + { + int thisLen = Math.Min(packageSize, length - sentLen); + WSTools.Build(byteBlock, dataFrame, buffer, offset, thisLen); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + sentLen += thisLen; + offset += thisLen; + } + } + } + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpClientBase client, byte[] buffer, int packageSize) + { + SubSendWithWSAsync(client, buffer, 0, buffer.Length, packageSize); + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpClientBase client, ByteBlock byteBlock, int packageSize) + { + SubSendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len, packageSize); + } + + #endregion 异步分包发送 + + #endregion 客户端 + + #region 服务器 + + /// + /// 发送Ping报文。 + /// + /// + /// + public static bool Ping(this HttpSocketClient client) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping }); + return true; + } + catch + { + return false; + } + } + + /// + /// 发送Pong报文。 + /// + /// + /// + public static bool Pong(this HttpSocketClient client) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong }); + return true; + } + catch + { + return false; + } + } + + /// + /// 发送Close报文。 + /// + /// + /// + /// + public static bool CloseWithWS(this HttpSocketClient client, string msg) + { + try + { + SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg)); + return true; + } + catch + { + return false; + } + } + + #region 同步发送 + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendBinary(buffer, offset, length).BuildResponse(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, ByteBlock byteBlock) + { + SendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, byte[] buffer) + { + SendWithWS(client, buffer, 0, buffer.Length); + } + + /// + /// 采用WebSocket协议,发送文本数据。 + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, string text) + { + using (ByteBlock byteBlock = new ByteBlock(text.Length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendText(text).BuildResponse(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送WS数据。 + /// + /// + /// + public static void SendWithWS(this HttpSocketClient client, WSDataFrame dataFrame) + { + using (ByteBlock byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) + { + dataFrame.BuildResponse(byteBlock); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + #endregion 同步发送 + + #region 异步发送 + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, byte[] buffer, int offset, int length) + { + using (ByteBlock byteBlock = new ByteBlock(length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendBinary(buffer, offset, length).BuildResponse(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, ByteBlock byteBlock) + { + SendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 采用WebSocket协议,发送二进制流数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, byte[] buffer) + { + SendWithWSAsync(client, buffer, 0, buffer.Length); + } + + /// + /// 采用WebSocket协议,发送文本数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, string text) + { + using (ByteBlock byteBlock = new ByteBlock(text.Length + 1024)) + { + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.AppendText(text).BuildResponse(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// 采用WebSocket协议,发送WS数据。 + /// + /// + /// + public static void SendWithWSAsync(this HttpSocketClient client, WSDataFrame dataFrame) + { + using (ByteBlock byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024)) + { + dataFrame.BuildResponse(byteBlock); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + #endregion 异步发送 + + #region 同步分包发送 + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpSocketClient client, byte[] buffer, int offset, int length, int packageSize) + { + lock (client) + { + if (packageSize >= length) + { + SendWithWS(client, buffer, offset, length); + return; + } + int sentLen = 0; + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.FIN = false; + dataFrame.Opcode = WSDataType.Binary; + + int count; + if (length % packageSize == 0) + { + count = length / packageSize; + } + else + { + count = length / packageSize + 1; + } + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + dataFrame.Opcode = WSDataType.Cont; + } + if (i == count - 1)//最后 + { + dataFrame.FIN = true; + } + using (ByteBlock byteBlock = new ByteBlock(packageSize + 1024)) + { + int thisLen = Math.Min(packageSize, length - sentLen); + WSTools.Build(byteBlock, dataFrame, buffer, offset, thisLen); + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + sentLen += thisLen; + offset += thisLen; + } + } + } + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpSocketClient client, byte[] buffer, int packageSize) + { + SubSendWithWS(client, buffer, 0, buffer.Length, packageSize); + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWS(this HttpSocketClient client, ByteBlock byteBlock, int packageSize) + { + SubSendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len, packageSize); + } + + #endregion 同步分包发送 + + #region 异步分包发送 + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpSocketClient client, byte[] buffer, int offset, int length, int packageSize) + { + lock (client) + { + if (packageSize >= length) + { + SendWithWSAsync(client, buffer, offset, length); + return; + } + int sentLen = 0; + WSDataFrame dataFrame = new WSDataFrame(); + dataFrame.FIN = false; + dataFrame.Opcode = WSDataType.Binary; + + int count; + if (length % packageSize == 0) + { + count = length / packageSize; + } + else + { + count = length / packageSize + 1; + } + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + dataFrame.Opcode = WSDataType.Cont; + } + if (i == count - 1)//最后 + { + dataFrame.FIN = true; + } + using (ByteBlock byteBlock = new ByteBlock(packageSize + 1024)) + { + int thisLen = Math.Min(packageSize, length - sentLen); + WSTools.Build(byteBlock, dataFrame, buffer, offset, thisLen); + client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len); + sentLen += thisLen; + offset += thisLen; + } + } + } + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpSocketClient client, byte[] buffer, int packageSize) + { + SubSendWithWSAsync(client, buffer, 0, buffer.Length, packageSize); + } + + /// + /// 分包发送。 + /// + /// 按packageSize的值,每次发送数据包。 + /// + /// + /// + /// + /// + public static void SubSendWithWSAsync(this HttpSocketClient client, ByteBlock byteBlock, int packageSize) + { + SubSendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len, packageSize); + } + + #endregion 异步分包发送 + + #endregion 服务器 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs b/src/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs new file mode 100644 index 000000000..7a37f4be0 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Extensions/WSDataFrameExtensions.cs @@ -0,0 +1,158 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WSDataFrame辅助扩展类 + /// + public static class WSDataFrameExtensions + { + /// + /// 追加文本 + /// + /// + /// + /// + /// + public static WSDataFrame AppendText(this WSDataFrame dataFrame, string text, Encoding encoding = default) + { + dataFrame.Opcode = WSDataType.Text; + byte[] data = (encoding == default ? Encoding.UTF8 : encoding).GetBytes(text); + if (dataFrame.PayloadData == null) + { + dataFrame.PayloadData = new ByteBlock(); + } + dataFrame.PayloadData.Write(data); + return dataFrame; + } + + /// + /// 追加二进制流 + /// + /// + /// + /// + /// + /// + public static WSDataFrame AppendBinary(this WSDataFrame dataFrame, byte[] buffer, int offset, int length) + { + dataFrame.Opcode = WSDataType.Binary; + if (dataFrame.PayloadData == null) + { + dataFrame.PayloadData = new ByteBlock(); + } + dataFrame.PayloadData.Write(buffer, offset, length); + return dataFrame; + } + + /// + /// 构建请求数据(含Make) + /// + /// + /// + /// + public static bool BuildRequest(this WSDataFrame dataFrame, ByteBlock byteBlock) + { + dataFrame.FIN = true; + dataFrame.Mask = true; + if (dataFrame.MaskingKey == null) + { + dataFrame.SetMaskString("RRQM"); + } + return dataFrame.Build(byteBlock, true); + } + + /// + /// 构建请求数据(含Make) + /// + /// + /// + public static byte[] BuildRequestToBytes(this WSDataFrame dataFrame) + { + dataFrame.FIN = true; + dataFrame.Mask = true; + if (dataFrame.MaskingKey == null) + { + dataFrame.SetMaskString("RRQM"); + } + using (ByteBlock byteBlock = new ByteBlock()) + { + dataFrame.Build(byteBlock, true); + byte[] data = byteBlock.ToArray(); + return data; + } + } + + /// + /// 构建响应数据(无Make) + /// + /// + /// + /// + public static bool BuildResponse(this WSDataFrame dataFrame, ByteBlock byteBlock) + { + dataFrame.FIN = true; + + return dataFrame.Build(byteBlock, false); + } + + /// + /// 构建响应数据(无Make) + /// + /// + /// + public static byte[] BuildResponseToBytes(this WSDataFrame dataFrame) + { + dataFrame.FIN = true; + + using (ByteBlock byteBlock = new ByteBlock()) + { + dataFrame.Build(byteBlock, false); + byte[] data = byteBlock.ToArray(); + return data; + } + } + + /// + /// 设置Mask。 + /// + /// + /// + /// + public static WSDataFrame SetMaskString(this WSDataFrame dataFrame, string mask) + { + byte[] masks = Encoding.UTF8.GetBytes(mask); + if (masks.Length != 4) + { + throw new OverlengthException("Mask只能为ASCII,且只能为四位。"); + } + dataFrame.MaskingKey = masks; + return dataFrame; + } + + /// + /// 当时,转换为Text消息。 + /// + /// + /// + /// + public static string ToText(this WSDataFrame dataFrame, Encoding encoding = default) + { + return (encoding == default ? Encoding.UTF8 : encoding).GetString(dataFrame.PayloadData.Buffer, 0, dataFrame.PayloadLength); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs b/src/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs new file mode 100644 index 000000000..51537ddb9 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Extensions/WebSocketExtensions.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocketExtensions + /// + public static class WebSocketExtensions + { + /// + /// 心跳Timer + /// + public static readonly DependencyProperty HeartbeatTimerProperty = + DependencyProperty.Register("HeartbeatTimer", typeof(WebSocketExtensions), null); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs b/src/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs new file mode 100644 index 000000000..8d7c57013 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Extensions/WebSocketPluginsManagerExtension.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http.WebSockets; + +namespace TouchSocket.Core +{ + /// + /// WebSocketPluginsManagerExtension + /// + public static class WebSocketPluginsManagerExtension + { + /// + /// 使用WebSocket插件 + /// + /// 插件类型实例 + public static WebSocketServerPlugin UseWebSocket(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs b/src/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs new file mode 100644 index 000000000..05a0cc702 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Extensions/WebSocketServerExtensions.cs @@ -0,0 +1,92 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocketServerExtensions + /// + public static class WebSocketServerExtensions + { + /// + /// 转化Protocol协议标识为 + /// + /// + /// Http上下文 + public static bool SwitchProtocolToWebSocket(this TClient client, HttpContext httpContext) where TClient : HttpSocketClient + { + if (client.Protocol == Protocol.WebSocket) + { + return true; + } + if (client.Protocol == Protocol.Http) + { + if (WSTools.TryGetResponse(httpContext.Request, httpContext.Response)) + { + HttpContextEventArgs args = new HttpContextEventArgs(new HttpContext(httpContext.Request, httpContext.Response)) + { + IsPermitOperation = true + }; + client.PluginsManager?.Raise(nameof(IWebSocketPlugin.OnHandshaking), client, args); + + if (args.IsPermitOperation) + { + client.SetDataHandlingAdapter(new WebSocketDataHandlingAdapter()); + client.Protocol = Protocol.WebSocket; + client.SetValue(WebSocketServerPlugin.HandshakedProperty, true);//设置握手状态 + + using (ByteBlock byteBlock = new ByteBlock()) + { + args.Context.Response.Build(byteBlock); + client.DefaultSend(byteBlock); + } + client.PluginsManager?.Raise(nameof(IWebSocketPlugin.OnHandshaked), client, new HttpContextEventArgs(httpContext)); + return true; + } + else + { + args.Context.Response.SetStatus("403", "Forbidden"); + using (ByteBlock byteBlock = new ByteBlock()) + { + args.Context.Response.Build(byteBlock); + client.DefaultSend(byteBlock); + } + + client.Close("主动拒绝WebSocket连接"); + } + } + else + { + client.Close("WebSocket连接协议不正确"); + } + } + return false; + } + + /// + /// 转化Protocol协议标识为 + /// + /// + /// Http上下文 + public static Task SwitchProtocolToWebSocketAsync(this TClient client, HttpContext httpContext) where TClient : HttpSocketClient + { + return EasyTask.Run(() => + { + return SwitchProtocolToWebSocket(client, httpContext); + }); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs b/src/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs new file mode 100644 index 000000000..d855c9bd3 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Interface/IWebSocketClient.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// 用户终端接口 + /// + public interface IWebSocketClient : IHttpClient + { + /// + /// 连接到ws服务器 + /// + /// + /// + /// + ITcpClient Connect(CancellationToken token, int timeout = 5000); + + /// + /// 异步连接到ws服务器 + /// + /// + /// + /// + Task ConnectAsync(CancellationToken token, int timeout = 5000); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs b/src/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs new file mode 100644 index 000000000..787a32402 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Interface/IWebSocketPlugin.cs @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocket插件 + /// + public interface IWebSocketPlugin : IPlugin + { + /// + /// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。 + /// + /// + /// + [AsyncRaiser] + void OnClosing(ITcpClientBase client, MsgEventArgs e); + + /// + /// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。 + /// + /// + /// + Task OnClosingAsync(ITcpClientBase client, MsgEventArgs e); + + /// + /// 当收到WS数据时。 + /// + /// + /// + [AsyncRaiser] + void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e); + + /// + /// 当收到WS数据时。 + /// + /// + /// + /// + Task OnHandleWSDataFrameAsync(ITcpClientBase client, WSDataFrameEventArgs e); + + /// + /// 表示完成握手后。 + /// + /// + /// + [AsyncRaiser] + void OnHandshaked(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 表示完成握手后。 + /// + /// + /// + /// + Task OnHandshakedAsync(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 表示在即将握手连接时。 + /// + /// + /// + [AsyncRaiser] + void OnHandshaking(ITcpClientBase client, HttpContextEventArgs e); + + /// + /// 表示在即将握手连接时。 + /// + /// + /// + /// + Task OnHandshakingAsync(ITcpClientBase client, HttpContextEventArgs e); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs b/src/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs new file mode 100644 index 000000000..3aff93794 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Plugins/WSCommandLinePlugin.cs @@ -0,0 +1,138 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WS命令行插件。 + /// + public abstract class WSCommandLinePlugin : WebSocketPluginBase + { + private readonly Dictionary pairs = new Dictionary(); + private readonly ILog m_logger; + + /// + /// 字符串转换器,默认支持基础类型和Json。可以自定义。 + /// + public StringConverter Converter { get; } + + /// + /// 是否返回执行异常。 + /// + public bool ReturnException { get; set; } = true; + + /// + /// 当有执行异常时,不返回异常。 + /// + /// + public WSCommandLinePlugin NoReturnException() + { + ReturnException = false; + return this; + } + + /// + /// WSCommandLinePlugin + /// + /// + /// + protected WSCommandLinePlugin(ILog logger) + { + m_logger = logger ?? throw new ArgumentNullException(nameof(logger)); + Converter = new StringConverter(); + var ms = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(a => a.Name.EndsWith("Command")); + foreach (var item in ms) + { + pairs.Add(item.Name.Replace("Command", string.Empty), new Method(item)); + } + } + + /// + /// + /// + /// + /// + protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + if (e.DataFrame.Opcode == WSDataType.Text) + { + try + { + string[] strs = e.DataFrame.ToText().Split(' '); + if (strs.Length > 0 && pairs.TryGetValue(strs[0], out Method method)) + { + var ps = method.Info.GetParameters(); + object[] os = new object[ps.Length]; + int index = 0; + for (int i = 0; i < ps.Length; i++) + { + if (ps[i].ParameterType.IsInterface && typeof(ITcpClientBase).IsAssignableFrom(ps[i].ParameterType)) + { + os[i] = client; + } + else + { + os[i] = Converter.ConvertFrom(strs[index + 1], ps[i].ParameterType); + index++; + } + } + + e.Handled = true; + + try + { + object result = method.Invoke(this, os); + if (method.HasReturn) + { + if (client is HttpClient httpClient) + { + httpClient.SendWithWS(Converter.ConvertTo(result)); + } + else if (client is HttpSocketClient httpSocketClient) + { + httpSocketClient.SendWithWS(Converter.ConvertTo(result)); + } + } + } + catch (Exception ex) + { + if (ReturnException) + { + if (client is HttpClient httpClient) + { + httpClient.SendWithWS(Converter.ConvertTo(ex.Message)); + } + else if (client is HttpSocketClient httpSocketClient) + { + httpSocketClient.SendWithWS(Converter.ConvertTo(ex.Message)); + } + } + } + } + } + catch (Exception ex) + { + m_logger.Exception(this, ex); + } + } + + base.OnHandleWSDataFrame(client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs b/src/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs new file mode 100644 index 000000000..221a24481 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Plugins/WebSocketHeartbeatPlugin.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WebSocketHeartbeatPlugin + /// + [SingletonPlugin] + public class WebSocketHeartbeatPlugin : WebSocketPluginBase + { + private readonly int m_timeTick; + + /// + /// 初始化一个适用于WebSocket的心跳插件 + /// + /// + [DependencyInject(1000 * 5)] + public WebSocketHeartbeatPlugin(int interval) + { + m_timeTick = interval; + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(ITcpClientBase client, HttpContextEventArgs e) + { + if (client is HttpClientBase httpClientBase) + { + if (client.GetValue(WebSocketExtensions.HeartbeatTimerProperty) is Timer timer) + { + timer.Dispose(); + } + client.SetValue(WebSocketExtensions.HeartbeatTimerProperty, new Timer((o) => + { + httpClientBase.Ping(); + }, null, 0, m_timeTick)); + } + base.OnHandshaked(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + base.OnDisconnected(client, e); + if (client.GetValue(WebSocketExtensions.HeartbeatTimerProperty) is Timer timer) + { + timer.Dispose(); + client.SetValue(WebSocketExtensions.HeartbeatTimerProperty, null); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs b/src/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs new file mode 100644 index 000000000..2420a0662 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Plugins/WebSocketPluginBase.cs @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// WS插件基类 + /// + public class WebSocketPluginBase : WebSocketPluginBase + { + } + + /// + /// WS插件基类 + /// + public class WebSocketPluginBase : HttpPluginBase, IWebSocketPlugin + { + #region 虚函数 + + /// + /// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。 + /// + /// + /// + protected virtual void OnClosing(ITcpClientBase client, MsgEventArgs e) + { + } + + /// + /// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。 + /// + /// + /// + /// + protected virtual Task OnClosingAsync(ITcpClientBase client, MsgEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 处理WS数据帧。 + /// + /// + /// + protected virtual void OnHandleWSDataFrame(TClient client, WSDataFrameEventArgs e) + { + } + + /// + /// 处理WS数据帧。 + /// + /// + /// + /// + protected virtual Task OnHandleWSDataFrameAsync(TClient client, WSDataFrameEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 表示完成握手后。 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 表示完成握手后。 + /// + /// + /// + /// + protected virtual Task OnHandshakedAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 表示在即将握手连接时。 + /// 在此处拒绝操作,则会返回403 Forbidden。 + /// 也可以向注入更多信息。 + /// + /// + /// + protected virtual void OnHandshaking(TClient client, HttpContextEventArgs e) + { + } + + /// + /// 表示在即将握手连接时。 + /// + /// + /// + /// + protected virtual Task OnHandshakingAsync(TClient client, HttpContextEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数 + + void IWebSocketPlugin.OnClosing(ITcpClientBase client, MsgEventArgs e) + { + OnClosing(client, e); + } + + Task IWebSocketPlugin.OnClosingAsync(ITcpClientBase client, MsgEventArgs e) + { + return OnClosingAsync(client, e); + } + + void IWebSocketPlugin.OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + OnHandleWSDataFrame((TClient)client, e); + } + + Task IWebSocketPlugin.OnHandleWSDataFrameAsync(ITcpClientBase client, WSDataFrameEventArgs e) + { + return OnHandleWSDataFrameAsync((TClient)client, e); + } + + void IWebSocketPlugin.OnHandshaked(ITcpClientBase client, HttpContextEventArgs e) + { + OnHandshaked((TClient)client, e); + } + + Task IWebSocketPlugin.OnHandshakedAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnHandshakedAsync((TClient)client, e); + } + + void IWebSocketPlugin.OnHandshaking(ITcpClientBase client, HttpContextEventArgs e) + { + OnHandshaking((TClient)client, e); + } + + Task IWebSocketPlugin.OnHandshakingAsync(ITcpClientBase client, HttpContextEventArgs e) + { + return OnHandshakingAsync((TClient)client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs b/src/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs new file mode 100644 index 000000000..61a965647 --- /dev/null +++ b/src/TouchSocket/Http/WebSockets/Plugins/WebSocketServerPlugin.cs @@ -0,0 +1,164 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Http.WebSockets +{ + /// + /// 基于Http的WebSocket的扩展。 + /// 此组件只能挂载在 + /// + [SingletonPlugin] + public class WebSocketServerPlugin : HttpPluginBase + { + /// + /// 表示是否完成WS握手 + /// + public static readonly DependencyProperty HandshakedProperty = + DependencyProperty.Register("Handshaked", typeof(WebSocketServerPlugin), false); + + /// + /// 表示WebSocketVersion + /// + public static readonly DependencyProperty WebSocketVersionProperty = + DependencyProperty.Register("WebSocketVersion", typeof(WebSocketServerPlugin), "13"); + + private readonly IPluginsManager m_pluginsManager; + + private string m_wSUrl = "/ws"; + + /// + /// WebSocketServerPlugin + /// + /// + public WebSocketServerPlugin(IPluginsManager pluginsManager) + { + m_pluginsManager = pluginsManager ?? throw new ArgumentNullException(nameof(pluginsManager)); + } + + /// + /// 是否默认处理Close报文。 + /// + public bool AutoClose { get; set; } = true; + + /// + /// 处理WS数据的回调 + /// + public Action HandleWSDataFrameCallback { get; set; } + + /// + /// 用于WebSocket连接的路径,默认为“/ws” + /// 如果设置为null或空,则意味着所有的连接都将解释为WS + /// + public string WSUrl + { + get => m_wSUrl; + set => m_wSUrl = string.IsNullOrEmpty(value) ? "/" : value; + } + + /// + /// 不处理Close报文。 + /// + /// + public WebSocketServerPlugin NoAutoClose() + { + AutoClose = false; + return this; + } + + /// + /// 设置处理WS数据的回调。 + /// + /// + public WebSocketServerPlugin SetCallback(Action action) + { + HandleWSDataFrameCallback = action; + return this; + } + + /// + /// 用于WebSocket连接的路径,默认为“/ws” + /// 如果设置为null或空,则意味着所有的连接都将解释为WS + /// + /// + /// + public WebSocketServerPlugin SetWSUrl(string url) + { + WSUrl = url; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (WSUrl == "/" || e.Context.Request.UrlEquals(WSUrl)) + { + if (client.Protocol == Protocol.Http) + { + e.Handled = true; + if (client is HttpSocketClient socketClient) + { + socketClient.SwitchProtocolToWebSocket(e.Context); + } + } + } + base.OnGet(client, e); + } + + /// + /// 处理WS数据帧。覆盖父类方法将不会触发回调和插件。 + /// + /// + /// + protected virtual void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + if (e.DataFrame.Opcode == WSDataType.Close && AutoClose) + { + string msg = e.DataFrame.PayloadData?.ToString(); + m_pluginsManager.Raise(nameof(IWebSocketPlugin.OnClosing), client, new MsgEventArgs() { Message = msg }); + client.Close(msg); + return; + } + + if (m_pluginsManager.Raise(nameof(IWebSocketPlugin.OnHandleWSDataFrame), client, e)) + { + return; + } + HandleWSDataFrameCallback?.Invoke(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + if (client.Protocol == Protocol.WebSocket) + { + if (e.RequestInfo is WSDataFrame dataFrame) + { + e.Handled = true; + OnHandleWSDataFrame(client, new WSDataFrameEventArgs(dataFrame)); + } + } + base.OnReceivedData(client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/LICENSE.txt b/src/TouchSocket/LICENSE.txt new file mode 100644 index 000000000..b09cd7856 --- /dev/null +++ b/src/TouchSocket/LICENSE.txt @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/TouchSocket/Resources/AssemblyInfo.cs b/src/TouchSocket/Resources/AssemblyInfo.cs new file mode 100644 index 000000000..04b334a75 --- /dev/null +++ b/src/TouchSocket/Resources/AssemblyInfo.cs @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Runtime.CompilerServices; + +#if NET6_0_OR_GREATER +#else +[assembly: SuppressIldasm()] +#endif diff --git a/src/TouchSocket/Resources/TouchSocketStatus.cs b/src/TouchSocket/Resources/TouchSocketStatus.cs new file mode 100644 index 000000000..7406387df --- /dev/null +++ b/src/TouchSocket/Resources/TouchSocketStatus.cs @@ -0,0 +1,251 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.ComponentModel; + +namespace TouchSocket.Resources +{ + /// + /// TouchSocket资源枚举 + /// + public enum TouchSocketStatus : byte + { + /// + /// 未知错误 + /// + [Description("未知错误")] + UnknownError, + + /// + /// 操作成功 + /// + [Description("操作成功")] + Success, + + /// + /// 操作超时 + /// + [Description("操作超时")] + Overtime, + + /// + /// 用户主动取消操作。 + /// + [Description("用户主动取消操作。")] + Canceled, + + /// + /// 参数‘{0}’为空。 + /// + [Description("参数‘{0}’为空。")] + ArgumentNull, + + /// + ///发生异常,信息:{0}。 + /// + [Description("发生异常,信息:{0}。")] + Exception, + + #region TouchRpc + + /// + /// 不允许路由该包,信息:{0}。 + /// + [Description("不允许路由该包,信息:{0}。")] + RoutingNotAllowed, + + /// + /// 未找到该公共方法,或该方法未标记为Rpc + /// + [Description("未找到该公共方法,或该方法未标记为Rpc")] + RpcMethodNotFind, + + /// + /// 方法已被禁用 + /// + [Description("方法已被禁用")] + RpcMethodDisable, + + /// + /// 函数执行异常,详细信息:{0} + /// + [Description("函数执行异常,详细信息:{0}")] + RpcInvokeException, + + /// + /// 事件操作器异常 + /// + [Description("事件操作器异常。")] + GetEventArgsFail, + + /// + /// 通道设置失败。 + /// + [Description("通道设置失败。")] + SetChannelFail, + + /// + /// ID为{0}的通道已存在。 + /// + [Description("ID为{0}的通道已存在。")] + ChannelExisted, + + /// + /// 远程终端拒绝该操作,反馈信息:{0}。 + /// + [Description("远程终端拒绝该操作,反馈信息:{0}。")] + RemoteRefuse, + + /// + /// 从‘{0}’创建写入流失败,信息:{1}。" + /// + [Description("从‘{0}’创建写入流失败,信息:{1}。")] + CreateWriteStreamFail, + + /// + ///没有找到路径‘{0}’对应的流文件。 + /// + [Description("没有找到路径‘{0}’对应的流文件。")] + StreamNotFind, + + /// + /// 没有找到ID为{0}的客户端。 + /// + [Description("没有找到ID为{0}的客户端。")] + ClientNotFind, + + /// + /// 路径‘{0}’对应的流文件,仍然被‘{1}’对象应用。 + /// + [Description("路径‘{0}’对应的流文件,仍然被‘{1}’对象应用。")] + StreamReferencing, + + /// + /// 接收流容器为空 + /// + [Description("流容器为空。")] + StreamBucketNull, + + /// + /// 从‘{0}’路径加载流异常,信息:‘{1}’。 + /// + [Description("从‘{0}’路径加载流异常,信息:‘{1}’。")] + LoadStreamFail, + + /// + /// 目录‘{0}’已存在。 + /// + [Description("目录‘{0}’已存在。")] + DirectoryExisted, + + /// + /// 文件‘{0}’已存在。 + /// + [Description("文件‘{0}’已存在。")] + FileExisted, + + /// + /// 文件‘{0}’不存在。 + /// + [Description("文件‘{0}’不存在。")] + FileNotExists, + + /// + /// 目录‘{0}’不存在。 + /// + [Description("目录‘{0}’不存在。")] + DirectoryNotExists, + + /// + /// 名称为“{0}”的事件已存在 + /// + [Description("名称为“{0}”的事件已存在。")] + EventExisted, + + /// + /// 名称为“{0}”的事件不存在 + /// + [Description("名称为“{0}”的事件不存在。")] + EventNotExist, + + /// + /// 资源句柄{0}对应的资源没有找到,可能操作已超时。 + /// + [Description("资源句柄{0}对应的资源没有找到,可能操作已超时。")] + ResourceHandleNotFind, + + /// + /// 还有{0}个资源没有完成。 + /// + [Description("还有{0}个资源没有完成。")] + HasUnFinished, + + /// + /// 文件长度太长。 + /// + [Description("文件长度太长。")] + FileLengthTooLong, + + /// + /// 读取文件长度错误。 + /// + [Description("读取文件长度错误。")] + LengthErrorWhenRead, + + /// + /// 没有找到任何可用的目标Id。 + /// + [Description("没有找到任何可用的目标Id。")] + NotFindAnyTargetId, + + #endregion TouchRpc + + #region Core + + /// + /// Token消息为‘{0}’的已注册。 + /// + [Description("Token消息为‘{0}’的已注册。")] + TokenExisted, + + /// + /// Token消息为‘{0}’的未注册。 + /// + [Description("Token消息为‘{0}’的未注册。")] + MessageNotFound, + + #endregion Core + + #region Client + + /// + /// 数据处理适配器为空,可能客户端已掉线。 + /// + [Description("数据处理适配器为空,可能客户端已掉线。")] + NullDataAdapter, + + /// + /// 客户端没有连接 + /// + [Description("客户端没有连接。")] + NotConnected, + + /// + /// 授权密钥无效,程序将在5秒后退出。请检查密钥,或者不使用企业版功能。 + /// + [Description("授权密钥无效,程序将在5秒后退出。请检查密钥,或者不使用企业版功能。")] + LicenceKeyInvalid, + + #endregion Client + } +} \ No newline at end of file diff --git a/src/TouchSocket/Resources/TouchSocketStatusExtension.cs b/src/TouchSocket/Resources/TouchSocketStatusExtension.cs new file mode 100644 index 000000000..d0a9b24ef --- /dev/null +++ b/src/TouchSocket/Resources/TouchSocketStatusExtension.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Resources +{ + /// + /// StatusExtension + /// + internal static class TouchSocketStatusExtension + { + /// + /// 转为状态字 + /// + /// + /// + public static TouchSocketStatus ToStatus(this byte value) + { + return (TouchSocketStatus)value; + } + + /// + /// 转为数值 + /// + /// + /// + public static byte ToValue(this TouchSocketStatus value) + { + return (byte)value; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs b/src/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs new file mode 100644 index 000000000..5cc5697de --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Attribute/IRpcActionFilter.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Rpc +{ + /// + /// RPC行为过滤器。 + /// + public interface IRpcActionFilter + { + /// + /// 成功执行Rpc后。 + /// 如果修改的InvokeStatus,或Result。则会影响RPC最终结果 + /// + /// + /// + /// + void Executed(ICallContext callContext,object[] parameters, ref InvokeResult invokeResult); + + /// + /// 成功执行Rpc后。 + /// 如果修改的InvokeStatus,或Result。则会影响RPC最终结果 + /// + /// + /// + /// + Task ExecutedAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult); + + /// + /// 执行Rpc遇见异常。 + /// 如果修改的InvokeStatus,或Result。则会影响RPC最终结果 + /// + /// + /// + /// + /// + void ExecutException(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception); + + /// + /// 执行Rpc遇见异常。 + /// 如果修改的InvokeStatus,或Result。则会影响RPC最终结果 + /// + /// + /// + /// + /// + Task ExecutExceptionAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception); + + /// + /// 在执行Rpc之前。 + /// 的InvokeStatus不为。则不会执行RPC + /// 同时,当的InvokeStatus为。会直接返回结果 + /// + /// + /// + /// + void Executing(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult); + + /// + /// 在执行Rpc之前。 + /// 的InvokeStatus不为。则不会执行RPC + /// 同时,当的InvokeStatus为。会直接返回结果 + /// + /// + /// + /// + Task ExecutingAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs b/src/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs new file mode 100644 index 000000000..70b7d66dc --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Attribute/RpcActionFilterAttribute.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// RpcActionFilterAttribute + /// + public abstract class RpcActionFilterAttribute : Attribute, IRpcActionFilter + { + /// + public virtual void Executed(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + } + + /// + public virtual Task ExecutedAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + return EasyTask.CompletedTask; + } + + /// + public virtual void ExecutException(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception) + { + } + + /// + public virtual Task ExecutExceptionAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult, Exception exception) + { + return EasyTask.CompletedTask; + } + + /// + public virtual void Executing(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + } + + /// + public virtual Task ExecutingAsync(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + return EasyTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs b/src/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs new file mode 100644 index 000000000..45a4a2703 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Attribute/RpcAttribute.cs @@ -0,0 +1,889 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc方法属性基类 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public abstract class RpcAttribute : Attribute + { + private readonly Dictionary m_exceptions = new Dictionary(); + + /// + /// 构造函数 + /// + public RpcAttribute() + { + MethodFlags = MethodFlags.None; + m_exceptions.Add(typeof(TimeoutException), "调用超时"); + m_exceptions.Add(typeof(RpcInvokeException), "Rpc调用异常"); + m_exceptions.Add(typeof(Exception), "其他异常"); + } + + /// + /// 调用键。 + /// + public string InvokenKey { get; set; } + + /// + /// 类生成器 + /// + public ClassCodeGenerator ClassCodeGenerator { get; private set; } + + /// + /// 异常提示 + /// + public Dictionary Exceptions => m_exceptions; + + /// + /// 生成代码 + /// + public CodeGeneratorFlag GeneratorFlag { get; protected set; } = + CodeGeneratorFlag.Sync | CodeGeneratorFlag.Async | CodeGeneratorFlag.ExtensionSync | CodeGeneratorFlag.ExtensionAsync + | CodeGeneratorFlag.IncludeInterface | CodeGeneratorFlag.IncludeInstance | CodeGeneratorFlag.IncludeExtension; + + /// + /// 函数标识 + /// + public MethodFlags MethodFlags { get; set; } + + /// + /// 重新指定生成的函数名称。可以使用类似“JsonRpc_{0}”的模板格式。 + /// + public string MethodName { get; set; } + + /// + /// 当使用TryCanInvoke不能调用时,执行的代码。 + /// + /// + public virtual string GetCannotInvoke(MethodInstance methodInstance) + { + return "throw new RpcException(\"Rpc无法执行。\");"; + } + + /// + /// 获取注释信息 + /// + /// + /// + public virtual string GetDescription(MethodInstance methodInstance) + { + return string.IsNullOrEmpty(methodInstance.Description) ? "无注释信息" : methodInstance.Description; + } + + /// + /// 获取扩展的代理代码 + /// + /// + /// + public virtual string GetExtensionsMethodProxyCode(MethodInstance methodInstance) + { + StringBuilder codeString = new StringBuilder(); + + string description = GetDescription(methodInstance); + bool isOut; + bool isRef; + + ParameterInfo[] parameters; + List parametersStr = GetParameters(methodInstance, out isOut, out isRef, out parameters); + var InterfaceTypes = GetGenericInterfaceTypes(); + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionSync)) + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + foreach (var item in Exceptions) + { + codeString.AppendLine($"/// {item.Value}"); + } + + codeString.Append("public static "); + codeString.Append(GetReturn(methodInstance, false)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, false)); + codeString.Append("(");//方法参数 + + codeString.Append($"this TClient client"); + + codeString.Append(","); + for (int i = 0; i < parametersStr.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(parametersStr[i]); + } + if (parametersStr.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(") where TClient:"); + + for (int i = 0; i < InterfaceTypes.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(InterfaceTypes[i].FullName); + } + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if (client.TryCanInvoke?.Invoke(client)==false)"); + codeString.AppendLine("{"); + codeString.AppendLine(GetCannotInvoke(methodInstance)); + codeString.AppendLine("}"); + + if (parametersStr.Count > 0) + { + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + + foreach (ParameterInfo parameter in parameters) + { + if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut) + { + codeString.Append($"default({GetProxyParameterName(parameter)})"); + } + else + { + codeString.Append(parameter.Name); + } + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + + if (isOut || isRef) + { + codeString.Append($"Type[] types = new Type[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append($"typeof({GetProxyParameterName(parameter)})"); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + } + + if (methodInstance.HasReturn) + { + if (parametersStr.Count == 0) + { + codeString.Append(string.Format("{0} returnData=client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else if (isOut || isRef) + { + codeString.Append(string.Format("{0} returnData=client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append(string.Format("{0} returnData=client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (parametersStr.Count == 0) + { + codeString.Append("client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else if (isOut || isRef) + { + codeString.Append("client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append("client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + if (isOut || isRef) + { + codeString.AppendLine("if(parameters!=null)"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, GetProxyParameterName(parameters[i]), i)); + } + codeString.AppendLine("}"); + if (isOut) + { + codeString.AppendLine("else"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].IsOut) + { + codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, GetProxyParameterName(parameters[i]))); + } + } + codeString.AppendLine("}"); + } + } + + if (methodInstance.HasReturn) + { + codeString.AppendLine("return returnData;"); + } + + codeString.AppendLine("}"); + } + + //以下生成异步 + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.ExtensionAsync) && !isOut && !isRef)//没有out或者ref + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + codeString.Append("public static "); + codeString.Append(GetReturn(methodInstance, true)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, true)); + codeString.Append("(");//方法参数 + + codeString.Append($"this TClient client"); + + codeString.Append(","); + for (int i = 0; i < parametersStr.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parametersStr[i]); + } + if (parametersStr.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(") where TClient:"); + + for (int i = 0; i < InterfaceTypes.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(InterfaceTypes[i].FullName); + } + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if (client.TryCanInvoke?.Invoke(client)==false)"); + codeString.AppendLine("{"); + codeString.AppendLine($"throw new RpcException(\"Rpc无法执行。\");"); + codeString.AppendLine("}"); + + if (parametersStr.Count > 0) + { + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append(parameter.Name); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + + if (methodInstance.HasReturn) + { + if (parametersStr.Count == 0) + { + codeString.Append(string.Format("return client.InvokeAsync<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else + { + codeString.Append(string.Format("return client.InvokeAsync<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (parametersStr.Count == 0) + { + codeString.Append("return client.InvokeAsync("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else + { + codeString.Append("return client.InvokeAsync("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + codeString.AppendLine("}"); + } + return codeString.ToString(); + } + + /// + /// 获取生成的函数泛型限定名称。默认 + /// + /// + public virtual Type[] GetGenericInterfaceTypes() + { + return new Type[] { typeof(IRpcClient) }; + } + + /// + /// 获取生成实体类时的代码块 + /// + /// + /// + public virtual string GetInstanceProxyCode(MethodInstance methodInstance) + { + StringBuilder codeString = new StringBuilder(); + + string description = GetDescription(methodInstance); + ParameterInfo[] parameters; + bool isOut; + bool isRef; + List parametersStr = GetParameters(methodInstance, out isOut, out isRef, out parameters); + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.Sync)) + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + foreach (var item in Exceptions) + { + codeString.AppendLine($"/// {item.Value}"); + } + + codeString.Append("public "); + codeString.Append(GetReturn(methodInstance, false)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, false)); + codeString.Append("(");//方法参数 + + for (int i = 0; i < parametersStr.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parametersStr[i]); + } + if (parametersStr.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(")"); + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if(Client==null)"); + codeString.AppendLine("{"); + codeString.AppendLine("throw new RpcException(\"IRpcClient为空,请先初始化或者进行赋值\");"); + codeString.AppendLine("}"); + codeString.AppendLine("if (Client.TryCanInvoke?.Invoke(Client)==false)"); + codeString.AppendLine("{"); + codeString.AppendLine($"throw new RpcException(\"Rpc无法执行。\");"); + codeString.AppendLine("}"); + + if (parametersStr.Count > 0) + { + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + + foreach (ParameterInfo parameter in parameters) + { + if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut) + { + codeString.Append($"default({GetProxyParameterName(parameter)})"); + } + else + { + codeString.Append(parameter.Name); + } + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + + if (isOut || isRef) + { + codeString.Append($"Type[] types = new Type[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append($"typeof({GetProxyParameterName(parameter)})"); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + } + + if (methodInstance.HasReturn) + { + if (parametersStr.Count == 0) + { + codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else if (isOut || isRef) + { + codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (parametersStr.Count == 0) + { + codeString.Append("Client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else if (isOut || isRef) + { + codeString.Append("Client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append("Client.Invoke("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + if (isOut || isRef) + { + codeString.AppendLine("if(parameters!=null)"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, GetProxyParameterName(parameters[i]), i)); + } + codeString.AppendLine("}"); + if (isOut) + { + codeString.AppendLine("else"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].IsOut) + { + codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, GetProxyParameterName(parameters[i]))); + } + } + codeString.AppendLine("}"); + } + } + + if (methodInstance.HasReturn) + { + codeString.AppendLine("return returnData;"); + } + + codeString.AppendLine("}"); + } + + //以下生成异步 + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.Async) && !isOut && !isRef)//没有out或者ref + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + codeString.Append("public "); + codeString.Append(GetReturn(methodInstance, true)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, true)); + codeString.Append("(");//方法参数 + + for (int i = 0; i < parametersStr.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parametersStr[i]); + } + if (parametersStr.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(")"); + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if(Client==null)"); + codeString.AppendLine("{"); + codeString.AppendLine("throw new RpcException(\"IRpcClient为空,请先初始化或者进行赋值\");"); + codeString.AppendLine("}"); + + codeString.AppendLine("if (Client.TryCanInvoke?.Invoke(Client)==false)"); + codeString.AppendLine("{"); + codeString.AppendLine($"throw new RpcException(\"Rpc无法执行。\");"); + codeString.AppendLine("}"); + + if (parametersStr.Count > 0) + { + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append(parameter.Name); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + + if (methodInstance.HasReturn) + { + if (parametersStr.Count == 0) + { + codeString.Append(string.Format("return Client.InvokeAsync<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else + { + codeString.Append(string.Format("return Client.InvokeAsync<{0}>", GetProxyParameterName(methodInstance.Info.ReturnParameter))); + codeString.Append("("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (parametersStr.Count == 0) + { + codeString.Append("return Client.InvokeAsync("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, null);"); + } + else + { + codeString.Append("return Client.InvokeAsync("); + codeString.Append($"\"{GetInvokenKey(methodInstance)}\""); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + codeString.AppendLine("}"); + } + return codeString.ToString(); + } + + /// + /// 获取接口的代理代码 + /// + /// + /// + public virtual string GetInterfaceProxyCode(MethodInstance methodInstance) + { + StringBuilder codeString = new StringBuilder(); + bool isOut = false; + bool isRef = false; + string description = GetDescription(methodInstance); + List parameters = GetParameters(methodInstance, out isOut, out isRef, out _); + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.Sync)) + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + foreach (var item in Exceptions) + { + codeString.AppendLine($"/// {item.Value}"); + } + + codeString.Append(GetReturn(methodInstance, false)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, false)); + codeString.Append("(");//方法参数 + for (int i = 0; i < parameters.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parameters[i]); + } + if (parameters.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(");"); + } + + if (GeneratorFlag.HasFlag(CodeGeneratorFlag.Async) && !isOut && !isRef)//没有out或者ref + { + codeString.AppendLine("///"); + codeString.AppendLine($"///{description}"); + codeString.AppendLine("///"); + foreach (var item in Exceptions) + { + codeString.AppendLine($"/// {item.Value}"); + } + + codeString.Append(GetReturn(methodInstance, true)); + codeString.Append(" "); + codeString.Append(GetMethodName(methodInstance, true)); + codeString.Append("(");//方法参数 + + for (int i = 0; i < parameters.Count; i++) + { + if (i > 0) + { + codeString.Append(","); + } + codeString.Append(parameters[i]); + } + if (parameters.Count > 0) + { + codeString.Append(","); + } + codeString.Append(GetInvokeOption()); + codeString.AppendLine(");"); + } + + return codeString.ToString(); + } + + /// + /// 获取调用键 + /// + /// + /// + public virtual string GetInvokenKey(MethodInstance methodInstance) + { + if (!InvokenKey.IsNullOrEmpty()) + { + return InvokenKey; + } + return $"{methodInstance.ServerType.FullName}.{methodInstance.Name}".ToLower(); + } + + /// + /// 获取调用配置 + /// + /// + public virtual string GetInvokeOption() + { + return "IInvokeOption invokeOption = default"; + } + + /// + /// 获取生成的函数名称 + /// + /// + /// + /// + public virtual string GetMethodName(MethodInstance methodInstance, bool isAsync) + { + string name; + if (string.IsNullOrEmpty(MethodName)) + { + name = methodInstance.Name; + } + else + { + name = MethodName.Format(methodInstance.Name); + } + return isAsync ? name + "Async" : name; + } + + /// + /// 获取参数生成 + /// + /// + /// + /// + /// + /// + public virtual List GetParameters(MethodInstance methodInstance, out bool isOut, out bool isRef, out ParameterInfo[] parameters) + { + List list = new List(); + isOut = false; + isRef = false; + + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + List infos = new List(methodInstance.Parameters); + infos.RemoveAt(0); + parameters = infos.ToArray(); + } + else + { + parameters = methodInstance.Parameters; + } + + for (int i = 0; i < parameters.Length; i++) + { + StringBuilder codeString = new StringBuilder(); + if (parameters[i].ParameterType.Name.Contains("&")) + { + if (parameters[i].IsOut) + { + isOut = true; + codeString.Append(string.Format("out {0} {1}", GetProxyParameterName(parameters[i]), parameters[i].Name)); + } + else + { + isRef = true; + codeString.Append(string.Format("ref {0} {1}", GetProxyParameterName(parameters[i]), parameters[i].Name)); + } + } + else + { + codeString.Append(string.Format("{0} {1}", GetProxyParameterName(parameters[i]), parameters[i].Name)); + } + + if (parameters[i].HasDefaultValue) + { + object defaultValue = parameters[i].DefaultValue; + if (defaultValue == null) + { + codeString.Append(string.Format("=null")); + } + else if (defaultValue.ToString() == string.Empty) + { + codeString.Append(string.Format("=\"\"")); + } + else if (defaultValue.GetType() == typeof(string)) + { + codeString.Append(string.Format("=\"{0}\"", defaultValue)); + } + else if (defaultValue.GetType() == typeof(bool)) + { + codeString.Append(string.Format("={0}", defaultValue.ToString().ToLower())); + } + else if (typeof(ValueType).IsAssignableFrom(defaultValue.GetType())) + { + codeString.Append(string.Format("={0}", defaultValue)); + } + } + + list.Add(codeString.ToString()); + } + + return list; + } + + /// + /// 从类型获取代理名 + /// + /// + /// + public virtual string GetProxyParameterName(ParameterInfo parameterInfo) + { + return ClassCodeGenerator.GetTypeFullName(parameterInfo); + } + + /// + /// 获取返回值 + /// + /// + /// + /// + public virtual string GetReturn(MethodInstance methodInstance, bool isAsync) + { + if (isAsync) + { + if (methodInstance.ReturnType == null) + { + return "Task"; + } + else + { + return $"Task<{GetProxyParameterName(methodInstance.Info.ReturnParameter)}>"; + } + } + else + { + if (methodInstance.ReturnType == null) + { + return "void"; + } + else + { + return GetProxyParameterName(methodInstance.Info.ReturnParameter); + } + } + } + + internal void SetClassCodeGenerator(ClassCodeGenerator classCodeGenerator) + { + ClassCodeGenerator = classCodeGenerator; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs b/src/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs new file mode 100644 index 000000000..27bce8ec2 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Attribute/RpcProxyAttribute.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc +{ + /// + /// 代理类 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)] + public class RpcProxyAttribute : Attribute + { + /// + /// 构造函数 + /// + /// + public RpcProxyAttribute(string className) + { + if (string.IsNullOrEmpty(className)) + { + throw new ArgumentException($"“{nameof(className)}”不能为 null 或空。", nameof(className)); + } + + ClassName = className; + } + + /// + /// 构造函数 + /// + public RpcProxyAttribute() + { + } + + /// + /// 代理类名 + /// + public string ClassName { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Code/ClassCellCode.cs b/src/TouchSocket/Rpc/Global/Code/ClassCellCode.cs new file mode 100644 index 000000000..82abcf460 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Code/ClassCellCode.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 属性单元代码。 + /// + public class ClassCellCode + { + /// + /// 属性名 + /// + public string Name { get; set; } + + /// + /// 代码本体 + /// + public string Code { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs b/src/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs new file mode 100644 index 000000000..a771fa812 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Code/ClassCodeGenerator.cs @@ -0,0 +1,523 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// 代码辅助类 + /// + public class ClassCodeGenerator + { + private static readonly string[] m_dicType = { "Dictionary`2", "IDictionary`2" }; + private static readonly string[] m_listType = { "List`1", "HashSet`1", "IList`1", "ISet`1", "ICollection`1", "IEnumerable`1" }; + private readonly Assembly[] m_assembly; + + /// + /// 构造函数 + /// + /// + public ClassCodeGenerator(Assembly[] assembly) + { + m_assembly = assembly; + PropertyDic = new ConcurrentDictionary(); + //GenericTypeDic = new ConcurrentDictionary(); + } + + /// + /// 程序集 + /// + public Assembly[] Assembly => m_assembly; + + ///// + ///// 泛型类型字典 + ///// + //public ConcurrentDictionary GenericTypeDic { get; private set; } + + /// + /// 属性类型字典。 + /// + public ConcurrentDictionary PropertyDic { get; private set; } + + /// + /// 获取类单元参数 + /// + /// + public ClassCellCode[] GetClassCellCodes() + { + return PropertyDic.Values.ToArray(); + } + + /// + /// 获取类型全名 + /// + /// + /// + public string GetTypeFullName(Type type) + { + if (type.FullName == null) + { + return type.Name.Replace("&", string.Empty); + } + else if (type == typeof(void)) + { + return null; + } + else if (typeof(Task).IsAssignableFrom(type)) + { + Type[] ts = type.GetGenericArguments(); + if (ts.Length == 1) + { + return ts[0].Name; + } + else + { + return type.Name; + } + } + else if (type.IsArray) + { + Type elementType = type.GetElementType(); + return GetTypeFullName(elementType) + type.Name.Replace(elementType.Name, string.Empty); + } + else if (type.IsValueTuple()) + { + Type[] elementTypes = type.GetGenericArguments(); + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("("); + + List strings = new List(); + var tupleNames = new List(); + if (tupleElementNames != null && tupleElementNames.Count > 0) + { + tupleNames.AddRange(tupleElementNames.Skip(0).Take(elementTypes.Length)); + tupleElementNames.RemoveRange(0, elementTypes.Length); + } + for (int i = 0; i < elementTypes.Length; i++) + { + string item = GetTypeFullName(elementTypes[i]); + if (tupleNames.Count > 0) + { + strings.Add($"{item} {tupleNames[i]}"); + } + else + { + strings.Add($"{item}"); + } + } + //var strs = elementTypes.Select(e => GetTypeFullName(e)); + + + //foreach (var item in strs) + //{ + + //} + stringBuilder.Append(string.Join(",", strings)); + stringBuilder.Append(")"); + return stringBuilder.ToString(); + } + else if (type.IsByRef) + { + return GetTypeFullName(type.GetElementType()); + } + else if (type.IsPrimitive || type == typeof(string)) + { + return type.FullName; + } + else if (m_listType.Contains(type.Name)) + { + string typeInnerString = GetTypeFullName(type.GetGenericArguments()[0]); + string typeString = $"System.Collections.Generic.{type.Name.Replace("`1", string.Empty)}<{typeInnerString}>"; + return typeString; + } + else if (m_listType.Contains(type.Name) || m_dicType.Contains(type.Name)) + { + string keyString = GetTypeFullName(type.GetGenericArguments()[0]); + string valueString = GetTypeFullName(type.GetGenericArguments()[1]); + string typeString = $"System.Collections.Generic.{type.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>"; + return typeString; + } + else if (PropertyDic.ContainsKey(type)) + { + return PropertyDic[type].Name; + } + else + { + return type.FullName; + } + } + + private List tupleElementNames; + /// + /// 获取类型全名 + /// + /// + /// + public string GetTypeFullName(ParameterInfo parameterInfo) + { + //Type type= parameterInfo.ParameterType.GetRefOutType(); + //if (type.IsGenericType && type.FullName.Contains("System.ValueTuple")) + //{ + // Type[] elementType = type.GetGenericArguments(); + // var strs = elementType.Select(e => GetTypeFullName(e)); + + // else + // { + // StringBuilder stringBuilder=new StringBuilder(); + // stringBuilder.Append("("); + // int i = 0; + // foreach (var item in strs) + // { + // stringBuilder.Append($"{item} {names[i]} "); + // if (names.Count-1>i) + // { + // stringBuilder.Append(","); + // } + // i++; + // } + // stringBuilder.Append(")"); + // return stringBuilder.ToString(); + // } + //} + if (parameterInfo.ParameterType.FullName.Contains("System.ValueTuple")) + { + tupleElementNames = parameterInfo.GetTupleElementNames()?.ToList(); + if (tupleElementNames.Count == 3) + { + + } + } + else + { + tupleElementNames = default; + } + return GetTypeFullName(parameterInfo.ParameterType); + } + + internal void CheckDeep() + { + //foreach (var strItem in GenericTypeDic) + //{ + // bool goon = true; + // string strItemNew = strItem.Value; + // while (goon) + // { + // goon = false; + // foreach (var item in GenericTypeDic.Keys) + // { + // if (strItemNew.Contains(item.FullName)) + // { + // strItemNew = strItemNew.Replace(item.FullName, item.Name); + // goon = true; + // } + // } + // } + // GenericTypeDic[strItem.Key] = strItemNew; + //} + + foreach (var strItem in PropertyDic) + { + bool goon = true; + string strItemNew = strItem.Value.Code; + while (goon) + { + goon = false; + foreach (var item in PropertyDic.Keys) + { + if (strItemNew.Contains(item.FullName)) + { + strItemNew = strItemNew.Replace(item.FullName, item.Name); + goon = true; + } + } + } + PropertyDic[strItem.Key].Code = strItemNew; + } + } + + internal void AddTypeString(Type type, ref int deep) + { + if (CodeGenerator.m_ignoreTypes.Contains(type)) + { + return; + } + if (CodeGenerator.m_ignoreAssemblies.Contains(type.Assembly)) + { + return; + } + deep++; + if (deep > 50) + { + return; + } + if (type.IsByRef) + { + type = type.GetRefOutType(); + } + + if (type.IsPrimitive && type == typeof(string)) + { + return; + } + + if (type == TouchSocketCoreUtility.objType) + { + return; + } + if (type.IsInterface || type.IsAbstract) + { + return; + } + if (type.IsArray) + { + AddTypeString(type.GetElementType(), ref deep); + } + else if (type.IsGenericType) + { + Type[] types = type.GetGenericArguments(); + //if (m_listType.Contains(type.Name)) + //{ + // string typeInnerString = GetTypeFullName(types[0]); + // string typeString = $"System.Collections.Generic.{type.Name.Replace("`1", string.Empty)}<{typeInnerString}>"; + // if (!GenericTypeDic.ContainsKey(type)&& !type.FullName.Contains("System.ValueTuple")) + // { + // GenericTypeDic.TryAdd(type, typeString); + // } + //} + //else if (m_dicType.Contains(type.Name)) + //{ + // string keyString = GetTypeFullName(types[0]); + // string valueString = GetTypeFullName(types[1]); + // string typeString = $"System.Collections.Generic.{type.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>"; + // if (!GenericTypeDic.ContainsKey(type) && !type.FullName.Contains("System.ValueTuple")) + // { + // GenericTypeDic.TryAdd(type, typeString); + // } + //} + + foreach (Type itemType in types) + { + AddTypeString(itemType, ref deep); + } + } + else if (type.IsEnum) + { + Type baseType = Enum.GetUnderlyingType(type); + StringBuilder stringBuilder = new StringBuilder(); + if (baseType == TouchSocketCoreUtility.byteType) + { + stringBuilder.AppendLine($"public enum {type.Name}:byte"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(byte)item},"); + } + } + else if (baseType == TouchSocketCoreUtility.shortType) + { + stringBuilder.AppendLine($"public enum {type.Name}:short"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(short)item},"); + } + } + else if (baseType == TouchSocketCoreUtility.intType) + { + stringBuilder.AppendLine($"public enum {type.Name}:int"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(int)item},"); + } + } + else if (baseType == TouchSocketCoreUtility.longType) + { + stringBuilder.AppendLine($"public enum {type.Name}:long"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(long)item},"); + } + } + + stringBuilder.AppendLine("}"); + if (!PropertyDic.ContainsKey(type)) + { + string className; + if (type.GetCustomAttribute() is RpcProxyAttribute attribute) + { + className = attribute.ClassName ?? type.Name; + } + else if (CodeGenerator.TryGetProxyTypeName(type, out className)) + { + } + else if (AllowGen(type.Assembly)) + { + className = type.Name; + } + else + { + return; + } + PropertyDic.TryAdd(type, new ClassCellCode() { Name = className, Code = stringBuilder.ToString() }); + } + } + else + { + string className; + if (type.GetCustomAttribute() is RpcProxyAttribute attribute) + { + className = attribute.ClassName ?? type.Name; + } + else if (CodeGenerator.TryGetProxyTypeName(type, out className)) + { + } + else if (AllowGen(type.Assembly)) + { + className = type.Name; + } + else + { + return; + } + StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.AppendLine(""); + if (type.IsStruct()) + { + stringBuilder.AppendLine($"public struct {className}"); + } + else + { + stringBuilder.AppendLine($"public class {className}"); + } + + if (!type.IsStruct() && type.BaseType != typeof(object)) + { + AddTypeString(type.BaseType, ref deep); + if (type.BaseType.IsGenericType) + { + Type[] types = type.BaseType.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType, ref deep); + } + if (m_listType.Contains(type.BaseType.Name)) + { + string typeString = GetTypeFullName(types[0]); + stringBuilder.Append($":{type.BaseType.Name.Replace("`1", string.Empty)}<{typeString}>"); + } + else if (m_dicType.Contains(type.BaseType.Name)) + { + string keyString = GetTypeFullName(types[0]); + string valueString = GetTypeFullName(types[1]); + stringBuilder.Append($": {type.BaseType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>"); + } + } + else if (type.BaseType.IsClass) + { + stringBuilder.AppendLine($": {GetTypeFullName(type.BaseType)}"); + } + } + + stringBuilder.AppendLine("{"); + PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.GetProperty | BindingFlags.SetProperty); + + foreach (PropertyInfo itemProperty in propertyInfos) + { + AddTypeString(itemProperty.PropertyType, ref deep); + if (PropertyDic.ContainsKey(itemProperty.PropertyType)) + { + stringBuilder.Append($"public {itemProperty.PropertyType.Name} {itemProperty.Name}"); + } + else if (itemProperty.PropertyType.IsGenericType) + { + Type[] types = itemProperty.PropertyType.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType, ref deep); + } + + if (m_listType.Contains(itemProperty.PropertyType.Name)) + { + string typeString = GetTypeFullName(types[0]); + stringBuilder.Append($"public {itemProperty.PropertyType.Name.Replace("`1", string.Empty)}<{typeString}> {itemProperty.Name}"); + } + else if (m_dicType.Contains(itemProperty.PropertyType.Name)) + { + string keyString = GetTypeFullName(types[0]); + string valueString = GetTypeFullName(types[1]); + stringBuilder.Append($"public {itemProperty.PropertyType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}> {itemProperty.Name}"); + } + } + else + { + AddTypeString(itemProperty.PropertyType, ref deep); + stringBuilder.Append($"public {GetTypeFullName(itemProperty.PropertyType)} {itemProperty.Name}"); + } + + stringBuilder.AppendLine("{get;set;}"); + } + + stringBuilder.AppendLine("}"); + + if (!PropertyDic.ContainsKey(type)) + { + PropertyDic.TryAdd(type, new ClassCellCode() { Name = className, Code = stringBuilder.ToString() }); + } + } + } + + //internal void AddTypeString(ParameterInfo parameterInfo, ref int deep) + //{ + // if (parameterInfo.ParameterType.FullName.Contains("System.ValueTuple")) + // { + // tupleElementNames = parameterInfo.GetTupleElementNames()?.ToList(); + // } + // else + // { + // tupleElementNames = default; + // } + + // AddTypeString(parameterInfo.ParameterType, ref deep); + //} + private bool AllowGen(Assembly assembly) + { + foreach (var item in m_assembly) + { + if (assembly == item) + { + return true; + } + } + return false; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Code/CodeGenerator.cs b/src/TouchSocket/Rpc/Global/Code/CodeGenerator.cs new file mode 100644 index 000000000..98c9bef1a --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Code/CodeGenerator.cs @@ -0,0 +1,497 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// 代码生成器 + /// + public static class CodeGenerator + { + internal static readonly Dictionary m_proxyType = new Dictionary(); + internal static readonly List m_assemblies = new List(); + internal static readonly List m_ignoreAssemblies = new List(); + internal static readonly List m_ignoreTypes = new List(); + + /// + /// 添加不需要代理的程序集 + /// + /// + public static void AddIgnoreProxyAssembly(Assembly assembly) + { + m_ignoreAssemblies.Add(assembly); + } + + /// + /// 添加不需要代理的类型 + /// + /// + public static void AddIgnoreProxyType(Type type) + { + m_ignoreTypes.Add(type); + } + + /// + /// 添加需要代理的程序集 + /// + /// + public static void AddProxyAssembly(Assembly assembly) + { + m_assemblies.Add(assembly); + } + + /// + /// 添加代理类型 + /// + /// + /// + public static void AddProxyType(Type type, bool deepSearch = true) + { + if (type.IsPrimitive || type == typeof(string)) + { + return; + } + if (!m_proxyType.ContainsKey(type)) + { + RpcProxyAttribute attribute = type.GetCustomAttribute(); + m_proxyType.Add(type, attribute == null ? type.Name : attribute.ClassName); + if (deepSearch) + { + PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty); + foreach (var item in properties) + { + AddProxyType(item.PropertyType); + } + } + } + } + + /// + /// 添加代理类型 + /// + /// + /// + public static void AddProxyType(bool deepSearch = true) + { + AddProxyType(typeof(T), deepSearch); + } + + /// + /// 是否包含类型 + /// + /// + /// + public static bool ContainsType(Type type) + { + return m_proxyType.ContainsKey(type); + } + + /// + /// 转换为cs代码。 + /// + /// + /// + /// + public static string ConvertToCode(string @namespace, params ServerCellCode[] serverCodes) + { + Dictionary serverCellCodes = new Dictionary(); + Dictionary classCellCodes = new Dictionary(); + StringBuilder codeString = new StringBuilder(); + foreach (var serverCellCode in serverCodes) + { + if (serverCellCodes.ContainsKey(serverCellCode.Name)) + { + if (serverCellCode.IncludeExtension) + { + serverCellCodes[serverCellCode.Name].IncludeExtension = true; + } + + if (serverCellCode.IncludeInstance) + { + serverCellCodes[serverCellCode.Name].IncludeInstance = true; + } + + if (serverCellCode.IncludeInterface) + { + serverCellCodes[serverCellCode.Name].IncludeInterface = true; + } + + var ccm = serverCellCodes[serverCellCode.Name].Methods; + foreach (var item in serverCellCode.Methods.Keys) + { + if (!ccm.ContainsKey(item)) + { + ccm.Add(item, serverCellCode.Methods[item]); + } + } + } + else + { + serverCellCodes.Add(serverCellCode.Name, serverCellCode); + } + + foreach (var item in serverCellCode.ClassCellCodes.Keys) + { + if (!classCellCodes.ContainsKey(item)) + { + classCellCodes.Add(item, serverCellCode.ClassCellCodes[item]); + } + } + } + + string namesp = string.IsNullOrEmpty(@namespace) ? "RRQMProxy" : @namespace; + + codeString.AppendLine("using System;"); + codeString.AppendLine("using TouchSocket.Core;"); + codeString.AppendLine("using TouchSocket.Sockets;"); + codeString.AppendLine("using TouchSocket.Rpc;"); + codeString.AppendLine("using TouchSocket.Rpc.TouchRpc;"); + codeString.AppendLine("using System.Collections.Generic;"); + codeString.AppendLine("using System.Diagnostics;"); + codeString.AppendLine("using System.Text;"); + codeString.AppendLine("using System.Threading.Tasks;"); + codeString.AppendLine(string.Format("namespace {0}", namesp)); + codeString.AppendLine("{"); + + foreach (var serverCellCode in serverCellCodes.Values) + { + if (serverCellCode.IncludeInterface) + { + //接口 + codeString.AppendLine($"public interface I{serverCellCode.Name}:{typeof(IRemoteServer).FullName}");//类开始 + codeString.AppendLine("{"); + foreach (var item in serverCellCode.Methods.Values) + { + codeString.AppendLine(item.InterfaceTemple); + } + codeString.AppendLine("}"); + //接口 + } + + if (serverCellCode.IncludeInstance) + { + //类 + if (serverCellCode.IncludeInterface) + { + codeString.AppendLine($"public class {serverCellCode.Name} :I{serverCellCode.Name}");//类开始 + } + else + { + codeString.AppendLine($"public class {serverCellCode.Name}");//类开始 + } + + codeString.AppendLine("{"); + codeString.AppendLine($"public {serverCellCode.Name}(IRpcClient client)"); + codeString.AppendLine("{"); + codeString.AppendLine("this.Client=client;"); + codeString.AppendLine("}"); + codeString.AppendLine("public IRpcClient Client{get;private set; }"); + foreach (var item in serverCellCode.Methods.Values) + { + codeString.AppendLine(item.CodeTemple); + } + codeString.AppendLine("}"); + //类 + } + + if (serverCellCode.IncludeExtension) + { + //扩展类 + codeString.AppendLine($"public static class {serverCellCode.Name}Extensions");//类开始 + codeString.AppendLine("{"); + foreach (var item in serverCellCode.Methods.Values) + { + codeString.AppendLine(item.ExtensionsTemple); + } + codeString.AppendLine("}"); + //扩展类 + } + } + + foreach (var item in classCellCodes.Values) + { + codeString.AppendLine(item.Code); + } + + codeString.AppendLine("}"); + + return codeString.ToString(); + } + + /// + /// 生成代码代理 + /// + /// 服务类型 + /// 属性标签 + /// + public static ServerCellCode Generator() where TServer : IRpcServer where TAttribute : RpcAttribute + { + return Generator(typeof(TServer), typeof(TAttribute)); + } + + /// + /// 生成代码代理 + /// + /// 服务类型 + /// + /// + public static ServerCellCode Generator(Type serverType, Type attributeType) + { + ServerCellCode serverCellCode = new ServerCellCode(); + MethodInstance[] methodInstances = GetMethodInstances(serverType); + + List assemblies = new List(m_assemblies); + assemblies.Add(serverType.Assembly); + + foreach (var item in m_ignoreAssemblies) + { + assemblies.Remove(item); + } + + ClassCodeGenerator classCodeGenerator = new ClassCodeGenerator(assemblies.ToArray()); + + serverCellCode.Name = serverType.IsInterface ? + (serverType.Name.StartsWith("I") ? serverType.Name.Remove(0, 1) : serverType.Name) : serverType.Name; + List instances = new List(); + + foreach (var item in m_proxyType.Keys) + { + int deep = 0; + classCodeGenerator.AddTypeString(item, ref deep); + } + + foreach (MethodInstance methodInstance in methodInstances) + { + foreach (RpcAttribute att in methodInstance.RpcAttributes) + { + if (attributeType == att.GetType()) + { + if (methodInstance.ReturnType != null) + { + int deep = 0; + classCodeGenerator.AddTypeString(methodInstance.ReturnType, ref deep); + } + + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + i = 1; + } + for (; i < methodInstance.ParameterTypes.Length; i++) + { + int deep = 0; + classCodeGenerator.AddTypeString(methodInstance.ParameterTypes[i], ref deep); + } + + instances.Add(methodInstance); + break; + } + } + } + + classCodeGenerator.CheckDeep(); + + //foreach (var item in classCodeGenerator.GenericTypeDic.Keys.ToArray()) + //{ + // if (m_ignoreTypes.Contains(item)) + // { + // classCodeGenerator.GenericTypeDic.TryRemove(item, out _); + // } + + // if (m_ignoreAssemblies.Contains(item.Assembly)) + // { + // classCodeGenerator.GenericTypeDic.TryRemove(item, out _); + // } + //} + + foreach (var item in classCodeGenerator.PropertyDic.Keys.ToArray()) + { + if (m_ignoreTypes.Contains(item)) + { + classCodeGenerator.PropertyDic.TryRemove(item, out _); + } + + if (m_ignoreAssemblies.Contains(item.Assembly)) + { + classCodeGenerator.PropertyDic.TryRemove(item, out _); + } + } + + foreach (var item in classCodeGenerator.GetClassCellCodes()) + { + serverCellCode.ClassCellCodes.Add(item.Name, item); + } + + //ServerCodeGenerator serverCodeGenerator = new ServerCodeGenerator(classCodeGenerator); + + bool first = true; + foreach (var item in instances) + { + MethodCellCode methodCellCode = new MethodCellCode(); + RpcAttribute rpcAttribute = (RpcAttribute)item.GetAttribute(attributeType); + if (rpcAttribute == null) + { + continue; + } + rpcAttribute.SetClassCodeGenerator(classCodeGenerator); + if (first) + { + if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.IncludeInterface)) + { + serverCellCode.IncludeInterface = true; + } + if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.IncludeInstance)) + { + serverCellCode.IncludeInstance = true; + } + if (rpcAttribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.IncludeExtension)) + { + serverCellCode.IncludeExtension = true; + } + first = false; + } + + methodCellCode.InterfaceTemple = rpcAttribute.GetInterfaceProxyCode(item); + methodCellCode.CodeTemple = rpcAttribute.GetInstanceProxyCode(item); + methodCellCode.ExtensionsTemple = rpcAttribute.GetExtensionsMethodProxyCode(item); + methodCellCode.Name = ((RpcAttribute)item.GetAttribute(attributeType)).GetMethodName(item, false); + serverCellCode.Methods.Add(methodCellCode.Name, methodCellCode); + } + + return serverCellCode; + } + + /// + /// 从类型获取函数实例 + /// + /// + /// + public static MethodInstance[] GetMethodInstances() where TServer : IRpcServer + { + return GetMethodInstances(typeof(TServer)); + } + + /// + /// 生成代理代码 + /// + /// + /// + /// + /// + public static string GetProxyCodes(string @namespace, Type[] serverTypes, Type[] attributeTypes) + { + List serverCellCodeList = new List(); + foreach (var item in serverTypes) + { + foreach (var item1 in attributeTypes) + { + serverCellCodeList.Add(Generator(item, item1)); + } + } + return ConvertToCode(@namespace, serverCellCodeList.ToArray()); + } + + /// + /// 从类型获取函数实例 + /// + /// + /// + public static MethodInstance[] GetMethodInstances(Type serverType) + { + if (!typeof(IRpcServer).IsAssignableFrom(serverType)) + { + throw new RpcException($"服务类型必须从{nameof(IRpcServer)}派生。"); + } + List instances = new List(); + + MethodInfo[] methodInfos = serverType.GetMethods(); + + foreach (MethodInfo method in methodInfos) + { + if (method.IsGenericMethod) + { + continue; + } + IEnumerable attributes = method.GetCustomAttributes(true); + if (attributes.Count() > 0) + { + MethodInstance methodInstance = new MethodInstance(method); + methodInstance.ServerType = serverType; + methodInstance.RpcAttributes = attributes.ToArray(); + methodInstance.Description = method.GetCustomAttribute()?.Description; + methodInstance.IsEnable = true; + methodInstance.Parameters = method.GetParameters(); + + object[] filters = method.GetCustomAttributes(true); + List actionFilters = new List(); + foreach (var item in filters) + { + if (item is IRpcActionFilter filter) + { + actionFilters.Add(filter); + } + } + if (actionFilters.Count > 0) + { + methodInstance.Filters = actionFilters.ToArray(); + } + foreach (var item in attributes) + { + methodInstance.MethodFlags |= item.MethodFlags; + } + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + if (methodInstance.Parameters.Length == 0 || !typeof(ICallContext).IsAssignableFrom(methodInstance.Parameters[0].ParameterType)) + { + throw new RpcException($"函数:{method},标识包含{MethodFlags.IncludeCallContext}时,必须包含{nameof(ICallContext)}或其派生类参数,且为第一参数。"); + } + } + List names = new List(); + foreach (var parameterInfo in methodInstance.Parameters) + { + names.Add(parameterInfo.Name); + } + methodInstance.ParameterNames = names.ToArray(); + ParameterInfo[] parameters = method.GetParameters(); + List types = new List(); + foreach (var parameter in parameters) + { + types.Add(parameter.ParameterType.GetRefOutType()); + } + methodInstance.ParameterTypes = types.ToArray(); + instances.Add(methodInstance); + } + } + + return instances.ToArray(); + } + + /// + /// 获取类型代理名称 + /// + /// + /// + /// + public static bool TryGetProxyTypeName(Type type, out string className) + { + return m_proxyType.TryGetValue(type, out className); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Code/MethodCellCode.cs b/src/TouchSocket/Rpc/Global/Code/MethodCellCode.cs new file mode 100644 index 000000000..41f488911 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Code/MethodCellCode.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 生成的代码单元 + /// + + public class MethodCellCode + { + /// + /// 方法名 + /// + public string Name { get; set; } + + /// + /// 代码本体 + /// + public string CodeTemple { get; set; } + + /// + /// 接口代码。 + /// + public string InterfaceTemple { get; set; } + + /// + /// 扩展代码 + /// + public string ExtensionsTemple { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Code/ServerCellCode.cs b/src/TouchSocket/Rpc/Global/Code/ServerCellCode.cs new file mode 100644 index 000000000..5dd70d195 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Code/ServerCellCode.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Generic; + +namespace TouchSocket.Rpc +{ + /// + /// 服务单元代码 + /// + public class ServerCellCode + { + /// + /// 构造函数 + /// + public ServerCellCode() + { + methods = new Dictionary(); + classCellCodes = new Dictionary(); + } + + /// + /// 包含接口 + /// + public bool IncludeInterface { get; set; } + + /// + /// 包含实例 + /// + public bool IncludeInstance { get; set; } + + /// + /// 包含扩展 + /// + public bool IncludeExtension { get; set; } + + /// + /// 服务名 + /// + public string Name { get; set; } + + private Dictionary methods; + + /// + /// 方法集合 + /// + public Dictionary Methods + { + get => methods; + set => methods = value; + } + + private Dictionary classCellCodes; + + /// + /// 类参数集合。 + /// + public Dictionary ClassCellCodes + { + get => classCellCodes; + set => classCellCodes = value; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Code/ServerCodeGenerator.cs b/src/TouchSocket/Rpc/Global/Code/ServerCodeGenerator.cs new file mode 100644 index 000000000..b2c51e8c3 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Code/ServerCodeGenerator.cs @@ -0,0 +1,335 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//using System; +//using System.Collections.Generic; +//using System.Reflection; +//using System.Text; + +//namespace TouchSocket.Rpc +//{ +// /// +// /// 服务代码生成 +// /// +// public class ServerCodeGenerator +// { +// private readonly ClassCodeGenerator m_classCodeGenerator; + +// /// +// /// 构造函数 +// /// +// /// +// public ServerCodeGenerator(ClassCodeGenerator classCodeGenerator) +// { +// this.m_classCodeGenerator = classCodeGenerator; +// } + +// /// +// /// 类代码生成器 +// /// +// public ClassCodeGenerator ClassCodeGenerator => this.m_classCodeGenerator; + +// /// +// /// 获取接口代码 +// /// +// /// +// /// +// /// +// public string GetInterfaceProxy(MethodInstance methodInstance, RpcAttribute attribute) +// { +// } + +// /// +// /// 获取函数代码 +// /// +// /// +// /// +// /// +// public string GetMethodProxy(MethodInstance methodInstance, RpcAttribute attribute) +// { +// return attribute.GetInstanceProxyCode(methodInstance,this.m_classCodeGenerator); +// } + +// ///// +// ///// 获取函数代码 +// ///// +// ///// +// ///// +// ///// +// //public string GetMethodProxy(MethodInstance methodInstance, RpcAttribute attribute) +// //{ +// // StringBuilder codeString = new StringBuilder(); + +// // string description = attribute.GetDescription(methodInstance); +// // ParameterInfo[] parameters; +// // bool isOut; +// // bool isRef; +// // List parametersStr = attribute.GetParameters(methodInstance, this.m_classCodeGenerator, out isOut, out isRef, out parameters); +// // if (attribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.Sync)) +// // { +// // codeString.AppendLine("///"); +// // codeString.AppendLine($"///{description}"); +// // codeString.AppendLine("///"); +// // foreach (var item in attribute.Exceptions) +// // { +// // codeString.AppendLine($"/// {item.Value}"); +// // } + +// // codeString.Append("public "); +// // codeString.Append(attribute.GetReturn(methodInstance, this.m_classCodeGenerator, false)); +// // codeString.Append(" "); +// // codeString.Append(attribute.GetMethodName(methodInstance, false)); +// // codeString.Append("(");//方法参数 + +// // for (int i = 0; i < parametersStr.Count; i++) +// // { +// // if (i > 0) +// // { +// // codeString.Append(","); +// // } +// // codeString.Append(parametersStr[i]); +// // } +// // if (parametersStr.Count > 0) +// // { +// // codeString.Append(","); +// // } +// // codeString.Append(attribute.GetInvokeOption()); +// // codeString.AppendLine(")"); + +// // codeString.AppendLine("{");//方法开始 + +// // codeString.AppendLine("if(Client==null)"); +// // codeString.AppendLine("{"); +// // codeString.AppendLine("throw new RpcException(\"IRpcClient为空,请先初始化或者进行赋值\");"); +// // codeString.AppendLine("}"); +// // codeString.AppendLine("if (Client.TryCanInvoke?.Invoke(Client)==false)"); +// // codeString.AppendLine("{"); +// // codeString.AppendLine($"throw new RpcException(\"Rpc无法执行。\");"); +// // codeString.AppendLine("}"); + +// // if (parametersStr.Count > 0) +// // { +// // codeString.Append($"object[] parameters = new object[]"); +// // codeString.Append("{"); + +// // foreach (ParameterInfo parameter in parameters) +// // { +// // if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut) +// // { +// // codeString.Append($"default({this.GetName(parameter.ParameterType)})"); +// // } +// // else +// // { +// // codeString.Append(parameter.Name); +// // } +// // if (parameter != parameters[parameters.Length - 1]) +// // { +// // codeString.Append(","); +// // } +// // } +// // codeString.AppendLine("};"); + +// // if (isOut || isRef) +// // { +// // codeString.Append($"Type[] types = new Type[]"); +// // codeString.Append("{"); +// // foreach (ParameterInfo parameter in parameters) +// // { +// // codeString.Append($"typeof({this.GetName(parameter.ParameterType)})"); +// // if (parameter != parameters[parameters.Length - 1]) +// // { +// // codeString.Append(","); +// // } +// // } +// // codeString.AppendLine("};"); +// // } +// // } + +// // if (methodInstance.HasReturn) +// // { +// // if (parametersStr.Count == 0) +// // { +// // codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", this.GetName(methodInstance.ReturnType))); +// // codeString.Append("("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption, null);"); +// // } +// // else if (isOut || isRef) +// // { +// // codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", this.GetName(methodInstance.ReturnType))); +// // codeString.Append("("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption,ref parameters,types);"); +// // } +// // else +// // { +// // codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", this.GetName(methodInstance.ReturnType))); +// // codeString.Append("("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption, parameters);"); +// // } +// // } +// // else +// // { +// // if (parametersStr.Count == 0) +// // { +// // codeString.Append("Client.Invoke("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption, null);"); +// // } +// // else if (isOut || isRef) +// // { +// // codeString.Append("Client.Invoke("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption,ref parameters,types);"); +// // } +// // else +// // { +// // codeString.Append("Client.Invoke("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption, parameters);"); +// // } +// // } +// // if (isOut || isRef) +// // { +// // codeString.AppendLine("if(parameters!=null)"); +// // codeString.AppendLine("{"); +// // for (int i = 0; i < parameters.Length; i++) +// // { +// // codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, this.GetName(parameters[i].ParameterType), i)); +// // } +// // codeString.AppendLine("}"); +// // if (isOut) +// // { +// // codeString.AppendLine("else"); +// // codeString.AppendLine("{"); +// // for (int i = 0; i < parameters.Length; i++) +// // { +// // if (parameters[i].IsOut) +// // { +// // codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, this.GetName(parameters[i].ParameterType))); +// // } +// // } +// // codeString.AppendLine("}"); +// // } +// // } + +// // if (methodInstance.HasReturn) +// // { +// // codeString.AppendLine("return returnData;"); +// // } + +// // codeString.AppendLine("}"); +// // } + +// // //以下生成异步 +// // if (attribute.GeneratorFlag.HasFlag(CodeGeneratorFlag.Async) && !isOut && !isRef)//没有out或者ref +// // { +// // codeString.AppendLine("///"); +// // codeString.AppendLine($"///{description}"); +// // codeString.AppendLine("///"); +// // codeString.Append("public "); +// // codeString.Append(attribute.GetReturn(methodInstance, this.m_classCodeGenerator, true)); +// // codeString.Append(" "); +// // codeString.Append(attribute.GetMethodName(methodInstance, true)); +// // codeString.Append("(");//方法参数 + +// // for (int i = 0; i < parametersStr.Count; i++) +// // { +// // if (i > 0) +// // { +// // codeString.Append(","); +// // } +// // codeString.Append(parametersStr[i]); +// // } +// // if (parametersStr.Count > 0) +// // { +// // codeString.Append(","); +// // } +// // codeString.Append(attribute.GetInvokeOption()); +// // codeString.AppendLine(")"); + +// // codeString.AppendLine("{");//方法开始 + +// // codeString.AppendLine("if(Client==null)"); +// // codeString.AppendLine("{"); +// // codeString.AppendLine("throw new RpcException(\"IRpcClient为空,请先初始化或者进行赋值\");"); +// // codeString.AppendLine("}"); + +// // codeString.AppendLine("if (Client.TryCanInvoke?.Invoke(Client)==false)"); +// // codeString.AppendLine("{"); +// // codeString.AppendLine($"throw new RpcException(\"Rpc无法执行。\");"); +// // codeString.AppendLine("}"); + +// // if (parametersStr.Count > 0) +// // { +// // codeString.Append($"object[] parameters = new object[]"); +// // codeString.Append("{"); +// // foreach (ParameterInfo parameter in parameters) +// // { +// // codeString.Append(parameter.Name); +// // if (parameter != parameters[parameters.Length - 1]) +// // { +// // codeString.Append(","); +// // } +// // } +// // codeString.AppendLine("};"); +// // } + +// // if (methodInstance.HasReturn) +// // { +// // if (parametersStr.Count == 0) +// // { +// // codeString.Append(string.Format("return Client.InvokeAsync<{0}>", this.GetName(methodInstance.ReturnType))); +// // codeString.Append("("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption, null);"); +// // } +// // else +// // { +// // codeString.Append(string.Format("return Client.InvokeAsync<{0}>", this.GetName(methodInstance.ReturnType))); +// // codeString.Append("("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption, parameters);"); +// // } +// // } +// // else +// // { +// // if (parametersStr.Count == 0) +// // { +// // codeString.Append("return Client.InvokeAsync("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption, null);"); +// // } +// // else +// // { +// // codeString.Append("return Client.InvokeAsync("); +// // codeString.Append($"\"{attribute.GetInvokenKey(methodInstance)}\""); +// // codeString.AppendLine(",invokeOption, parameters);"); +// // } +// // } +// // codeString.AppendLine("}"); +// // } +// // return codeString.ToString(); +// //} + +// /// +// /// 获取扩展函数代码 +// /// +// /// +// /// +// /// +// public string GetExtensionsMethodProxy(MethodInstance methodInstance, RpcAttribute attribute) +// { +// } +// } +//} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Common/ActionMap.cs b/src/TouchSocket/Rpc/Global/Common/ActionMap.cs new file mode 100644 index 000000000..b271040c8 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Common/ActionMap.cs @@ -0,0 +1,111 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Rpc +{ + /// + /// 服务映射图 + /// + public class ActionMap : IEnumerable> + { + private readonly ConcurrentDictionary m_actionMap = new ConcurrentDictionary(); + + /// + /// 服务键集合 + /// + public IEnumerable ActionKeys => m_actionMap.Keys; + + /// + /// 添加调用 + /// + /// + /// + public void Add(string actionKey, MethodInstance methodInstance) + { + if (m_actionMap.ContainsKey(actionKey)) + { + throw new System.Exception($"调用键为{actionKey}的函数已存在。"); + } + m_actionMap.TryAdd(actionKey, methodInstance); + } + + /// + /// 获取所有服务函数实例 + /// + /// + public MethodInstance[] GetAllMethodInstances() + { + return m_actionMap.Values.ToArray(); + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator> GetEnumerator() + { + return m_actionMap.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_actionMap.GetEnumerator(); + } + + /// + /// 通过actionKey获取函数实例 + /// + /// + /// + public MethodInstance GetMethodInstance(string actionKey) + { + m_actionMap.TryGetValue(actionKey, out MethodInstance methodInstance); + return methodInstance; + } + + /// + /// 移除 + /// + /// + /// + public bool Remove(string actionKey, out MethodInstance methodInstance) + { + return m_actionMap.TryRemove(actionKey, out methodInstance); + } + + /// + /// 移除 + /// + /// + /// + public bool Remove(string actionKey) + { + return m_actionMap.TryRemove(actionKey, out _); + } + + /// + /// 通过actionKey获取函数实例 + /// + /// + /// + /// + public bool TryGetMethodInstance(string actionKey, out MethodInstance methodInstance) + { + return m_actionMap.TryGetValue(actionKey, out methodInstance); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Common/FeedbackType.cs b/src/TouchSocket/Rpc/Global/Common/FeedbackType.cs new file mode 100644 index 000000000..50e7a9c04 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Common/FeedbackType.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 反馈类型 + /// + public enum FeedbackType : byte + { + /// + /// 仅发送 + /// + OnlySend, + + /// + /// 等待,直到发送抵达 + /// + WaitSend, + + /// + /// 等待,直到调用完成 + /// + WaitInvoke + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Common/InvokeResult.cs b/src/TouchSocket/Rpc/Global/Common/InvokeResult.cs new file mode 100644 index 000000000..72c2fc669 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Common/InvokeResult.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc +{ + /// + /// 调用结果 + /// + public struct InvokeResult + { + /// + /// 状态 + /// + public InvokeStatus Status { get; set; } + + /// + /// 信息 + /// + public string Message { get; set; } + + /// + /// 执行返回值结果 + /// + public object Result { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Common/MethodInstance.cs b/src/TouchSocket/Rpc/Global/Common/MethodInstance.cs new file mode 100644 index 000000000..9cb2e0dcb --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Common/MethodInstance.cs @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Linq; +using System.Reflection; +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc函数实例 + /// + public class MethodInstance : Method + { + /// + /// 构造函数 + /// + /// + public MethodInstance(MethodInfo methodInfo) : base(methodInfo) + { + } + + /// + /// 服务实例工厂 + /// + public IRpcServerFactory ServerFactory { get; internal set; } + + /// + /// 描述属性 + /// + public string Description { get; internal set; } + + /// + /// 筛选器 + /// + public IRpcActionFilter[] Filters { get; internal set; } + + /// + /// 是否可用 + /// + public bool IsEnable { get; set; } + + /// + /// 是否为单例 + /// + public bool IsSingleton { get; internal set; } + + /// + /// 函数标识 + /// + public MethodFlags MethodFlags { get; internal set; } + + /// + /// 参数名集合 + /// + public string[] ParameterNames { get; internal set; } + + /// + /// 参数集合 + /// + public ParameterInfo[] Parameters { get; internal set; } + + /// + /// 参数类型集合,已处理out及ref,无参数时为空集合, + /// + public Type[] ParameterTypes { get; internal set; } + + /// + /// Rpc属性集合 + /// + public RpcAttribute[] RpcAttributes { get; internal set; } + + /// + /// 实例类型 + /// + public Type ServerType { get; internal set; } + + /// + /// 获取指定类型属性标签 + /// + /// + /// + public T GetAttribute() + { + object attribute = RpcAttributes.FirstOrDefault((a) => { return typeof(T).IsAssignableFrom(a.GetType()); }); + if (attribute == null) + { + return default; + } + return (T)attribute; + } + + /// + /// 获取指定类型属性标签 + /// + /// + /// + public object GetAttribute(Type attributeType) + { + object attribute = RpcAttributes.FirstOrDefault((a) => { return attributeType.IsAssignableFrom(a.GetType()); }); + if (attribute == null) + { + return default; + } + return attribute; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Common/RpcServer.cs b/src/TouchSocket/Rpc/Global/Common/RpcServer.cs new file mode 100644 index 000000000..90099950a --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Common/RpcServer.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// Rpc范围类 + /// + public abstract class RpcServer : IRpcServer + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs b/src/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs new file mode 100644 index 000000000..f1ba4a383 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Common/RpcServerFactory.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc +{ + /// + /// RpcServerFactory + /// + public class RpcServerFactory : IRpcServerFactory + { + private readonly IContainer m_container; + + /// + /// 构造函数 + /// + /// + public RpcServerFactory(IContainer container) + { + m_container = container; + } + + IRpcServer IRpcServerFactory.Create(ICallContext callContext, object[] ps) + { + return (IRpcServer)m_container.Resolve(callContext.MethodInstance.ServerType); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Common/RpcStore.cs b/src/TouchSocket/Rpc/Global/Common/RpcStore.cs new file mode 100644 index 000000000..54e829040 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Common/RpcStore.cs @@ -0,0 +1,704 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc仓库 + /// + public class RpcStore : DisposableObject, IEnumerable + { + /// + /// 命名空间 + /// + public const string Namespace = "namespace"; + + /// + /// 代理键 + /// + public const string ProxyKey = "proxy"; + + private static readonly ConcurrentDictionary m_proxyAttributeMap = new ConcurrentDictionary(); + private readonly ConcurrentDictionary m_parsers = new ConcurrentDictionary(); + private readonly ConcurrentDictionary> m_serverTypes = new ConcurrentDictionary>(); + private string m_proxyUrl = "/proxy"; + private HttpService m_service; + + static RpcStore() + { + SearchAttribute(); + } + + /// + /// 实例化一个Rpc仓库。 + /// 需要指定容器。一般和对应的服务器、客户端共用一个容器比较好。 + /// 如果,仅仅是只有一个解析器的话,可以考虑从配置中,调用 + /// + public RpcStore(IContainer container) + { + Container = container ?? throw new ArgumentNullException(nameof(container)); + Container.RegisterSingleton(this); + + if (!container.IsRegistered(typeof(IRpcServerFactory))) + { + Container.RegisterSingleton(); + } + + SearchAttribute(); + } + + /// + /// 代理属性映射。 + /// + public static ConcurrentDictionary ProxyAttributeMap => m_proxyAttributeMap; + + /// + /// 内置IOC容器 + /// + public IContainer Container { get; private set; } + + /// + /// 解析器集合。 + /// 如果想快速获得对象,请使用,一般key为对象类型名称,或自定义的。 + /// + public IRpcParser[] RpcParsers => m_parsers.Values.ToArray(); + + /// + /// 请求代理。 + /// + public Func OnRequestProxy { get; set; } + + /// + /// 代理路径。默认为“/proxy”。 + /// 必须以“/”开头 + /// + public string ProxyUrl + { + get => m_proxyUrl; + set + { + if (string.IsNullOrEmpty(value)) + { + value = "/"; + } + m_proxyUrl = value; + } + } + + /// + /// 服务类型 + /// + public Type[] ServerTypes => m_serverTypes.Keys.ToArray(); + + /// + /// 获取IRpcParser + /// + /// + /// + public IRpcParser this[string key] => m_parsers[key]; + + /// + /// 从远程获取代理 + /// + /// + /// + public static string GetProxyInfo(string url) + { + string result = Get(url); + if (string.IsNullOrEmpty(result)) + { + throw new Exception("未知错误"); + } + return result; + } + + /// + /// 添加Rpc解析器 + /// + /// 名称 + /// 解析器实例 + /// 是否应用已注册服务 + public void AddRpcParser(string key, IRpcParser parser, bool applyServer = true) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (!m_parsers.TryAdd(key, parser)) + { + throw new Exception("相同键值得解析器已经存在。"); + } + parser.SetRpcStore(this); + if (applyServer) + { + foreach (var item in m_serverTypes) + { + parser.OnRegisterServer(item.Value.ToArray()); + } + } + } + + /// + /// 获取服务类型对应的服务方法。 + /// + /// + /// + public MethodInstance[] GetServerMethodInstances(Type serverType) + { + return m_serverTypes[serverType].ToArray(); + } + + /// + /// 执行Rpc + /// + /// + /// + /// + /// + public InvokeResult Execute(IRpcServer rpcServer, object[] ps, ICallContext callContext) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + InvokeResult invokeResult = new InvokeResult(); + try + { + if (callContext.MethodInstance.Filters != null) + { + for (int i = 0; i < callContext.MethodInstance.Filters.Length; i++) + { + callContext.MethodInstance.Filters[i].Executing(callContext,ps, ref invokeResult); + callContext.MethodInstance.Filters[i].ExecutingAsync(callContext, ps, ref invokeResult); + } + } + + if (invokeResult.Status != InvokeStatus.Ready) + { + return invokeResult; + } + + if (callContext.MethodInstance.HasReturn) + { + invokeResult.Result = callContext.MethodInstance.Invoke(rpcServer, ps); + } + else + { + callContext.MethodInstance.Invoke(rpcServer, ps); + } + invokeResult.Status = InvokeStatus.Success; + if (callContext.MethodInstance.Filters != null) + { + for (int i = 0; i < callContext.MethodInstance.Filters.Length; i++) + { + callContext.MethodInstance.Filters[i].Executed(callContext, ps, ref invokeResult); + callContext.MethodInstance.Filters[i].ExecutedAsync(callContext, ps, ref invokeResult); + } + } + } + catch (TargetInvocationException ex) + { + invokeResult.Status = InvokeStatus.InvocationException; + if (ex.InnerException != null) + { + invokeResult.Message = "函数内部发生异常,信息:" + ex.InnerException.Message; + } + else + { + invokeResult.Message = "函数内部发生异常,信息:未知"; + } + if (callContext.MethodInstance.Filters != null) + { + for (int i = 0; i < callContext.MethodInstance.Filters.Length; i++) + { + callContext.MethodInstance.Filters[i].ExecutException(callContext, ps, ref invokeResult, ex); + callContext.MethodInstance.Filters[i].ExecutExceptionAsync(callContext, ps, ref invokeResult, ex); + } + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + if (callContext.MethodInstance.Filters != null) + { + for (int i = 0; i < callContext.MethodInstance.Filters.Length; i++) + { + callContext.MethodInstance.Filters[i].ExecutException(callContext, ps, ref invokeResult, ex); + callContext.MethodInstance.Filters[i].ExecutExceptionAsync(callContext, ps, ref invokeResult, ex); + } + } + } + + return invokeResult; + } + + /// + /// 获取所有已注册的函数。 + /// + public MethodInstance[] GetAllMethods() + { + List methods = new List(); + foreach (var item in m_serverTypes.Values) + { + methods.AddRange(item); + } + + return methods.ToArray(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_parsers.Values.GetEnumerator(); + } + + /// + /// 返回枚举对象 + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + return m_parsers.Values.GetEnumerator(); + } + + /// + /// 本地获取代理 + /// + /// + /// + /// + public string GetProxyCodes(string @namespace, Type[] attrbuteTypes) + { + var cellCodes = GetProxyInfo(attrbuteTypes == null ? ProxyAttributeMap.Values.ToArray() : attrbuteTypes); + return CodeGenerator.ConvertToCode(@namespace, cellCodes); + } + + /// + /// 本地获取代理 + /// + /// + /// + public string GetProxyCodes(string @namespace) + { + return GetProxyCodes(@namespace, null); + } + + /// + /// 从本地获取代理 + /// + /// + public ServerCellCode[] GetProxyInfo() + { + return GetProxyInfo(ProxyAttributeMap.Values.ToArray()); + } + + /// + /// 从本地获取代理 + /// + /// + /// + public ServerCellCode[] GetProxyInfo(Type[] attrbuteType) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + List codes = new List(); + + foreach (var attrbute in attrbuteType) + { + foreach (var item in m_serverTypes.Keys) + { + ServerCellCode serverCellCode = CodeGenerator.Generator(item, attrbute); + codes.Add(serverCellCode); + } + } + return codes.ToArray(); + } + + /// + /// 移除Rpc解析器 + /// + /// + /// + /// + public bool RemoveRpcParser(string parserName, out IRpcParser parser) + { + return m_parsers.TryRemove(parserName, out parser); + } + + /// + /// 移除Rpc解析器 + /// + /// + /// + public bool RemoveRpcParser(string parserName) + { + return RemoveRpcParser(parserName, out _); + } + + /// + /// 分享代理。 + /// + /// + public void ShareProxy(IPHost iPHost) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + if (m_service != null) + { + return; + } + m_service = new HttpService(); + m_service.Setup(new TouchSocketConfig() + .SetListenIPHosts(new IPHost[] { iPHost })) + .Start(); + + m_service.AddPlugin(new InternalPlugin(this)); + } + + /// + /// 关闭分享中心 + /// + public void StopShareProxy() + { + m_service.SafeDispose(); + } + + /// + /// 获取IRpcParser + /// + /// + /// + /// + public bool TryGetRpcParser(string key, out IRpcParser parser) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + return m_parsers.TryGetValue(key, out parser); + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer(IRpcServer provider) + { + return UnregisterServer(provider.GetType()); + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer(Type providerType) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + if (!typeof(IRpcServer).IsAssignableFrom(providerType)) + { + throw new RpcException("类型不相符"); + } + + if (RemoveServer(providerType, out MethodInstance[] instances)) + { + foreach (var parser in this) + { + parser.OnUnregisterServer(instances); + } + + return instances.Length; + } + return 0; + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer() where T : RpcServer + { + return UnregisterServer(typeof(T)); + } + + internal bool TryRemove(string key, out IRpcParser parser) + { + return m_parsers.TryRemove(key, out parser); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (!DisposedValue) + { + StopShareProxy(); + foreach (var item in this) + { + item.SafeDispose(); + } + } + + base.Dispose(disposing); + } + + private static string Get(string url) + { + string result = null; + HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); + //添加参数 + HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); + Stream stream = resp.GetResponseStream(); + try + { + //获取内容 + using (StreamReader reader = new StreamReader(stream)) + { + result = reader.ReadToEnd(); + } + } + finally + { + resp.SafeDispose(); + stream.Close(); + } + return result; + } + + private static void SearchAttribute() + { + List types = new List(); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in assemblies) + { + try + { + Type[] t1 = assembly.GetTypes().Where(p => typeof(RpcAttribute).IsAssignableFrom(p) && !p.IsAbstract).ToArray(); + types.AddRange(t1); + } + catch + { + } + } + + foreach (Type type in types) + { + ProxyAttributeMap.TryAdd(type.Name.Replace("Attribute", string.Empty).ToLower(), type); + } + } + + private bool RemoveServer(Type type, out MethodInstance[] methodInstances) + { + foreach (var newType in m_serverTypes.Keys) + { + if (newType.FullName == type.FullName) + { + m_serverTypes.TryRemove(newType, out var list); + methodInstances = list.ToArray(); + return true; + } + } + methodInstances = null; + return false; + } + + #region 注册 + + /// + /// 注册为单例服务 + /// + /// + /// + /// + public void RegisterServer(Type serverFromType, IRpcServer rpcServer) + { + if (!typeof(IRpcServer).IsAssignableFrom(serverFromType)) + { + throw new RpcException($"注册类型必须与{nameof(IRpcServer)}有继承关系"); + } + + if (!serverFromType.IsAssignableFrom(rpcServer.GetType())) + { + throw new RpcException("实例类型必须与注册类型有继承关系。"); + } + foreach (var item in m_serverTypes.Keys) + { + if (item.FullName == serverFromType.FullName) + { + throw new RpcException($"名为{serverFromType.FullName}的类型已注册。"); + } + } + + MethodInstance[] methodInstances = CodeGenerator.GetMethodInstances(serverFromType); + foreach (var item in methodInstances) + { + item.IsSingleton = true; + //item.ServerFactory = new RpcServerFactory(this.Container); + item.ServerFactory = Container.Resolve() ?? throw new ArgumentNullException($"{nameof(IRpcServerFactory)}"); + } + m_serverTypes.TryAdd(serverFromType, new List(methodInstances)); + Container.RegisterSingleton(serverFromType, rpcServer); + + foreach (var parser in this) + { + parser.OnRegisterServer(methodInstances); + } + } + + /// + /// 注册服务 + /// + /// + /// + /// + public void RegisterServer(Type serverFromType, Type serverToType) + { + if (!typeof(IRpcServer).IsAssignableFrom(serverFromType)) + { + throw new RpcException($"注册类型必须与{nameof(IRpcServer)}有继承关系"); + } + + if (!serverFromType.IsAssignableFrom(serverToType)) + { + throw new RpcException("实例类型必须与注册类型有继承关系。"); + } + + foreach (var item in m_serverTypes.Keys) + { + if (item.FullName == serverFromType.FullName) + { + throw new RpcException($"名为{serverFromType.FullName}的类型已注册。"); + } + } + + bool singleton; + if (typeof(ITransientRpcServer).IsAssignableFrom(serverFromType)) + { + singleton = false; + Container.RegisterTransient(serverFromType, serverToType); + } + else + { + singleton = true; + Container.RegisterSingleton(serverFromType, serverToType); + } + MethodInstance[] methodInstances = CodeGenerator.GetMethodInstances(serverFromType); + + foreach (var item in methodInstances) + { + item.IsSingleton = singleton; + //item.ServerFactory = new RpcServerFactory(this.Container); + item.ServerFactory = Container.Resolve() ?? throw new ArgumentNullException($"{nameof(IRpcServerFactory)}"); + } + + m_serverTypes.TryAdd(serverFromType, new List(methodInstances)); + + foreach (var parser in this) + { + parser.OnRegisterServer(methodInstances); + } + } + + #endregion 注册 + } + + internal class InternalPlugin : HttpPluginBase + { + private readonly RpcStore m_rpcStore; + + public InternalPlugin(RpcStore rpcCerter) + { + m_rpcStore = rpcCerter; + } + + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (e.Context.Request.UrlEquals(m_rpcStore.ProxyUrl)) + { + bool? b = m_rpcStore.OnRequestProxy?.Invoke(e.Context.Request); + if (b == false) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + e.Context.Response + .FromText("拒绝响应内容") + .SetStatus("403", "Forbidden") + .Build(byteBlock); + client.DefaultSend(byteBlock); + } + return; + } + string value = e.Context.Request.Query[RpcStore.ProxyKey]; + List types = new List(); + + if (value.Equals("all", StringComparison.CurrentCultureIgnoreCase)) + { + types = RpcStore.ProxyAttributeMap.Values.ToList(); + } + else + { + string[] vs = value.Split(','); + foreach (var item in vs) + { + if (RpcStore.ProxyAttributeMap.TryGetValue(item, out Type type)) + { + types.Add(type); + } + } + } + + string names = e.Context.Request.Query[RpcStore.Namespace]; + + names = string.IsNullOrEmpty(names) ? "RRQMProxy" : names; + + string code = CodeGenerator.ConvertToCode(names, m_rpcStore.GetProxyInfo(types.ToArray())); + + using (ByteBlock byteBlock = new ByteBlock()) + { + e.Context.Response + .SetStatus() + .SetContent(code) + .SetContentTypeFromFileName($"{names}.cs") + .Build(byteBlock); + client.DefaultSend(byteBlock); + } + } + base.OnGet(client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs b/src/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs new file mode 100644 index 000000000..a3028726d --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Common/TransientRpcServer.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// TransientRpcServer + /// + public abstract class TransientRpcServer : RpcServer, ITransientRpcServer where TCallContext : ICallContext + { + ICallContext ITransientRpcServer.CallContext { get; set; } + + /// + /// 调用上下文。 + /// + protected TCallContext CallContext => (((ITransientRpcServer)this).CallContext is TCallContext Transient) ? Transient : default; + } + + /// + /// TransientRpcServer + /// + public abstract class TransientRpcServer : RpcServer, ITransientRpcServer + { + ICallContext ITransientRpcServer.CallContext { get; set; } + + /// + /// 调用上下文。 + /// + protected ICallContext CallContext => ((ITransientRpcServer)this).CallContext; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs b/src/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs new file mode 100644 index 000000000..5e01e1393 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Enum/CodeGeneratorFlag.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc +{ + /// + /// 代码生成标识 + /// + [Flags] + public enum CodeGeneratorFlag + { + /// + /// 生成同步代码 + /// + Sync = 1, + + /// + /// 生成异步代码 + /// + Async = 2, + + /// + /// 生成扩展同步代码 + /// + ExtensionSync = 4, + + /// + /// 生成扩展异步代码 + /// + ExtensionAsync = 8, + + /// + /// 包含接口 + /// + IncludeInterface = 16, + + /// + /// 包含实例 + /// + IncludeInstance = 32, + + /// + /// 包含扩展 + /// + IncludeExtension = 64 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs b/src/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs new file mode 100644 index 000000000..c4513d25f --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Enum/InvokeStatus.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 调用状态 + /// + public enum InvokeStatus : byte + { + /// + /// 就绪 + /// + Ready, + + /// + /// 未找到服务 + /// + UnFound, + + /// + /// 不可用 + /// + UnEnable, + + /// + /// 成功调用 + /// + Success, + + /// + /// 调用内部异常 + /// + InvocationException, + + /// + /// 其他异常 + /// + Exception + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Enum/MethodFlags.cs b/src/TouchSocket/Rpc/Global/Enum/MethodFlags.cs new file mode 100644 index 000000000..ffbeac17b --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Enum/MethodFlags.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc +{ + /// + /// 函数标识 + /// + [Flags] + public enum MethodFlags + { + /// + /// 空 + /// + None = 1, + + /// + /// 包含调用上下文 + /// + IncludeCallContext = 2 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs b/src/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs new file mode 100644 index 000000000..6b6775aaa --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Exceptions/RpcExceptions.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc异常 + /// + [Serializable] + public class RpcException : Exception + { + /// + ///构造函数 + /// + public RpcException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + + /// + /// Rpc调用异常 + /// + [Serializable] + public class RpcInvokeException : Exception + { + /// + ///构造函数 + /// + public RpcInvokeException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcInvokeException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcInvokeException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcInvokeException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs b/src/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs new file mode 100644 index 000000000..fde751491 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Extensions/RpcConfigExtensions.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using TouchSocket.Rpc; + +namespace TouchSocket.Core +{ + /// + /// RpcExtensions + /// + public static class RpcConfigExtensions + { + /// + /// 指定RpcStore的创建。 + /// + public static readonly DependencyProperty RpcStoreProperty = + DependencyProperty.Register("RpcStore", typeof(RpcConfigExtensions), null); + + /// + /// 配置RpcStore的创建。 + /// + /// + /// 当RpcStore完成配置时回调 + /// 可以使用现有的值,如果赋值为null,则会重新创建。 + public static TouchSocketConfig ConfigureRpcStore(this TouchSocketConfig config, Action action, RpcStore value = default) + { + if (value == default) + { + value = new RpcStore(config.Container); + } + action?.Invoke(value); + config.SetValue(RpcStoreProperty, value); + return config; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs b/src/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs new file mode 100644 index 000000000..6adde29ee --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Extensions/RpcParserExtensions.cs @@ -0,0 +1,198 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc +{ + /// + /// RpcParserExtensions + /// + public static class RpcParserExtensions + { + /// + /// 获取本地代理 + /// + /// + /// + /// + /// + public static string GetProxyCodes(this IRpcParser rpcParser, string @namespace, Type[] attrbuteTypes) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.GetProxyCodes(@namespace, attrbuteTypes); + } + + /// + /// 获取本地代理 + /// + /// + /// + /// + public static string GetProxyCodes(this IRpcParser rpcParser, string @namespace) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.GetProxyCodes(@namespace, null); + } + + /// + /// 注册所有服务 + /// + /// 返回搜索到的服务数 + public static int RegisterAllServer(this IRpcParser rpcParser) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.RegisterAllServer(); + } + + /// + /// 注册所有服务 + /// + /// 返回注册实例 + public static void RegisterServer(this IRpcParser rpcParser) where TFrom : class, IRpcServer where TTo : TFrom + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(); + } + + /// + /// 注册服务 + /// + /// + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser, Type providerInterfaceType, Type providerType) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(providerInterfaceType, providerType); + } + + /// + /// 注册为单例服务 + /// + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser, TFrom serverProvider) where TFrom : class, IRpcServer + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(serverProvider); + } + + /// + /// 注册为单例服务 + /// + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser, Type providerInterfaceType, IRpcServer serverProvider) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(providerInterfaceType, serverProvider); + } + + /// + /// 注册服务 + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser) where T : IRpcServer + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(); + } + + /// + /// 注册服务 + /// + /// + /// + /// + public static void RegisterServer(this IRpcParser rpcParser, Type fromType) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + rpcParser.RpcStore.RegisterServer(fromType); + } + + /// + /// 移除注册服务 + /// + /// + /// + /// + public static int UnregisterServer(this IRpcParser rpcParser, IRpcServer provider) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.UnregisterServer(provider); + } + + /// + /// 移除注册服务 + /// + /// + /// + /// + public static int UnregisterServer(this IRpcParser rpcParser, Type providerType) + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.UnregisterServer(providerType); + } + + /// + /// 移除注册服务 + /// + /// + /// + public static int UnregisterServer(this IRpcParser rpcParser) where T : RpcServer + { + if (rpcParser.RpcStore == null) + { + throw new ArgumentNullException(nameof(rpcParser.RpcStore), $"RpcStore为空,这一般是该解析器没有完成初始化配置所导致的。"); + } + return rpcParser.RpcStore.UnregisterServer(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs b/src/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs new file mode 100644 index 000000000..b4fc6b240 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Extensions/RpcStoreExtensions.cs @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace TouchSocket.Rpc +{ + /// + /// RpcStoreExtensions + /// + public static class RpcStoreExtensions + { + /// + /// 注册所有服务 + /// + /// 返回搜索到的服务数 + public static int RegisterAllServer(this RpcStore rpcStore) + { + List types = new List(); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in assemblies) + { + try + { + Type[] t1 = assembly.GetTypes().Where(p => typeof(IRpcServer).IsAssignableFrom(p) && !p.IsAbstract && p.IsClass).ToArray(); + types.AddRange(t1); + } + catch + { + } + } + + foreach (Type type in types) + { + rpcStore.RegisterServer(type); + } + return types.Count; + } + + /// + /// 注册服务 + /// + /// + /// + public static void RegisterServer(this RpcStore rpcStore) where T : IRpcServer + { + rpcStore.RegisterServer(typeof(T)); + } + + /// + /// 注册服务 + /// + /// + /// + /// + public static void RegisterServer(this RpcStore rpcStore, Type providerType) + { + rpcStore.RegisterServer(providerType, providerType); + } + + /// + /// 注册服务 + /// + /// + /// + /// + public static void RegisterServer(this RpcStore rpcStore) where TFrom : class, IRpcServer where TTo : TFrom + { + rpcStore.RegisterServer(typeof(TFrom), typeof(TTo)); + } + + /// + /// 注册为单例服务 + /// + /// + /// + public static void RegisterServer(this RpcStore rpcStore, TFrom rpcServer) where TFrom : class, IRpcServer + { + rpcStore.RegisterServer(typeof(TFrom), rpcServer); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Interface/ICallContext.cs b/src/TouchSocket/Rpc/Global/Interface/ICallContext.cs new file mode 100644 index 000000000..117b6a61b --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Interface/ICallContext.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc +{ + /// + /// 调用上下文 + /// + public interface ICallContext + { + /// + /// 调用此服务的主体。 + /// + /// + /// 当该服务在及派生中调用时,该值一般为对象。 + /// 当该服务在及派生中调用时,该值一般为对象。 + /// 当该服务在及派生中调用时,该值一般为对象。 + /// + /// + /// + object Caller { get; } + + /// + /// 本次调用的 + /// + MethodInstance MethodInstance { get; } + + /// + /// 可取消的调用令箭 + /// + CancellationTokenSource TokenSource { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs b/src/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs new file mode 100644 index 000000000..210b989b9 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Interface/IInvokeOption.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; + +namespace TouchSocket.Rpc +{ + /// + /// 调用配置接口 + /// + public interface IInvokeOption + { + /// + /// 可以取消的调用令箭 + /// + public CancellationToken Token { get; set; } + + /// + /// 调用反馈 + /// + public FeedbackType FeedbackType { get; set; } + + /// + /// 调用超时 + /// + public int Timeout { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs b/src/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs new file mode 100644 index 000000000..b1c9c6eb0 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Interface/IRemoteServer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// 远程服务接口 + /// + public interface IRemoteServer + { + /// + /// 客户端 + /// + IRpcClient Client { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Interface/IRpcClient.cs b/src/TouchSocket/Rpc/Global/Interface/IRpcClient.cs new file mode 100644 index 000000000..4cc60ccd1 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Interface/IRpcClient.cs @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Threading.Tasks; +using TouchSocket.Rpc.TouchRpc; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc接口 + /// + public interface IRpcClient : IDisposable + { + /// + /// 检验能否执行Rpc调用 + /// + Func TryCanInvoke { get; set; } + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + void Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters); + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + /// 服务器返回结果 + T Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters); + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// 对应类型集合 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + /// 返回值 + T Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types); + + /// + /// Rpc调用 + /// + /// 调用键 + /// 参数 + /// + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + void Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types); + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters); + + /// + /// Rpc调用 + /// 如果调用端为客户端,则会调用服务器Rpc服务。 + /// 如果调用端为服务器,则会反向调用客户端Rpc服务。 + /// + /// 调用键 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// Rpc服务器未注册 + /// 其他异常 + /// 服务器返回结果 + Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Interface/IRpcParser.cs b/src/TouchSocket/Rpc/Global/Interface/IRpcParser.cs new file mode 100644 index 000000000..215cefb46 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Interface/IRpcParser.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc +{ + /// + /// Rpc解析器 + /// + public interface IRpcParser : IDisposable + { + /// + /// RPC仓库。 + /// + public RpcStore RpcStore { get; } + + /// + /// 设置此解析器的服务器实例 + /// + void SetRpcStore(RpcStore rpcStore); + + /// + /// 注册服务 + /// + /// + void OnRegisterServer(MethodInstance[] methodInstances); + + /// + /// 取消注册服务 + /// + /// + void OnUnregisterServer(MethodInstance[] methodInstances); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Interface/IRpcServer.cs b/src/TouchSocket/Rpc/Global/Interface/IRpcServer.cs new file mode 100644 index 000000000..8b0ed875b --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Interface/IRpcServer.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// Rpc服务接口 + /// + public interface IRpcServer + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs b/src/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs new file mode 100644 index 000000000..0eb92a97a --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Interface/IRpcServerFactory.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// IRpcServerFactory + /// + public interface IRpcServerFactory + { + /// + /// 创建rpc实例 + /// + /// + /// + /// + public IRpcServer Create(ICallContext callContext, object[] ps); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs b/src/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs new file mode 100644 index 000000000..cce102114 --- /dev/null +++ b/src/TouchSocket/Rpc/Global/Interface/ITransientRpcServer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc +{ + /// + /// Rpc服务接口 + /// + public interface ITransientRpcServer : IRpcServer + { + /// + /// 调用上下文 + /// + ICallContext CallContext { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs b/src/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs new file mode 100644 index 000000000..cc7942905 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Attribute/JsonRpcAttribute.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// 适用于JsonRpc的标记 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class JsonRpcAttribute : RpcAttribute + { + /// + /// 适用于JsonRpc的标记. + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + /// + public JsonRpcAttribute(bool methodInvoke = false) + { + MethodInvoke = methodInvoke; + } + + /// + /// 适用于JsonRpc的标记. + /// + /// + public JsonRpcAttribute(string invokenKey) + { + InvokenKey = invokenKey; + } + + /// + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + public bool MethodInvoke { get; } + + /// + /// + /// + /// + public override Type[] GetGenericInterfaceTypes() + { + return new Type[] { typeof(IJsonRpcClient) }; + } + + /// + /// + /// + /// + /// + public override string GetInvokenKey(MethodInstance methodInstance) + { + if (MethodInvoke) + { + return GetMethodName(methodInstance, false); + } + else + { + return base.GetInvokenKey(methodInstance); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs b/src/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs new file mode 100644 index 000000000..13caeb26b --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Common/JsonResponseContext.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpc响应器 + /// + public class JsonResponseContext + { + /// + /// jsonrpc + /// + public string jsonrpc { get; set; } + + /// + /// result + /// + public object result { get; set; } + + /// + /// error + /// + public error error { get; set; } + + /// + /// id + /// + public string id { get; set; } + } + + /// + /// 错误 + /// +#pragma warning disable IDE1006 // 命名样式 + + public class error +#pragma warning restore IDE1006 // 命名样式 + { + /// + /// code + /// + public int code { get; set; } + + /// + /// message + /// + public string message { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs new file mode 100644 index 000000000..af69df595 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcCallContext.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpc调用上下文 + /// + internal class JsonRpcCallContext : IJsonRpcCallContext + { + private CancellationTokenSource m_tokenSource; + + /// + /// Json字符串 + /// + public string JsonString { get; internal set; } + + /// + /// + /// + public object Caller { get; internal set; } + + /// + /// JsonRpc上下文 + /// + public JsonRpcContext JsonRpcContext { get; internal set; } + + /// + /// + /// + public MethodInstance MethodInstance { get; internal set; } + + /// + /// + /// + public CancellationTokenSource TokenSource + { + get + { + if (m_tokenSource == null) + { + m_tokenSource = new CancellationTokenSource(); + } + return m_tokenSource; + } + } + + /// + /// + /// + public HttpContext HttpContext { get; internal set; } + + /// + /// + /// + public JRPT JRPT { get; internal set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs new file mode 100644 index 000000000..d8dcaf7b6 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcContext.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpcPackage + /// + public class JsonRpcContext : JsonRpcRequest + { + /// + /// parameters + /// + public object[] parameters; + + /// + /// needResponse + /// + public bool needResponse; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs new file mode 100644 index 000000000..b67ae222f --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcRequest.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpcRequest + /// + public class JsonRpcRequest + { + /// + /// jsonrpc + /// + public string jsonrpc = "2.0"; + + /// + /// method + /// + public string method; + + /// + /// @params + /// + public object @params; + + /// + /// id + /// + public string id; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs new file mode 100644 index 000000000..06515d12a --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcResponse.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpcSuccessResponse + /// + public class JsonRpcSuccessResponse + { + /// + /// jsonrpc + /// + public string jsonrpc = "2.0"; + + /// + /// result + /// + public object result; + + /// + /// id + /// + public string id; + } + + /// + /// JsonRpcErrorResponse + /// + public class JsonRpcErrorResponse + { + /// + /// jsonrpc + /// + public string jsonrpc = "2.0"; + + /// + /// error + /// + public error error; + + /// + /// id + /// + public string id; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs new file mode 100644 index 000000000..315554b59 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Common/JsonRpcWaitResult.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.JsonRpc +{ + internal class JsonRpcWaitResult : WaitResult + { + internal object Return; + + internal error error; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs b/src/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs new file mode 100644 index 000000000..f4c8359b5 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Components/JsonRpcClient.cs @@ -0,0 +1,874 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Sockets; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Http.WebSockets; +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpc客户端 + /// + public class JsonRpcClient : DisposableObject, ITcpClient, IJsonRpcClient + { + private readonly WaitHandlePool m_waitHandle; + private JRPT m_jrpt; + + /// + /// 构造函数 + /// + public JsonRpcClient() + { + m_waitHandle = new WaitHandlePool(); + } + + /// + /// + /// + public int BufferLength => Client.BufferLength; + + /// + /// + /// + public bool CanSend => Client.CanSend; + + /// + /// + /// + public bool CanSetDataHandlingAdapter => Client.CanSetDataHandlingAdapter; + + /// + /// 内部客户端 + /// + public ITcpClient Client { get; private set; } + + /// + /// + /// + public TouchSocketConfig Config => Client.Config; + + /// + /// + /// + public MessageEventHandler Connected { get => Client.Connected; set => Client.Connected = value; } + + /// + /// + /// + public ConnectingEventHandler Connecting { get => Client.Connecting; set => Client.Connecting = value; } + + /// + /// + /// + public IContainer Container => ((IClient)Client).Container; + + /// + /// + /// + public DataHandlingAdapter DataHandlingAdapter => Client.DataHandlingAdapter; + + /// + /// + /// + public DisconnectEventHandler Disconnected { get => Client.Disconnected; set => Client.Disconnected = value; } + + /// + public DisconnectEventHandler Disconnecting { get => Client.Disconnecting; set => Client.Disconnecting = value; } + + /// + /// + /// + public string IP => Client.IP; + + /// + public bool IsClient => Client.IsClient; + + /// + /// 协议类型 + /// + public JRPT JRPT => m_jrpt; + + /// + /// + /// + public DateTime LastReceivedTime => Client.LastReceivedTime; + + /// + /// + /// + public DateTime LastSendTime => Client.LastSendTime; + + /// + /// + /// + public ILog Logger => Client.Logger; + + /// + /// + /// + public Socket MainSocket => Client.MainSocket; + + /// + /// + /// + public Func OnHandleRawBuffer { get => Client.OnHandleRawBuffer; set => Client.OnHandleRawBuffer = value; } + + /// + /// + /// + public Func OnHandleReceivedData { get => Client.OnHandleReceivedData; set => Client.OnHandleReceivedData = value; } + + /// + /// + /// + public bool Online => Client.Online; + + /// + /// + /// + public IPluginsManager PluginsManager => Client.PluginsManager; + + /// + /// + /// + public int Port => Client.Port; + + /// + /// + /// + public Protocol Protocol { get => Client.Protocol; set => Client.Protocol = value; } + + /// + /// + /// + public ReceiveType ReceiveType => Client.ReceiveType; + + /// + /// + /// + public IPHost RemoteIPHost => Client.RemoteIPHost; + + /// + /// + /// + public Func TryCanInvoke { get; set; } + + /// + /// + /// + public bool UsePlugin => Client.UsePlugin; + + /// + /// + /// + public bool UseSsl => Client.UseSsl; + + /// + /// + /// + public void Close() + { + Client.Close(); + } + + /// + /// + /// + public void Close(string msg) + { + Client.Close(msg); + } + + /// + /// + /// + public ITcpClient Connect(int timeout = 5000) + { + Client.OnHandleReceivedData = HandleReceivedData; + Client.Connect(timeout); + return this; + } + + /// + /// + /// + public Task ConnectAsync(int timeout = 5000) + { + return EasyTask.Run(() => + { + return Connect(timeout); + }); + } + + /// + /// + /// + public void DefaultSend(byte[] buffer, int offset, int length) + { + Client.DefaultSend(buffer, offset, length); + } + + /// + /// + /// + public Task DefaultSendAsync(byte[] buffer, int offset, int length) + { + return Client.DefaultSendAsync(buffer, offset, length); + } + + /// + /// + /// + public Stream GetStream() + { + return Client.GetStream(); + } + + /// + /// + /// + public TValue GetValue(IDependencyProperty dp) + { + return Client.GetValue(dp); + } + + /// + /// + /// + public void Send(byte[] buffer, int offset, int length) + { + Client.Send(buffer, offset, length); + } + + /// + /// + /// + public void Send(IRequestInfo requestInfo) + { + Client.Send(requestInfo); + } + + /// + /// + /// + public void Send(IList> transferBytes) + { + Client.Send(transferBytes); + } + + /// + /// + /// + public Task SendAsync(byte[] buffer, int offset, int length) + { + return Client.SendAsync(buffer, offset, length); + } + + /// + /// + /// + public Task SendAsync(IRequestInfo requestInfo) + { + return Client.SendAsync(requestInfo); + } + + /// + /// + /// + public Task SendAsync(IList> transferBytes) + { + return Client.SendAsync(transferBytes); + } + + /// + /// + /// + public void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + Client.SetDataHandlingAdapter(adapter); + } + + /// + /// + /// + public ITcpClient Setup(TouchSocketConfig config) + { + m_jrpt = config.GetValue(JsonRpcConfigExtensions.JRPTProperty); + switch (m_jrpt) + { + case JRPT.Http: + Client ??= new HttpClient(); + break; + + case JRPT.Websocket: + Client ??= new WebSocketClient(); + break; + + case JRPT.Tcp: + default: + Client ??= new Sockets.TcpClient(); + break; + } + return Client.Setup(config); + } + + /// + /// + /// + public ITcpClient Setup(string ipHost) + { + TouchSocketConfig config = new TouchSocketConfig(); + config.SetRemoteIPHost(new IPHost(ipHost)); + return Setup(config); + } + + /// + /// + /// + public DependencyObject SetValue(IDependencyProperty dp, TValue value) + { + return Client.SetValue(dp, value); + } + + /// + /// 处理数据 + /// + /// + /// + private bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + string jsonString = null; + switch (m_jrpt) + { + case JRPT.Http: + { + HttpResponse httpResponse = (HttpResponse)requestInfo; + jsonString = httpResponse.GetBody(); + break; + } + case JRPT.Websocket: + { + if (requestInfo is WSDataFrame dataFrame && dataFrame.Opcode == WSDataType.Text) + { + jsonString = dataFrame.ToText(); + } + break; + } + case JRPT.Tcp: + default: + { + if (byteBlock == null) + { + return true; + } + else + { + jsonString = byteBlock.ToString(); + } + break; + } + } + + if (string.IsNullOrEmpty(jsonString)) + { + return true; + } + + try + { + if (jsonString.Contains("error") || jsonString.Contains("result")) + { + JsonResponseContext responseContext = jsonString.FromJson(); + if (responseContext != null && !responseContext.id.IsNullOrEmpty()) + { + JsonRpcWaitResult waitContext = new JsonRpcWaitResult + { + Status = 1, + Sign = long.Parse(responseContext.id), + error = responseContext.error, + Return = responseContext.result + }; + m_waitHandle.SetRun(waitContext); + } + } + } + catch + { + } + return true; + } + + #region RPC调用 + + /// + /// + /// + /// + /// + public bool HasValue(IDependencyProperty dp) + { + return Client.HasValue(dp); + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + JsonRpcWaitResult context = new JsonRpcWaitResult(); + WaitData waitData = m_waitHandle.GetWaitData(context); + + using (ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength)) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + parameters ??= new object[0]; + JsonRpcRequest jsonRpcRequest = new JsonRpcRequest() + { + method = method, + @params = parameters + }; + + if (invokeOption.FeedbackType == FeedbackType.WaitInvoke) + { + jsonRpcRequest.id = context.Sign.ToString(); + } + else + { + jsonRpcRequest.id = null; + } + switch (m_jrpt) + { + case JRPT.Tcp: + { + byteBlock.Write(SerializeConvert.JsonSerializeToBytes(jsonRpcRequest)); + break; + } + case JRPT.Http: + { + HttpRequest request = new HttpRequest(); + request.Method = "POST"; + request.SetUrl(RemoteIPHost.GetUrlPath()); + request.FromJson(jsonRpcRequest.ToJson()); + request.Build(byteBlock); + break; + } + case JRPT.Websocket: + { + ((WebSocketClient)Client).SendWithWS(jsonRpcRequest.ToJson()); + break; + } + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitInvoke: + { + this.Send(byteBlock); + waitData.Wait(invokeOption.Timeout); + JsonRpcWaitResult resultContext = (JsonRpcWaitResult)waitData.WaitResult; + m_waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new TimeoutException("等待结果超时"); + } + if (resultContext.error != null) + { + throw new RpcException(resultContext.error.message); + } + + if (resultContext.Return == null) + { + return default; + } + if (typeof(T).IsPrimitive || typeof(T) == typeof(string)) + { + return (T)resultContext.Return.ToString().ParseToType(typeof(T)); + } + + return resultContext.Return.ToJson().FromJson(); + } + default: + return default; + } + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + JsonRpcWaitResult context = new JsonRpcWaitResult(); + WaitData waitData = m_waitHandle.GetWaitData(context); + + using (ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength)) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + parameters ??= new object[0]; + JsonRpcRequest jsonRpcRequest = new JsonRpcRequest() + { + method = method, + @params = parameters + }; + + if (invokeOption.FeedbackType == FeedbackType.WaitInvoke) + { + jsonRpcRequest.id = context.Sign.ToString(); + } + else + { + jsonRpcRequest.id = null; + } + switch (m_jrpt) + { + case JRPT.Tcp: + { + byteBlock.Write(SerializeConvert.JsonSerializeToBytes(jsonRpcRequest)); + break; + } + case JRPT.Websocket: + { + ((WebSocketClient)Client).SendWithWS(jsonRpcRequest.ToJson()); + break; + } + case JRPT.Http: + { + HttpRequest request = new HttpRequest(); + request.Method = "POST"; + request.SetUrl(RemoteIPHost.GetUrlPath()); + request.FromJson(jsonRpcRequest.ToJson()); + request.Build(byteBlock); + } + break; + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitSend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitInvoke: + { + this.Send(byteBlock); + waitData.Wait(invokeOption.Timeout); + JsonRpcWaitResult resultContext = (JsonRpcWaitResult)waitData.WaitResult; + m_waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new TimeoutException("等待结果超时"); + } + if (resultContext.error != null) + { + throw new RpcException(resultContext.error.message); + } + break; + } + default: + return; + } + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// 函数式调用 + /// + /// 函数名 + /// 参数 + /// Rpc调用设置 + /// + /// + /// + public async Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + JsonRpcWaitResult context = new JsonRpcWaitResult(); + WaitData waitData = m_waitHandle.GetWaitData(context); + + using (ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength)) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + parameters ??= new object[0]; + JsonRpcRequest jsonRpcRequest = new JsonRpcRequest() + { + method = method, + @params = parameters + }; + + if (invokeOption.FeedbackType == FeedbackType.WaitInvoke) + { + jsonRpcRequest.id = context.Sign.ToString(); + } + else + { + jsonRpcRequest.id = null; + } + switch (m_jrpt) + { + case JRPT.Tcp: + { + byteBlock.Write(SerializeConvert.JsonSerializeToBytes(jsonRpcRequest)); + break; + } + case JRPT.Websocket: + { + ((WebSocketClient)Client).SendWithWS(jsonRpcRequest.ToJson()); + break; + } + case JRPT.Http: + { + HttpRequest request = new HttpRequest(); + request.Method = "POST"; + request.SetUrl(RemoteIPHost.GetUrlPath()); + request.FromJson(jsonRpcRequest.ToJson()); + request.Build(byteBlock); + } + break; + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitSend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitInvoke: + { + this.Send(byteBlock); + await waitData.WaitAsync(invokeOption.Timeout); + JsonRpcWaitResult resultContext = (JsonRpcWaitResult)waitData.WaitResult; + m_waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new TimeoutException("等待结果超时"); + } + if (resultContext.error != null) + { + throw new RpcException(resultContext.error.message); + } + break; + } + default: + return; + } + } + } + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// Rpc异常 + /// 其他异常 + /// 服务器返回结果 + public async Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + JsonRpcWaitResult context = new JsonRpcWaitResult(); + WaitData waitData = m_waitHandle.GetWaitData(context); + + using (ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength)) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + parameters ??= new object[0]; + JsonRpcRequest jsonRpcRequest = new JsonRpcRequest() + { + method = method, + @params = parameters + }; + + if (invokeOption.FeedbackType == FeedbackType.WaitInvoke) + { + jsonRpcRequest.id = context.Sign.ToString(); + } + else + { + jsonRpcRequest.id = null; + } + switch (m_jrpt) + { + case JRPT.Tcp: + { + byteBlock.Write(SerializeConvert.JsonSerializeToBytes(jsonRpcRequest)); + break; + } + case JRPT.Http: + { + HttpRequest request = new HttpRequest(); + request.Method = "POST"; + request.SetUrl(RemoteIPHost.GetUrlPath()); + request.FromJson(jsonRpcRequest.ToJson()); + request.Build(byteBlock); + break; + } + case JRPT.Websocket: + { + ((WebSocketClient)Client).SendWithWS(jsonRpcRequest.ToJson()); + break; + } + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + { + this.Send(byteBlock); + m_waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitInvoke: + { + this.Send(byteBlock); + await waitData.WaitAsync(invokeOption.Timeout); + JsonRpcWaitResult resultContext = (JsonRpcWaitResult)waitData.WaitResult; + m_waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new TimeoutException("等待结果超时"); + } + if (resultContext.error != null) + { + throw new RpcException(resultContext.error.message); + } + + if (resultContext.Return == null) + { + return default; + } + if (typeof(T).IsPrimitive || typeof(T) == typeof(string)) + { + return (T)resultContext.Return.ToString().ParseToType(typeof(T)); + } + + return resultContext.Return.ToJson().FromJson(); + } + default: + return default; + } + } + } + + /// + /// + /// + /// + /// + /// + public DependencyObject RemoveValue(IDependencyProperty dp) + { + return Client.RemoveValue(dp); + } + + #endregion RPC调用 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs b/src/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs new file mode 100644 index 000000000..e3976f012 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Config/JsonRpcConfigExtensions.cs @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Rpc.JsonRpc; + +namespace TouchSocket.Sockets +{ + /// + /// JsonRpcConfigExtensions + /// + public static class JsonRpcConfigExtensions + { + /// + /// 构建JsonRpc类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithJsonRpcClient(this TouchSocketConfig config) where TClient : IJsonRpcClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建JsonRpc类客户端,并连接 + /// + /// + /// + public static JsonRpcClient BuildWithJsonRpcClient(this TouchSocketConfig config) + { + return BuildWithJsonRpcClient(config); + } + + /// + /// TcpJsonRpc + /// + public static Protocol TcpJsonRpc { get; private set; } = new Protocol("TcpJsonRpc"); + + /// + /// 转化Protocol协议标识 + /// + /// + public static void SwitchProtocolToTcpJsonRpc(this ITcpClientBase client) + { + client.Protocol = TcpJsonRpc; + } + + /// + /// 设置JsonRpc的协议。 + /// + public static readonly DependencyProperty JRPTProperty = + DependencyProperty.Register("JRPT", typeof(JsonRpcConfigExtensions), JRPT.Tcp); + + /// + /// 设置JsonRpc的协议。默认为 + /// + /// + /// + /// + public static TouchSocketConfig SetJRPT(this TouchSocketConfig config, JRPT value) + { + config.SetValue(JRPTProperty, value); + return config; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs b/src/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs new file mode 100644 index 000000000..103e6583d --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Enum/JRPT.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpc协议类型 + /// + public enum JRPT : byte + { + /// + /// 普通TCP协议 + /// + Tcp, + + /// + /// Http协议 + /// + Http, + + /// + /// Websocket协议 + /// + Websocket + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs b/src/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs new file mode 100644 index 000000000..f8b046518 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Extensions/JsonRpcPluginsManagerExtension.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.JsonRpc; + +namespace TouchSocket.Core +{ + /// + /// JsonRpcPluginsManagerExtension + /// + public static class JsonRpcPluginsManagerExtension + { + /// + /// 使用JsonRpc的插件。仅服务器可用。 + /// + /// + /// + public static JsonRpcParserPlugin UseJsonRpc(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs b/src/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs new file mode 100644 index 000000000..999c48d6e --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcCallContext.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.WebApi; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// IJsonRpcCallContext + /// + public interface IJsonRpcCallContext : IHttpCallContext + { + /// + /// Json字符串 + /// + public string JsonString { get; } + + /// + /// JsonRpc数据包 + /// + public JsonRpcContext JsonRpcContext { get; } + + /// + /// 表明当前的调用协议。 + /// + JRPT JRPT { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs b/src/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs new file mode 100644 index 000000000..09f108ec7 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Interface/IJsonRpcClient.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// IJsonRpcClient + /// + public interface IJsonRpcClient : ITcpClient, IRpcClient + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs b/src/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs new file mode 100644 index 000000000..a8831a9c3 --- /dev/null +++ b/src/TouchSocket/Rpc/JsonRpc/Plugins/JsonRpcParserPlugin.cs @@ -0,0 +1,430 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Http.WebSockets; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.JsonRpc +{ + /// + /// JsonRpcParser解析器插件 + /// + public class JsonRpcParserPlugin : WebSocketPluginBase, IRpcParser + { + private readonly ActionMap m_actionMap; + private string m_jsonRpcUrl = "/jsonrpc"; + private RpcStore m_rpcStore; + + /// + /// 构造函数 + /// + public JsonRpcParserPlugin([DependencyParamterInject(true)] RpcStore rpcStore) + { + m_actionMap = new ActionMap(); + rpcStore?.AddRpcParser(GetType().Name, this); + } + + /// + /// JsonRpc的调用键。 + /// + public ActionMap ActionMap => m_actionMap; + + /// + /// 自动转换协议 + /// + public bool AutoSwitch { get; set; } = true; + + /// + /// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。 + /// + public string JsonRpcUrl + { + get => m_jsonRpcUrl; + set => m_jsonRpcUrl = string.IsNullOrEmpty(value) ? "/" : value; + } + + /// + /// + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// 不需要自动转化协议。 + /// 仅当服务器是TCP时生效。此时如果携带协议为TcpJsonRpc时才会解释为jsonRpc。 + /// + /// + public JsonRpcParserPlugin NoSwitchProtocol() + { + AutoSwitch = false; + return this; + } + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is JsonRpcAttribute attribute) + { + m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is JsonRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcService) + { + m_rpcStore = rpcService; + } + + #endregion RPC解析器 + + /// + /// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。 + /// + /// + /// + public JsonRpcParserPlugin SetJsonRpcUrl(string jsonRpcUrl) + { + JsonRpcUrl = jsonRpcUrl; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnConnecting(ITcpClientBase client, OperationEventArgs e) + { + if (AutoSwitch && client.Protocol == Protocol.TCP) + { + client.SwitchProtocolToTcpJsonRpc(); + } + base.OnConnecting(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e) + { + if (e.DataFrame.Opcode == WSDataType.Text) + { + string jsonRpcStr = e.DataFrame.ToText(); + if (jsonRpcStr.Contains("jsonrpc")) + { + e.Handled = true; + ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext() + { + Caller = client, + JRPT = JRPT.Websocket, + JsonString = jsonRpcStr + }); + } + } + } + + /// + /// + /// + /// + /// + protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + if (m_jsonRpcUrl == "/" || e.Context.Request.UrlEquals(m_jsonRpcUrl)) + { + e.Handled = true; + ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext() + { + Caller = client, + JRPT = JRPT.Http, + JsonString = e.Context.Request.GetBody(), + HttpContext = e.Context + }); + } + base.OnPost(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + if (client.Protocol == JsonRpcConfigExtensions.TcpJsonRpc) + { + string jsonRpcStr = e.ByteBlock.ToString(); + if (jsonRpcStr.Contains("jsonrpc")) + { + e.Handled = true; + ThreadPool.QueueUserWorkItem(InvokeWaitCallback, new JsonRpcCallContext() + { + Caller = client, + JRPT = JRPT.Tcp, + JsonString = e.ByteBlock.ToString() + }); + } + } + base.OnReceivedData(client, e); + } + + private static void Response(JsonRpcCallContext callContext, object result, error error) + { + try + { + using (ByteBlock responseByteBlock = new ByteBlock()) + { + object jobject = null; + if (error == null) + { + jobject = new JsonRpcSuccessResponse + { + result = result, + id = callContext.JsonRpcContext.id + }; + } + else + { + jobject = new JsonRpcErrorResponse + { + error = error, + id = callContext.JsonRpcContext.id + }; + } + ITcpClientBase client = (ITcpClientBase)callContext.Caller; + if (callContext.JRPT == JRPT.Http) + { + HttpResponse httpResponse = callContext.HttpContext.Response; + httpResponse.FromJson(jobject.ToJson()); + httpResponse.Answer(); + } + else if (callContext.JRPT == JRPT.Websocket) + { + ((HttpSocketClient)client).SendWithWS(jobject.ToJson()); + } + else + { + responseByteBlock.Write(jobject.ToJson().ToUTF8Bytes()); + client.Send(responseByteBlock); + } + } + } + catch + { + } + } + + private void BuildRequestContext(ref JsonRpcCallContext callContext) + { + JsonRpcContext jsonRpcContext = SerializeConvert.JsonDeserializeFromString(callContext.JsonString); + callContext.JsonRpcContext = jsonRpcContext; + if (jsonRpcContext.id != null) + { + jsonRpcContext.needResponse = true; + } + + if (m_actionMap.TryGetMethodInstance(jsonRpcContext.method, out MethodInstance methodInstance)) + { + callContext.MethodInstance = methodInstance; + if (jsonRpcContext.@params == null) + { + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + if (methodInstance.ParameterNames.Length > 1) + { + throw new RpcException("调用参数计数不匹配"); + } + else + { + jsonRpcContext.parameters = new object[] { callContext }; + } + } + else + { + if (methodInstance.ParameterNames.Length != 0) + { + throw new RpcException("调用参数计数不匹配"); + } + } + } + if (jsonRpcContext.@params is Dictionary obj) + { + jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length]; + //内联 + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + jsonRpcContext.parameters[0] = callContext; + i = 1; + } + for (; i < methodInstance.ParameterNames.Length; i++) + { + if (obj.TryGetValue(methodInstance.ParameterNames[i], out object jToken)) + { + Type type = methodInstance.ParameterTypes[i]; + jsonRpcContext.parameters[i] = jToken.ToJson().FromJson(type); + } + else if (methodInstance.Parameters[i].HasDefaultValue) + { + jsonRpcContext.parameters[i] = methodInstance.Parameters[i].DefaultValue; + } + else + { + throw new RpcException("调用参数计数不匹配"); + } + } + } + else + { + IList array = (IList)jsonRpcContext.@params; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + if (array.Count != methodInstance.ParameterNames.Length - 1) + { + throw new RpcException("调用参数计数不匹配"); + } + jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length]; + + jsonRpcContext.parameters[0] = callContext; + for (int i = 0; i < array.Count; i++) + { + jsonRpcContext.parameters[i + 1] = array[i].ToJson().FromJson(methodInstance.ParameterTypes[i + 1]); + } + } + else + { + if (array.Count != methodInstance.ParameterNames.Length) + { + throw new RpcException("调用参数计数不匹配"); + } + jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length]; + + for (int i = 0; i < array.Count; i++) + { + jsonRpcContext.parameters[i] = array[i].ToJson().FromJson(methodInstance.ParameterTypes[i]); + } + } + } + } + } + + private void InvokeWaitCallback(object context) + { + if (context is null) + { + return; + } + JsonRpcCallContext callContext = (JsonRpcCallContext)context; + InvokeResult invokeResult = new InvokeResult(); + + try + { + BuildRequestContext(ref callContext); + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + + if (callContext.MethodInstance != null) + { + if (!callContext.MethodInstance.IsEnable) + { + invokeResult.Status = InvokeStatus.UnEnable; + } + } + else + { + invokeResult.Status = InvokeStatus.UnFound; + } + + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = callContext.MethodInstance.ServerFactory.Create(callContext, callContext.JsonRpcContext.parameters); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + + invokeResult = m_rpcStore.Execute(rpcServer, callContext.JsonRpcContext.parameters, callContext); + } + + if (!callContext.JsonRpcContext.needResponse) + { + return; + } + error error = null; + switch (invokeResult.Status) + { + case InvokeStatus.Success: + { + break; + } + case InvokeStatus.UnFound: + { + error = new error(); + error.code = -32601; + error.message = "函数未找到"; + break; + } + case InvokeStatus.UnEnable: + { + error = new error(); + error.code = -32601; + error.message = "函数已被禁用"; + break; + } + case InvokeStatus.InvocationException: + { + error = new error(); + error.code = -32603; + error.message = "函数内部异常"; + break; + } + case InvokeStatus.Exception: + { + error = new error(); + error.code = -32602; + error.message = invokeResult.Message; + break; + } + default: + return; + } + + Response(callContext, invokeResult.Result, error); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs b/src/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs new file mode 100644 index 000000000..1d887f6e2 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Attribute/TouchRpcAttribute.cs @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpc方法标记属性类 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class TouchRpcAttribute : RpcAttribute + { + /// + /// 适用于TouchRpc的标记. + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + /// + public TouchRpcAttribute(bool methodInvoke = false) + { + MethodInvoke = methodInvoke; + } + + /// + /// 适用于TouchRpc的标记. + /// + /// + public TouchRpcAttribute(string invokenKey) + { + InvokenKey = invokenKey; + } + + /// + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + public bool MethodInvoke { get; } + + /// + /// + /// + /// + /// + public override string GetInvokenKey(MethodInstance methodInstance) + { + if (MethodInvoke) + { + return GetMethodName(methodInstance, false); + } + else + { + return base.GetInvokenKey(methodInstance); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs b/src/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs new file mode 100644 index 000000000..25e812fb8 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Channel/Channel.cs @@ -0,0 +1,739 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 通道 + /// + [DebuggerDisplay("ID={ID},Status={Status}")] + public abstract class Channel : DisposableObject + { + /// + /// 是否具有数据可读 + /// + public abstract int Available { get; } + + /// + /// 缓存容量 + /// + public abstract int CacheCapacity { get; set; } + + /// + /// 判断当前通道能否调用 + /// + public abstract bool CanMoveNext { get; } + + /// + /// 能否写入 + /// + public abstract bool CanWrite { get; } + + /// + /// 通道ID + /// + public abstract int ID { get; } + + /// + /// 最后一次操作时显示消息 + /// + public abstract string LastOperationMes { get; } + + /// + /// 状态 + /// + public abstract ChannelStatus Status { get; } + + /// + /// 目的ID地址。仅当该通道由两个客户端打通时有效。 + /// + public abstract string TargetId { get; } + + /// + /// 超时时间,默认1000*10ms。 + /// + public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10); + + /// + /// 是否被使用 + /// + public abstract bool Using { get; } + + /// + /// 取消 + /// + public abstract void Cancel(string operationMes = null); + + /// + /// 异步取消 + /// + /// + public Task CancelAsync(string operationMes = null) + { + return EasyTask.Run(() => + { + Cancel(operationMes); + }); + } + + /// + /// 完成操作 + /// + public abstract void Complete(string operationMes = null); + + /// + /// 异步完成操作 + /// + /// + public Task CompleteAsync(string operationMes = null) + { + return EasyTask.Run(() => + { + Complete(operationMes); + }); + } + + /// + /// 获取当前的数据 + /// + public abstract byte[] GetCurrent(); + + /// + /// 继续。 + /// 调用该指令时,接收方会跳出接收,但是通道依然可用,所以接收方需要重新调用 + /// + /// + public abstract void HoldOn(string operationMes = null); + + /// + /// 异步调用继续 + /// + /// + /// + public Task HoldOnAsync(string operationMes = null) + { + return EasyTask.Run(() => + { + HoldOn(operationMes); + }); + } + + /// + /// 转向下个元素 + /// + /// + public abstract bool MoveNext(); + + /// + /// 转向下个元素 + /// + /// + public Task MoveNextAsync() + { + return EasyTask.Run(() => + { + return MoveNext(); + }); + } + + /// + /// 阻塞读取数据,直到有数据,或者超时。 + /// + /// + public Task ReadAsync() + { + return EasyTask.Run(() => + { + if (MoveNext()) + { + return GetCurrent(); + } + return null; + }); + } + + /// + /// 尝试写入。 + /// + /// + /// + /// + /// + public bool TryWrite(byte[] data, int offset, int length) + { + if (CanWrite) + { + try + { + Write(data, offset, length); + return true; + } + catch + { + } + } + return false; + } + + /// + /// 尝试写入 + /// + /// + /// + public bool TryWrite(byte[] data) + { + return TryWrite(data, 0, data.Length); + } + + /// + /// 异步尝试写入 + /// + /// + /// + /// + /// + public async Task TryWriteAsync(byte[] data, int offset, int length) + { + if (CanWrite) + { + try + { + await WriteAsync(data, offset, length); + return true; + } + catch + { + } + } + return false; + } + + /// + /// 异步尝试写入 + /// + /// + /// + public Task TryWriteAsync(byte[] data) + { + return TryWriteAsync(data, 0, data.Length); + } + + /// + /// 写入通道 + /// + /// + /// + /// + public abstract void Write(byte[] data, int offset, int length); + + /// + /// 写入通道 + /// + /// + public void Write(byte[] data) + { + Write(data, 0, data.Length); + } + + /// + /// 写入通道 + /// + /// + /// + /// + public Task WriteAsync(byte[] data, int offset, int length) + { + return Task.Run(() => + { + this.Write(data, offset, length); + }); + } + + /// + /// 写入通道 + /// + /// + public void WriteAsync(byte[] data) + { + WriteAsync(data, 0, data.Length); + } + } + + internal class InternalChannel : Channel + { + private readonly RpcActor m_actor; + private readonly IntelligentDataQueue m_dataQueue; + private readonly AutoResetEvent m_moveWaitHandle; + private readonly string m_targetId; + private readonly Timer m_timer; + private int m_cacheCapacity; + private volatile bool m_canFree; + private byte[] m_currentData; + private int m_id; + private string m_lastOperationMes; + private DateTime m_lastOperationTime; + private ChannelStatus m_status; + private bool m_using; + + public InternalChannel(RpcActor client, string targetId) + { + m_actor = client; + m_lastOperationTime = DateTime.Now; + m_targetId = targetId; + m_status = ChannelStatus.Default; + m_cacheCapacity = 1024 * 1024 * 5; + m_dataQueue = new IntelligentDataQueue(m_cacheCapacity) + { + OverflowWait = false, + OnQueueChanged = OnQueueChanged + }; + m_moveWaitHandle = new AutoResetEvent(false); + m_canFree = true; + m_timer = new Timer((o) => + { + if (DateTime.Now - m_lastOperationTime > TimeSpan.FromTicks(Timeout.Ticks * 3)) + { + this.SafeDispose(); + } + }, null, 1000, 1000); + } + + /// + /// 析构函数 + /// + ~InternalChannel() + { + Dispose(false); + } + + /// + /// 是否具有数据可读 + /// + public override int Available => m_dataQueue.Count; + + /// + /// 缓存容量 + /// + public override int CacheCapacity + { + get => m_cacheCapacity; + set + { + if (value < 0) + { + value = 1024; + } + m_cacheCapacity = value; + m_dataQueue.MaxSize = value; + } + } + + /// + /// 判断当前通道能否调用 + /// + public override bool CanMoveNext + { + get + { + if (Available > 0) + { + return true; + } + if ((byte)m_status >= 4) + { + return false; + } + return true; + } + } + + /// + /// 能否写入 + /// + public override bool CanWrite => (byte)m_status <= 3; + + /// + /// ID + /// + public override int ID => m_id; + + /// + /// 最后一次操作时显示消息 + /// + public override string LastOperationMes + { + get => m_lastOperationMes; + } + + /// + /// 状态 + /// + public override ChannelStatus Status => m_status; + + /// + /// 目的ID地址。 + /// + public override string TargetId => m_targetId; + + /// + /// 是否被使用 + /// + public override bool Using => m_using; + + #region 操作 + + /// + /// 取消 + /// + public override void Cancel(string operationMes = null) + { + if ((byte)m_status > 3) + { + return; + } + try + { + this.RequestCancel(true); + ChannelPackage channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = ChannelDataType.CancelOrder, + Message = operationMes, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + m_lastOperationTime = DateTime.Now; + } + catch + { + } + } + + /// + /// 完成操作 + /// + public override void Complete(string operationMes = null) + { + if ((byte)m_status > 3) + { + return; + } + + this.RequestComplete(true); + ChannelPackage channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = ChannelDataType.CompleteOrder, + Message = operationMes, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + m_lastOperationTime = DateTime.Now; + } + + /// + /// 继续。 + /// 调用该指令时,接收方会跳出接收,但是通道依然可用,所以接收方需要重新调用 + /// + /// + public override void HoldOn(string operationMes = null) + { + if ((byte)m_status > 3) + { + return; + } + ChannelPackage channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = ChannelDataType.HoldOnOrder, + Message = operationMes, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + m_lastOperationTime = DateTime.Now; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if ((byte)m_status > 3) + { + return; + } + m_timer.SafeDispose(); + + try + { + this.RequestDispose(true); + ChannelPackage channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = ChannelDataType.HoldOnOrder, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + m_lastOperationTime = DateTime.Now; + } + catch + { + } + base.Dispose(disposing); + } + + #endregion 操作 + + /// + /// 获取当前的数据 + /// + public override byte[] GetCurrent() + { + return this.m_currentData; + } + + /// + /// 转向下个元素 + /// + /// + public override bool MoveNext() + { + if (!this.CanMoveNext) + { + return false; + } + if (m_dataQueue.TryDequeue(out ChannelPackage channelPackage)) + { + switch (channelPackage.DataType) + { + case ChannelDataType.DataOrder: + { + m_currentData = channelPackage.Data.Array; + return true; + } + case ChannelDataType.CompleteOrder: + RequestComplete(true); + return false; + + case ChannelDataType.CancelOrder: + RequestCancel(true); + return false; + + case ChannelDataType.DisposeOrder: + RequestDispose(true); + return false; + + case ChannelDataType.HoldOnOrder: + m_status = ChannelStatus.HoldOn; + return false; + + case ChannelDataType.QueueRun: + this.m_canFree = true; + return false; + + case ChannelDataType.QueuePause: + this.m_canFree = false; + return false; + + default: + return false; + } + } + + m_moveWaitHandle.Reset(); + if (m_moveWaitHandle.WaitOne(Timeout)) + { + return MoveNext(); + } + else + { + m_status = ChannelStatus.Overtime; + return false; + } + } + + /// + /// 写入通道 + /// + /// + /// + /// + public override void Write(byte[] data, int offset, int length) + { + if ((byte)m_status > 3) + { + throw new Exception($"通道已{m_status}"); + } + + if (!SpinWait.SpinUntil(() => { return m_canFree; }, Timeout)) + { + throw new TimeoutException(); + } + ChannelPackage channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + DataType = ChannelDataType.DataOrder, + Data = new ArraySegment(data, offset, length), + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + m_lastOperationTime = DateTime.Now; + } + + internal void ReceivedData(ChannelPackage channelPackage) + { + m_lastOperationTime = DateTime.Now; + if (channelPackage.RunNow) + { + switch (channelPackage.DataType) + { + case ChannelDataType.CompleteOrder: + this.m_lastOperationMes = channelPackage.Message; + RequestComplete(false); + break; + + case ChannelDataType.CancelOrder: + this.m_lastOperationMes = channelPackage.Message; + RequestCancel(false); + break; + + case ChannelDataType.DisposeOrder: + RequestDispose(false); + break; + + case ChannelDataType.HoldOnOrder: + this.m_lastOperationMes = channelPackage.Message; + m_status = ChannelStatus.HoldOn; + break; + + case ChannelDataType.QueueRun: + this.m_canFree = true; + return; + + case ChannelDataType.QueuePause: + this.m_canFree = false; + return; + + default: + return; + } + } + m_dataQueue.Enqueue(channelPackage); + m_moveWaitHandle.Set(); + } + + internal void SetID(int id) + { + m_id = id; + } + + internal void SetUsing() + { + m_using = true; + } + + private void Clear() + { + try + { + lock (this) + { + m_moveWaitHandle.Set(); + m_moveWaitHandle.SafeDispose(); + m_actor.RemoveChannel(m_id); + m_dataQueue.Clear(); + } + } + catch + { + } + } + + private void OnQueueChanged(bool free) + { + if ((byte)m_status > 3) + { + return; + } + + try + { + ChannelPackage channelPackage = new ChannelPackage() + { + ChannelId = this.m_id, + RunNow = true, + DataType = free ? ChannelDataType.QueueRun : ChannelDataType.QueuePause, + SourceId = this.m_actor.ID, + TargetId = this.m_targetId, + Route = this.m_targetId.HasValue() + }; + this.m_actor.SendChannelPackage(channelPackage); + m_lastOperationTime = DateTime.Now; + } + catch + { + } + } + + private void RequestCancel(bool clear) + { + m_status = ChannelStatus.Cancel; + if (clear) + { + Clear(); + } + } + + private void RequestComplete(bool clear) + { + m_status = ChannelStatus.Completed; + if (clear) + { + Clear(); + } + } + + internal void RequestDispose(bool clear) + { + if ((byte)m_status > 3) + { + return; + } + m_status = ChannelStatus.Disposed; + if (clear) + { + Clear(); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs b/src/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs new file mode 100644 index 000000000..9e411bc18 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Channel/ChannelPackage.cs @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal enum ChannelDataType : byte + { + DataOrder, + CompleteOrder, + CancelOrder, + DisposeOrder, + HoldOnOrder, + QueueRun, + QueuePause + } + + internal class ChannelPackage : MsgRouterPackage, IQueueData + { + public int ChannelId { get; set; } + public ArraySegment Data { get; set; } + public ChannelDataType DataType { get; set; } + public bool RunNow { get; set; } + int IQueueData.Size => this.Data == null ? 0 : this.Data.Count; + + public int GetLen() + { + if (Data == null) + { + return 1024; + } + return Data.Count + 1024; + } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(RunNow); + byteBlock.Write((byte)DataType); + byteBlock.Write(ChannelId); + byteBlock.WriteBytesPackage(Data.Array, Data.Offset, Data.Count); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + this.RunNow = byteBlock.ReadBoolean(); + this.DataType = (ChannelDataType)byteBlock.ReadByte(); + this.ChannelId = byteBlock.ReadInt32(); + var data = byteBlock.ReadBytesPackage(); + if (data != null) + { + this.Data = new ArraySegment(data); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs b/src/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs new file mode 100644 index 000000000..b7db940a6 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Channel/ChannelStatus.cs @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 通道状态 + /// + public enum ChannelStatus : byte + { + /// + /// 默认 + /// + Default = 0, + + /// + /// 继续下移 + /// + Moving = 1, + + /// + /// 超时 + /// + Overtime = 2, + + /// + /// 继续 + /// + HoldOn = 3, + + /// + /// 取消 + /// + Cancel = 4, + + /// + /// 完成 + /// + Completed = 5, + + /// + /// 已释放 + /// + Disposed = 6 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs b/src/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs new file mode 100644 index 000000000..0ac6bc6eb --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Channel/WaitCreateChannelPackage.cs @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// WaitCreateChannel + /// + internal class WaitCreateChannelPackage : WaitRouterPackage + { + /// + /// 随机ID + /// + public bool Random { get; set; } + + /// + /// 通道ID + /// + public int ChannelID { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(Random); + byteBlock.Write(ChannelID); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + this.Random = byteBlock.ReadBoolean(); + this.ChannelID = byteBlock.ReadInt32(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs b/src/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs new file mode 100644 index 000000000..16d4a1adf --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/FlowOperator.cs @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 关于具有流速的操作器。 + /// + public abstract class FlowOperator + { + /// + /// 已完成长度 + /// + protected long completedLength; + + /// + /// 进度 + /// + protected float m_progress; + + private long m_speed; + private long m_speedTemp; + + /// + /// 已完成长度 + /// + /// + public long CompletedLength { get => completedLength; } + + /// + /// 由的结果,判断是否已结束操作。 + /// + public virtual bool IsEnd { get => Result.ResultCode != ResultCode.Default; } + + /// + /// 数据源的全部长度。 + /// + public long Length { get; protected set; } + + /// + /// 最大传输速度。 + /// + public int MaxSpeed { get; protected set; } = int.MaxValue; + + /// + /// 元数据 + /// + public Metadata Metadata { get; set; } + + /// + /// 进度 + /// + public float Progress => m_progress; + + /// + /// 执行结果 + /// + public Result Result { get; protected set; } + + /// + /// 超时时间,默认10*1000ms。 + /// + public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10); + + /// + /// 可取消令箭 + /// + public CancellationToken Token { get; set; } + + /// + /// 从上次获取到此次获得的速度 + /// + /// + public long Speed() + { + m_speed = m_speedTemp; + m_speedTemp = 0; + return m_speed; + } + + internal void SetLength(long len) + { + Length = len; + } + + /// + /// 设置结果状态 + /// + /// + /// + internal Result SetResult(Result result) + { + Result = result; + return result; + } + + /// + /// 添加流速(线程安全) + /// + /// + protected internal virtual void AddFlow(int flow) + { + Interlocked.Add(ref m_speedTemp, flow); + m_progress = (float)((double)Interlocked.Add(ref completedLength, flow) / Length); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs b/src/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs new file mode 100644 index 000000000..f820795d9 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/Interface/IDependencyTouchRpc.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IDependencyTouchRpc + /// + public interface IDependencyTouchRpc : ITouchRpc, IDependencyObject + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs b/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs new file mode 100644 index 000000000..5c6fcdb97 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpc.cs @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITouchRpc + /// + public interface ITouchRpc : IRpcActor + { + /// + /// Rpc执行角色 + /// + RpcActor RpcActor { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs b/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs new file mode 100644 index 000000000..24ee4b105 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcCallContext.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITouchRpcCallContext + /// + public interface ITouchRpcCallContext : ICallContext + { + /// + /// 当不为空时,调用 + /// + /// + public bool TryCancel(); + + /// + /// TouchRpcContext + /// + TouchRpcPackage TouchRpcPackage { get; } + + /// + /// 序列化类型 + /// + public SerializationType SerializationType { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs b/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs new file mode 100644 index 000000000..65b282d6d --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/Interface/ITouchRpcService.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITouchRpcService + /// + public interface ITouchRpcService : IRpcParser, ITargetRpcActor + { + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 协议 + /// 数据 + /// 偏移 + /// 长度 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + void Send(string targetId, short protocol, byte[] buffer, int offset, int length); + + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 协议 + /// 数据 + /// 偏移 + /// 长度 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + Task SendAsync(string targetId, short protocol, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs b/src/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs new file mode 100644 index 000000000..f1a23c089 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/TouchRpcUtility.cs @@ -0,0 +1,281 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcUtility + /// + public partial class TouchRpcUtility + { + /// + /// TouchRpc字符串 + /// + public const string TouchRpc = "TOUCHRPC"; + + /// + /// TouchRpc + /// + public static Protocol TouchRpcProtocol { get; private set; } = new Protocol(TouchRpc); + + /// + /// 传输分包 + /// + public const int TransferPackage = 1024 * 512; + + #region 基本协议,0-99; + + /// + /// 握手 + /// + public const short P_0_Handshake_Request = 0; + + /// + /// 重置ID + /// + public const short P_1_ResetID_Request = -1; + + /// + /// 握手响应 + /// + public const short P_1000_Handshake_Response = -1000; + + /// + /// 重置ID响应 + /// + public const short P_1001_ResetID_Response = -1001; + + /// + /// Ping回应 + /// + public const short P_1002_Ping_Response = -1002; + + /// + /// Ping + /// + public const short P_2_Ping_Request = -2; + + #endregion 基本协议,0-99; + + #region 通道协议,100-199; + + /// + /// 创建一个面向对方的通道 + /// + public const short P_100_CreateChannel_Request = -100; + + /// + /// 创建通道回应 + /// + public const short P_1100_CreateChannel_Response = -1100; + + /// + /// 通道数据 + /// + public const short P_101_ChannelPackage = -101; + + #endregion 通道协议,100-199; + + #region Rpc协议,200-299; + + /// + /// 调用响应 + /// + public const short P_1200_Invoke_Response = -1200; + + ///// + ///// 调用ID客户端响应 + ///// + //public const short P_1201_Invoke2C_Response = -1201; + + /// + /// 调用 + /// + public const short P_200_Invoke_Request = -200; + + ///// + ///// 调用ID客户端 + ///// + //public const short P_201_Invoke2C_Request = -201; + + /// + /// 取消调用 + /// + public const short P_204_CancelInvoke = -204; + + ///// + ///// 取消调用 + ///// + //public const short P_205_CancelInvoke2C = -205; + + #endregion Rpc协议,200-299; + + #region Stream协议 400-499 + + /// + /// 向服务器发送流响应 + /// + public const short P_1400_SendStreamToSocketClient_Response = -1400; + + /// + /// 向服务器发送流 + /// + public const short P_400_SendStreamToSocketClient_Request = -400; + + /// + /// 向客户端发送流 + /// + public const short P_401_SendStreamToClient = -401; + + #endregion Stream协议 400-499 + + #region FileTransfer协议 500-599 + + /// + /// 拉取文件响应 + /// + public const short P_1500_PullFile_Response = -1500; + + /// + /// 开始拉取文件响应 + /// + public const short P_1501_BeginPullFile_Response = -1501; + + /// + /// 推送文件响应 + /// + public const short P_1502_PushFile_Response = -1502; + + ///// + ///// 从客户端拉取文件响应 + ///// + //public const short P_1503_PullFile2C_Response = -1503; + + ///// + ///// 客户端拉取文件转发响应 + ///// + //public const short P_1504_PullFileFC_Response = -1504; + + ///// + ///// 开始从客户端拉取文件响应 + ///// + //public const short P_1505_BeginPullFile2C_Response = -1505; + + ///// + ///// 开始从客户端拉取文件转发响应 + ///// + //public const short P_1506_BeginPullFileFC_Response = -1506; + + ///// + ///// 推送到客户端响应 + ///// + //public const short P_1507_PushFile2C_Response = -1507; + + ///// + ///// 推送到客户端转发响应 + ///// + //public const short P_1508_PushFileFC_Response = -1508; + + /// + /// 拉取文件 + /// + public const short P_500_PullFile_Request = -500; + + /// + /// 开始拉取文件 + /// + public const short P_501_BeginPullFile_Request = -501; + + /// + /// 推送文件 + /// + public const short P_502_PushFile_Request = -502; + + ///// + ///// 从客户端拉取文件 + ///// + //public const short P_503_PullFile2C_Request = -503; + + ///// + ///// 客户端拉取文件转发 + ///// + //public const short P_504_PullFileFC_Request = -504; + + ///// + ///// 开始从客户端拉取文件 + ///// + //public const short P_505_BeginPullFile2C_Request = -505; + + ///// + ///// 开始从客户端拉取文件转发 + ///// + //public const short P_506_BeginPullFileFC_Request = -506; + + ///// + ///// 推送到客户端 + ///// + //public const short P_507_PushFile2C_Request = -507; + + ///// + ///// 推送到客户端转发 + ///// + //public const short P_508_PushFileFC_Request = -508; + + /// + /// 推送文件状态确认 + /// + public const short P_509_PushFileAck_Request = -509; + + ///// + ///// 推送文件到客户端状态确认 + ///// + //public const short P_511_PushFileAck2C_Request = -511; + + /// + /// 拉取小文件请求 + /// + public const short P_517_PullSmallFile_Request = -517; + + /// + /// 拉取确认小文件响应 + /// + public const short P_1517_PullSmallFile_Response = -1517; + + /// + /// 推送小文件请求 + /// + public const short P_518_PushSmallFile_Request = -518; + + /// + /// 推送确认小文件响应 + /// + public const short P_1518_PushSmallFile_Response = -1518; + + #endregion FileTransfer协议 500-599 + + #region Redis 600-699 + + /// + /// Redis + /// + public const short P_600_Redis_Request = -600; + + /// + /// Redis回应 + /// + public const short P_1600_Redis_Response = -1600; + + #endregion Redis 600-699 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs b/src/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs new file mode 100644 index 000000000..130e5bd90 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/WaitPingPackage.cs @@ -0,0 +1,20 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class WaitPingPackage : WaitRouterPackage + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs b/src/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs new file mode 100644 index 000000000..7e3ba1df6 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/WaitSetID.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 设置ID + /// + public class WaitSetID : WaitResult + { + /// + /// 重置Id + /// + public WaitSetID() + { + } + + /// + /// 构造函数 + /// + /// + /// + public WaitSetID(string oldID, string newID) + { + OldID = oldID; + NewID = newID; + } + + /// + /// 旧ID + /// + public string OldID { get; set; } + + /// + /// 新ID + /// + public string NewID { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs b/src/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs new file mode 100644 index 000000000..ea4fbcd48 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Common/WaitVerify.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 验证消息 + /// + public class WaitVerify : WaitResult + { + /// + /// 令箭 + /// + public string Token { get; set; } + + internal bool Handle { get; set; } + + /// + /// 元数据 + /// + public Metadata Metadata { get; set; } + + /// + /// ID + /// + public string ID { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs new file mode 100644 index 000000000..286306e43 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcClient.cs @@ -0,0 +1,627 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// HttpRpcClient + /// + public partial class HttpTouchRpcClient : HttpClientBase, IHttpTouchRpcClient + { + private readonly ActionMap m_actionMap; + private readonly RpcActor m_rpcActor; + private RpcStore m_rpcStore; + + /// + /// 创建一个HttpTouchRpcClient实例。 + /// + public HttpTouchRpcClient() + { + m_actionMap = new ActionMap(); + m_rpcActor = new RpcActor(false) + { + OutputSend = RpcActorSend, + OnHandshaked = OnRpcActorHandshaked, + OnRouting = OnRpcActorRouting, + OnReceived = OnRpcActorReceived, + OnClose = OnRpcServiceClose, + OnStreamTransfering = OnRpcActorStreamTransfering, + OnStreamTransfered = OnRpcActorStreamTransfered, + OnFileTransfering = OnRpcActorFileTransfering, + OnFileTransfered = OnRpcActorFileTransfered, + GetInvokeMethod = GetInvokeMethod, + Caller = this + }; + } + + /// + /// 服务器映射 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public string ID => m_rpcActor.ID; + + /// + public bool IsHandshaked => m_rpcActor != null && m_rpcActor.IsHandshaked; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + public override ITcpClient Connect(int timeout = 5000) + { + lock (SyncRoot) + { + if (IsHandshaked) + { + return this; + } + if (!Online) + { + base.Connect(timeout); + } + HttpRequest httpRequest = new HttpRequest(); + httpRequest.InitHeaders() + .AsMethod(TouchRpcUtility.TouchRpc); + var response = RequestContent(httpRequest); + if (response.StatusCode == "200") + { + this.SwitchProtocolToTouchRpc(); + m_rpcActor.Handshake(Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty), + Config.GetValue(TouchRpcConfigExtensions.DefaultIdProperty), default, + timeout, Config.GetValue(TouchRpcConfigExtensions.MetadataProperty)); + return this; + } + else + { + throw new Exception(response.StatusMessage); + } + } + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public void ResetID(string newId) + { + m_rpcActor.ResetID(newId); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + /// + protected override void Dispose(bool disposing) + { + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (Protocol == TouchRpcUtility.TouchRpcProtocol && byteBlock != null) + { + m_rpcActor.InputReceivedData(byteBlock); + return; + } + base.HandleReceivedData(byteBlock, requestInfo); + } + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + base.LoadConfig(config); + m_rpcActor.Logger = Container.Resolve(); + m_rpcActor.FileController = Container.GetFileResourceController(); + RootPath = Config.GetValue(TouchRpcConfigExtensions.RootPathProperty); + m_rpcActor.SerializationSelector = Config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty); + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + } + + #region 发送 + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override void Send(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override void Send(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override Task SendAsync(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override Task SendAsync(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + #endregion 发送 + + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + m_rpcActor?.Close(e.Message); + base.OnDisconnected(e); + } + + #region 小文件 + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + #endregion 小文件 + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return ActionMap.GetMethodInstance(arg); + } + + private void OnRpcActorFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), this, e)) + { + return; + } + OnFileTransfered(e); + } + + private void OnRpcActorFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), this, e)) + { + return; + } + OnFileTransfering(e); + } + + private void OnRpcActorHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), this, e)) + { + return; + } + OnHandshaked(e); + } + + private void OnRpcActorReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), this, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(protocol, byteBlock); + } + + private void OnRpcActorRouting(RpcActor actor, PackageRouterEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), this, e)) + { + return; + } + OnRouting(e); + } + + private void OnRpcActorStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), this, e)) + { + return; + } + OnStreamTransfered(e); + } + + private void OnRpcActorStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), this, e)) + { + return; + } + OnStreamTransfering(e); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + Close(arg2); + } + + private void RpcActorSend(RpcActor actor, ArraySegment[] transferBytes) + { + base.Send(transferBytes); + } + + #endregion 内部委托绑定 + + #region 事件触发 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + protected virtual void OnFileTransfered(FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + protected virtual void OnFileTransfering(FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + protected virtual void OnHandshaked(MsgEventArgs e) + { + } + + /// + /// 收到数据。 + /// + /// + /// + protected virtual void OnReceived(short protocol, ByteBlock byteBlock) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + protected virtual void OnRouting(PackageRouterEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + protected virtual void OnStreamTransfered(StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + protected virtual void OnStreamTransfering(StreamOperationEventArgs e) + { + } + + #endregion 事件触发 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActor.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs new file mode 100644 index 000000000..72c5d97d4 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcService.cs @@ -0,0 +1,600 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Http Rpc解释器 + /// + public class HttpTouchRpcService : HttpTouchRpcService + { + } + + /// + /// HttpRpcParser泛型类型 + /// + /// + public partial class HttpTouchRpcService : HttpService, IHttpTouchRpcService where TClient : HttpTouchRpcSocketClient + { + /// + /// 创建一个HttpTouchRpcService实例。 + /// + public HttpTouchRpcService() + { + m_actionMap = new ActionMap(); + m_rpcActorGroup = new RpcActorGroup + { + OnClose = OnRpcServiceClose, + OnRouting = OnRpcServiceRouting, + GetInvokeMethod = GetInvokeMethod, + OnFileTransfered = OnRpcServiceFileTransfered, + OnFileTransfering = OnRpcServiceFileTransfering, + OnFindRpcActor = OnRpcServiceFindRpcActor, + OnHandshaked = OnRpcServiceHandshaked, + OnHandshaking = OnRpcServiceHandshaking, + OnReceived = OnRpcServiceReceived, + OnStreamTransfered = OnRpcServiceStreamTransfered, + OnStreamTransfering = OnRpcServiceStreamTransfering, + OutputSend = RpcServiceOutputSend + }; + } + + #region 字段 + + private readonly ActionMap m_actionMap; + private readonly RpcActorGroup m_rpcActorGroup; + private RpcStore m_rpcStore; + + #endregion 字段 + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// 连接令箭 + /// + public string VerifyToken => Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + base.LoadConfig(config); + m_rpcActorGroup.Config = config; + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + } + + /// + protected override void OnConnecting(TClient socketClient, OperationEventArgs e) + { + socketClient.m_internalOnRpcActorInit = PrivateOnRpcActorInit; + base.OnConnecting(socketClient, e); + } + + #region 事件 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + protected virtual void OnFileTransfered(TClient client, FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + protected virtual void OnFileTransfering(TClient client, FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在验证Token时 + /// + /// 客户端 + /// 参数 + protected virtual void OnHandshaking(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 收到协议数据 + /// + /// + /// + /// + protected virtual void OnReceived(TClient client, short protocol, ByteBlock byteBlock) + { + } + + /// + /// 在需要转发路由包时。 + /// + /// + /// + protected virtual void OnRouting(TClient client, PackageRouterEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfered(TClient client, StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfering(TClient client, StreamOperationEventArgs e) + { + } + + private void PrivateOnRpcActorInit(HttpTouchRpcSocketClient client) + { + client.SetRpcActor(m_rpcActorGroup.CreateRpcActor(client)); + } + + #endregion 事件 + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullSmallFile(path, metadata, timeout, token); + } + else + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullSmallFileAsync(path, metadata, timeout, token); + } + else + { + return Task.FromResult(new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + else + { + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + else + { + return Task.FromResult(new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + #endregion 小文件 + + #region Rpc + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Ping(timeout); + } + return false; + } + + #endregion Rpc + + #region 通道 + + /// + public Channel CreateChannel(string targetId) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.CreateChannel(); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Channel CreateChannel(string targetId, int id) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.CreateChannel(id); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion 通道 + + #region File + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion File + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + TClient client = (TClient)actor.Caller; + client.Close(arg2); + } + + private void OnRpcServiceFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), client, e)) + { + return; + } + OnFileTransfered(client, e); + } + + private void OnRpcServiceFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), client, e)) + { + return; + } + OnFileTransfering(client, e); + } + + private RpcActor OnRpcServiceFindRpcActor(string arg) + { + if (TryGetSocketClient(arg, out TClient client)) + { + return client.RpcActor; + } + return null; + } + + private void OnRpcServiceHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), client, e)) + { + return; + } + OnHandshaked(client, e); + } + + private void OnRpcServiceHandshaking(RpcActor actor, VerifyOptionEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (e.Token == VerifyToken) + { + e.IsPermitOperation = true; + } + else + { + e.Message = "Token不受理"; + } + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaking), client, e)) + { + return; + } + OnHandshaking(client, e); + } + + private void OnRpcServiceReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), client, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(client, protocol, byteBlock); + } + + private void OnRpcServiceRouting(RpcActor actor, PackageRouterEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), client, e)) + { + return; + } + OnRouting(client, e); + } + + private void OnRpcServiceStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), client, e)) + { + return; + } + OnStreamTransfered(client, e); + } + + private void OnRpcServiceStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), client, e)) + { + return; + } + OnStreamTransfering(client, e); + } + + private void RpcServiceOutputSend(RpcActor actor, ArraySegment[] arg3) + { + TClient client = (TClient)actor.Caller; + client.RpcActorSend(arg3); + } + + #endregion 内部委托绑定 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActorGroup.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + + #region 发送 + + /// + public void Send(string id, short protocol, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(id, out TClient client)) + { + client.Send(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + public Task SendAsync(string id, short protocol, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(id, out TClient client)) + { + return client.SendAsync(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + #endregion 发送 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs new file mode 100644 index 000000000..ad5b8d986 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Http/HttpTouchRpcSocketClient.cs @@ -0,0 +1,429 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Http服务器辅助类 + /// + public partial class HttpTouchRpcSocketClient : HttpSocketClient, IHttpTouchRpcSocketClient + { + internal Action m_internalOnRpcActorInit; + private RpcActor m_rpcActor; + + /// + public bool IsHandshaked => m_rpcActor == null ? false : m_rpcActor.IsHandshaked; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + /// + /// 连接令箭 + /// + public string VerifyToken => Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public T Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public override void ResetID(string newID) + { + m_rpcActor.ResetID(newID); + DirectResetID(newID); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + internal void RpcActorSend(ArraySegment[] transferBytes) + { + base.Send(transferBytes); + } + + internal void SetRpcActor(RpcActor rpcActor) + { + m_rpcActor = rpcActor; + m_rpcActor.OnResetID = ThisOnResetID; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (Protocol == TouchRpcUtility.TouchRpcProtocol && byteBlock != null) + { + m_rpcActor.InputReceivedData(byteBlock); + } + else + { + base.HandleReceivedData(byteBlock, requestInfo); + } + } + + /// + /// + /// + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + m_rpcActor?.Close(e.Message); + base.OnDisconnected(e); + } + + /// + /// + /// + /// + protected override void OnReceivedHttpRequest(HttpRequest request) + { + if (request.Method == TouchRpcUtility.TouchRpc) + { + request.SafeDispose(); + InitRpcActor(); + this.DefaultSend(new HttpResponse().SetStatus().BuildAsBytes()); + return; + } + base.OnReceivedHttpRequest(request); + } + + private void InitRpcActor() + { + this.SwitchProtocolToTouchRpc(); + m_internalOnRpcActorInit?.Invoke(this); + m_rpcActor.ID = ID; + } + + private void ThisOnResetID(bool first, RpcActor rpcActor, WaitSetID waitSetID) + { + DirectResetID(waitSetID.NewID); + } + + #region 发送 + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override void Send(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override void Send(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// + /// + /// + /// + /// + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override Task SendAsync(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override Task SendAsync(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + #endregion 发送 + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs new file mode 100644 index 000000000..3745d8deb --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcClient.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IHttpRpcClient + /// + public interface IHttpTouchRpcClient : IHttpClient, IHttpRpcClientBase, IRpcParser + { + } + + /// + /// IHttpTouchRpcSocketClient + /// + public interface IHttpTouchRpcSocketClient : IHttpRpcClientBase + { + } + + /// + /// IHttpRpcClientBase + /// + public interface IHttpRpcClientBase : IHttpClientBase, IDependencyTouchRpc + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs new file mode 100644 index 000000000..6232fb2e4 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Http/Interface/IHttpTouchRpcService.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IHttpTouchRpcService + /// + public interface IHttpTouchRpcService : IHttpService, ITouchRpcService + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs b/src/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs new file mode 100644 index 000000000..739847d35 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/RpcActorGroup.cs @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActorGroup + /// + public partial class RpcActorGroup + { + #region 委托 + + /// + /// 获取调用函数 + /// + public Func GetInvokeMethod { get; set; } + + /// + /// 请求关闭 + /// + public Action OnClose { get; set; } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + public Action OnFileTransfered { get; set; } + + /// + /// 在文件传输即将进行时触发。 + /// + public Action OnFileTransfering { get; set; } + + /// + /// 查找其他RpcActor + /// + public Func OnFindRpcActor { get; set; } + + /// + /// 在完成握手连接时 + /// + public Action OnHandshaked { get; set; } + + /// + /// 握手 + /// + public Action OnHandshaking { get; set; } + + /// + /// 接收到数据 + /// + public Action OnReceived { get; set; } + + /// + /// 需要路由 + /// + public Action OnRouting { get; set; } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + public Action OnStreamTransfered { get; set; } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + public Action OnStreamTransfering { get; set; } + + /// + /// 发送数据接口 + /// + public Action[]> OutputSend { get; set; } + + #endregion 委托 + + /// + /// 配置 + /// + public TouchSocketConfig Config { get; set; } + + /// + /// RpcStore + /// + public RpcStore RpcStore { get; set; } + + /// + /// 创建RpcActor + /// + /// + /// + public RpcActor CreateRpcActor(object caller) + { + RpcActor rpcActor = new RpcActor(true) + { + FileController = this.Config.Container.GetFileResourceController(), + Logger = Config.Container.Resolve(), + Caller = caller, + RpcStore = RpcStore, + OnHandshaking = OnHandshaking, + GetInvokeMethod = GetInvokeMethod, + OnHandshaked = OnHandshaked, + OutputSend = OutputSend, + OnReceived = OnReceived, + OnClose = OnClose, + OnFindRpcActor = OnFindRpcActor, + OnRouting = OnRouting, + OnStreamTransfering = OnStreamTransfering, + OnStreamTransfered = OnStreamTransfered, + OnFileTransfering = OnFileTransfering, + OnFileTransfered = OnFileTransfered, + RootPath = Config.GetValue(TouchRpcConfigExtensions.RootPathProperty), + SerializationSelector = Config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty) + }; + return rpcActor; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs new file mode 100644 index 000000000..5c751b6e1 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcClient.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITcpRpcClient + /// + public interface ITcpTouchRpcClient : ITcpRpcClientBase, ITcpClient, IRpcParser + { + } + + /// + /// ITcpTouchRpcSocketClient + /// + public interface ITcpTouchRpcSocketClient : ITcpRpcClientBase + { + } + + /// + /// ITcpRpcClientBase + /// + public interface ITcpRpcClientBase : ITcpClientBase, IDependencyTouchRpc + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs new file mode 100644 index 000000000..ca1512847 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/Interface/ITcpTouchRpcService.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITcpTouchRpcService + /// + public interface ITcpTouchRpcService : ITcpService, ITouchRpcService + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs new file mode 100644 index 000000000..e7589bea4 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcClient.cs @@ -0,0 +1,625 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TcpTouchRpcClient + /// + public partial class TcpTouchRpcClient : TcpClientBase, ITcpTouchRpcClient + { + private readonly ActionMap m_actionMap; + + private readonly RpcActor m_rpcActor; + + private RpcStore m_rpcStore; + + /// + /// 创建一个TcpTouchRpcClient实例。 + /// + public TcpTouchRpcClient() + { + m_actionMap = new ActionMap(); + m_rpcActor = new RpcActor(false) + { + OutputSend = RpcActorSend, + OnRouting = OnRpcActorRouting, + OnHandshaked = OnRpcActorHandshaked, + OnReceived = OnRpcActorReceived, + OnClose = OnRpcServiceClose, + GetInvokeMethod = GetInvokeMethod, + OnStreamTransfering = OnRpcActorStreamTransfering, + OnStreamTransfered = OnRpcActorStreamTransfered, + OnFileTransfering = OnRpcActorFileTransfering, + OnFileTransfered = OnRpcActorFileTransfered, + Caller = this + }; + } + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public string ID => m_rpcActor.ID; + + /// + public bool IsHandshaked => m_rpcActor == null ? false : m_rpcActor.IsHandshaked; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + /// 建立Tcp连接,并且执行握手。 + /// + /// + /// + public override ITcpClient Connect(int timeout = 5000) + { + lock (SyncRoot) + { + if (IsHandshaked) + { + return this; + } + if (!Online) + { + base.Connect(timeout); + } + + m_rpcActor.Handshake(Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty), + Config.GetValue(TouchRpcConfigExtensions.DefaultIdProperty), default, + timeout, Config.GetValue(TouchRpcConfigExtensions.MetadataProperty)); + return this; + } + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public T Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public void ResetID(string id) + { + m_rpcActor.ResetID(id); + } + + #region 发送 + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override void Send(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override void Send(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override Task SendAsync(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override Task SendAsync(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + #endregion 发送 + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + + /// + protected override void Dispose(bool disposing) + { + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + m_rpcActor.InputReceivedData(byteBlock); + } + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + base.LoadConfig(config); + RootPath = config.GetValue(TouchRpcConfigExtensions.RootPathProperty); + m_rpcActor.SerializationSelector = config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty); + m_rpcActor.Logger = Container.Resolve(); + m_rpcActor.FileController = Container.GetFileResourceController(); + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + + this.SwitchProtocolToTouchRpc(); + } + + /// + protected override void OnConnecting(ConnectingEventArgs e) + { + SetDataHandlingAdapter(new FixedHeaderPackageAdapter()); + base.OnConnecting(e); + } + + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + m_rpcActor.Close(e.Message); + base.OnDisconnected(e); + } + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcActorFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), this, e)) + { + return; + } + OnFileTransfered(e); + } + + private void OnRpcActorFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), this, e)) + { + return; + } + OnFileTransfering(e); + } + + private void OnRpcActorHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), this, e)) + { + return; + } + OnHandshaked(e); + } + + private void OnRpcActorReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), this, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(protocol, byteBlock); + } + + private void OnRpcActorRouting(RpcActor actor, PackageRouterEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), this, e)) + { + return; + } + OnRouting(e); + } + + private void OnRpcActorStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), this, e)) + { + return; + } + OnStreamTransfered(e); + } + + private void OnRpcActorStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), this, e)) + { + return; + } + OnStreamTransfering(e); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + Close(arg2); + } + + private void RpcActorSend(RpcActor actor, ArraySegment[] transferBytes) + { + base.Send(transferBytes); + } + + #endregion 内部委托绑定 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActor.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + + #region 事件触发 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + protected virtual void OnFileTransfered(FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + protected virtual void OnFileTransfering(FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + protected virtual void OnHandshaked(VerifyOptionEventArgs e) + { + } + + /// + /// 收到数据。 + /// + /// + /// + protected virtual void OnReceived(short protocol, ByteBlock byteBlock) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + protected virtual void OnRouting(PackageRouterEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + protected virtual void OnStreamTransfered(StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + protected virtual void OnStreamTransfering(StreamOperationEventArgs e) + { + } + + #endregion 事件触发 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs new file mode 100644 index 000000000..e56349620 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcService.cs @@ -0,0 +1,598 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TcpTouchRpcService + /// + public class TcpTouchRpcService : TcpTouchRpcService + { + } + + /// + /// TcpTouchRpcService泛型类型 + /// + /// + public partial class TcpTouchRpcService : TcpService, ITcpTouchRpcService where TClient : TcpTouchRpcSocketClient + { + /// + /// 创建一个TcpTouchRpcService实例。 + /// + public TcpTouchRpcService() + { + m_actionMap = new ActionMap(); + m_rpcActorGroup = new RpcActorGroup + { + OnClose = OnRpcServiceClose, + OnRouting = OnRpcServiceRouting, + GetInvokeMethod = GetInvokeMethod, + OnFileTransfered = OnRpcServiceFileTransfered, + OnFileTransfering = OnRpcServiceFileTransfering, + OnFindRpcActor = OnRpcServiceFindRpcActor, + OnHandshaked = OnRpcServiceHandshaked, + OnHandshaking = OnRpcServiceHandshaking, + OnReceived = OnRpcServiceReceived, + OnStreamTransfered = OnRpcServiceStreamTransfered, + OnStreamTransfering = OnRpcServiceStreamTransfering, + OutputSend = RpcServiceOutputSend + }; + } + + #region 字段 + + private readonly ActionMap m_actionMap; + private readonly RpcActorGroup m_rpcActorGroup; + private RpcStore m_rpcStore; + + #endregion 字段 + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// 连接令箭 + /// + public string VerifyToken => Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + base.LoadConfig(config); + m_rpcActorGroup.Config = config; + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + } + + /// + /// 客户端请求连接 + /// + /// + /// + protected override void OnConnecting(TClient socketClient, OperationEventArgs e) + { + socketClient.SetRpcActor(m_rpcActorGroup.CreateRpcActor(socketClient)); + base.OnConnecting(socketClient, e); + } + + #region 事件 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + protected virtual void OnFileTransfered(TClient client, FileTransferStatusEventArgs e) + { + } + + /// + /// 在需要转发路由包时。 + /// + /// + /// + protected virtual void OnRouting(TClient client, PackageRouterEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + protected virtual void OnFileTransfering(TClient client, FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在验证Token时 + /// + /// 客户端 + /// 参数 + protected virtual void OnHandshaking(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 收到协议数据 + /// + /// + /// + /// + protected virtual void OnReceived(TClient client, short protocol, ByteBlock byteBlock) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfered(TClient client, StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。覆盖父类方法将不会触发事件和插件。 + /// + /// + /// + protected virtual void OnStreamTransfering(TClient client, StreamOperationEventArgs e) + { + } + + #endregion 事件 + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullSmallFile(path, metadata, timeout, token); + } + else + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullSmallFileAsync(path, metadata, timeout, token); + } + else + { + return Task.FromResult(new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + else + { + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + else + { + return Task.FromResult(new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + } + + #endregion 小文件 + + #region Rpc + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Invoke(targetId, method, invokeOption, ref parameters, types); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Invoke(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.InvokeAsync(method, invokeOption, parameters); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.Ping(timeout); + } + return false; + } + + #endregion Rpc + + #region 通道 + + /// + public Channel CreateChannel(string targetId) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.CreateChannel(); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Channel CreateChannel(string targetId, int id) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.CreateChannel(id); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion 通道 + + #region File + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PullFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushFile(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + if (TryGetSocketClient(targetId, out TClient client)) + { + return client.PushFileAsync(fileOperator); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion File + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + TClient client = (TClient)actor.Caller; + client.Close(arg2); + } + + private void OnRpcServiceRouting(RpcActor actor, PackageRouterEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), client, e)) + { + return; + } + OnRouting(client, e); + } + + private void OnRpcServiceFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), client, e)) + { + return; + } + OnFileTransfered(client, e); + } + + private void OnRpcServiceFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), client, e)) + { + return; + } + OnFileTransfering(client, e); + } + + private RpcActor OnRpcServiceFindRpcActor(string arg) + { + if (TryGetSocketClient(arg, out TClient client)) + { + return client.RpcActor; + } + return null; + } + + private void OnRpcServiceHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), client, e)) + { + return; + } + OnHandshaked(client, e); + } + + private void OnRpcServiceHandshaking(RpcActor actor, VerifyOptionEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (e.Token == VerifyToken) + { + e.IsPermitOperation = true; + } + else + { + e.Message = "Token不受理"; + } + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaking), client, e)) + { + return; + } + OnHandshaking(client, e); + } + + private void OnRpcServiceReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), client, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(client, protocol, byteBlock); + } + + private void OnRpcServiceStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), client, e)) + { + return; + } + OnStreamTransfered(client, e); + } + + private void OnRpcServiceStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + TClient client = (TClient)actor.Caller; + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), client, e)) + { + return; + } + OnStreamTransfering(client, e); + } + + private void RpcServiceOutputSend(RpcActor actor, ArraySegment[] arg3) + { + TClient client = (TClient)actor.Caller; + client.RpcActorSend(arg3); + } + + #endregion 内部委托绑定 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActorGroup.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + + #region 发送 + + /// + public void Send(string targetId, short protocol, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(targetId, out TClient client)) + { + client.Send(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + /// + public Task SendAsync(string targetId, short protocol, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(targetId, out TClient client)) + { + return client.SendAsync(protocol, buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + } + + #endregion 发送 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs new file mode 100644 index 000000000..c41ce30e9 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Tcp/TcpTouchRpcSocketClient.cs @@ -0,0 +1,407 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc服务器辅助类 + /// + public partial class TcpTouchRpcSocketClient : SocketClient, ITcpTouchRpcSocketClient + { + private RpcActor m_rpcActor; + + /// + public bool IsHandshaked => m_rpcActor == null ? false : m_rpcActor.IsHandshaked; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + /// + /// 验证超时时间,默认为3000ms + /// + public int VerifyTimeout => Config.GetValue(TouchRpcConfigExtensions.VerifyTimeoutProperty); + + /// + /// 连接令箭 + /// + public string VerifyToken => Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty); + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public T Invoke(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string id, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(id, method, invokeOption, parameters); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + /// + public override void ResetID(string newID) + { + m_rpcActor.ResetID(newID); + DirectResetID(newID); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + internal void RpcActorSend(ArraySegment[] transferBytes) + { + base.Send(transferBytes); + } + + internal void SetRpcActor(RpcActor rpcActor) + { + m_rpcActor = rpcActor; + m_rpcActor.OnResetID = ThisOnResetID; + } + + /// + protected override void Dispose(bool disposing) + { + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + m_rpcActor.InputReceivedData(byteBlock); + } + + /// + protected override void OnConnected(TouchSocketEventArgs e) + { + EasyTask.DelayRun(VerifyTimeout, this, (client) => + { + if (!client.IsHandshaked) + { + client.Close("验证超时"); + } + }); + m_rpcActor.ID = ID; + base.OnConnected(e); + } + + /// + protected override void OnConnecting(OperationEventArgs e) + { + this.SwitchProtocolToTouchRpc(); + base.OnConnecting(e); + } + + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + m_rpcActor.Close(e.Message); + base.OnDisconnected(e); + } + + private void ThisOnResetID(bool first, RpcActor rpcActor, WaitSetID waitSetID) + { + DirectResetID(waitSetID.NewID); + } + + #region 发送 + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override void Send(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override void Send(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + /// 不允许直接发送 + /// + /// + /// + /// + public override Task SendAsync(byte[] buffer, int offset, int length) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + /// + /// 不允许直接发送 + /// + /// + public override Task SendAsync(IList> transferBytes) + { + throw new Exception("不允许直接发送,请指定任意大于0的协议,然后发送。"); + } + + #endregion 发送 + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs new file mode 100644 index 000000000..60fd923e7 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Udp/Interface/IUdpTouchRpc.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IUdpTouchRpc + /// + public interface IUdpTouchRpc : IUdpSession, IRpcParser, IRpcClient, IDependencyTouchRpc + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs new file mode 100644 index 000000000..15f39a7d1 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Udp/UdpTouchRpc.cs @@ -0,0 +1,385 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// UDP Rpc解释器 + /// + public partial class UdpTouchRpc : UdpSessionBase, IUdpTouchRpc + { + private readonly ActionMap m_actionMap; + private readonly Timer m_timer; + private readonly ConcurrentDictionary m_udpRpcActors; + private RpcStore m_rpcStore; + private SerializationSelector m_serializationSelector; + + /// + /// 构造函数 + /// + public UdpTouchRpc() + { + m_timer = new Timer((obj) => + { + m_udpRpcActors.Remove((kv) => + { + if (--kv.Value.Tick < 0) + { + return true; + } + return false; + }); + }, null, 1000 * 30, 1000 * 30); + m_actionMap = new ActionMap(); + m_udpRpcActors = new ConcurrentDictionary(); + } + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + /// 不需要握手,所以此值一直为True。 + /// + public bool IsHandshaked => true; + + string IRpcActor.RootPath { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + /// + public RpcActor RpcActor => GetUdpRpcActor(); + + /// + public RpcStore RpcStore => m_rpcStore; + + /// + public SerializationSelector SerializationSelector => m_serializationSelector; + + /// + public Func TryCanInvoke { get; set; } + + bool IRpcActor.ChannelExisted(int id) + { + throw new NotImplementedException(); + } + + Channel IRpcActor.CreateChannel() + { + throw new NotImplementedException(); + } + + Channel IRpcActor.CreateChannel(int id) + { + throw new NotImplementedException(); + } + + Channel ITargetRpcActor.CreateChannel(string targetId) + { + throw new NotImplementedException(); + } + + Channel ITargetRpcActor.CreateChannel(string targetId, int id) + { + throw new NotImplementedException(); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + GetUdpRpcActor().Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return GetUdpRpcActor().Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return GetUdpRpcActor().Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + GetUdpRpcActor().Invoke(method, invokeOption, ref parameters, types); + } + + void ITargetRpcClient.Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + throw new NotImplementedException(); + } + + T ITargetRpcClient.Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + throw new NotImplementedException(); + } + + void ITargetRpcClient.Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + throw new NotImplementedException(); + } + + T ITargetRpcClient.Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + throw new NotImplementedException(); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return GetUdpRpcActor().InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return GetUdpRpcActor().InvokeAsync(method, invokeOption, parameters); + } + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcService) + { + m_rpcStore = rpcService; + } + + #endregion RPC解析器 + + Task ITargetRpcClient.InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + throw new NotImplementedException(); + } + + Task ITargetRpcClient.InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + throw new NotImplementedException(); + } + + /// + public bool Ping(int timeout = 5000) + { + return GetUdpRpcActor().Ping(timeout); + } + + bool ITargetRpcActor.Ping(string targetId, int timeout) + { + throw new NotImplementedException(); + } + + Result IRpcActor.PullFile(FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Result ITargetRpcActor.PullFile(string targetId, FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Task IRpcActor.PullFileAsync(FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Task ITargetRpcActor.PullFileAsync(string targetId, FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + PullSmallFileResult IRpcActor.PullSmallFile(string path, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + PullSmallFileResult ITargetRpcActor.PullSmallFile(string targetId, string path, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Task IRpcActor.PullSmallFileAsync(string path, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Task ITargetRpcActor.PullSmallFileAsync(string targetId, string path, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Result IRpcActor.PushFile(FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Result ITargetRpcActor.PushFile(string targetId, FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Task IRpcActor.PushFileAsync(FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Task ITargetRpcActor.PushFileAsync(string targetId, FileOperator fileOperator) + { + throw new NotImplementedException(); + } + + Result IRpcActor.PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Result ITargetRpcActor.PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Task IRpcActor.PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + Task ITargetRpcActor.PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata, int timeout, CancellationToken token) + { + throw new NotImplementedException(); + } + + void IRpcActor.ResetID(string newID) + { + throw new NotImplementedException(); + } + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + GetUdpRpcActor().Send(protocol, buffer, offset, length); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return GetUdpRpcActor().SendAsync(protocol, buffer, offset, length); + } + + Result IRpcActor.SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata) + { + throw new NotImplementedException(); + } + + Task IRpcActor.SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata) + { + throw new NotImplementedException(); + } + + bool IRpcActor.TrySubscribeChannel(int id, out Channel channel) + { + throw new NotImplementedException(); + } + + /// + protected override void Dispose(bool disposing) + { + m_timer.SafeDispose(); + m_udpRpcActors.Clear(); + base.Dispose(disposing); + } + + /// + protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + GetUdpRpcActor(remoteEndPoint).InputReceivedData(byteBlock); + } + + /// + protected override void LoadConfig(TouchSocketConfig config) + { + m_serializationSelector = config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty); + + if (config.GetValue(RpcConfigExtensions.RpcStoreProperty) is RpcStore rpcStore) + { + rpcStore.AddRpcParser(GetType().Name, this); + } + else + { + new RpcStore(config.Container).AddRpcParser(GetType().Name, this); + } + base.LoadConfig(config); + } + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private UdpRpcActor GetUdpRpcActor(EndPoint endPoint) + { + if (!m_udpRpcActors.TryGetValue(endPoint, out UdpRpcActor udpRpcActor)) + { + udpRpcActor = new UdpRpcActor(this, endPoint, Container.Resolve()) + { + Caller = new UdpCaller(this, endPoint), + RpcStore = m_rpcStore, + GetInvokeMethod = GetInvokeMethod, + SerializationSelector = m_serializationSelector + }; + m_udpRpcActors.TryAdd(endPoint, udpRpcActor); + } + udpRpcActor.Tick++; + return udpRpcActor; + } + + private UdpRpcActor GetUdpRpcActor() + { + if (RemoteIPHost == null) + { + throw new ArgumentNullException(nameof(RemoteIPHost)); + } + return GetUdpRpcActor(RemoteIPHost.EndPoint); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs new file mode 100644 index 000000000..eacbb7e92 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Websocket/Interface/IWSTouchRpcClient.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IWSTouchRpcClient + /// + public interface IWSTouchRpcClient : ITouchRpc, IPluginObject, IRpcParser + { + /// + /// 异步连接 + /// + /// 验证超时时间 + /// + Task ConnectAsync(int timeout = 5000); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs b/src/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs new file mode 100644 index 000000000..647a4adf7 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Components/Websocket/WSTouchRpcClient.cs @@ -0,0 +1,715 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// WSTouchRpcClient + /// + public partial class WSTouchRpcClient : DisposableObject, IWSTouchRpcClient, IRpcActor, ISenderBase + { + private readonly ActionMap m_actionMap; + private readonly ArraySegment m_buffer; + private readonly RpcActor m_rpcActor; + private ClientWebSocket m_client; + private TouchSocketConfig m_config; + private IPHost m_remoteIPHost; + private RpcStore m_rpcStore; + + /// + /// 创建一个WSTouchRpcClient实例。 + /// + public WSTouchRpcClient() + { + m_buffer = new ArraySegment(new byte[1024 * 64]); + m_actionMap = new ActionMap(); + m_rpcActor = new RpcActor(false) + { + OutputSend = RpcActorSend, + OnRouting = OnRpcActorRouting, + OnHandshaked = OnRpcActorHandshaked, + OnReceived = OnRpcActorReceived, + GetInvokeMethod = GetInvokeMethod, + OnClose = OnRpcServiceClose, + OnStreamTransfering = OnRpcActorStreamTransfering, + OnStreamTransfered = OnRpcActorStreamTransfered, + OnFileTransfering = OnRpcActorFileTransfering, + OnFileTransfered = OnRpcActorFileTransfered, + Caller = this + }; + } + + /// + /// 方法映射表 + /// + public ActionMap ActionMap { get => m_actionMap; } + + /// + public bool CanSend => m_client.State == WebSocketState.Open; + + /// + /// 客户端配置 + /// + public TouchSocketConfig Config => m_config; + + /// + public IContainer Container { get; private set; } + + /// + /// 断开连接 + /// + public DisconnectEventHandler Disconnected { get; set; } + + /// + public string ID => m_rpcActor.ID; + + /// + public bool IsHandshaked => m_rpcActor.IsHandshaked; + + /// + /// 最后活动时间 + /// + public DateTime LastActiveTime { get; private set; } + + /// + public ILog Logger => m_rpcActor.Logger; + + /// + public IPluginsManager PluginsManager { get; private set; } + + /// + public IPHost RemoteIPHost => m_remoteIPHost; + + /// + public string RootPath { get => m_rpcActor.RootPath; set => m_rpcActor.RootPath = value; } + + /// + public RpcActor RpcActor => m_rpcActor; + + /// + public RpcStore RpcStore { get => m_rpcStore; } + + /// + public SerializationSelector SerializationSelector => m_rpcActor.SerializationSelector; + + /// + public Func TryCanInvoke { get => m_rpcActor.TryCanInvoke; set => m_rpcActor.TryCanInvoke = value; } + + /// + public bool UsePlugin { get; private set; } + + /// + public bool ChannelExisted(int id) + { + return m_rpcActor.ChannelExisted(id); + } + + /// + /// 关闭 + /// + /// + public void Close(string msg) + { + if (m_client?.State != WebSocketState.Open) + { + return; + } + m_client.SafeDispose(); + m_rpcActor.SafeDispose(); + BreakOut($"调用{nameof(Close)}", true); + } + + /// + public async Task ConnectAsync(int timeout = 5000) + { + if (!RemoteIPHost.IsUri) + { + throw new Exception("RemoteIPHost必须为Uri格式。"); + } + if (m_client == null || m_client.State != WebSocketState.Open) + { + m_client.SafeDispose(); + m_client = new ClientWebSocket(); + await m_client.ConnectAsync(RemoteIPHost.Uri, default); + + _ = BeginReceive(null); + } + + if (IsHandshaked) + { + return; + } + + m_rpcActor.Handshake(Config.GetValue(TouchRpcConfigExtensions.VerifyTokenProperty), + Config.GetValue(TouchRpcConfigExtensions.DefaultIdProperty), default, + timeout, Config.GetValue(TouchRpcConfigExtensions.MetadataProperty)); + } + + /// + public Channel CreateChannel() + { + return m_rpcActor.CreateChannel(); + } + + /// + public Channel CreateChannel(int id) + { + return m_rpcActor.CreateChannel(id); + } + + /// + public Channel CreateChannel(string targetId) + { + return m_rpcActor.CreateChannel(targetId); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + return m_rpcActor.CreateChannel(targetId, id); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + return m_rpcActor.Ping(targetId, timeout); + } + + /// + public bool Ping(int timeout = 5000) + { + return m_rpcActor.Ping(timeout); + } + + /// + public void ResetID(string newID) + { + m_rpcActor.ResetID(newID); + } + + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + m_rpcActor.Send(protocol, buffer, offset, length); + } + + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return m_rpcActor.SendAsync(protocol, buffer, offset, length); + } + + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStream(stream, streamOperator, metadata); + } + + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = null) + { + return m_rpcActor.SendStreamAsync(stream, streamOperator, metadata); + } + + /// + /// 配置 + /// + /// + /// + public IWSTouchRpcClient Setup(string ipHost) + { + TouchSocketConfig config = new TouchSocketConfig(); + config.SetRemoteIPHost(new IPHost(ipHost)); + return Setup(config); + } + + /// + /// 配置 + /// + /// + /// + public IWSTouchRpcClient Setup(TouchSocketConfig clientConfig) + { + m_config = clientConfig; + LoadConfig(m_config); + return this; + } + + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + return m_rpcActor.TrySubscribeChannel(id, out channel); + } + + /// + protected override void Dispose(bool disposing) + { + m_client.SafeDispose(); + m_rpcActor.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TouchSocketConfig config) + { + if (config == null) + { + throw new Exception("配置文件为空"); + } + m_remoteIPHost = config.GetValue(Sockets.TouchSocketConfigExtension.RemoteIPHostProperty); + Container = config.Container; + UsePlugin = config.IsUsePlugin; + PluginsManager = config.PluginsManager; + + m_rpcActor.Logger = Container.Resolve(); + m_rpcActor.FileController = Container.GetFileResourceController(); + RootPath = Config.GetValue(TouchRpcConfigExtensions.RootPathProperty); + m_rpcActor.SerializationSelector = Config.GetValue(TouchRpcConfigExtensions.SerializationSelectorProperty); + } + + /// + /// 已断开连接。 + /// + /// + protected virtual void OnDisconnected(DisconnectEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnDisconnected), this, e)) + { + return; + } + Disconnected?.Invoke(this, e); + } + + private async Task BeginReceive(ByteBlock byteBlock) + { + try + { + byteBlock ??= new ByteBlock(); + var result = await m_client.ReceiveAsync(m_buffer, default); + if (result.Count == 0) + { + BreakOut("远程终端主动关闭", false); + } + LastActiveTime = DateTime.Now; + byteBlock.Write(m_buffer.Array, 0, result.Count); + if (result.EndOfMessage) + { + try + { + m_rpcActor.InputReceivedData(byteBlock); + } + catch + { + } + finally + { + byteBlock.SafeDispose(); + } + await BeginReceive(null); + } + else + { + await BeginReceive(byteBlock); + } + } + catch (Exception ex) + { + BreakOut(ex.Message, false); + } + } + + private void BreakOut(string msg, bool manual) + { + m_client.SafeDispose(); + m_rpcActor.SafeDispose(); + OnDisconnected(new DisconnectEventArgs(manual, msg)); + } + + #region 小文件 + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFile(path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(targetId, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PullSmallFileAsync(path, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return m_rpcActor.PushSmallFileAsync(savePath, fileInfo, metadata, timeout, token); + } + + #endregion 小文件 + + #region FileTransfer + + /// + public Result PullFile(FileOperator fileOperator) + { + return m_rpcActor.PullFile(fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PullFileAsync(targetId, fileOperator); + } + + /// + public Result PushFile(FileOperator fileOperator) + { + return m_rpcActor.PushFile(fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFile(targetId, fileOperator); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return m_rpcActor.PushFileAsync(targetId, fileOperator); + } + + #endregion FileTransfer + + #region RPC + + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(method, invokeOption, parameters); + } + + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(method, invokeOption, ref parameters, types); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, parameters); + } + + /// + public void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(targetId, method, invokeOption, ref parameters, types); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + /// + public Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(targetId, method, invokeOption, parameters); + } + + #endregion RPC + + #region 内部委托绑定 + + private MethodInstance GetInvokeMethod(string arg) + { + return m_actionMap.GetMethodInstance(arg); + } + + private void OnRpcActorFileTransfered(RpcActor actor, FileTransferStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfered), this, e)) + { + return; + } + OnFileTransfered(e); + } + + private void OnRpcActorFileTransfering(RpcActor actor, FileOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnFileTransfering), this, e)) + { + return; + } + OnFileTransfering(e); + } + + private void OnRpcActorHandshaked(RpcActor actor, VerifyOptionEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnHandshaked), this, e)) + { + return; + } + OnHandshaked(e); + } + + private void OnRpcActorReceived(RpcActor actor, short protocol, ByteBlock byteBlock) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnReceivedProtocolData), this, new ProtocolDataEventArgs(protocol, byteBlock))) + { + return; + } + + OnReceived(protocol, byteBlock); + } + + private void OnRpcActorRouting(RpcActor actor, PackageRouterEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnRouting), this, e)) + { + return; + } + OnRouting(e); + } + + private void OnRpcActorStreamTransfered(RpcActor actor, StreamStatusEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfered), this, e)) + { + return; + } + OnStreamTransfered(e); + } + + private void OnRpcActorStreamTransfering(RpcActor actor, StreamOperationEventArgs e) + { + if (UsePlugin && PluginsManager.Raise(nameof(ITouchRpcPlugin.OnStreamTransfering), this, e)) + { + return; + } + OnStreamTransfering(e); + } + + private void OnRpcServiceClose(RpcActor actor, string arg2) + { + Close(arg2); + } + + private async void RpcActorSend(RpcActor actor, ArraySegment[] transferBytes) + { + LastActiveTime = DateTime.Now; + for (int i = 0; i < transferBytes.Length; i++) + { + if (i == transferBytes.Length - 1) + { + await m_client.SendAsync(transferBytes[i], WebSocketMessageType.Binary, true, CancellationToken.None); + } + else + { + await m_client.SendAsync(transferBytes[i], WebSocketMessageType.Binary, false, CancellationToken.None); + } + } + } + + #endregion 内部委托绑定 + + #region 事件触发 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + protected virtual void OnFileTransfered(FileTransferStatusEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + protected virtual void OnFileTransfering(FileOperationEventArgs e) + { + } + + /// + /// 在完成握手连接时 + /// + /// + protected virtual void OnHandshaked(VerifyOptionEventArgs e) + { + } + + /// + /// 收到数据。 + /// + /// + /// + protected virtual void OnReceived(short protocol, ByteBlock byteBlock) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + protected virtual void OnRouting(PackageRouterEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + protected virtual void OnStreamTransfered(StreamStatusEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + protected virtual void OnStreamTransfering(StreamOperationEventArgs e) + { + } + + #endregion 事件触发 + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is TouchRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcStore) + { + m_rpcActor.RpcStore = rpcStore; + m_rpcStore = rpcStore; + } + + #endregion RPC解析器 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs b/src/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs new file mode 100644 index 000000000..3a4f023ef --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Config/TouchRpcConfigExtensions.cs @@ -0,0 +1,284 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc配置扩展 + /// + public static class TouchRpcConfigExtensions + { + /// + /// 默认使用Id。 + /// + public static readonly DependencyProperty DefaultIdProperty = + DependencyProperty.Register("DefaultId", typeof(TouchRpcConfigExtensions), null); + + /// + /// TouchClient连接时的元数据, 所需类型 + /// + public static readonly DependencyProperty MetadataProperty = DependencyProperty.Register("Metadata", typeof(TouchRpcConfigExtensions), null); + + /// + /// 序列化转换器, 所需类型 + /// + public static readonly DependencyProperty SerializationSelectorProperty = + DependencyProperty.Register("SerializationSelector", typeof(TouchRpcConfigExtensions), new DefaultSerializationSelector()); + + /// + /// 验证超时时间,默认为3000ms, 所需类型 + /// + public static readonly DependencyProperty VerifyTimeoutProperty = + DependencyProperty.Register("VerifyTimeout", typeof(TouchRpcConfigExtensions), 3000); + + /// + /// 连接令箭,当为null或空时,重置为默认值“rrqm”, 所需类型 + /// + public static readonly DependencyProperty VerifyTokenProperty = + DependencyProperty.Register("VerifyToken", typeof(TouchRpcConfigExtensions), "rrqm"); + + /// + /// 设置默认的使用Id。仅在TouchRpc组件适用。 + /// + /// 使用该功能时,仅在服务器的Handshaking之后生效。且如果id重复,则会连接失败。 + /// + /// + /// + /// + /// + public static TouchSocketConfig SetDefaultId(this TouchSocketConfig config, string value) + { + config.SetValue(DefaultIdProperty, value); + return config; + } + + /// + /// 心跳频率,默认为间隔2000ms,3次。(设置为null时禁止心跳) + /// 仅适用于TouchRpcClient系类 + /// + /// + /// + /// + [Obsolete("该方法已被弃用。请使用插件UseTouchRpcHeartbeat替代。", true)] + public static TouchSocketConfig SetHeartbeatFrequency(this TouchSocketConfig config, object value) + { + throw new NotImplementedException(); + } + + /// + /// 设置TouchClient连接时的元数据 + /// 仅适用于TouchRpcClient系类 + /// + /// + /// + /// + public static TouchSocketConfig SetMetadata(this TouchSocketConfig config, Metadata value) + { + config.SetValue(MetadataProperty, value); + return config; + } + + /// + /// 设置序列化转换器 + /// + /// + /// + /// + public static TouchSocketConfig SetSerializationSelector(this TouchSocketConfig config, SerializationSelector value) + { + config.SetValue(SerializationSelectorProperty, value); + return config; + } + + /// + /// 验证超时时间,默认为3000ms. + /// 该配置仅有效 + /// + /// + /// + /// + public static TouchSocketConfig SetVerifyTimeout(this TouchSocketConfig config, int value) + { + config.SetValue(VerifyTimeoutProperty, value); + return config; + } + + /// + /// 连接令箭,当为null或空时,重置为默认值“rrqm” + /// + /// + /// + /// + public static TouchSocketConfig SetVerifyToken(this TouchSocketConfig config, string value) + { + config.SetValue(VerifyTokenProperty, value); + return config; + } + + #region FileTransfer + + /// + /// 根目录 + /// 所需类型 + /// + public static readonly DependencyProperty RootPathProperty = DependencyProperty.Register("RootPath", typeof(TouchRpcConfigExtensions), string.Empty); + + /// + /// 设置根路径 + /// + /// + /// + /// + public static TouchSocketConfig SetRootPath(this TouchSocketConfig config, string value) + { + config.SetValue(RootPathProperty, value); + return config; + } + + #endregion FileTransfer + + #region 创建TcpTouchRpc + + /// + /// 构建TcpTouchRpc类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithTcpTouchRpcClient(this TouchSocketConfig config) where TClient : ITcpTouchRpcClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建TcpTouchRpc类客户端,并连接 + /// + /// + /// + public static TcpTouchRpcClient BuildWithTcpTouchRpcClient(this TouchSocketConfig config) + { + return BuildWithTcpTouchRpcClient(config); + } + + /// + /// 构建TcpTouchRpc类服务器,并启动。 + /// + /// + /// + /// + public static TService BuildWithTcpTouchRpcService(this TouchSocketConfig config) where TService : ITcpTouchRpcService + { + TService service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建TcpTouchRpc类服务器,并启动。 + /// + /// + /// + public static TcpTouchRpcService BuildWithTcpTouchRpcService(this TouchSocketConfig config) + { + return BuildWithTcpTouchRpcService(config); + } + + #endregion 创建TcpTouchRpc + + #region 创建HttpTouchRpc + + /// + /// 构建HttpTouchRpc类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithHttpTouchRpcClient(this TouchSocketConfig config) where TClient : IHttpTouchRpcClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建HttpTouchRpc类客户端,并连接 + /// + /// + /// + public static HttpTouchRpcClient BuildWithHttpTouchRpcClient(this TouchSocketConfig config) + { + return BuildWithHttpTouchRpcClient(config); + } + + /// + /// 构建HttpTouchRpc类服务器,并启动。 + /// + /// + /// + /// + public static TService BuildWithHttpTouchRpcService(this TouchSocketConfig config) where TService : IHttpTouchRpcService + { + TService service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建HttpTouchRpc类服务器,并启动。 + /// + /// + /// + public static HttpTouchRpcService BuildWithHttpTouchRpcService(this TouchSocketConfig config) + { + return BuildWithHttpTouchRpcService(config); + } + + #endregion 创建HttpTouchRpc + + #region 创建UdpTouchRpc + + /// + /// 构建UdpTouchRpc类 + /// + /// + /// + /// + public static TClient BuildWithUdpTouchRpc(this TouchSocketConfig config) where TClient : IUdpTouchRpc + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Start(); + return client; + } + + /// + /// 构建UdpTouchRpc类客户端 + /// + /// + /// + public static UdpTouchRpc BuildWithUdpTouchRpc(this TouchSocketConfig config) + { + return BuildWithUdpTouchRpc(config); + } + + #endregion 创建UdpTouchRpc + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs b/src/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs new file mode 100644 index 000000000..6ac1de9c7 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Enum/RouteType.cs @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 路由类型 + /// + public readonly struct RouteType + { + private readonly string value; + + /// + /// 路由类型 + /// + /// + public RouteType(string value) + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentException($"“{nameof(value)}”不能为 null 或空。", nameof(value)); + } + + this.value = value.ToLower().Trim(); + } + + /// + /// 判断RouteType是相等。 + /// + /// + /// + /// + public static bool operator ==(RouteType a, RouteType b) + { + return a.value == b.value; + } + + /// + /// 判断RouteType不相等。 + /// + /// + /// + /// + public static bool operator !=(RouteType a, RouteType b) + { + return a.value != b.value; + } + + /// + /// + /// + /// + /// + public override bool Equals(object obj) + { + if (obj is RouteType type) + { + return this == type; + } + return false; + } + + /// + /// + /// + /// + public override int GetHashCode() + { + return this.value.GetHashCode(); + } + + /// + /// + /// + /// + public override string ToString() => value; + + /// + /// 一个Ping探测路由包 + /// + public static readonly RouteType Ping = new RouteType("Ping"); + + /// + /// 创建通道路由包。 + /// + public static readonly RouteType CreateChannel = new RouteType("CreateChannel"); + + /// + /// Rpc调用的路由包 + /// + public static readonly RouteType Rpc = new RouteType("Rpc"); + + /// + /// 拉取文件的路由包 + /// + public static readonly RouteType PullFile = new RouteType("PullFile"); + + /// + /// 加载远程流数据 + /// + public static readonly RouteType LoadRemoteStream = new RouteType("LoadRemoteStream"); + + /// + /// 推送文件的路由包 + /// + public static readonly RouteType PushFile = new RouteType("PushFile"); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs b/src/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs new file mode 100644 index 000000000..68b7cd576 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Enum/TransferFlags.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 传输标识 + /// + [Flags] + public enum TransferFlags : byte + { + /// + /// 无任何标识 + /// + None = 0, + + /// + /// 断点续传。 + /// 使用该标识时,会使用文件长度验证续传的有效性。如果需要,也可以附加验证。 + /// + BreakpointResume = 1, + + /// + /// MD5验证。该标识在文件传输完成时,也会再次验证文件长度。 + /// + MD5Verify = 2, + + /// + /// 当传输失败时,删除所有缓存文件。 + /// 注意:当启用断点续传时,该标识无效 + /// + DeleteWhenFail = 4 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs b/src/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs new file mode 100644 index 000000000..e78e90068 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Enum/TransferType.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 传输类型 + /// + [Flags] + public enum TransferType + { + /// + /// 推送 + /// + Push = 0, + + /// + /// 拉取 + /// + Pull = 1, + + /// + /// 分块推送 + /// + SectionPush = 2, + + /// + /// 分块拉取 + /// + SectionPull = 4, + + /// + /// 小文件推送 + /// + SmallPush = 8, + + /// + /// 小文件拉取 + /// + SmallPull = 16 + } + + /// + /// TransferTypeExtension + /// + public static class TransferTypeExtension + { + /// + /// 表示当前传输类型是否属于其中的一种。 + /// + /// + /// + public static bool IsPull(this TransferType transferType) + { + return transferType == TransferType.Pull || transferType == TransferType.SmallPull || transferType == TransferType.SectionPull; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs new file mode 100644 index 000000000..e01498202 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/FileOperationEventArgs.cs @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 操作文件事件类 + /// + public class FileOperationEventArgs : MsgEventArgs + { + private string m_savePath; + private string m_resourcePath; + private readonly Metadata m_metadata; + + /// + /// FileOperationEventArgs + /// + /// + /// + /// + public FileOperationEventArgs(TransferType transferType, FileOperator fileOperator, RemoteFileInfo fileInfo) + { + FileOperator = fileOperator; + TransferType = transferType; + FileInfo = fileInfo; + } + + /// + /// FileOperationEventArgs + /// + /// + /// + /// + public FileOperationEventArgs(TransferType transferType, Metadata metadata, RemoteFileInfo fileInfo) + { + FileOperator = default; + TransferType = transferType; + FileInfo = fileInfo; + m_metadata = metadata; + } + + /// + /// 存放路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// 但是必须包含文件名及扩展名。 + /// + public string SavePath + { + get => FileOperator == null ? m_savePath : FileOperator.SavePath; + set + { + if (FileOperator == null) + { + m_savePath = value; + } + else + { + FileOperator.SavePath = value; + } + } + } + + /// + /// 请求文件路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// + public string ResourcePath + { + get => FileOperator == null ? m_resourcePath : FileOperator.ResourcePath; + set + { + if (FileOperator == null) + { + m_resourcePath = value; + } + else + { + FileOperator.ResourcePath = value; + } + } + } + + /// + /// 元数据 + /// + public Metadata Metadata => FileOperator == null ? m_metadata : FileOperator.Metadata; + + /// + /// 文件操作器 + /// + public FileOperator FileOperator { get; private set; } + + /// + /// 文件信息 + /// + public RemoteFileInfo FileInfo { get; private set; } + + /// + /// 传输标识 + /// + public TransferFlags Flags { get => FileOperator == null ? TransferFlags.None : FileOperator.Flags; } + + /// + /// 传输类型 + /// + public TransferType TransferType { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs new file mode 100644 index 000000000..25d696018 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/FileTransferStatusEventArgs.cs @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件传输状态 + /// + public class FileTransferStatusEventArgs : FileOperationEventArgs + { + /// + /// FileTransferStatusEventArgs + /// + /// + /// + /// + /// + public FileTransferStatusEventArgs(TransferType transferType, Metadata metadata, RemoteFileInfo fileInfo, Result result) + : base(transferType, metadata, fileInfo) + { + Result = result; + } + + /// + /// FileTransferStatusEventArgs + /// + /// + /// + /// + /// + public FileTransferStatusEventArgs(TransferType transferType, Result result, RemoteFileInfo fileInfo, FileOperator fileOperator) + : base(transferType, fileOperator, fileInfo) + { + Result = result; + } + + /// + /// FileTransferStatusEventArgs + /// + /// + /// + public FileTransferStatusEventArgs(Result result, FileOperationEventArgs args) + : base(args.TransferType, args.FileOperator, args.FileInfo) + { + Result = result; + } + + /// + /// 结果 + /// + public Result Result { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs new file mode 100644 index 000000000..a43f12d1c --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/HttpVerifyOptionEventArgs.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Http验证 + /// + public class HttpVerifyOptionEventArgs : HttpContextEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public HttpVerifyOptionEventArgs(HttpContext context, string token) : base(context) + { + Token = token; + } + + /// + /// 验证令箭 + /// + public string Token { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs new file mode 100644 index 000000000..1ac24a43c --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/PackageRouterEventArgs.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// PackageRouterEventArgs + /// + public class PackageRouterEventArgs : MsgEventArgs + { + /// + /// PackageRouterEventArgs + /// + /// + /// + public PackageRouterEventArgs(RouteType routerType, RouterPackage package) + { + RouterType = routerType; + Package = package; + } + + /// + /// 路由类型 + /// + public RouteType RouterType { get; private set; } + + /// + /// 路由数据包。一般为不完全数据,仅包含基本的路由信息。 + /// + public RouterPackage Package { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs new file mode 100644 index 000000000..ab93b93df --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/ProtocolDataEventArgs.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 协议数据事件 + /// + public class ProtocolDataEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public ProtocolDataEventArgs(short protocol, ByteBlock byteBlock) + { + Protocol = protocol; + ByteBlock = byteBlock; + } + + /// + /// 数据流,实际解析时应当偏移两个字节 + /// + public ByteBlock ByteBlock { get; } + + /// + /// 协议 + /// + public short Protocol { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs new file mode 100644 index 000000000..22c9e9362 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamEventArgs.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.IO; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 流事件参数 + /// + public class StreamEventArgs : MsgEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public StreamEventArgs(Metadata metadata, StreamInfo streamInfo) + { + Metadata = metadata; + StreamInfo = streamInfo; + } + + /// + /// 用于接收流的容器 + /// + public Stream Bucket { get; set; } + + /// + /// 用于可传输的元数据 + /// + public Metadata Metadata { get; private set; } + + /// + /// 流信息 + /// + public StreamInfo StreamInfo { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs new file mode 100644 index 000000000..0e395f0f1 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamOperationEventArgs.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 接收流数据 + /// + public class StreamOperationEventArgs : StreamEventArgs + { + /// + /// 构造函数 + /// + /// + /// + /// + public StreamOperationEventArgs(StreamOperator streamOperator, Metadata metadata, StreamInfo streamInfo) : base(metadata, streamInfo) + { + StreamOperator = streamOperator ?? throw new ArgumentNullException(nameof(streamOperator)); + IsPermitOperation = true; + } + + /// + /// 流操作 + /// + public StreamOperator StreamOperator { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs new file mode 100644 index 000000000..1894073c3 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/StreamStatusEventArgs.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 具有返回状态的流 + /// + public class StreamStatusEventArgs : StreamEventArgs + { + private Result result; + + /// + /// 结果 + /// + public Result Result => result; + + /// + /// 构造函数 + /// + /// + /// + /// + public StreamStatusEventArgs(Result result, Metadata metadata, StreamInfo streamInfo) : base(metadata, streamInfo) + { + this.result = result; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs new file mode 100644 index 000000000..9e7b1e531 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/EventArgs/VerifyOptionEventArgs.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 连接验证 + /// + public class VerifyOptionEventArgs : MsgEventArgs + { + /// + /// 令箭 + /// + public string Token { get; private set; } + + /// + /// 元数据 + /// + public Metadata Metadata { get; private set; } + + /// + /// 构造函数 + /// + /// + /// + public VerifyOptionEventArgs(string token, Metadata metadata) + { + Token = token; + Metadata = metadata; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs b/src/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs new file mode 100644 index 000000000..06be32bd8 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Exceptions/ProtocolException.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 协议异常 + /// + [Serializable] + public class ProtocolException : Exception + { + /// + /// 构造函数 + /// + public ProtocolException() + { } + + /// + /// 构造函数 + /// + /// + public ProtocolException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public ProtocolException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected ProtocolException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs b/src/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs new file mode 100644 index 000000000..489343906 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Exceptions/TokenVerifyException.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Token验证异常 + /// + [Serializable] + public class TokenVerifyException : Exception + { + /// + /// 构造函数 + /// + public TokenVerifyException() + { } + + /// + /// 构造函数 + /// + /// + public TokenVerifyException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public TokenVerifyException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected TokenVerifyException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs b/src/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs new file mode 100644 index 000000000..7eb85843d --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Exceptions/TouchRpcExceptions.cs @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc添加方法键异常 + /// + public class RpcKeyException : Exception + { + /// + ///构造函数 + /// + public RpcKeyException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcKeyException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcKeyException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcKeyException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + + /// + /// Rpc无注册异常 + /// + public class RpcNoRegisterException : Exception + { + /// + ///构造函数 + /// + public RpcNoRegisterException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcNoRegisterException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcNoRegisterException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcNoRegisterException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + + /// + /// 序列化异常类 + /// + public class RpcSerializationException : Exception + { + /// + ///构造函数 + /// + public RpcSerializationException() : base() { } + + /// + ///构造函数 + /// + /// + public RpcSerializationException(string message) : base(message) { } + + /// + ///构造函数 + /// + /// + /// + public RpcSerializationException(string message, System.Exception inner) : base(message, inner) { } + + /// + ///构造函数 + /// + /// + /// + protected RpcSerializationException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs b/src/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs new file mode 100644 index 000000000..b99394dbf --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Extensions/RpcActorExtensions.cs @@ -0,0 +1,244 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActorExtensions + /// + public static partial class RpcActorExtensions + { + #region 尝试发送 + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + /// + /// + public static bool TrySend(this TRpcActor rpcActor, short protocol, byte[] buffer, int offset, int length) where TRpcActor : IRpcActor + { + try + { + rpcActor.Send(protocol, buffer, offset, length); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + public static bool TrySend(this TRpcActor rpcActor, short protocol, byte[] buffer) where TRpcActor : IRpcActor + { + try + { + rpcActor.Send(protocol, buffer, 0, buffer.Length); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + public static bool TrySend(this TRpcActor rpcActor, short protocol) where TRpcActor : IRpcActor + { + try + { + rpcActor.Send(protocol); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + public static bool TrySend(this TRpcActor rpcActor, short protocol, ByteBlock byteBlock) where TRpcActor : IRpcActor + { + try + { + rpcActor.Send(protocol, byteBlock); + return true; + } + catch + { + return false; + } + } + + #endregion 尝试发送 + + #region 尝试异步发送 + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task TrySendAsync(this TRpcActor rpcActor, short protocol, byte[] buffer, int offset, int length) where TRpcActor : IRpcActor + { + try + { + await rpcActor.SendAsync(protocol, buffer, offset, length); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + /// + public static async Task TrySendAsync(this TRpcActor rpcActor, short protocol, byte[] buffer) where TRpcActor : IRpcActor + { + try + { + await rpcActor.SendAsync(protocol, buffer, 0, buffer.Length); + return true; + } + catch + { + return false; + } + } + + /// + /// 尝试发送 + /// + /// + /// + /// + /// + public static async Task TrySendAsync(this TRpcActor rpcActor, short protocol) where TRpcActor : IRpcActor + { + try + { + await rpcActor.SendAsync(protocol); + return true; + } + catch + { + return false; + } + } + + #endregion 尝试异步发送 + + #region 发送 + + /// + /// + /// + /// + /// + /// + /// + public static void Send(this TRpcActor rpcActor, short protocol, byte[] buffer) where TRpcActor : IRpcActor + { + rpcActor.Send(protocol, buffer, 0, buffer.Length); + } + + /// + /// + /// + /// + /// + /// + public static void Send(this TRpcActor rpcActor, short protocol) where TRpcActor : IRpcActor + { + rpcActor.Send(protocol, TouchSocketCoreUtility.ZeroBytes, 0, 0); + } + + /// + /// + /// + /// + /// + /// + /// + public static void Send(this TRpcActor rpcActor, short protocol, ByteBlock byteBlock) where TRpcActor : IRpcActor + { + rpcActor.Send(protocol, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public static Task SendAsync(this TRpcActor rpcActor, short protocol, byte[] buffer) where TRpcActor : IRpcActor + { + return rpcActor.SendAsync(protocol, buffer, 0, buffer.Length); + } + + /// + /// + /// + /// + /// + /// + /// + public static Task SendAsync(this TRpcActor rpcActor, short protocol) where TRpcActor : IRpcActor + { + return rpcActor.SendAsync(protocol, TouchSocketCoreUtility.ZeroBytes, 0, 0); + } + + #endregion 发送 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs b/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs new file mode 100644 index 000000000..f86c3aa75 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcContainerExtension.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcContainerExtension + /// + public static class TouchRpcContainerExtension + { + /// + /// 设置文件资源控制器。 + /// + /// + /// + public static IContainer SetFileResourceController(this IContainer container, IFileResourceController value) + { + return container.RegisterSingleton(value); + } + + /// + /// 设置文件资源控制器。 + /// + /// + /// + public static IContainer SetFileResourceController(this IContainer container) where T : class, IFileResourceController + { + return container.RegisterSingleton(); + } + + /// + /// 默认的全局资源控制器。 + /// + public static readonly FileResourceController FileController = new FileResourceController(); + + /// + /// 获取文件资源控制器。如果没有注册的话,会新建一个 + /// + /// + public static IFileResourceController GetFileResourceController(this IContainer container) + { + if (container.IsRegistered(typeof(IFileResourceController))) + { + return container.Resolve(); + } + return FileController; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs b/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs new file mode 100644 index 000000000..22bfb802a --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcExtensions.cs @@ -0,0 +1,334 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RPC辅助扩展 + /// + public static partial class TouchRpcExtensions + { + /// + /// 创建一个直接向目标地址请求的Rpc客户端。 + /// + /// + /// + public static IRpcClient CreateIDRpcClient(this TRpcActor client, string targetId) where TRpcActor : IRpcActor + { + return new IDRpcActor(targetId, client); + } + + #region 批量传输(弃用) + + /// + /// 批量拉取文件 + /// + /// 终端 + /// 并行数量 + /// 批量操作器 + [Obsolete("此方法因为特殊原因已被弃用。")] + public static void PullFiles(this IRpcActor client, int multipleCount, FileOperator[] fileOperators) + { + if (multipleCount < 1) + { + throw new Exception("并行数量不能小于1。"); + } + + if (fileOperators is null) + { + throw new ArgumentNullException(nameof(fileOperators)); + } + + int index = 0; + int t = 0; + int complatedLen = 0; + List> results = new List>(); + + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) => + { + int st = multipleCount - t; + for (int i = 0; i < st; i++) + { + if (index == fileOperators.Length) + { + break; + } + Task result = client.PullFileAsync(fileOperators[index]); + results.Add(result); + index++; + t++; + } + + List> cr = new List>(); + + foreach (var item in results) + { + if (item.IsCompleted) + { + cr.Add(item); + t--; + complatedLen++; + if (complatedLen == fileOperators.Length) + { + loop.Dispose(); + } + } + } + + foreach (var item in cr) + { + results.Remove(item); + } + }); + + loopAction.Run(); + } + + /// + /// 异步批量拉取文件 + /// + /// 终端 + /// 并行数量 + /// 批量操作器 + [Obsolete("此方法因为特殊原因已被弃用。")] + public static void PullFilesAsync(this IRpcActor client, int multipleCount, FileOperator[] fileOperators) + { + if (multipleCount < 1) + { + throw new Exception("并行数量不能小于1。"); + } + + if (fileOperators is null) + { + throw new ArgumentNullException(nameof(fileOperators)); + } + + int index = 0; + int t = 0; + int complatedLen = 0; + List> results = new List>(); + + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) => + { + int st = multipleCount - t; + for (int i = 0; i < st; i++) + { + if (index == fileOperators.Length) + { + break; + } + Task result = client.PullFileAsync(fileOperators[index]); + results.Add(result); + index++; + t++; + } + + List> cr = new List>(); + + foreach (var item in results) + { + if (item.IsCompleted) + { + cr.Add(item); + t--; + complatedLen++; + if (complatedLen == fileOperators.Length) + { + loop.Dispose(); + } + } + } + + foreach (var item in cr) + { + results.Remove(item); + } + }); + + loopAction.RunAsync(); + } + + /// + /// 批量推送文件 + /// + /// 终端 + /// 并行数量 + /// 批量操作器 + [Obsolete("此方法因为特殊原因已被弃用。")] + public static void PushFiles(this IRpcActor client, int multipleCount, FileOperator[] fileOperators) + { + if (multipleCount < 1) + { + throw new Exception("并行数量不能小于1。"); + } + + if (fileOperators is null) + { + throw new ArgumentNullException(nameof(fileOperators)); + } + + int index = 0; + int t = 0; + int complatedLen = 0; + List> results = new List>(); + + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) => + { + int st = multipleCount - t; + for (int i = 0; i < st; i++) + { + if (index == fileOperators.Length) + { + break; + } + Task result = client.PushFileAsync(fileOperators[index]); + results.Add(result); + index++; + t++; + } + + List> cr = new List>(); + + foreach (var item in results) + { + if (item.IsCompleted) + { + cr.Add(item); + t--; + complatedLen++; + if (complatedLen == fileOperators.Length) + { + loop.Dispose(); + } + } + } + + foreach (var item in cr) + { + results.Remove(item); + } + }); + + loopAction.Run(); + } + + /// + /// 异步批量推送文件 + /// + /// 终端 + /// 并行数量 + /// 批量操作器 + [Obsolete("此方法因为特殊原因已被弃用。")] + public static void PushFilesAsync(this IRpcActor client, int multipleCount, FileOperator[] fileOperators) + { + if (multipleCount < 1) + { + throw new Exception("并行数量不能小于1。"); + } + + if (fileOperators is null) + { + throw new ArgumentNullException(nameof(fileOperators)); + } + + int index = 0; + int t = 0; + int complatedLen = 0; + List> results = new List>(); + + LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) => + { + int st = multipleCount - t; + for (int i = 0; i < st; i++) + { + if (index == fileOperators.Length) + { + break; + } + Task result = client.PushFileAsync(fileOperators[index]); + results.Add(result); + index++; + t++; + } + + List> cr = new List>(); + + foreach (var item in results) + { + if (item.IsCompleted) + { + cr.Add(item); + t--; + complatedLen++; + if (complatedLen == fileOperators.Length) + { + loop.Dispose(); + } + } + } + + foreach (var item in cr) + { + results.Remove(item); + } + }); + + loopAction.RunAsync(); + } + + #endregion 批量传输(弃用) + + /// + /// 转化Protocol协议标识为TouchRpc + /// + /// + public static void SwitchProtocolToTouchRpc(this ITcpClientBase client) + { + client.SetDataHandlingAdapter(new FixedHeaderPackageAdapter()); + client.Protocol = TouchRpcUtility.TouchRpcProtocol; + } + + /// + /// 转为ResultCode + /// + /// + /// + public static ResultCode ToResultCode(this ChannelStatus channelStatus) + { + switch (channelStatus) + { + case ChannelStatus.Default: + return ResultCode.Default; + + case ChannelStatus.Overtime: + return ResultCode.Overtime; + + case ChannelStatus.Cancel: + return ResultCode.Canceled; + + case ChannelStatus.Completed: + return ResultCode.Success; + + case ChannelStatus.Moving: + case ChannelStatus.Disposed: + default: + return ResultCode.Error; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs b/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs new file mode 100644 index 000000000..c2f463170 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcPluginsManagerExtension.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.TouchRpc; +using TouchSocket.Sockets; + +namespace TouchSocket.Core +{ + /// + /// TouchRpcPluginsManagerExtension + /// + public static partial class TouchRpcPluginsManagerExtension + { + /// + /// 使用Redis插件。仅:TouchRpc组成员会生效。 + /// + /// + /// + public static RedisPlugin UseRedis(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + + /// + /// TouchRpc心跳。仅客户端适用。 + /// + /// 默认心跳每3秒进行一次。最大失败3次即判定为断开连接。 + /// + /// + /// + /// + /// + public static TouchRpcHeartbeatPlugin UseTouchRpcHeartbeat(this IPluginsManager pluginsManager) where TClient : class, ITcpClientBase, IDependencyTouchRpc + { + return pluginsManager.Add>(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs b/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs new file mode 100644 index 000000000..09d0972dd --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Extensions/TouchRpcServiceExtension.cs @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcServiceExtension + /// + public static class TouchRpcServiceExtension + { + /// + public static void Send(this ITouchRpcService service, string targetId, short protocol, byte[] buffer) + { + service.Send(targetId, protocol, buffer, 0, buffer.Length); + } + + /// + public static void Send(this ITouchRpcService service, string targetId, short protocol) + { + service.Send(targetId, protocol, TouchSocketCoreUtility.ZeroBytes, 0, 0); + } + + /// + public static void Send(this ITouchRpcService service, string targetId, short protocol, ByteBlock byteBlock) + { + service.Send(targetId, protocol, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + public static Task SendAsync(this ITouchRpcService service, string targetId, short protocol, byte[] buffer) + { + return service.SendAsync(targetId, protocol, buffer, 0, buffer.Length); + } + + /// + public static Task SendAsync(this ITouchRpcService service, string targetId, short protocol) + { + return service.SendAsync(targetId, protocol, TouchSocketCoreUtility.ZeroBytes, 0, 0); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs b/src/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs new file mode 100644 index 000000000..0ae0eee72 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/FileOperator.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件传输操作器 + /// + public class FileOperator : RemoteFileOperator + { + /// + /// 传输标识 + /// + public TransferFlags Flags { get; set; } + + /// + /// 存放路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// 但是必须包含文件名及扩展名。 + /// + public string SavePath { get; set; } + + /// + /// 资源文件路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// + public string ResourcePath { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs b/src/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs new file mode 100644 index 000000000..b3b2f99fc --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/FileResourceController.cs @@ -0,0 +1,132 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件资源控制器。 + /// + public class FileResourceController : IFileResourceController + { + + /// + public virtual void GetFileInfo(string path, bool md5, ref T fileInfo) where T : RemoteFileInfo + { + FileInfo info = new FileInfo(path); + fileInfo.FullName = info.FullName; + fileInfo.Name = info.Name; + fileInfo.Attributes = info.Attributes; + fileInfo.CreationTime = info.CreationTime; + fileInfo.Length = info.Length; + fileInfo.LastAccessTime = info.LastAccessTime; + fileInfo.LastWriteTime = info.LastWriteTime; + + if (md5) + { + using FileStream fileStream = File.OpenRead(path); + fileInfo.MD5 = FileUtility.GetStreamMD5(fileStream); + } + } + + /// + public virtual string GetFullPath(string root, string path) + { + if (path.IsNullOrEmpty()) + { + return string.Empty; + } + if (Path.IsPathRooted(path)) + { + return path; + } + else + { + return Path.GetFullPath(Path.Combine(root, path)); + } + } + + /// + public virtual bool TryReadTempInfo(string path, TransferFlags flags, ref TouchRpcFileInfo info) + { + if (flags == TransferFlags.None) + { + return false; + } + string filePath = path + ".rrqm"; + string tempPath = path + ".temp"; + if (File.Exists(filePath) && File.Exists(tempPath)) + { + try + { + FileInfo fileInfo = new FileInfo(filePath); + TouchRpcFileInfo tempInfo = SerializeConvert.JsonDeserializeFromString(File.ReadAllText(tempPath)); + if (flags.HasFlag(TransferFlags.BreakpointResume)) + { + if (tempInfo.Length != info.Length) + { + return false; + } + if (flags.HasFlag(TransferFlags.MD5Verify)) + { + if ((tempInfo.MD5 == info.MD5 && info.MD5.HasValue())) + { + info.Position = tempInfo.Position; + return true; + } + } + else + { + info.Position = tempInfo.Position; + return true; + } + } + else + { + return false; + } + } + catch + { + return false; + } + } + return false; + } + + /// + public virtual int ReadAllBytes(FileInfo fileInfo, byte[] buffer) + { + using (FileStorageReader reader = FilePool.GetReader(fileInfo)) + { + return reader.Read(buffer, 0, buffer.Length); + } + } + + /// + public virtual void WriteAllBytes(FileInfo fileInfo, byte[] buffer, int offset, int length) + { + FileUtility.Delete(fileInfo.FullName); + using (var writer = FilePool.GetWriter(fileInfo)) + { + writer.Write(buffer, offset, length); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs b/src/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs new file mode 100644 index 000000000..7daf4b9be --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/IFileResourceController.cs @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; +using System.IO; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件资源控制器。 + /// + public interface IFileResourceController + { + /// + /// 获取文件信息 + /// + /// + /// + /// + /// + void GetFileInfo(string path, bool md5, ref T fileInfo) where T : RemoteFileInfo; + + /// + /// 获取全路径 + /// + /// + /// + /// + string GetFullPath(string root, string path); + + /// + /// 读取缓存文件信息 + /// + /// + /// + /// + /// + bool TryReadTempInfo(string path, TransferFlags flags, ref TouchRpcFileInfo info); + + /// + /// 读取文件的所有数据 + /// + /// + /// + /// + int ReadAllBytes(FileInfo fileInfo, byte[] buffer); + + /// + /// 写入数据到文件 + /// + /// + /// + /// + /// + void WriteAllBytes(FileInfo fileInfo, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs b/src/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs new file mode 100644 index 000000000..8dd017f8d --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/PullSmallFileResult.cs @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// PullSmallFileResult + /// + public class PullSmallFileResult : ResultBase + { + /// + /// 初始化PullSmallFileResult + /// + /// + /// + public PullSmallFileResult(ResultCode resultCode, string message) : base(resultCode, message) + { + } + + /// + /// 初始化PullSmallFileResult + /// + /// + public PullSmallFileResult(byte[] bytes) : base(ResultCode.Success) + { + Value = bytes; + } + + /// + /// 初始化PullSmallFileResult + /// + /// + public PullSmallFileResult(ResultCode resultCode) : base(resultCode) + { + } + + /// + /// 实际的文件数据 + /// + public byte[] Value { get; private set; } + + /// + /// 将拉取的数据保存为文件。 + /// + /// + /// + /// + public Result Save(string path, bool overwrite = true) + { + try + { + if (overwrite) + { + FileUtility.Delete(path); + } + using (FileStorageWriter writer = FilePool.GetWriter(path)) + { + writer.Write(Value); + return Result.Success; + } + } + catch (Exception ex) + { + return new Result(ex); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs b/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs new file mode 100644 index 000000000..89b9c5e4a --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileInfo.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.IO; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RemoteFileInfo + /// + public class RemoteFileInfo : RemoteFileSystemInfo + { + /// + /// 初始化一个RemoteFileInfo + /// + public RemoteFileInfo() + { + } + + /// + /// 从FileInfo初始化一个RemoteFileInfo + /// + /// + public RemoteFileInfo(FileInfo fileInfo) + { + FullName = fileInfo.FullName; + Name = fileInfo.Name; + Length = fileInfo.Length; + Attributes = fileInfo.Attributes; + CreationTime = fileInfo.CreationTime; + LastWriteTime = fileInfo.LastWriteTime; + LastAccessTime = fileInfo.LastAccessTime; + } + + /// + /// 文件MD5 + /// + public string MD5 { get; set; } + + /// + /// 文件大小 + /// + public long Length { get; set; } + + /// + public override void Package(ByteBlock byteBlock) + { + base.Package(byteBlock); + byteBlock.Write(MD5); + byteBlock.Write(Length); + } + + /// + public override void Unpackage(ByteBlock byteBlock) + { + base.Unpackage(byteBlock); + MD5 = byteBlock.ReadString(); + Length = byteBlock.ReadInt64(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs b/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs new file mode 100644 index 000000000..778823eca --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileOperator.cs @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 远程文件控制器。 + /// + public class RemoteFileOperator : StreamOperator + { + internal void SetFileCompletedLength(long completedLength) + { + this.completedLength = completedLength; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs b/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs new file mode 100644 index 000000000..ea913bef3 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/RemoteFileSystemInfo.cs @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 远程文件系统信息 + /// + public abstract class RemoteFileSystemInfo : PackageBase + { + /// + /// 目录或文件的名称。 + /// + public string Name { get; set; } + + /// + /// 目录或文件的完整目录。 + /// + public string FullName { get; set; } + + /// + /// 上次写入当前文件或目录的时间 + /// + public DateTime LastWriteTime { get; set; } + + /// + /// 上次访问当前文件或目录的时间 + /// + public DateTime LastAccessTime { get; set; } + + /// + /// 当前文件或目录的创建时间 + /// + public DateTime CreationTime { get; set; } + + /// + /// 当前文件或目录的特性 + /// + public FileAttributes Attributes { get; set; } + + /// + public override void Package(ByteBlock byteBlock) + { + byteBlock.Write(LastWriteTime); + byteBlock.Write(LastAccessTime); + byteBlock.Write(CreationTime); + byteBlock.Write((int)Attributes); + byteBlock.Write(FullName); + byteBlock.Write(Name); + } + + /// + public override void Unpackage(ByteBlock byteBlock) + { + LastWriteTime = byteBlock.ReadDateTime(); + LastAccessTime = byteBlock.ReadDateTime(); + CreationTime = byteBlock.ReadDateTime(); + Attributes = (FileAttributes)byteBlock.ReadInt32(); + FullName = byteBlock.ReadString(); + Name = byteBlock.ReadString(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs b/src/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs new file mode 100644 index 000000000..2610349b9 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileInfo.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcFileInfo + /// + public class TouchRpcFileInfo : RemoteFileInfo + { + /// + /// 流位置 + /// + public long Position { get; set; } + + /// + public override void Package(ByteBlock byteBlock) + { + base.Package(byteBlock); + byteBlock.Write(Position); + } + + /// + public override void Unpackage(ByteBlock byteBlock) + { + base.Unpackage(byteBlock); + Position = byteBlock.ReadInt64(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs b/src/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs new file mode 100644 index 000000000..9e9c739d5 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/TouchRpcFileStream.cs @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件流 + /// + internal class TouchRpcFileStream : DisposableObject + { + private static int m_saveInterval = 1000; + + private TouchRpcFileInfo m_fileInfo; + + private FileStorageWriter m_fileWriter; + private TimeSpan m_lastTime; + + private string m_path; + + private bool m_resume; + + /// + /// 进度保存时间,默认1000毫秒。 + /// + public static int SaveInterval + { + get => m_saveInterval; + set + { + if (value < 0) + { + value = 0; + } + m_saveInterval = value; + } + } + + public FileStorageWriter FileWriter => m_fileWriter; + + public static TouchRpcFileStream Create(string path, ref TouchRpcFileInfo fileInfo, bool resume) + { + TouchRpcFileStream stream = new TouchRpcFileStream(); + stream.m_fileWriter = FilePool.GetWriter(path + ".rrqm"); + stream.m_fileWriter.Position = fileInfo.Position; + stream.m_fileInfo = fileInfo; + stream.m_path = path; + stream.m_resume = resume; + return stream; + } + + public void FinishStream() + { + if (m_fileWriter.Position != m_fileInfo.Length) + { + throw new Exception("已完成传输,但是文件长度不对。"); + } + if (File.Exists(m_path)) + { + File.Delete(m_path); + } + m_fileWriter.SafeDispose(); + + string rrqmPath = m_path + ".rrqm"; + string tempPath = m_path + ".temp"; + + if (!SpinWait.SpinUntil(() => + { + File.Move(rrqmPath, m_path); + if (File.Exists(tempPath)) + { + File.Delete(tempPath); + } + if (File.Exists(m_path)) + { + return true; + } + return false; + }, 5000)) + { + throw new IOException("已完成传输,但是在保存路径并未检测到文件存在。"); + } + } + + public void Write(byte[] buffer, int offset, int length) + { + m_fileWriter.Write(buffer, offset, length); + SaveProgress(); + } + + protected override void Dispose(bool disposing) + { + m_fileWriter.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// 保存进度 + /// + private void SaveProgress() + { + if (m_resume) + { + if (DateTime.Now.TimeOfDay - m_lastTime > TimeSpan.FromMilliseconds(m_saveInterval)) + { + try + { + File.WriteAllText(m_path + ".temp", m_fileInfo.ToJson()); + m_lastTime = DateTime.Now.TimeOfDay; + } + catch + { + } + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs b/src/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs new file mode 100644 index 000000000..3cf6c3439 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/WaitFileInfoPackage.cs @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 文件信息 + /// + internal class WaitFileInfoPackage : WaitRouterPackage + { + /// + /// 元数据 + /// + public Metadata Metadata { get; set; } + + /// + /// 文件信息 + /// + public TouchRpcFileInfo FileInfo { get; set; } + + /// + /// 传输标识 + /// + public TransferFlags Flags { get; set; } + + /// + /// 存放路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// 但是必须包含文件名及扩展名。 + /// + public string SavePath { get; set; } + + /// + /// 请求文件路径, + /// 可输入绝对路径,也可以输入相对路径。 + /// + public string ResourcePath { get; set; } + + /// + /// 事件Code + /// + public int EventHashCode { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.WritePackage(Metadata); + byteBlock.WritePackage(FileInfo); + byteBlock.Write((byte)Flags); + byteBlock.Write(SavePath); + byteBlock.Write(ResourcePath); + byteBlock.Write(EventHashCode); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + this.Metadata = byteBlock.ReadPackage(); + this.FileInfo = byteBlock.ReadPackage(); + this.Flags = (TransferFlags)byteBlock.ReadByte(); + this.SavePath = byteBlock.ReadString(); + this.ResourcePath = byteBlock.ReadString(); + this.EventHashCode = byteBlock.ReadInt32(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs b/src/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs new file mode 100644 index 000000000..3095e597a --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/WaitPushFileAckPackage.cs @@ -0,0 +1,20 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class WaitPushFileAckPackage : WaitRouterPackage + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs b/src/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs new file mode 100644 index 000000000..bef738a29 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/WaitSmallFilePackage.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class WaitSmallFilePackage : WaitRouterPackage + { + public byte[] Data { get; set; } + public RemoteFileInfo FileInfo { get; set; } + public int Len { get; set; } + public Metadata Metadata { get; set; } + public string Path { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(Path); + byteBlock.WritePackage(Metadata); + byteBlock.WritePackage(FileInfo); + byteBlock.WriteBytesPackage(Data, 0, Len); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + Path = byteBlock.ReadString(); + Metadata = byteBlock.ReadPackage(); + FileInfo = byteBlock.ReadPackage(); + Data = byteBlock.ReadBytesPackage(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs b/src/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs new file mode 100644 index 000000000..8cd7fcbcf --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/File/WaitTransferPackage.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 等待传输 + /// + internal class WaitTransferPackage : WaitRouterPackage + { + /// + /// 通道标识 + /// + public int ChannelID { get; set; } + + /// + /// 路径 + /// + public string Path { get; set; } + + /// + /// 流位置 + /// + public long Position { get; set; } + + /// + /// 事件Code + /// + public int EventHashCode { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write(ChannelID); + byteBlock.Write(Path); + byteBlock.Write(Position); + byteBlock.Write(EventHashCode); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + this.ChannelID = byteBlock.ReadInt32(); + this.Path = byteBlock.ReadString(); + this.Position = byteBlock.ReadInt64(); + this.EventHashCode = byteBlock.ReadInt32(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs b/src/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs new file mode 100644 index 000000000..dcb3775a9 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/MessageQueue/DeliverEventArgs.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 投递事件 + /// + public class DeliverEventArgs : EventArgs + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs b/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs new file mode 100644 index 000000000..6f98c33f2 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClient.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// MessageQueueClient + /// + public abstract class MessageQueueClient + { + /// + /// 序列化转换器。 + /// + public BytesConverter Converter { get; set; } + + ///// + ///// 队列 + ///// + ///// + ///// + ///// + ///// + //public abstract void Publish(string queue, byte[] buffer,int offset,int length); + + //public abstract void Subscribe(string queue,Action<> data); + } + + internal class InternalMessageQueueClient : MessageQueueClient + { + private RpcActor m_rpcActor; + + public InternalMessageQueueClient(RpcActor rpcActor, BytesConverter converter) + { + m_rpcActor = rpcActor; + Converter = converter; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs b/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs new file mode 100644 index 000000000..66f9297f2 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueueClientExtensions.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// MessageQueueClientExtensions + /// + public static class MessageQueueClientExtensions + { + /// + /// 获取或设置MessageQueueClient的注入键。 + /// + public static readonly DependencyProperty MessageQueueClientProperty = + DependencyProperty.Register("MessageQueueClient", typeof(MessageQueueClientExtensions), null); + + /// + /// 获取MessageQueueClient + /// + /// + /// + /// + /// + public static MessageQueueClient GetMessageQueueClient(this TClient client) where TClient : IDependencyTouchRpc, IDependencyObject + { + return client.GetValue(MessageQueueClientProperty); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs b/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs new file mode 100644 index 000000000..5ea3ecc2b --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/MessageQueue/MessageQueuePlugin.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// MessageQueuePlugin + /// + public class MessageQueuePlugin : TouchRpcPluginBase + { + /// + /// 定义元素的序列化和反序列化。 + /// 注意:Byte[]类型不用考虑。内部单独会做处理。 + /// + public BytesConverter Converter { get; private set; } = new BytesConverter(); + + /// + /// 定义元素的序列化和反序列化。 + /// 注意:Byte[]类型不用考虑。内部单独会做处理。 + /// + /// + public void SetConverter(BytesConverter converter) + { + Converter = converter; + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(IDependencyTouchRpc client, VerifyOptionEventArgs e) + { + client.SetValue(MessageQueueClientExtensions.MessageQueueClientProperty, new InternalMessageQueueClient(client.RpcActor, Converter)); + base.OnHandshaked(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedProtocolData(IDependencyTouchRpc client, ProtocolDataEventArgs e) + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs b/src/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs new file mode 100644 index 000000000..97c8549a8 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Plugins/ITouchRpcPlugin.cs @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITouchRpcPlugin + /// + public partial interface ITouchRpcPlugin : IPlugin + { + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + [AsyncRaiser] + void OnFileTransfered(ITouchRpc client, FileTransferStatusEventArgs e); + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + /// + Task OnFileTransferedAsync(ITouchRpc client, FileTransferStatusEventArgs e); + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + [AsyncRaiser] + void OnFileTransfering(ITouchRpc client, FileOperationEventArgs e); + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + /// + Task OnFileTransferingAsync(ITouchRpc client, FileOperationEventArgs e); + + /// + /// 在完成握手连接时。 + /// + /// + /// + [AsyncRaiser] + void OnHandshaked(ITouchRpc client, VerifyOptionEventArgs e); + + /// + /// 当需要转发路由包时 + /// + /// + /// + [AsyncRaiser] + void OnRouting(ITouchRpc client, PackageRouterEventArgs e); + + /// + /// 当需要转发路由包时 + /// + /// + /// + Task OnRoutingAsync(ITouchRpc client, PackageRouterEventArgs e); + + /// + /// 在完成握手连接时。 + /// + /// + /// + /// + Task OnHandshakedAsync(ITouchRpc client, VerifyOptionEventArgs e); + + /// + /// 在验证Token时 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e); + + /// + /// 在验证Token时 + /// + /// + /// + /// + Task OnHandshakingAsync(ITouchRpc client, VerifyOptionEventArgs e); + + /// + /// 收到协议数据 + /// + /// + /// + [AsyncRaiser] + void OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e); + + /// + /// 收到协议数据 + /// + /// + /// + /// + Task OnReceivedProtocolDataAsync(ITouchRpc client, ProtocolDataEventArgs e); + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// 当流数据传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + [AsyncRaiser] + void OnStreamTransfered(ITouchRpc client, StreamStatusEventArgs e); + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// 当流数据传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + /// + Task OnStreamTransferedAsync(ITouchRpc client, StreamStatusEventArgs e); + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + [AsyncRaiser] + void OnStreamTransfering(ITouchRpc client, StreamOperationEventArgs e); + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + /// + Task OnStreamTransferingAsync(ITouchRpc client, StreamOperationEventArgs e); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs b/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs new file mode 100644 index 000000000..d1e1cafd4 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcActionPlugin.cs @@ -0,0 +1,182 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 具有委托能力的插件 + /// + public sealed partial class TouchRpcActionPlugin : TouchRpcPluginBase where TClient : ITouchRpc + { + private Action m_fileTransfered; + private Action m_fileTransfering; + private Action m_handshaked; + private Action m_handshaking; + private Action m_receivedProtocolData; + private Action m_streamTransfered; + private Action m_streamTransfering; + + /// + /// SetFileTransfered + /// + /// + /// + public TouchRpcActionPlugin SetFileTransfered(Action action) + { + m_fileTransfered = action; + return this; + } + + /// + /// SetFileTransfering + /// + /// + /// + public TouchRpcActionPlugin SetFileTransfering(Action action) + { + m_fileTransfering = action; + return this; + } + + /// + /// SetHandshaked + /// + /// + /// + public TouchRpcActionPlugin SetHandshaked(Action action) + { + m_handshaked = action; + return this; + } + + /// + /// SetHandshaking + /// + /// + /// + public TouchRpcActionPlugin SetHandshaking(Action action) + { + m_handshaking = action; + return this; + } + + /// + /// SetReceivedProtocolData + /// + /// + /// + public TouchRpcActionPlugin SetReceivedProtocolData(Action action) + { + m_receivedProtocolData = action; + return this; + } + + /// + /// SetStreamTransfered + /// + /// + /// + public TouchRpcActionPlugin SetStreamTransfered(Action action) + { + m_streamTransfered = action; + return this; + } + + /// + /// SetStreamTransfering + /// + /// + /// + public TouchRpcActionPlugin SetStreamTransfering(Action action) + { + m_streamTransfering = action; + return this; + } + + #region 重写 + + /// + /// + /// + /// + /// + protected override void OnFileTransfered(ITouchRpc client, FileTransferStatusEventArgs e) + { + m_fileTransfered?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnFileTransfering(ITouchRpc client, FileOperationEventArgs e) + { + m_fileTransfering?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(ITouchRpc client, VerifyOptionEventArgs e) + { + m_handshaked?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e) + { + m_handshaking?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e) + { + m_receivedProtocolData?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnStreamTransfered(ITouchRpc client, StreamStatusEventArgs e) + { + m_streamTransfered?.Invoke((TClient)client, e); + } + + /// + /// + /// + /// + /// + protected override void OnStreamTransfering(ITouchRpc client, StreamOperationEventArgs e) + { + m_streamTransfering?.Invoke((TClient)client, e); + } + + #endregion 重写 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs b/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs new file mode 100644 index 000000000..c00ef2f4a --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcHeartbeatPlugin.cs @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpcHeartbeatPlugin + /// + [SingletonPlugin] + public class TouchRpcHeartbeatPlugin : TouchRpcPluginBase where TClient : IDependencyObject, ITcpClientBase, IDependencyTouchRpc + { + private TClient m_client; + + private Thread m_thread; + + /// + /// 连接失败次数。当成功连接时,会重置为0。 + /// + public int FailedCount { get; private set; } + + /// + /// 心跳间隔。默认3秒。 + /// + public TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(3); + + /// + /// 最大失败次数,默认3。 + /// + public int MaxFailCount { get; set; } = 3; + + /// + /// 心跳间隔。默认3秒。 + /// + /// + /// + public TouchRpcHeartbeatPlugin SetInterval(TimeSpan value) + { + if (value == TimeSpan.Zero || value == TimeSpan.MaxValue || value == TimeSpan.MinValue) + { + throw new InvalidTimeZoneException("设置的时间必须为有效值。"); + } + Interval = value; + return this; + } + + /// + /// 最大失败次数,默认3。 + /// + /// + /// + public TouchRpcHeartbeatPlugin SetMaxFailCount(int value) + { + MaxFailCount = value; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + m_client = client; + if (m_thread == null) + { + m_thread = new Thread(ThreadHeartbeat) + { + IsBackground = true, + Name = $"HeartbeatThread" + }; + m_thread.Start(); + } + base.OnHandshaked(client, e); + } + + private void ThreadHeartbeat(object obj) + { + while (true) + { + if (DisposedValue) + { + return; + } + if (m_client.IsHandshaked && (DateTime.Now.TimeOfDay - m_client.GetLastActiveTime().TimeOfDay > Interval)) + { + if (m_client.Ping()) + { + FailedCount = 0; + } + else + { + FailedCount++; + if (FailedCount > MaxFailCount) + { + m_client.SafeClose("自动心跳失败次数达到最大,已断开连接。"); + } + } + } + + Thread.Sleep(Interval); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs b/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs new file mode 100644 index 000000000..367ac7a13 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Plugins/TouchRpcPluginBase.cs @@ -0,0 +1,275 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpc插件基类 + /// + public class TouchRpcPluginBase : TouchRpcPluginBase + { + } + + /// + /// TouchRpc插件基类 + /// + public partial class TouchRpcPluginBase : TcpPluginBase, ITouchRpcPlugin + { + #region 虚函数 + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + protected virtual void OnFileTransfered(TClient client, FileTransferStatusEventArgs e) + { + } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + /// + /// + /// + protected virtual Task OnFileTransferedAsync(TClient client, FileTransferStatusEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + protected virtual void OnFileTransfering(TClient client, FileOperationEventArgs e) + { + } + + /// + /// 在文件传输即将进行时触发。 + /// + /// + /// + /// + protected virtual Task OnFileTransferingAsync(TClient client, FileOperationEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在完成握手连接时。 + /// + /// + /// + protected virtual void OnHandshaked(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在完成握手连接时。 + /// + /// + /// + /// + protected virtual Task OnHandshakedAsync(TClient client, VerifyOptionEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在验证Token时 + /// + /// + /// + protected virtual void OnHandshaking(TClient client, VerifyOptionEventArgs e) + { + } + + /// + /// 在验证Token时 + /// + /// + /// + /// + protected virtual Task OnHandshakingAsync(TClient client, VerifyOptionEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 收到协议数据 + /// + /// + /// + protected virtual void OnReceivedProtocolData(TClient client, ProtocolDataEventArgs e) + { + } + + /// + /// 收到协议数据 + /// + /// + /// + /// + protected virtual Task OnReceivedProtocolDataAsync(TClient client, ProtocolDataEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当需要转发路由包时 + /// + /// + /// + protected virtual void OnRouting(TClient client, PackageRouterEventArgs e) + { + } + + /// + /// 当需要转发路由包时 + /// + /// + /// + /// + protected virtual Task OnRoutingAsync(TClient client, PackageRouterEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + /// + protected virtual void OnStreamTransfered(TClient client, StreamStatusEventArgs e) + { + } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + /// + /// + /// + protected virtual Task OnStreamTransferedAsync(TClient client, StreamStatusEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + protected virtual void OnStreamTransfering(TClient client, StreamOperationEventArgs e) + { + } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + /// + /// + /// + protected virtual Task OnStreamTransferingAsync(TClient client, StreamOperationEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数 + + void ITouchRpcPlugin.OnFileTransfered(ITouchRpc client, FileTransferStatusEventArgs e) + { + OnFileTransfered((TClient)client, e); + } + + Task ITouchRpcPlugin.OnFileTransferedAsync(ITouchRpc client, FileTransferStatusEventArgs e) + { + return OnFileTransferedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnFileTransfering(ITouchRpc client, FileOperationEventArgs e) + { + OnFileTransfering((TClient)client, e); + } + + Task ITouchRpcPlugin.OnFileTransferingAsync(ITouchRpc client, FileOperationEventArgs e) + { + return OnFileTransferingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnHandshaked(ITouchRpc client, VerifyOptionEventArgs e) + { + OnHandshaked((TClient)client, e); + } + + Task ITouchRpcPlugin.OnHandshakedAsync(ITouchRpc client, VerifyOptionEventArgs e) + { + return OnHandshakedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnHandshaking(ITouchRpc client, VerifyOptionEventArgs e) + { + OnHandshaking((TClient)client, e); + } + + Task ITouchRpcPlugin.OnHandshakingAsync(ITouchRpc client, VerifyOptionEventArgs e) + { + return OnHandshakingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnReceivedProtocolData(ITouchRpc client, ProtocolDataEventArgs e) + { + OnReceivedProtocolData((TClient)client, e); + } + + Task ITouchRpcPlugin.OnReceivedProtocolDataAsync(ITouchRpc client, ProtocolDataEventArgs e) + { + return OnReceivedProtocolDataAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnRouting(ITouchRpc client, PackageRouterEventArgs e) + { + OnRouting((TClient)client, e); + } + + Task ITouchRpcPlugin.OnRoutingAsync(ITouchRpc client, PackageRouterEventArgs e) + { + return OnRoutingAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnStreamTransfered(ITouchRpc client, StreamStatusEventArgs e) + { + OnStreamTransfered((TClient)client, e); + } + + Task ITouchRpcPlugin.OnStreamTransferedAsync(ITouchRpc client, StreamStatusEventArgs e) + { + return OnStreamTransferedAsync((TClient)client, e); + } + + void ITouchRpcPlugin.OnStreamTransfering(ITouchRpc client, StreamOperationEventArgs e) + { + OnStreamTransfering((TClient)client, e); + } + + Task ITouchRpcPlugin.OnStreamTransferingAsync(ITouchRpc client, StreamOperationEventArgs e) + { + return OnStreamTransferingAsync((TClient)client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs new file mode 100644 index 000000000..9a03dc063 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisClient.cs @@ -0,0 +1,576 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 具有远程键值存贮的操作端。 + /// + public abstract class RedisClient : ICache + { + /// + /// 序列化转换器。 + /// + public BytesConverter Converter { get; set; } + + /// + /// 超时设定。默认30000ms + /// + public int Timeout { get; set; } = 30 * 1000; + + /// + /// + /// + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public bool Add(string key, TValue value, int duration = 60000) + { + var cache = new CacheEntry(key) + { + Duration = TimeSpan.FromSeconds(duration) + }; + if (!(value is byte[])) + { + cache.Value = Converter.ConvertTo(value); + } + return AddCache(cache); + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public bool AddCache(ICacheEntry entity) + { + if (ContainsCache(entity.Key)) + { + return false; + } + else + { + return SetCache(entity); + } + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task AddCacheAsync(ICacheEntry entity) + { + return EasyTask.Run(() => + { + return AddCache(entity); + }); + } + + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract void ClearCache(); + + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task ClearCacheAsync() + { + return EasyTask.Run(() => + { + ClearCache(); + }); + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract bool ContainsCache(string key); + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task ContainsCacheAsync(string key) + { + return EasyTask.Run(() => + { + return ContainsCache(key); + }); + } + + /// + /// 获取缓存的键值对。 + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public TValue Get(string key) + { + if (TryGet(key, out var cache)) + { + return cache; + } + return default; + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract ICacheEntry GetCache(string key); + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task> GetCacheAsync(string key) + { + return EasyTask.Run(() => + { + return GetCache(key); + }); + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract bool RemoveCache(string key); + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task RemoveCacheAsync(string key) + { + return EasyTask.Run(() => + { + return RemoveCache(key); + }); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public bool Set(string key, TValue value, int duration = 60000) + { + var cache = new CacheEntry(key) + { + Duration = TimeSpan.FromSeconds(duration) + }; + if (value is byte[] bytes) + { + cache.Value = bytes; + } + else + { + cache.Value = Converter.ConvertTo(value); + } + return SetCache(cache); + } + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public abstract bool SetCache(ICacheEntry entity); + + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public Task SetCacheAsync(ICacheEntry entity) + { + return EasyTask.Run(() => + { + return SetCache(entity); + }); + } + + /// + /// 获取指定键的值。 + /// + /// + /// + /// + /// + /// 参数为空 + /// 操作超时 + /// 其他异常 + public bool TryGet(string key, out TValue value) + { + var cache = GetCache(key); + + if (cache != null) + { + if (cache.Value is null) + { + value = default; + return true; + } + if (cache.Value is TValue value1) + { + value = value1; + return true; + } + value = (TValue)Converter.ConvertFrom(cache.Value, typeof(TValue)); + return true; + } + value = default; + return false; + } + } + + /// + /// RedisClient + /// + internal class InternalRedisClient : RedisClient + { + private readonly RpcActor m_rpcActor; + + public InternalRedisClient(RpcActor rpcActor, BytesConverter converter) + { + m_rpcActor = rpcActor; + Converter = converter; + } + + public override void ClearCache() + { + var package = new RedisRequestWaitPackage + { + packageType = RedisPackageType.Clear + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock()) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + return; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + + public override bool ContainsCache(string key) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key)); + } + + var package = new RedisRequestWaitPackage + { + key = key, + packageType = RedisPackageType.Contains + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock()) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + return true; + } + else if (waitData.WaitResult.Status == byte.MaxValue) + { + return false; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + + public override ICacheEntry GetCache(string key) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key)); + } + + RedisRequestWaitPackage package = new RedisRequestWaitPackage() + { + key = key, + packageType = RedisPackageType.Get + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024)) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + RedisResponseWaitPackage responsePackage = (RedisResponseWaitPackage)waitData.WaitResult; + if (responsePackage.Status == 1) + { + return new CacheEntry(key) + { + Value = responsePackage.value + }; + } + else if (responsePackage.Status == byte.MaxValue) + { + return new CacheEntry(key); + } + else + { + return default; + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new TimeoutException(TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + + public override bool RemoveCache(string key) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key)); + } + + var package = new RedisRequestWaitPackage + { + key = key, + packageType = RedisPackageType.Remove + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024)) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + return true; + } + else if (waitData.WaitResult.Status == byte.MaxValue) + { + return false; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(Resources.TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: return false; + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new TimeoutException(Resources.TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + + public override bool SetCache(ICacheEntry cache) + { + if (string.IsNullOrEmpty(cache.Key)) + { + throw new ArgumentException($"“{nameof(cache.Key)}”不能为 null 或空。", nameof(cache.Key)); + } + + if (cache is null) + { + throw new ArgumentNullException(nameof(cache)); + } + + var package = new RedisRequestWaitPackage + { + key = cache.Key, + timeSpan = cache.Duration, + value = cache.Value, + packageType = RedisPackageType.Set + }; + + var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package); + try + { + using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024)) + { + package.Package(byteBlock); + m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + switch (waitData.Wait(Timeout)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + return true; + } + else if (waitData.WaitResult.Status == byte.MaxValue) + { + return false; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + } + case WaitDataStatus.Overtime: throw new TimeoutException(Resources.TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: return false; + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new TimeoutException(Resources.TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + m_rpcActor.WaitHandlePool.Destroy(waitData); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs new file mode 100644 index 000000000..14b1c2584 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisClientExtensions.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RedisClientExtensions + /// + public static class RedisClientExtensions + { + /// + /// 获取或设置RedisClient的注入键。 + /// + public static readonly DependencyProperty RedisClientProperty = + DependencyProperty.Register("RedisClient", typeof(RedisClientExtensions), null); + + /// + /// 获取RedisClient + /// + /// + /// + /// + /// + public static RedisClient GetRedisClient(this TClient client) where TClient : IDependencyTouchRpc, IDependencyObject + { + return client.GetValue(RedisClientProperty); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs new file mode 100644 index 000000000..422d89e60 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisPackageType.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.TouchRpc +{ + internal enum RedisPackageType : byte + { + Set, + Get, + Contains, + Remove, + Clear + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs new file mode 100644 index 000000000..74e849a7d --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisPlugin.cs @@ -0,0 +1,181 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RedisPlugin + /// + public class RedisPlugin : TouchRpcPluginBase + { + /// + /// 定义元素的序列化和反序列化。 + /// 注意:Byte[]类型不用考虑。内部单独会做处理。 + /// + public BytesConverter Converter { get; private set; } = new BytesConverter(); + + /// + /// 实际储存缓存。 + /// + public ICache ICache { get; set; } = new MemoryCache(); + + /// + /// 设置实际储存缓存。 + /// + /// + public void SetCache(ICache cache) + { + ICache = cache; + } + + /// + /// 定义元素的序列化和反序列化。 + /// 注意:Byte[]类型不用考虑。内部单独会做处理。 + /// + /// + public void SetConverter(BytesConverter converter) + { + Converter = converter; + } + + /// + /// + /// + /// + /// + protected override void OnHandshaked(IDependencyTouchRpc client, VerifyOptionEventArgs e) + { + client.SetValue(RedisClientExtensions.RedisClientProperty, new InternalRedisClient(client.RpcActor, Converter)); + base.OnHandshaked(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnReceivedProtocolData(IDependencyTouchRpc client, ProtocolDataEventArgs e) + { + switch (e.Protocol) + { + case TouchRpcUtility.P_600_Redis_Request: + { + var waitResult = new RedisResponseWaitPackage(); + try + { + e.Handled = true; + RedisRequestWaitPackage package = new RedisRequestWaitPackage(); + package.Unpackage(e.ByteBlock.Seek(2)); + waitResult.Sign = package.Sign; + + switch (package.packageType) + { + case RedisPackageType.Set: + { + bool success = ICache.SetCache(new CacheEntry(package.key) + { + Duration = package.timeSpan.Value, + Value = package.value + }); + if (success) + { + waitResult.Status = 1; + } + else + { + waitResult.Status = byte.MaxValue; + } + break; + } + case RedisPackageType.Get: + { + var cache = ICache.GetCache(package.key); + if (cache != null) + { + waitResult.Status = 1; + waitResult.value = cache.Value; + } + else + { + waitResult.Status = byte.MaxValue; + } + } + break; + + case RedisPackageType.Contains: + { + if (ICache.ContainsCache(package.key)) + { + waitResult.Status = 1; + } + else + { + waitResult.Status = byte.MaxValue; + } + } + break; + + case RedisPackageType.Remove: + { + if (ICache.RemoveCache(package.key)) + { + waitResult.Status = 1; + } + else + { + waitResult.Status = byte.MaxValue; + } + } + break; + + case RedisPackageType.Clear: + { + ICache.ClearCache(); + waitResult.Status = 1; + } + break; + + default: + return; + } + } + catch (Exception ex) + { + waitResult.Status = 2; + waitResult.Message = ex.Message; + } + + using (ByteBlock byteBlock = new ByteBlock()) + { + waitResult.Package(byteBlock); + client.Send(TouchRpcUtility.P_1600_Redis_Response, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + } + + case TouchRpcUtility.P_1600_Redis_Response: + { + e.Handled = true; + var waitResult = new RedisResponseWaitPackage(); + waitResult.Unpackage(e.ByteBlock.Seek(2)); + client.RpcActor.WaitHandlePool.SetRun(waitResult); + break; + } + default: + break; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs new file mode 100644 index 000000000..1d6ff954c --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisRequestWaitPackage.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class RedisRequestWaitPackage : RedisResponseWaitPackage + { + public string key; + public TimeSpan? timeSpan; + public RedisPackageType packageType; + + public override void Package(ByteBlock byteBlock) + { + base.Package(byteBlock); + byteBlock.Write(key); + byteBlock.Write((byte)packageType); + if (timeSpan.HasValue) + { + byteBlock.Write((byte)1); + byteBlock.Write(timeSpan.Value); + } + else + { + byteBlock.Write((byte)0); + } + } + + public override void Unpackage(ByteBlock byteBlock) + { + base.Unpackage(byteBlock); + key = byteBlock.ReadString(); + packageType = (RedisPackageType)byteBlock.ReadByte(); + if (byteBlock.ReadByte() == 1) + { + timeSpan = byteBlock.ReadTimeSpan(); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs new file mode 100644 index 000000000..83eaccf05 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Redis/RedisResponseWaitPackage.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class RedisResponseWaitPackage : WaitPackage + { + public byte[] value; + + public override void Package(ByteBlock byteBlock) + { + base.Package(byteBlock); + byteBlock.WriteBytesPackage(value); + } + + public override void Unpackage(ByteBlock byteBlock) + { + base.Unpackage(byteBlock); + value = byteBlock.ReadBytesPackage(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs b/src/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs new file mode 100644 index 000000000..7ca4b5c97 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Rpc/CanceledPackage.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class CanceledPackage : RouterPackage + { + public long Sign { get; set; } + + public override void PackageBody(ByteBlock byteBlock) + { + byteBlock.Write(Sign); + } + + public override void UnpackageBody(ByteBlock byteBlock) + { + Sign = byteBlock.ReadInt64(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs b/src/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs new file mode 100644 index 000000000..e1e7d730b --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Rpc/InvokeOption.cs @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc调用设置 + /// + public struct InvokeOption : IInvokeOption + { + /// + /// 默认设置。 + /// Timeout=5000ms + /// + public static InvokeOption OnlySend; + + /// + /// 默认设置。 + /// Timeout=5000ms + /// + public static InvokeOption WaitInvoke; + + /// + /// 默认设置。 + /// Timeout=5000 ms + /// + public static InvokeOption WaitSend; + + private int m_timeout; + + static InvokeOption() + { + OnlySend = new InvokeOption(timeout: 5000); + OnlySend.FeedbackType = FeedbackType.OnlySend; + + WaitSend = new InvokeOption(timeout: 5000); + WaitSend.FeedbackType = FeedbackType.WaitSend; + + WaitInvoke = new InvokeOption(timeout: 5000); + WaitInvoke.FeedbackType = FeedbackType.WaitInvoke; + } + + /// + /// 构造函数 + /// + /// + /// + /// + /// + public InvokeOption(int timeout = 5000, FeedbackType feedbackType = FeedbackType.WaitInvoke, SerializationType serializationType = SerializationType.FastBinary, + CancellationToken cancellationToken = default) : this() + { + Timeout = timeout; + FeedbackType = feedbackType; + SerializationType = serializationType; + Token = cancellationToken; + } + + /// + /// 调用反馈 + /// + public FeedbackType FeedbackType { get; set; } + + /// + /// TouchRpc序列化类型 + /// + public SerializationType SerializationType { get; set; } + + /// + /// 调用超时, + /// min=1000,默认5000 ms + /// + public int Timeout + { + get + { + if (m_timeout < 1000) + { + return 5000; + } + return m_timeout; + } + set => m_timeout = value; + } + + /// + /// 可以取消的调用令箭 + /// + public CancellationToken Token { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs b/src/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs new file mode 100644 index 000000000..d171c1924 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/DefaultSerializationSelector.cs @@ -0,0 +1,96 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 默认序列化选择器 + /// + public class DefaultSerializationSelector : SerializationSelector + { + /// + /// 反序列化 + /// + /// + /// + /// + /// + public override object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType) + { + if (parameterBytes == null) + { + return parameterType.GetDefault(); + } + switch (serializationType) + { + case SerializationType.FastBinary: + { + return SerializeConvert.FastBinaryDeserialize(parameterBytes, 0, parameterType); + } + case SerializationType.SystemBinary: + { + return SerializeConvert.BinaryDeserialize(parameterBytes, 0, parameterBytes.Length); + } + case SerializationType.Json: + { + return Encoding.UTF8.GetString(parameterBytes).FromJson(parameterType); + } + case SerializationType.Xml: + { + return SerializeConvert.XmlDeserializeFromBytes(parameterBytes, parameterType); + } + default: + throw new RpcException("未指定的反序列化方式"); + } + } + + /// + /// 序列化参数 + /// + /// + /// + /// + public override byte[] SerializeParameter(SerializationType serializationType, object parameter) + { + if (parameter == null) + { + return null; + } + switch (serializationType) + { + case SerializationType.FastBinary: + { + return SerializeConvert.FastBinarySerialize(parameter); + } + case SerializationType.SystemBinary: + { + return SerializeConvert.BinarySerialize(parameter); + } + case SerializationType.Json: + { + return SerializeConvert.JsonSerializeToBytes(parameter); + } + case SerializationType.Xml: + { + return SerializeConvert.XmlSerializeToBytes(parameter); + } + default: + throw new RpcException("未指定的序列化方式"); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs b/src/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs new file mode 100644 index 000000000..89c6d2150 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Rpc/Serialization/SerializationSelector.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 序列化选择器 + /// + public abstract class SerializationSelector + { + /// + /// 序列化Rpc方法返回值参数 + /// + /// + /// + /// + public abstract byte[] SerializeParameter(SerializationType serializationType, object parameter); + + /// + /// 反序列化传输对象 + /// + /// + /// + /// + /// + public abstract object DeserializeParameter(SerializationType serializationType, byte[] parameterBytes, Type parameterType); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs b/src/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs new file mode 100644 index 000000000..cb1b9469b --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcCallContext.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// TouchRpc上下文 + /// + internal class TouchRpcCallContext : ITouchRpcCallContext + { + private CancellationTokenSource m_tokenSource; + + /// + /// 当不为空时,调用 + /// + /// + public bool TryCancel() + { + if (m_tokenSource != null) + { + m_tokenSource.Cancel(); + return true; + } + return false; + } + + /// + /// + /// + public object Caller { get; internal set; } + + /// + /// 能取消的调用令箭,在客户端主动取消或网络故障时生效 + /// + public CancellationTokenSource TokenSource + { + get + { + if (m_tokenSource == null) + { + m_tokenSource = new CancellationTokenSource(); + } + return m_tokenSource; + } + } + + /// + /// TouchRpcContext + /// + public TouchRpcPackage TouchRpcPackage { get; internal set; } + + /// + /// + /// + public MethodInstance MethodInstance { get; internal set; } + + /// + /// 序列化类型 + /// + public SerializationType SerializationType => TouchRpcPackage == null ? (SerializationType)byte.MaxValue : TouchRpcPackage.SerializationType; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs b/src/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs new file mode 100644 index 000000000..82485d90e --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Rpc/TouchRpcPackage.cs @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Generic; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Rpc传输类 + /// + public sealed class TouchRpcPackage : WaitRouterPackage + { + /// + /// 反馈类型 + /// + public FeedbackType Feedback { get; private set; } + + /// + /// 参数是否包含引用类型 + /// + public bool IsByRef { get; internal set; } + + /// + /// 函数名 + /// + public string MethodName { get; internal set; } + + /// + /// 参数数据 + /// + public List ParametersBytes { get; internal set; } + + /// + /// 返回参数数据 + /// + public byte[] ReturnParameterBytes { get; internal set; } + + /// + /// 序列化类型 + /// + public SerializationType SerializationType { get; private set; } + + /// + public override void PackageBody(ByteBlock byteBlock) + { + base.PackageBody(byteBlock); + byteBlock.Write((byte)SerializationType); + byteBlock.Write((byte)Feedback); + byteBlock.Write(IsByRef); + byteBlock.Write(MethodName); + byteBlock.WriteBytesPackage(ReturnParameterBytes); + + if (ParametersBytes != null && ParametersBytes.Count > 0) + { + byteBlock.Write((byte)ParametersBytes.Count); + foreach (byte[] item in ParametersBytes) + { + byteBlock.WriteBytesPackage(item); + } + } + else + { + byteBlock.Write((byte)0); + } + } + + /// + public override void UnpackageBody(ByteBlock byteBlock) + { + base.UnpackageBody(byteBlock); + SerializationType = (SerializationType)byteBlock.ReadByte(); + Feedback = (FeedbackType)byteBlock.ReadByte(); + IsByRef = byteBlock.ReadBoolean(); + MethodName = byteBlock.ReadString(); + ReturnParameterBytes = byteBlock.ReadBytesPackage(); + + byte countPar = (byte)byteBlock.ReadByte(); + ParametersBytes = new List(); + for (int i = 0; i < countPar; i++) + { + ParametersBytes.Add(byteBlock.ReadBytesPackage()); + } + } + + internal void LoadInvokeOption(IInvokeOption option) + { + InvokeOption invokeOption = (InvokeOption)option; + Feedback = invokeOption.FeedbackType; + SerializationType = invokeOption.SerializationType; + } + + internal void ThrowStatus() + { + if (Status == 1) + { + return; + } + switch (Status.ToStatus()) + { + case TouchSocketStatus.ClientNotFind: + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(TargetId)); + } + case TouchSocketStatus.UnknownError: + case TouchSocketStatus.RpcMethodNotFind: + case TouchSocketStatus.RpcMethodDisable: + case TouchSocketStatus.RemoteRefuse: + case TouchSocketStatus.RpcInvokeException: + case TouchSocketStatus.RoutingNotAllowed: + case TouchSocketStatus.Exception: + default: + { + throw new RpcException(Status.ToStatus().GetDescription(Message)); + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs b/src/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs new file mode 100644 index 000000000..6a815c834 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Rpc/UdpCaller.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// Udp调用者 + /// + public class UdpCaller + { + private readonly EndPoint callerEndPoint; + + private readonly UdpSessionBase m_service; + + /// + /// 构造函数 + /// + /// + /// + public UdpCaller(UdpSessionBase service, EndPoint callerEndPoint) + { + m_service = service; + this.callerEndPoint = callerEndPoint; + } + + /// + /// 调用者终结点 + /// + public EndPoint CallerEndPoint => callerEndPoint; + + /// + /// Udp服务器 + /// + public UdpSessionBase Service => m_service; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs new file mode 100644 index 000000000..3ab79b2af --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IDRpcActor.cs @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// IDRpcActor + /// + public class IDRpcActor : IRpcClient + { + private readonly string m_targetId; + private readonly IRpcActor m_rpcActor; + + /// + /// 构造函数 + /// + /// + /// + public IDRpcActor(string targetId, IRpcActor rpcActor) + { + m_targetId = targetId; + m_rpcActor = rpcActor; + } + + /// + /// + /// + public Func TryCanInvoke { get => m_rpcActor.TryCanInvoke; set => m_rpcActor.TryCanInvoke = value; } + + /// + /// + /// + public void Dispose() + { + m_rpcActor.Dispose(); + } + + /// + /// + /// + /// + /// + /// + public void Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + m_rpcActor.Invoke(m_targetId, invokeKey, invokeOption, parameters); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public T Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.Invoke(m_targetId, invokeKey, invokeOption, parameters); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public T Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + return m_rpcActor.Invoke(m_targetId, invokeKey, invokeOption, ref parameters, types); + } + + /// + /// + /// + /// + /// + /// + /// + public void Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + m_rpcActor.Invoke(m_targetId, invokeKey, invokeOption, ref parameters, types); + } + + /// + /// + /// + /// + /// + /// + /// + public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(m_targetId, invokeKey, invokeOption, parameters); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return m_rpcActor.InvokeAsync(m_targetId, invokeKey, invokeOption, parameters); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs new file mode 100644 index 000000000..83919c083 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActor.cs @@ -0,0 +1,160 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActor接口 + /// + public partial interface IRpcActor : IRpcActorBase, IRpcClient, ITargetRpcActor + { + /// + /// 表示是否已经完成握手连接。 + /// + bool IsHandshaked { get; } + + /// + /// 根路径 + /// + string RootPath { get; set; } + + /// + /// 判断使用该ID的Channel是否存在。 + /// + /// + /// + bool ChannelExisted(int id); + + /// + /// 创建通道 + /// + /// + /// + Channel CreateChannel(); + + /// + /// 创建通道 + /// + /// 指定ID + /// + /// + Channel CreateChannel(int id); + + /// + /// 从对点拉取文件 + /// + /// + /// + Result PullFile(FileOperator fileOperator); + + /// + /// 异步从对点拉取文件 + /// + /// + /// + Task PullFileAsync(FileOperator fileOperator); + + /// + /// 拉取小文件。默认设置1024*1024字节大小。 + /// + /// 请求路径 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 拉取小文件。默认设置1024*1024字节大小。 + /// + /// 请求路径 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 向对点推送文件 + /// + /// + /// + Result PushFile(FileOperator fileOperator); + + /// + /// 异步向对点推送文件 + /// + /// + /// + Task PushFileAsync(FileOperator fileOperator); + + /// + /// 推送小文件。默认设置1024*1024字节大小。 + /// + /// 保存路径 + /// 推送的文件信息 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 推送小文件。默认设置1024*1024字节大小。 + /// + /// 保存路径 + /// 推送的文件信息 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 重新设置ID + /// + /// + void ResetID(string newId); + + /// + /// 发送流数据 + /// + /// + /// + /// + /// + Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = default); + + /// + /// 异步发送流数据 + /// + /// + /// + /// + /// + Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = default); + + /// + /// 订阅通道 + /// + /// + /// + /// + bool TrySubscribeChannel(int id, out Channel channel); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs new file mode 100644 index 000000000..ce243bde0 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/IRpcActorBase.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActorBase + /// + public interface IRpcActorBase + { + /// + /// 日志记录器 + /// + ILog Logger { get; } + + /// + /// 序列化选择器 + /// + SerializationSelector SerializationSelector { get; } + + /// + /// 向通信的对方执行ping。 + /// + /// + /// 如果返回True,则表示一定在线。如果返回false,则不一定代表不在线。 + bool Ping(int timeout = 5000); + + /// + /// 发送字节 + /// + /// + /// + /// + /// + void Send(short protocol, byte[] buffer, int offset, int length); + + /// + /// 发送字节 + /// + /// + /// + /// + /// + Task SendAsync(short protocol, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs new file mode 100644 index 000000000..9e239b473 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcActor.cs @@ -0,0 +1,137 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITargetRpcActor + /// + public partial interface ITargetRpcActor : ITargetRpcClient + { + /// + /// 创建一个和其他客户端的通道 + /// + /// 目标客户端ID + /// + /// + public Channel CreateChannel(string targetId); + + /// + /// 创建一个和其他客户端的通道 + /// + /// 目标客户端ID + /// 通道Id + /// + /// + public Channel CreateChannel(string targetId, int id); + + /// + /// 向指定的Id执行ping。 + /// + /// 目标客户端ID + /// 超时配置 + /// 如果返回True,则表示一定在线。如果返回false,则不一定代表不在线。 + bool Ping(string targetId, int timeout = 5000); + + #region 文件传输 + + /// + /// 从对点拉取文件 + /// + /// 目标客户端ID + /// 文件传输操作器 + /// + Result PullFile(string targetId, FileOperator fileOperator); + + /// + /// 异步从对点拉取文件 + /// + /// 目标客户端ID + /// 文件传输操作器 + /// + Task PullFileAsync(string targetId, FileOperator fileOperator); + + /// + /// 向对点推送文件 + /// + /// 目标客户端ID + /// 文件传输操作器 + /// + Result PushFile(string targetId, FileOperator fileOperator); + + /// + /// 异步向对点推送文件 + /// + /// 目标客户端ID + /// 文件传输操作器 + /// + Task PushFileAsync(string targetId, FileOperator fileOperator); + + #endregion 文件传输 + + #region 小文件 + + /// + /// 拉取小文件。默认设置1024*1024字节大小。 + /// + /// 目标客户端ID + /// 请求路径 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 拉取小文件。默认设置1024*1024字节大小。 + /// + /// 目标客户端Id + /// 请求路径 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 推送小文件到特定的Id。默认设置1024*1024字节大小。 + /// + /// 目标客户端Id + /// 保存路径 + /// 推送的文件信息 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + /// + /// 推送小文件。默认设置1024*1024字节大小。 + /// + /// + /// 保存路径 + /// 推送的文件信息 + /// 元数据 + /// 超时设置 + /// 可取消令箭 + /// + Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default); + + #endregion 小文件 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs new file mode 100644 index 000000000..be3731985 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Interface/ITargetRpcClient.cs @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// ITargetRpcClient + /// + public interface ITargetRpcClient + { + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + /// 返回值 + Task InvokeAsync(string targetId, string method, IInvokeOption invokeOption, params object[] parameters); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + void Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + /// 返回值 + T Invoke(string targetId, string method, IInvokeOption invokeOption, params object[] parameters); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + void Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types); + + /// + /// 调用对应ID的客户端Rpc + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// 调用超时 + /// 序列化异常 + /// 调用内部异常 + /// 没有找到ID对应的客户端 + /// 其他异常 + /// 返回值 + T Invoke(string targetId, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs new file mode 100644 index 000000000..c925a5190 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Channel.cs @@ -0,0 +1,228 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + public partial class RpcActor + { + private readonly ConcurrentDictionary m_userChannels; + + /// + /// + /// + /// + /// + public bool ChannelExisted(int id) + { + return m_userChannels.ContainsKey(id); + } + + /// + public Channel CreateChannel() + { + return this.PrivateCreateChannel(default, true); + } + + /// + public Channel CreateChannel(int id) + { + return this.PrivateCreateChannel(default, false, id); + } + + /// + public Channel CreateChannel(string targetId, int id) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor actor)) + { + return actor.CreateChannel(id); + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + return this.PrivateCreateChannel(targetId, false, id); + } + + private Channel PrivateCreateChannel(string targetId, bool random, int id = 0) + { + lock (SyncRoot) + { + if (random) + { + id = new object().GetHashCode(); + } + else + { + if (ChannelExisted(id)) + { + throw new Exception(TouchSocketStatus.ChannelExisted.GetDescription(id)); + } + } + + ByteBlock byteBlock = new ByteBlock(); + WaitCreateChannelPackage waitCreateChannel = new WaitCreateChannelPackage() + { + Random = random, + ChannelID = id, + SourceId = this.ID, + TargetId = targetId, + Route = targetId.HasValue() + }; + WaitData waitData = WaitHandlePool.GetWaitData(waitCreateChannel); + + try + { + waitCreateChannel.Package(byteBlock); + Send(TouchRpcUtility.P_100_CreateChannel_Request, byteBlock); + switch (waitData.Wait(10 * 1000)) + { + case WaitDataStatus.SetRunning: + { + WaitCreateChannelPackage result = (WaitCreateChannelPackage)waitData.WaitResult; + switch (result.Status.ToStatus()) + { + case TouchSocketStatus.Success: + { + InternalChannel channel = new InternalChannel(this, targetId); + channel.SetID(result.ChannelID); + channel.SetUsing(); + if (m_userChannels.TryAdd(result.ChannelID, channel)) + { + return channel; + } + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + case TouchSocketStatus.ClientNotFind: + { + throw new Exception(TouchSocketStatus.ClientNotFind.GetDescription(targetId)); + } + case TouchSocketStatus.RoutingNotAllowed: + default: + { + throw new Exception(result.Status.ToStatus().GetDescription(result.Message)); + } + } + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + } + default: + { + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + } + + internal void SendChannelPackage(ChannelPackage channelPackage) + { + using (ByteBlock byteBlock = new ByteBlock(channelPackage.GetLen())) + { + channelPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_101_ChannelPackage, byteBlock); + } + } + + /// + public Channel CreateChannel(string targetId) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor actor)) + { + return actor.CreateChannel(); + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + return this.PrivateCreateChannel(targetId, true); + } + + internal void RemoveChannel(int id) + { + m_userChannels.TryRemove(id, out _); + } + + /// + /// 订阅通道 + /// + /// + /// + /// + public bool TrySubscribeChannel(int id, out Channel channel) + { + if (m_userChannels.TryGetValue(id, out InternalChannel channelOut)) + { + if (channelOut.Using) + { + channel = null; + return false; + } + channelOut.SetUsing(); + channel = channelOut; + return true; + } + channel = null; + return false; + } + + private bool QueueChannelPackage(ChannelPackage channelPackage) + { + if (m_userChannels.TryGetValue(channelPackage.ChannelId, out InternalChannel channel)) + { + channel.ReceivedData(channelPackage); + return true; + } + + return false; + } + + private bool RequestCreateChannel(int id, string targetId) + { + lock (SyncRoot) + { + InternalChannel channel = new InternalChannel(this, targetId); + channel.SetID(id); + if (m_userChannels.TryAdd(id, channel)) + { + return true; + } + else + { + channel.SafeDispose(); + return false; + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs new file mode 100644 index 000000000..e2350c7fc --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-File.cs @@ -0,0 +1,1220 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Rpc.TouchRpc +{ + public partial class RpcActor + { + private readonly ConcurrentDictionary m_eventArgs; + private string m_rootPath = string.Empty; + + /// + public string RootPath + { + get => m_rootPath; + set + { + value ??= string.Empty; + m_rootPath = value; + } + } + + #region Pull + + /// + public Result PullFile(FileOperator fileOperator) + { + return this.PrivatePullFile(default, fileOperator); + } + + /// + public Result PullFile(string targetId, FileOperator fileOperator) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.PullFile(fileOperator); + } + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + + return this.PrivatePullFile(targetId, fileOperator); + } + + /// + public Task PullFileAsync(string targetId, FileOperator fileOperator) + { + return EasyTask.Run(() => + { + return PullFile(targetId, fileOperator); + }); + } + + /// + public Task PullFileAsync(FileOperator fileOperator) + { + return EasyTask.Run(() => + { + return PullFile(fileOperator); + }); + } + + private Result PreviewPullFile(string targetId, FileOperator fileOperator, WaitFileInfoPackage waitFileInfoPackage) + { + TouchRpcFileInfo fileInfo = waitFileInfoPackage.FileInfo; + fileOperator.SavePath = FileController.GetFullPath(m_rootPath, fileOperator.SavePath); + TouchRpcFileStream stream; + try + { + FileController.TryReadTempInfo(fileOperator.SavePath, fileOperator.Flags, ref fileInfo); + stream = TouchRpcFileStream.Create(fileOperator.SavePath, ref fileInfo, fileOperator.Flags.HasFlag(TransferFlags.BreakpointResume)); + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + + WaitTransferPackage waitTransfer = new WaitTransferPackage() + { + EventHashCode = waitFileInfoPackage.EventHashCode, + Path = fileInfo.FullName, + Position = fileInfo.Position, + SourceId = this.ID, + TargetId = targetId, + Route = targetId.HasValue() + }; + + WaitData waitData = WaitHandlePool.GetWaitData(waitTransfer); + ByteBlock byteBlock = new ByteBlock(); + Channel channel = default; + try + { + if (targetId == null) + { + channel = CreateChannel(); + } + else + { + channel = CreateChannel(targetId); + } + waitTransfer.ChannelID = channel.ID; + waitTransfer.Package(byteBlock); + Send(TouchRpcUtility.P_501_BeginPullFile_Request, byteBlock); + + if (fileOperator.Token.IsCancellationRequested) + { + waitData.SetCancellationToken(fileOperator.Token); + } + + switch (waitData.Wait(fileOperator.Timeout)) + { + case WaitDataStatus.SetRunning: + { + WaitTransferPackage waitTransferResult = (WaitTransferPackage)waitData.WaitResult; + switch (waitTransferResult.Status.ToStatus()) + { + case TouchSocketStatus.Success: + { + fileOperator.SetFileCompletedLength(fileInfo.Position); + fileOperator.SetLength(fileInfo.Length); + channel.Timeout = fileOperator.Timeout; + while (channel.MoveNext()) + { + if (fileOperator.Token.IsCancellationRequested) + { + channel.Cancel(); + fileOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + byte[] data = channel.GetCurrent(); + if (data != null) + { + stream.Write(data, 0, data.Length); + fileInfo.Position = stream.FileWriter.Position; + fileOperator.AddFlow(data.Length); + } + } + + if (channel.Status == ChannelStatus.Completed) + { + stream.FinishStream(); + return fileOperator.SetResult(new Result(ResultCode.Success)); + } + else + { + return fileOperator.SetResult(new Result(channel.Status.ToResultCode())); + } + } + case TouchSocketStatus.LoadStreamFail: + return fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.LoadStreamFail.GetDescription(fileInfo.FullName))); + + default: + return fileOperator.SetResult(new Result(ResultCode.Error, waitTransferResult.Status.ToStatus().GetDescription(waitTransferResult.Message))); + } + } + case WaitDataStatus.Overtime: + { + return fileOperator.SetResult(new Result(ResultCode.Overtime)); + } + case WaitDataStatus.Canceled: + { + return fileOperator.SetResult(new Result(ResultCode.Canceled)); + } + case WaitDataStatus.Disposed: + default: + { + return fileOperator.SetResult(new Result(ResultCode.Error)); + } + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + finally + { + WaitHandlePool.Destroy(waitData); + stream.SafeDispose(); + byteBlock.Dispose(); + channel.SafeDispose(); + } + } + + private Result PrivatePullFile(string targetId, FileOperator fileOperator) + { + if (fileOperator is null) + { + return new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(fileOperator))); + } + + WaitFileInfoPackage waitFileInfo = new WaitFileInfoPackage + { + SourceId = this.ID, + TargetId = targetId, + Route = targetId.HasValue(), + Metadata = fileOperator.Metadata, + SavePath = this.FileController.GetFullPath(this.m_rootPath, fileOperator.SavePath), + Flags = fileOperator.Flags, + ResourcePath = fileOperator.ResourcePath + }; + + WaitData waitData = WaitHandlePool.GetWaitData(waitFileInfo); + + ByteBlock byteBlock = new ByteBlock(); + try + { + waitFileInfo.Package(byteBlock); + Send(TouchRpcUtility.P_500_PullFile_Request, byteBlock); + + if (fileOperator.Token.IsCancellationRequested) + { + waitData.SetCancellationToken(fileOperator.Token); + } + + waitData.Wait(fileOperator.Timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitFileInfoPackage waitFileResult = (WaitFileInfoPackage)waitData.WaitResult; + switch (waitFileResult.Status.ToStatus()) + { + case TouchSocketStatus.Success: + return PreviewPullFile(targetId, fileOperator, waitFileResult); + + case TouchSocketStatus.FileNotExists: + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(waitFileResult.ResourcePath))); + + case TouchSocketStatus.RemoteRefuse: + default: + return fileOperator.SetResult(new Result(ResultCode.Fail, waitFileResult.Status.ToStatus().GetDescription(waitFileResult.Message))); + } + } + case WaitDataStatus.Overtime: + { + return fileOperator.SetResult(Result.Overtime); + } + case WaitDataStatus.Canceled: + { + return fileOperator.SetResult(Result.Canceled); + } + case WaitDataStatus.Disposed: + default: + { + return fileOperator.SetResult(Result.UnknownFail); + } + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ex)); + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + #endregion Pull + + #region Push + + /// + public Result PushFile(FileOperator fileOperator) + { + return PrivatePushFile(default, fileOperator); + } + + /// + public Result PushFile(string targetId, FileOperator fileOperator) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.PushFile(fileOperator); + } + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + return this.PrivatePushFile(default, fileOperator); + } + + /// + public Task PushFileAsync(string targetId, FileOperator fileOperator) + { + return EasyTask.Run(() => + { + return PushFile(targetId, fileOperator); + }); + } + + /// + public Task PushFileAsync(FileOperator fileOperator) + { + return EasyTask.Run(() => + { + return PushFile(fileOperator); + }); + } + + private Result PreviewPushFile(FileOperator fileOperator, WaitTransferPackage waitTransfer) + { + try + { + using FileStorageReader reader = FilePool.GetReader(waitTransfer.Path); + fileOperator.SetLength(reader.FileStorage.FileInfo.Length); + if (TrySubscribeChannel(waitTransfer.ChannelID, out Channel channel)) + { + ByteBlock byteBlock = BytePool.Default.GetByteBlock(TouchRpcUtility.TransferPackage); + try + { + long position = waitTransfer.Position; + reader.Position = position; + fileOperator.SetFileCompletedLength(waitTransfer.Position); + + channel.Timeout = fileOperator.Timeout; + while (true) + { + if (fileOperator.Token.IsCancellationRequested) + { + channel.Cancel("主动取消"); + fileOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + int r = reader.Read(byteBlock.Buffer, 0, (int)Math.Min(TouchRpcUtility.TransferPackage, fileOperator.MaxSpeed / 10.0)); + if (r == 0) + { + channel.Complete(); + WaitPushFileAckPackage waitResult = null; + if (SpinWait.SpinUntil(() => + { + if (m_eventArgs.TryRemove(waitTransfer.EventHashCode, out object obj)) + { + waitResult = (WaitPushFileAckPackage)obj; + return true; + } + return false; + }, fileOperator.Timeout)) + { + if (waitResult.Status.ToStatus() == TouchSocketStatus.Success) + { + return fileOperator.SetResult(new Result(ResultCode.Success)); + } + else + { + return fileOperator.SetResult(new Result(ResultCode.Error, waitResult.Message)); + } + } + else + { + return fileOperator.SetResult(new Result(ResultCode.Overtime, "等待最后状态确认超时。")); + } + } + else + { + position += r; + if (channel.TryWrite(byteBlock.Buffer, 0, r)) + { + fileOperator.AddFlow(r); + } + else + { + break; + } + } + } + if (channel.Status == ChannelStatus.Cancel && !string.IsNullOrEmpty(channel.LastOperationMes)) + { + return fileOperator.SetResult(new Result(ResultCode.Canceled, channel.LastOperationMes)); + } + else + { + return fileOperator.SetResult(new Result(channel.Status.ToResultCode())); + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + finally + { + byteBlock.Dispose(); + } + } + else + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.SetChannelFail.GetDescription())); + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.LoadStreamFail.GetDescription(waitTransfer.Path, ex.Message))); + } + } + + private Result PrivatePushFile(string targetId, FileOperator fileOperator) + { + if (fileOperator is null) + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(fileOperator)))); + } + + string fullPath = FileController.GetFullPath(m_rootPath, fileOperator.ResourcePath); + + if (!File.Exists(fullPath)) + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fullPath))); + } + + TouchRpcFileInfo fileInfo = new TouchRpcFileInfo(); + try + { + FileController.GetFileInfo(fullPath, fileOperator.Flags.HasFlag(TransferFlags.MD5Verify), ref fileInfo); + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + + WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage() + { + FileInfo = fileInfo, + Metadata = fileOperator.Metadata, + ResourcePath = this.FileController.GetFullPath(this.m_rootPath, fileOperator.ResourcePath), + SavePath = fileOperator.SavePath, + Flags = fileOperator.Flags, + TargetId = targetId, + SourceId = this.ID, + Route = targetId.HasValue() + }; + WaitData waitData = WaitHandlePool.GetWaitData(waitFileInfoPackage); + + try + { + SendPackage(TouchRpcUtility.P_502_PushFile_Request, waitFileInfoPackage); + waitData.SetCancellationToken(fileOperator.Token); + + waitData.Wait(fileOperator.Timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitTransferPackage waitResult = (WaitTransferPackage)waitData.WaitResult; + switch (waitResult.Status.ToStatus()) + { + case TouchSocketStatus.Success: + return PreviewPushFile(fileOperator, waitResult); + + case TouchSocketStatus.LoadStreamFail: + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.LoadStreamFail.GetDescription(waitResult.Path, waitResult.Message))); + } + case TouchSocketStatus.ClientNotFind: + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId))); + } + case TouchSocketStatus.DirectoryNotExists: + { + return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.DirectoryNotExists.GetDescription(waitResult.Path))); + } + case TouchSocketStatus.RemoteRefuse: + default: + return fileOperator.SetResult(new Result(ResultCode.Error, waitResult.Status.ToStatus().GetDescription(waitResult.Message))); + } + } + case WaitDataStatus.Overtime: + { + return fileOperator.SetResult(new Result(ResultCode.Overtime)); + } + case WaitDataStatus.Canceled: + { + return fileOperator.SetResult(new Result(ResultCode.Canceled)); + } + case WaitDataStatus.Disposed: + default: + { + return fileOperator.SetResult(new Result(ResultCode.Error)); + } + } + } + catch (Exception ex) + { + return fileOperator.SetResult(new Result(ex)); + } + finally + { + WaitHandlePool.Destroy(waitData); + } + } + + #endregion Push + + #region 小文件传输 + + /// + /// 允许传输的小文件的最大长度。默认1024*1024字节。 + /// 注意,当调整该值时,应该和对端保持一致。 + /// + public int MaxSmallFileLength { get; set; } = 1024 * 1024; + + /// + public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor actor)) + { + return actor.PullSmallFile(path, metadata, timeout, token); + } + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + + return PrivatePullSmallFile(targetId, path, metadata, timeout, token); + } + + /// + public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return PrivatePullSmallFile(default, path, metadata, timeout, token); + } + + /// + public Task PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return Task.Run(() => + { + return PullSmallFile(targetId, path, metadata, timeout, token); + }); + } + + /// + public Task PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return Task.Run(() => + { + return PullSmallFile(path, metadata, timeout, token); + }); + } + + /// + public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token); + } + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + return PrivatePushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return PrivatePushSmallFile(default, savePath, fileInfo, metadata, timeout, token); + } + + /// + public Task PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return Task.Run(() => + { + return PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token); + }); + } + + /// + public Task PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + return Task.Run(() => + { + return PushSmallFile(savePath, fileInfo, metadata, timeout, token); + }); + } + + private PullSmallFileResult PrivatePullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + WaitSmallFilePackage waitSmallFilePackage = new WaitSmallFilePackage() + { + Path = path, + SourceId = ID, + TargetId = targetId, + Route = targetId.HasValue(), + Metadata = metadata + }; + + WaitData waitData = WaitHandlePool.GetWaitData(waitSmallFilePackage); + + ByteBlock byteBlock = new ByteBlock(); + try + { + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_517_PullSmallFile_Request, byteBlock); + waitData.SetCancellationToken(token); + + waitData.Wait(timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitSmallFilePackage waitFile = (WaitSmallFilePackage)waitData.WaitResult; + switch (waitFile.Status.ToStatus()) + { + case TouchSocketStatus.Success: + { + return new PullSmallFileResult(waitFile.Data); + } + case TouchSocketStatus.FileNotExists: + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(waitFile.Path)); + } + case TouchSocketStatus.RemoteRefuse: + case TouchSocketStatus.LengthErrorWhenRead: + case TouchSocketStatus.FileLengthTooLong: + case TouchSocketStatus.ClientNotFind: + default: + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitFile.Message)); + } + } + } + case WaitDataStatus.Overtime: + { + return new PullSmallFileResult(ResultCode.Overtime); + } + case WaitDataStatus.Canceled: + { + return new PullSmallFileResult(ResultCode.Canceled); + } + case WaitDataStatus.Disposed: + default: + { + return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.UnknownError.GetDescription()); + } + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + private Result PrivatePushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default) + { + if (!File.Exists(fileInfo.FullName)) + { + return new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fileInfo.FullName)); + } + if (fileInfo.Length > MaxSmallFileLength) + { + return new Result(ResultCode.Error, TouchSocketStatus.FileLengthTooLong.GetDescription()); + } + WaitSmallFilePackage waitSmallFilePackage = new WaitSmallFilePackage() + { + Path = savePath, + SourceId = ID, + Metadata = metadata, + Route = targetId.HasValue(), + TargetId = targetId, + FileInfo = new RemoteFileInfo(fileInfo) + }; + + WaitData waitData = WaitHandlePool.GetWaitData(waitSmallFilePackage); + + ByteBlock byteBlock = new ByteBlock(); + byte[] buffer = BytePool.Default.GetByteCore((int)fileInfo.Length); + try + { + int r = FileController.ReadAllBytes(fileInfo, buffer); + if (r <= 0) + { + return new Result(ResultCode.Error, TouchSocketStatus.LengthErrorWhenRead.GetDescription()); + } + waitSmallFilePackage.Data = buffer; + waitSmallFilePackage.Len = r; + + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_518_PushSmallFile_Request, byteBlock); + waitData.SetCancellationToken(token); + + waitData.Wait(timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitSmallFilePackage waitFile = (WaitSmallFilePackage)waitData.WaitResult; + switch (waitFile.Status.ToStatus()) + { + case TouchSocketStatus.Success: + { + return Result.Success; + } + case TouchSocketStatus.RemoteRefuse: + { + return new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitFile.Message)); + } + case TouchSocketStatus.ClientNotFind: + { + return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription()); + } + default: + return new Result(ResultCode.Exception, waitFile.Message); + } + } + case WaitDataStatus.Overtime: + { + return Result.Overtime; + } + case WaitDataStatus.Canceled: + { + return Result.Canceled; + } + case WaitDataStatus.Disposed: + default: + { + return Result.UnknownFail; + } + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + BytePool.Default.Recycle(buffer); + } + } + + private void RequestPullSmallFile(object o) + { + //2.不响应 + //3.不允许 + //4.不存在 + //5.读取文件长度异常 + + byte[] buffer = BytePool.Default.GetByteCore(MaxSmallFileLength); + try + { + WaitSmallFilePackage waitSmallFilePackage = (WaitSmallFilePackage)o; + Result resultThis = Result.Success; + try + { + FileOperationEventArgs args = new FileOperationEventArgs(TransferType.SmallPull, + waitSmallFilePackage.Metadata, default) + { + ResourcePath = waitSmallFilePackage.Path + }; + + OnFileTransfering?.Invoke(this, args); + + string fullPath = FileController.GetFullPath(RootPath, args.ResourcePath); + waitSmallFilePackage.Path = fullPath; + if (args.IsPermitOperation) + { + if (File.Exists(fullPath)) + { + FileInfo fileInfo = new FileInfo(fullPath); + if (fileInfo.Length > MaxSmallFileLength) + { + waitSmallFilePackage.Status = TouchSocketStatus.FileLengthTooLong.ToValue(); + resultThis = new Result(ResultCode.Error, TouchSocketStatus.FileLengthTooLong.GetDescription()); + } + else + { + int r = FileController.ReadAllBytes(fileInfo, buffer); + if (r > 0) + { + waitSmallFilePackage.Data = buffer; + waitSmallFilePackage.Len = r; + waitSmallFilePackage.FileInfo = new RemoteFileInfo(fileInfo); + waitSmallFilePackage.Status = TouchSocketStatus.Success.ToValue(); + } + else + { + waitSmallFilePackage.Status = TouchSocketStatus.LengthErrorWhenRead.ToValue(); + resultThis = new Result(ResultCode.Error, TouchSocketStatus.LengthErrorWhenRead.GetDescription()); + } + } + } + else + { + waitSmallFilePackage.Status = TouchSocketStatus.FileNotExists.ToValue(); + resultThis = new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fullPath)); + } + } + else + { + waitSmallFilePackage.Status = TouchSocketStatus.RemoteRefuse.ToValue(); + waitSmallFilePackage.Message = args.Message; + resultThis = new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message)); + } + } + catch (Exception ex) + { + waitSmallFilePackage.Status = TouchSocketStatus.Exception.ToValue(); + waitSmallFilePackage.Message = ex.Message; + } + + using (ByteBlock byteBlock = new ByteBlock()) + { + waitSmallFilePackage.SwitchId(); + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_1517_PullSmallFile_Response, byteBlock); + } + + FileTransferStatusEventArgs resultArgs = new FileTransferStatusEventArgs( + TransferType.SmallPull, waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo, resultThis) + { + ResourcePath = waitSmallFilePackage.Path + }; + OnFileTransfered?.Invoke(this, resultArgs); + } + catch + { + } + finally + { + BytePool.Default.Recycle(buffer); + } + } + + private void RequestPushSmallFile(object o) + { + //2.不响应 + //3.不允许 + + try + { + WaitSmallFilePackage waitSmallFilePackage = (WaitSmallFilePackage)o; + Result resultThis = Result.Success; + try + { + FileOperationEventArgs args = new FileOperationEventArgs(TransferType.SmallPush, + waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo) + { + SavePath = waitSmallFilePackage.Path + }; + + OnFileTransfering?.Invoke(this, args); + + string fullPath = FileController.GetFullPath(RootPath, args.SavePath); + waitSmallFilePackage.Path = fullPath; + if (args.IsPermitOperation) + { + FileInfo fileInfo = new FileInfo(fullPath); + FileController.WriteAllBytes(fileInfo, waitSmallFilePackage.Data, 0, waitSmallFilePackage.Data.Length); + waitSmallFilePackage.Status = TouchSocketStatus.Success.ToValue(); + } + else + { + waitSmallFilePackage.Status = TouchSocketStatus.RemoteRefuse.ToValue(); + waitSmallFilePackage.Message = args.Message; + resultThis = new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message)); + } + } + catch (Exception ex) + { + waitSmallFilePackage.Status = TouchSocketStatus.Exception.ToValue(); + waitSmallFilePackage.Message = ex.Message; + } + waitSmallFilePackage.FileInfo = default; + waitSmallFilePackage.Data = default; + waitSmallFilePackage.SwitchId(); + using (ByteBlock byteBlock = new ByteBlock()) + { + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_1518_PushSmallFile_Response, byteBlock); + } + + FileTransferStatusEventArgs resultArgs = new FileTransferStatusEventArgs( + TransferType.SmallPush, waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo, resultThis) + { + SavePath = waitSmallFilePackage.Path + }; + OnFileTransfered?.Invoke(this, resultArgs); + } + catch + { + } + } + + #endregion 小文件传输 + + private void BeginPullFile(object o) + { + try + { + WaitTransferPackage waitTransferPackage = (WaitTransferPackage)o; + FileTransferStatusEventArgs e; + if (m_eventArgs.TryRemove(waitTransferPackage.EventHashCode, out object obj) && obj is FileOperationEventArgs args) + { + try + { + using (FileStorageReader reader = FilePool.GetReader(waitTransferPackage.Path)) + { + if (TrySubscribeChannel(waitTransferPackage.ChannelID, out Channel channel)) + { + ByteBlock byteBlock = BytePool.Default.GetByteBlock(TouchRpcUtility.TransferPackage); + FileOperator fileOperator = args.FileOperator; + fileOperator.SetLength(reader.FileStorage.FileInfo.Length); + try + { + waitTransferPackage.Status = TouchSocketStatus.Success.ToValue(); + waitTransferPackage.SwitchId(); + SendPackage(TouchRpcUtility.P_1501_BeginPullFile_Response, waitTransferPackage); + long position = waitTransferPackage.Position; + reader.Position = position; + fileOperator.SetFileCompletedLength(position); + while (true) + { + if (fileOperator.Token.IsCancellationRequested) + { + channel.Cancel("主动取消"); + fileOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + int r = reader.Read(byteBlock.Buffer, 0, + (int)Math.Min(TouchRpcUtility.TransferPackage, fileOperator.MaxSpeed / 10.0)); + if (r == 0) + { + channel.Complete(); + break; + } + else + { + position += r; + if (channel.TryWrite(byteBlock.Buffer, 0, r)) + { + fileOperator.AddFlow(r); + } + else + { + break; + } + } + } + } + catch + { + } + finally + { + byteBlock.Dispose(); + + e = new FileTransferStatusEventArgs( + fileOperator.SetResult(new Result(channel.Status.ToResultCode())), args); + OnFileTransfered?.Invoke(this, e); + } + + return; + } + else + { + waitTransferPackage.Status = TouchSocketStatus.SetChannelFail.ToValue(); + e = new FileTransferStatusEventArgs(new Result(ResultCode.Error, StringResStore.GetDescription(TouchSocketStatus.SetChannelFail)), args); + } + } + } + catch (Exception ex) + { + waitTransferPackage.Status = TouchSocketStatus.Exception.ToValue(); + waitTransferPackage.Message = ex.Message; + e = new FileTransferStatusEventArgs(new Result(ResultCode.Error, StringResStore.GetDescription(TouchSocketStatus.LoadStreamFail)), args); + } + } + else + { + e = new FileTransferStatusEventArgs(TransferType.Pull, default, default, new Result(ResultCode.Overtime, StringResStore.GetDescription(TouchSocketStatus.GetEventArgsFail))); + waitTransferPackage.Status = TouchSocketStatus.GetEventArgsFail.ToValue(); + } + + waitTransferPackage.SwitchId(); + SendPackage(TouchRpcUtility.P_1501_BeginPullFile_Response, waitTransferPackage); + + OnFileTransfered?.Invoke(this, e); + } + catch + { + } + } + + private void RequestPullFile(object o) + { + try + { + WaitFileInfoPackage waitFileInfoPackage = (WaitFileInfoPackage)o; + try + { + FileOperator fileOperator = new FileOperator() + { + Flags = waitFileInfoPackage.Flags, + ResourcePath = waitFileInfoPackage.ResourcePath, + SavePath = waitFileInfoPackage.SavePath, + Metadata = waitFileInfoPackage.Metadata + }; + + FileOperationEventArgs args = new FileOperationEventArgs(TransferType.Pull, + fileOperator, null); + + OnFileTransfering?.Invoke(this, args); + + args.ResourcePath = FileController.GetFullPath(m_rootPath, args.ResourcePath); + + if (args.IsPermitOperation) + { + if (File.Exists(args.ResourcePath)) + { + //合法传输 + TouchRpcFileInfo touchRpcFileInfo = new TouchRpcFileInfo(); + FileController.GetFileInfo(args.ResourcePath, args.Flags.HasFlag(TransferFlags.MD5Verify), ref touchRpcFileInfo); + waitFileInfoPackage.FileInfo = touchRpcFileInfo; + waitFileInfoPackage.Status = TouchSocketStatus.Success.ToValue(); + waitFileInfoPackage.EventHashCode = args.GetHashCode(); + if (m_eventArgs.TryAdd(args.GetHashCode(), args)) + { + EasyTask.DelayRun(1000 * 60, args, (a) => + { + if (m_eventArgs.TryRemove(a.GetHashCode(), out object obj) && obj is FileOperationEventArgs eventArgs) + { + FileTransferStatusEventArgs e = new FileTransferStatusEventArgs( + new Result(ResultCode.Overtime, StringResStore.GetDescription(TouchSocketStatus.Overtime)), eventArgs); + OnFileTransfered?.Invoke(this, e); + } + }); + } + else + { + waitFileInfoPackage.Status = TouchSocketStatus.UnknownError.ToValue(); + } + } + else + { + waitFileInfoPackage.Status = TouchSocketStatus.FileNotExists.ToValue(); + } + } + else + { + waitFileInfoPackage.Message = args.Message; + waitFileInfoPackage.Status = TouchSocketStatus.RemoteRefuse.ToValue(); + } + } + catch (Exception ex) + { + waitFileInfoPackage.Status = TouchSocketStatus.Exception.ToValue(); + waitFileInfoPackage.Message = ex.Message; + } + waitFileInfoPackage.SwitchId(); + this.SendPackage(TouchRpcUtility.P_1500_PullFile_Response, waitFileInfoPackage); + } + catch + { + } + } + + private void RequestPushFile(object o) + { + try + { + WaitFileInfoPackage waitFileInfoPackage = (WaitFileInfoPackage)o; + TouchRpcFileInfo fileInfo = waitFileInfoPackage.FileInfo; + FileOperator fileOperator = new FileOperator() + { + ResourcePath = waitFileInfoPackage.ResourcePath, + SavePath = waitFileInfoPackage.SavePath, + Flags = waitFileInfoPackage.Flags, + Metadata = waitFileInfoPackage.Metadata, + }; + WaitTransferPackage waitTransferPackage = new WaitTransferPackage() + { + Sign = waitFileInfoPackage.Sign, + TargetId = waitFileInfoPackage.SourceId, + SourceId = waitFileInfoPackage.TargetId, + Route = waitFileInfoPackage.Route, + }; + + FileOperationEventArgs args = new FileOperationEventArgs(TransferType.Push, fileOperator, fileInfo); + OnFileTransfering?.Invoke(this, args); + + waitTransferPackage.Path = args.ResourcePath; + waitTransferPackage.EventHashCode = args.GetHashCode(); + + if (!args.IsPermitOperation) + { + fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message))); + waitTransferPackage.Message = args.Message; + waitTransferPackage.Status = TouchSocketStatus.RemoteRefuse.ToValue(); + OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args)); + SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage); + return; + } + + string saveFullPath = FileController.GetFullPath(m_rootPath, args.SavePath); + + if (!Directory.Exists(Path.GetDirectoryName(saveFullPath))) + { + fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.DirectoryNotExists.GetDescription(Path.GetDirectoryName(saveFullPath)))); + waitTransferPackage.Message = args.Message; + waitTransferPackage.Status = TouchSocketStatus.DirectoryNotExists.ToValue(); + waitTransferPackage.Path = Path.GetDirectoryName(saveFullPath); + OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args)); + SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage); + return; + } + Channel channel = null; + try + { + FileController.TryReadTempInfo(saveFullPath, args.Flags, ref fileInfo); + using (TouchRpcFileStream stream = TouchRpcFileStream.Create(saveFullPath, ref fileInfo, args.Flags.HasFlag(TransferFlags.MD5Verify))) + { + if (waitFileInfoPackage.Route) + { + channel = CreateChannel(waitTransferPackage.SourceId); + } + else + { + channel = CreateChannel(); + } + + waitTransferPackage.ChannelID = channel.ID; + waitTransferPackage.Position = fileInfo.Position; + waitTransferPackage.Status = TouchSocketStatus.Success.ToValue(); + SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage); + + fileOperator.SetFileCompletedLength(fileInfo.Position); + fileOperator.SetLength(fileInfo.Length); + while (channel.MoveNext()) + { + if (fileOperator.Token.IsCancellationRequested) + { + channel.Cancel(); + fileOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + + byte[] data = channel.GetCurrent(); + if (data != null) + { + stream.Write(data, 0, data.Length); + fileInfo.Position = stream.FileWriter.Position; + fileOperator.AddFlow(data.Length); + } + } + + if (channel.Status == ChannelStatus.Completed) + { + stream.FinishStream(); + fileOperator.SetResult(new Result(ResultCode.Success)); + } + else + { + fileOperator.SetResult(new Result(channel.Status.ToResultCode())); + } + } + } + catch (Exception ex) + { + fileOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + channel?.Cancel(ex.Message); + } + finally + { + channel.SafeDispose(); + } + + OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args)); + if (channel?.Status == ChannelStatus.Completed && fileOperator.Result.IsSuccess()) + { + SendPackage(TouchRpcUtility.P_509_PushFileAck_Request, new WaitPushFileAckPackage() + { + TargetId = waitFileInfoPackage.SourceId, + SourceId = waitFileInfoPackage.TargetId, + Route = waitFileInfoPackage.Route, + Sign = args.GetHashCode(), + Status = TouchSocketStatus.Success.ToValue(), + Message = fileOperator.Result.Message + }); + } + else + { + SendPackage(TouchRpcUtility.P_509_PushFileAck_Request, new WaitPushFileAckPackage() + { + TargetId = waitFileInfoPackage.SourceId, + SourceId = waitFileInfoPackage.TargetId, + Route = waitFileInfoPackage.Route, + Sign = args.GetHashCode(), + Status = TouchSocketStatus.Exception.ToValue(), + Message = fileOperator.Result.Message + }); + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs new file mode 100644 index 000000000..8b5d76b40 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Rpc.cs @@ -0,0 +1,1085 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + public partial class RpcActor + { + private readonly ConcurrentDictionary m_contextDic; + + /// + public object Caller { get; set; } + + /// + public RpcStore RpcStore { get; set; } + + /// + public SerializationSelector SerializationSelector { get; set; } + + #region Rpc + + /// + public T Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + SourceId = ID + }; + WaitData waitData = WaitHandlePool.GetWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return default; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + if (resultContext.IsByRef) + { + try + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); + } + } + catch (System.Exception e) + { + throw new Exception(e.Message); + } + } + else + { + parameters = null; + } + return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + default: + return default; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public void Invoke(string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + SourceId = ID + }; + + WaitData waitData = WaitHandlePool.GetWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + if (resultContext.IsByRef) + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); + } + } + else + { + parameters = null; + } + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + default: + break; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public void Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + SourceId = ID + }; + + WaitData waitData = WaitHandlePool.GetWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + if (parameters != null) + { + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + } + + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + break; + + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + default: + break; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public T Invoke(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + SourceId = ID + }; + + WaitData waitData = WaitHandlePool.GetWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, Sign = rpcPackage.Sign }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + if (parameters != null) + { + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + } + + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return default; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + + default: + return default; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + Invoke(invokeKey, invokeOption, parameters); + }); + } + + /// + public Task InvokeAsync(string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + return Invoke(invokeKey, invokeOption, parameters); + }); + } + + #endregion Rpc + + #region IdRpc + + /// + public void Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (string.IsNullOrEmpty(invokeKey)) + { + throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor actor)) + { + actor.Invoke(invokeKey, invokeOption, parameters); + return; + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + Route = true, + TargetId = targetId, + SourceId = ID, + }; + + WaitData waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + if (parameters != null) + { + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + } + + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + break; + + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + break; + } + default: + break; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public T Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (string.IsNullOrEmpty(invokeKey)) + { + throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.Invoke(invokeKey, invokeOption, parameters); + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + TargetId = targetId, + SourceId = ID, + Route = true + }; + + WaitData waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + if (parameters != null) + { + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + } + + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return default; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + + default: + return default; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public void Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (string.IsNullOrEmpty(invokeKey)) + { + throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + rpcActor.Invoke(invokeKey, invokeOption, ref parameters, types); + return; + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + TargetId = targetId, + SourceId = ID, + Route = true + }; + + WaitData waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + if (resultContext.IsByRef) + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); + } + } + else + { + parameters = null; + } + break; + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return; + } + + default: + return; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public T Invoke(string targetId, string invokeKey, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (string.IsNullOrEmpty(targetId)) + { + throw new ArgumentException($"“{nameof(targetId)}”不能为 null 或空。", nameof(targetId)); + } + + if (string.IsNullOrEmpty(invokeKey)) + { + throw new ArgumentException($"“{nameof(invokeKey)}”不能为 null 或空。", nameof(invokeKey)); + } + + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.Invoke(invokeKey, invokeOption, ref parameters, types); + } + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription()); + } + + TouchRpcPackage rpcPackage = new TouchRpcPackage + { + MethodName = invokeKey, + TargetId = targetId, + SourceId = ID, + Route = true + }; + + WaitData waitData = WaitHandlePool.GetReverseWaitData(rpcPackage); + ByteBlock byteBlock = new ByteBlock(); + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + if (invokeOption.Token.CanBeCanceled) + { + waitData.SetCancellationToken(invokeOption.Token); + invokeOption.Token.Register(CanceledInvoke, new CanceledPackage() { SourceId = ID, TargetId = targetId, Sign = rpcPackage.Sign, Route = true }); + } + + try + { + rpcPackage.LoadInvokeOption(invokeOption); + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, parameter)); + } + rpcPackage.ParametersBytes = datas; + rpcPackage.Package(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + return default; + } + case FeedbackType.WaitSend: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + case FeedbackType.WaitInvoke: + { + Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 0, byteBlock.Len); + switch (waitData.Wait(invokeOption.Timeout)) + { + case WaitDataStatus.SetRunning: + { + TouchRpcPackage resultContext = (TouchRpcPackage)waitData.WaitResult; + resultContext.ThrowStatus(); + if (resultContext.IsByRef) + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ParametersBytes[i], types[i]); + } + } + else + { + parameters = null; + } + return (T)SerializationSelector.DeserializeParameter(resultContext.SerializationType, resultContext.ReturnParameterBytes, typeof(T)); + } + case WaitDataStatus.Overtime: + { + throw new TimeoutException("等待结果超时"); + } + } + return default; + } + + default: + return default; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + public Task InvokeAsync(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + Invoke(targetId, invokeKey, invokeOption, parameters); + }); + } + + /// + public Task InvokeAsync(string targetId, string invokeKey, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + return Invoke(targetId, invokeKey, invokeOption, parameters); + }); + } + + #endregion IdRpc + + private void CanceledInvoke(object obj) + { + if (obj is CanceledPackage canceled) + { + using (ByteBlock byteBlock = new ByteBlock()) + { + canceled.Package(byteBlock); + Send(TouchRpcUtility.P_204_CancelInvoke, byteBlock); + } + } + } + + private void InvokeThis(object o) + { + try + { + TouchRpcPackage rpcPackage = (TouchRpcPackage)o; + + List psData = rpcPackage.ParametersBytes; + if (rpcPackage.Feedback == FeedbackType.WaitSend) + { + using (ByteBlock returnByteBlock = new ByteBlock()) + { + var methodName = rpcPackage.MethodName; + var parametersBytes = rpcPackage.ParametersBytes; + + rpcPackage.SwitchId(); + rpcPackage.MethodName = default; + rpcPackage.ParametersBytes = default; + rpcPackage.Status = TouchSocketStatus.Success.ToValue(); + rpcPackage.Package(returnByteBlock); + Send(TouchRpcUtility.P_1200_Invoke_Response, returnByteBlock); + + rpcPackage.SwitchId(); + rpcPackage.MethodName = methodName; + rpcPackage.ParametersBytes = parametersBytes; + } + } + + InvokeResult invokeResult = new InvokeResult(); + object[] ps = null; + MethodInstance methodInstance = GetInvokeMethod?.Invoke(rpcPackage.MethodName); + TouchRpcCallContext callContext = null; + if (methodInstance != null) + { + try + { + if (methodInstance.IsEnable) + { + callContext = new TouchRpcCallContext() + { + Caller = Caller, + MethodInstance = methodInstance, + TouchRpcPackage = rpcPackage + }; + + m_contextDic.TryAdd(rpcPackage.Sign, callContext); + + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + ps = new object[methodInstance.ParameterTypes.Length]; + ps[0] = callContext; + for (int i = 0; i < psData.Count; i++) + { + ps[i + 1] = SerializationSelector.DeserializeParameter(rpcPackage.SerializationType, psData[i], methodInstance.ParameterTypes[i + 1]); + } + } + else + { + ps = new object[methodInstance.ParameterTypes.Length]; + for (int i = 0; i < methodInstance.ParameterTypes.Length; i++) + { + ps[i] = SerializationSelector.DeserializeParameter(rpcPackage.SerializationType, psData[i], methodInstance.ParameterTypes[i]); + } + } + } + else + { + invokeResult.Status = InvokeStatus.UnEnable; + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + } + else + { + invokeResult.Status = InvokeStatus.UnFound; + } + + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + invokeResult = RpcStore.Execute(rpcServer, ps, callContext); + } + + if (rpcPackage.Feedback == FeedbackType.OnlySend) + { + return; + } + + switch (invokeResult.Status) + { + case InvokeStatus.UnFound: + { + rpcPackage.Status = TouchSocketStatus.RpcMethodNotFind.ToValue(); + break; + } + case InvokeStatus.Success: + { + if (methodInstance.HasReturn) + { + rpcPackage.ReturnParameterBytes = SerializationSelector.SerializeParameter(rpcPackage.SerializationType, invokeResult.Result); + } + else + { + rpcPackage.ReturnParameterBytes = null; + } + + if (methodInstance.IsByRef) + { + rpcPackage.IsByRef = true; + rpcPackage.ParametersBytes = new List(); + + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + i = 1; + } + for (; i < ps.Length; i++) + { + rpcPackage.ParametersBytes.Add(SerializationSelector.SerializeParameter(rpcPackage.SerializationType, ps[i])); + } + } + else + { + rpcPackage.ParametersBytes = null; + } + + rpcPackage.Status = TouchSocketStatus.Success.ToValue(); + break; + } + case InvokeStatus.UnEnable: + { + rpcPackage.Status = TouchSocketStatus.RpcMethodDisable.ToValue(); + break; + } + case InvokeStatus.InvocationException: + { + rpcPackage.Status = TouchSocketStatus.RpcInvokeException.ToValue(); + rpcPackage.Message = invokeResult.Message; + break; + } + case InvokeStatus.Exception: + { + rpcPackage.Status = TouchSocketStatus.Exception.ToValue(); + rpcPackage.Message = invokeResult.Message; + break; + } + default: + return; + } + + m_contextDic.TryRemove(rpcPackage.Sign, out _); + + using (ByteBlock byteBlock = new ByteBlock()) + { + rpcPackage.MethodName = default; + rpcPackage.SwitchId(); + rpcPackage.Package(byteBlock); + Send(TouchRpcUtility.P_1200_Invoke_Response, byteBlock); + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs new file mode 100644 index 000000000..e1ee90260 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor-Stream.cs @@ -0,0 +1,295 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Rpc.TouchRpc +{ + public partial class RpcActor + { + /// + /// 发送流数据 + /// + /// + /// + /// + /// + public Result SendStream(Stream stream, StreamOperator streamOperator, Metadata metadata = default) + { + WaitStream waitStream = new WaitStream(); + WaitData waitData = WaitHandlePool.GetWaitData(waitStream); + waitStream.Metadata = metadata; + long size = stream.Length - stream.Position; + streamOperator.SetLength(size); + waitStream.Size = size; + waitStream.StreamType = stream.GetType().FullName; + ByteBlock byteBlock = BytePool.Default.GetByteBlock(TouchRpcUtility.TransferPackage); + byteBlock.WriteObject(waitStream); + try + { + Send(TouchRpcUtility.P_400_SendStreamToSocketClient_Request, byteBlock); + + waitData.SetCancellationToken(streamOperator.Token); + + waitData.Wait(streamOperator.Timeout); + + switch (waitData.Status) + { + case WaitDataStatus.SetRunning: + { + WaitStream waitStreamResult = (WaitStream)waitData.WaitResult; + if (waitStreamResult.Status == 1) + { + if (TrySubscribeChannel(waitStreamResult.ChannelID, out Channel channel)) + { + while (true) + { + if (streamOperator.Token.IsCancellationRequested) + { + channel.Cancel(); + return streamOperator.SetResult(new Result(ResultCode.Canceled)); + } + int r = stream.Read(byteBlock.Buffer, 0, + (int)Math.Min(TouchRpcUtility.TransferPackage, streamOperator.MaxSpeed / 10.0)); + if (r <= 0) + { + channel.Complete(); + return streamOperator.SetResult(new Result(ResultCode.Success)); + } + + channel.Write(byteBlock.Buffer, 0, r); + streamOperator.AddFlow(r); + } + } + else + { + return streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.SetChannelFail.GetDescription())); + } + } + else if (waitStreamResult.Status == 2) + { + return streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitStreamResult.Message))); + } + else if (waitStreamResult.Status == 3) + { + return streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.Exception.GetDescription(waitStreamResult.Message))); + } + else + { + return streamOperator.SetResult(new Result(ResultCode.Error)); + } + } + case WaitDataStatus.Overtime: + { + return streamOperator.SetResult(new Result(ResultCode.Overtime)); + } + case WaitDataStatus.Canceled: + { + return streamOperator.SetResult(new Result(ResultCode.Canceled)); + } + case WaitDataStatus.Disposed: + default: + { + return streamOperator.SetResult(new Result(ResultCode.Error)); + } + } + } + catch (Exception ex) + { + return streamOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + } + finally + { + WaitHandlePool.Destroy(waitData); + byteBlock.Dispose(); + } + } + + /// + /// 发送流数据 + /// + /// + /// + /// + /// + public Task SendStreamAsync(Stream stream, StreamOperator streamOperator, Metadata metadata = default) + { + return EasyTask.Run(() => + { + return SendStream(stream, streamOperator, metadata); + }); + } + + private void RequestStreamToClient(object obj) + { + try + { + WaitStream waitStream = (WaitStream)obj; + StreamOperator streamOperator = new StreamOperator(); + StreamInfo streamInfo = new StreamInfo(waitStream.Size, waitStream.StreamType); + StreamOperationEventArgs args = new StreamOperationEventArgs(streamOperator, waitStream.Metadata, streamInfo); + + try + { + OnStreamTransfering?.Invoke(this, args); + + if (args.IsPermitOperation) + { + if (args.Bucket != null) + { + waitStream.Status = 1; + Channel channel = CreateChannel(); + waitStream.ChannelID = channel.ID; + TaskTransferingStream(streamOperator, args, channel, waitStream.Size); + } + else + { + streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.StreamBucketNull.GetDescription())); + waitStream.Status = 3; + waitStream.Message = "未设置流容器"; + + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(new Result(ResultCode.Error, waitStream.Message), waitStream.Metadata, streamInfo) + { Message = args.Message }); + } + } + else + { + streamOperator.SetResult(new Result(ResultCode.Error, args.Message)); + waitStream.Status = 2; + waitStream.Message = args.Message; + + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitStream.Message)), waitStream.Metadata, streamInfo) + { Message = args.Message }); + } + } + catch (Exception ex) + { + streamOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + waitStream.Status = 3; + waitStream.Message = ex.Message; + + Logger.Log(LogType.Error, this, $"在{nameof(RequestStreamToClient)}中发生错误。", ex); + } + + waitStream.Metadata = null; + using (ByteBlock byteBlock = new ByteBlock()) + { + byteBlock.WriteObject(waitStream); + Send(TouchRpcUtility.P_401_SendStreamToClient, byteBlock); + } + } + catch + { + } + } + + private void RequestStreamToSocketClient(object obj) + { + try + { + WaitStream waitStream = (WaitStream)obj; + StreamOperator streamOperator = new StreamOperator(); + StreamInfo streamInfo = new StreamInfo(waitStream.Size, waitStream.StreamType); + StreamOperationEventArgs args = new StreamOperationEventArgs(streamOperator, waitStream.Metadata, streamInfo); + + try + { + OnStreamTransfering?.Invoke(this, args); + if (args.IsPermitOperation) + { + if (args.Bucket != null) + { + waitStream.Status = 1; + Channel channel = CreateChannel(); + waitStream.ChannelID = channel.ID; + TaskTransferingStream(streamOperator, args, channel, waitStream.Size); + } + else + { + streamOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.StreamBucketNull.GetDescription())); + waitStream.Status = 3; + waitStream.Message = "未设置流容器"; + + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(new Result(ResultCode.Error, waitStream.Message), waitStream.Metadata, streamInfo) + { Message = args.Message }); + } + } + else + { + streamOperator.SetResult(new Result(ResultCode.Error, args.Message)); + waitStream.Status = 2; + waitStream.Message = args.Message; + + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitStream.Message)), waitStream.Metadata, streamInfo) + { Message = args.Message }); + } + } + catch (Exception ex) + { + streamOperator.SetResult(new Result(ResultCode.Error, ex.Message)); + waitStream.Status = 3; + waitStream.Message = ex.Message; + + Logger.Log(LogType.Error, this, $"在{nameof(RequestStreamToSocketClient)}中发生错误。", ex); + } + + waitStream.Metadata = null; + using (ByteBlock byteBlock = new ByteBlock()) + { + byteBlock.WriteObject(waitStream); + Send(TouchRpcUtility.P_1400_SendStreamToSocketClient_Response, byteBlock); + } + } + catch + { + } + } + + private void TaskTransferingStream(StreamOperator streamOperator, StreamOperationEventArgs args, Channel channel, long size) + { + ThreadPool.QueueUserWorkItem((obj) => + { + try + { + streamOperator.SetLength(size); + Stream stream = args.Bucket; + while (channel.MoveNext()) + { + if (streamOperator.Token.IsCancellationRequested) + { + channel.Cancel(); + streamOperator.SetResult(new Result(ResultCode.Canceled)); + break; + } + var data = channel.GetCurrent(); + if (data != null) + { + stream.Write(data, 0, data.Length); + streamOperator.AddFlow(data.Length); + } + } + OnStreamTransfered?.Invoke(this, new StreamStatusEventArgs(streamOperator.SetResult(new Result(channel.Status.ToResultCode())), + args.Metadata, args.StreamInfo) + { Bucket = stream, Message = args.Message }); + } + catch + { + } + }); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs new file mode 100644 index 000000000..b796f5eda --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/RpcActor.cs @@ -0,0 +1,1387 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// RpcActor + /// + public partial class RpcActor : DisposableObject, IRpcActor + { + /// + /// 结束标识编码。 + /// + public static readonly byte[] EndCodes = new byte[] { 20, 17, 11, 25 }; + + #region 委托 + + /// + /// 获取调用函数的委托 + /// + public Func GetInvokeMethod { get; set; } + + /// + /// 请求关闭 + /// + public Action OnClose { get; set; } + + /// + /// 当文件传输结束之后。并不意味着完成传输,请通过属性值进行判断。 + /// + public Action OnFileTransfered { get; set; } + + /// + /// 当需要路由的时候 + /// + public Action OnRouting { get; set; } + + /// + /// 在文件传输即将进行时触发。 + /// + public Action OnFileTransfering { get; set; } + + /// + /// 查找其他RpcActor + /// + public Func OnFindRpcActor { get; set; } + + /// + /// 在完成握手连接时 + /// + public Action OnHandshaked { get; set; } + + /// + /// 握手 + /// + public Action OnHandshaking { get; set; } + + /// + /// 接收到数据 + /// + public Action OnReceived { get; set; } + + /// + /// 重设ID + /// + public Action OnResetID { get; set; } + + /// + /// 流数据处理,用户需要在此事件中对e.Bucket手动释放。 + /// + public Action OnStreamTransfered { get; set; } + + /// + /// 即将接收流数据,用户需要在此事件中对e.Bucket初始化。 + /// + public Action OnStreamTransfering { get; set; } + + /// + /// 发送数据接口 + /// + public Action[]> OutputSend { get; set; } + + #endregion 委托 + + #region 属性 + + /// + /// 文件资源访问接口。 + /// + public IFileResourceController FileController { get; set; } + + /// + /// 本节点ID + /// + public string ID { get; set; } + + /// + /// + /// + public bool IsHandshaked { get; private set; } + + /// + /// 是否为服务器组件 + /// + public bool IsService { get; private set; } + + /// + /// 日志 + /// + public ILog Logger { get; set; } + + /// + /// 获取可用于同步对的访问的对象。 + /// + public object SyncRoot { get; } = new object(); + + /// + /// + /// + public Func TryCanInvoke { get; set; } + + /// + /// 等待返回池 + /// + public WaitHandlePool WaitHandlePool { get; private set; } + + #endregion 属性 + + /// + /// 构造函数 + /// + public RpcActor(bool isService) + { + m_eventArgs = new ConcurrentDictionary(); + WaitHandlePool = new WaitHandlePool(); + m_userChannels = new ConcurrentDictionary(); + m_contextDic = new ConcurrentDictionary(); + IsService = isService; + } + + /// + /// 关闭 + /// + /// + public void Close(string message) + { + if (IsHandshaked) + { + IsHandshaked = false; + foreach (var item in m_userChannels.Values) + { + item.RequestDispose(false); + } + var keys = m_contextDic.Keys.ToArray(); + foreach (var item in keys) + { + if (m_contextDic.TryRemove(item, out TouchRpcCallContext rpcCallContext)) + { + rpcCallContext.TryCancel(); + } + } + WaitHandlePool.CancelAll(); + OnClose?.Invoke(this, message); + } + } + + /// + /// 建立对点 + /// + /// + /// + /// + public void Handshake(string verifyToken, string id, CancellationToken token = default, int timeout = 5000, Metadata metadata = null) + { + if (IsHandshaked) + { + return; + } + WaitVerify waitVerify = new WaitVerify() + { + Token = verifyToken, + ID = id, + Metadata = metadata + }; + WaitData waitData = WaitHandlePool.GetWaitData(waitVerify); + waitData.SetCancellationToken(token); + + try + { + SendFastObject(TouchRpcUtility.P_0_Handshake_Request, waitVerify); + switch (waitData.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + { + WaitVerify verifyResult = (WaitVerify)waitData.WaitResult; + if (verifyResult.Status == 1) + { + ID = verifyResult.ID; + IsHandshaked = true; + OnHandshaked?.Invoke(this, new VerifyOptionEventArgs(verifyToken, verifyResult.Metadata) { Message = "成功建立" }); + verifyResult.Handle = true; + return; + } + else if (verifyResult.Status == 3) + { + verifyResult.Handle = true; + Close("连接数量已达到服务器设定最大值"); + throw new Exception("连接数量已达到服务器设定最大值"); + } + else if (verifyResult.Status == 4) + { + verifyResult.Handle = true; + Close("服务器拒绝连接"); + throw new Exception("服务器拒绝连接"); + } + else + { + verifyResult.Handle = true; + Close(verifyResult.Message); + throw new TokenVerifyException(verifyResult.Message); + } + } + case WaitDataStatus.Overtime: + Close("连接超时"); + throw new TimeoutException("连接超时"); + case WaitDataStatus.Canceled: + case WaitDataStatus.Disposed: + default: + Close(null); + return; + } + } + finally + { + WaitHandlePool.Destroy(waitData); + } + } + + /// + /// 处理接收数据 + /// + /// + public void InputReceivedData(ByteBlock byteBlock) + { + short protocol = TouchSocketBitConverter.Default.ToInt16(byteBlock.Buffer, 0); + switch (protocol) + { + #region 0-99 + + case TouchRpcUtility.P_0_Handshake_Request: + { + try + { + WaitVerify waitVerify = byteBlock.Seek(2).ReadObject(); + VerifyOptionEventArgs args = new VerifyOptionEventArgs(waitVerify.Token, waitVerify.Metadata); + if (!waitVerify.ID.IsNullOrEmpty()) + { + OnResetID?.Invoke(true, this, new WaitSetID(ID, waitVerify.ID)); + ID = waitVerify.ID; + } + OnHandshaking?.Invoke(this, args); + + if (args.IsPermitOperation) + { + waitVerify.ID = ID; + waitVerify.Status = 1; + byteBlock.Reset(); + byteBlock.WriteObject(waitVerify); + Send(TouchRpcUtility.P_1000_Handshake_Response, byteBlock); + IsHandshaked = true; + args.Message = "Success"; + ThreadPool.QueueUserWorkItem((o) => + { + try + { + OnHandshaked?.Invoke(this, args); + } + catch + { + } + }, default); + } + else + { + waitVerify.Status = 2; + waitVerify.Message = args.Message; + byteBlock.Reset(); + byteBlock.WriteObject(waitVerify); + Send(TouchRpcUtility.P_1000_Handshake_Response, byteBlock); + Close(args.Message); + } + } + catch (Exception ex) + { + Close(ex.Message); + } + return; + } + case TouchRpcUtility.P_1000_Handshake_Response: + { + WaitVerify waitVerify = byteBlock.Seek(2).ReadObject(); + WaitHandlePool.SetRun(waitVerify); + SpinWait.SpinUntil(() => + { + return waitVerify.Handle; + }, 3000); + return; + } + case TouchRpcUtility.P_1_ResetID_Request: + { + try + { + byteBlock.Pos = 2; + WaitSetID waitSetID = byteBlock.ReadObject(); + try + { + OnResetID?.Invoke(false, this, waitSetID); + ID = waitSetID.NewID; + waitSetID.Status = 1; + } + catch (System.Exception ex) + { + waitSetID.Status = 2; + waitSetID.Message = ex.Message; + } + byteBlock.Reset(); + byteBlock.WriteObject(waitSetID); + Send(TouchRpcUtility.P_1001_ResetID_Response, byteBlock); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1001_ResetID_Response: + { + try + { + byteBlock.Pos = 2; + WaitHandlePool.SetRun(byteBlock.ReadObject()); + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_2_Ping_Request://心跳 + { + byteBlock.Pos = 2; + + try + { + WaitPingPackage waitPing = new WaitPingPackage(); + waitPing.UnpackageRouter(byteBlock); + if (IsService && waitPing.Route) + { + if (TryRoute(RouteType.Ping, waitPing)) + { + if (TryFindRpcActor(waitPing.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_2_Ping_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitPing.UnpackageBody(byteBlock); + waitPing.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitPing.UnpackageBody(byteBlock); + waitPing.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + } + else + { + waitPing.UnpackageBody(byteBlock); + waitPing.Status = TouchSocketStatus.Success.ToValue(); + } + waitPing.SwitchId(); + byteBlock.Reset(); + waitPing.Package(byteBlock); + Send(TouchRpcUtility.P_1002_Ping_Response, byteBlock); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1002_Ping_Response://心跳 + { + try + { + byteBlock.Pos = 2; + WaitPingPackage waitPing = new WaitPingPackage(); + waitPing.UnpackageRouter(byteBlock); + if (IsService && waitPing.Route) + { + if (TryFindRpcActor(waitPing.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1002_Ping_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitPing.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitPing); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 0-99 + + #region 100-199 + + case TouchRpcUtility.P_100_CreateChannel_Request: + { + try + { + byteBlock.Pos = 2; + WaitCreateChannelPackage waitCreateChannel = new WaitCreateChannelPackage(); + waitCreateChannel.UnpackageRouter(byteBlock); + if (this.IsService && waitCreateChannel.Route) + { + if (this.TryRoute(RouteType.CreateChannel, waitCreateChannel)) + { + if (TryFindRpcActor(waitCreateChannel.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_100_CreateChannel_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitCreateChannel.UnpackageBody(byteBlock); + waitCreateChannel.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitCreateChannel.UnpackageBody(byteBlock); + waitCreateChannel.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + } + else + { + waitCreateChannel.UnpackageBody(byteBlock); + + while (true) + { + if (RequestCreateChannel(waitCreateChannel.ChannelID, waitCreateChannel.Route ? waitCreateChannel.SourceId : waitCreateChannel.TargetId)) + { + waitCreateChannel.Status = TouchSocketStatus.Success.ToValue(); + break; + } + else + { + waitCreateChannel.Status = TouchSocketStatus.ChannelExisted.ToValue(); + } + + if (!waitCreateChannel.Random) + { + break; + } + waitCreateChannel.ChannelID = new object().GetHashCode(); + } + } + + waitCreateChannel.SwitchId(); + byteBlock.Reset(); + waitCreateChannel.Package(byteBlock); + Send(TouchRpcUtility.P_1100_CreateChannel_Response, byteBlock); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1100_CreateChannel_Response: + { + try + { + byteBlock.Pos = 2; + WaitCreateChannelPackage waitCreateChannel = new WaitCreateChannelPackage(); + waitCreateChannel.UnpackageRouter(byteBlock); + if (this.IsService && waitCreateChannel.Route) + { + if (TryFindRpcActor(waitCreateChannel.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1100_CreateChannel_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + } + else + { + waitCreateChannel.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitCreateChannel); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_101_ChannelPackage: + { + try + { + byteBlock.Pos = 2; + ChannelPackage channelPackage = new ChannelPackage(); + channelPackage.UnpackageRouter(byteBlock); + if (this.IsService && channelPackage.Route) + { + if (TryFindRpcActor(channelPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_101_ChannelPackage, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + else + { + channelPackage.UnpackageBody(byteBlock); + channelPackage.Message = TouchSocketStatus.ClientNotFind.GetDescription(channelPackage.TargetId); + channelPackage.SwitchId(); + channelPackage.RunNow = true; + channelPackage.DataType = ChannelDataType.DisposeOrder; + byteBlock.Reset(); + channelPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_101_ChannelPackage, byteBlock); + } + } + else + { + channelPackage.UnpackageBody(byteBlock); + QueueChannelPackage(channelPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 100-199 + + #region 200-299 + + case TouchRpcUtility.P_200_Invoke_Request: + { + try + { + byteBlock.Pos = 2; + WaitRouterPackage waitRouterPackage = new WaitRouterPackage(); + waitRouterPackage.UnpackageRouter(byteBlock); + if (IsService && waitRouterPackage.Route) + { + if (this.TryRoute(RouteType.Rpc, waitRouterPackage)) + { + if (TryFindRpcActor(waitRouterPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_200_Invoke_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitRouterPackage.UnpackageBody(byteBlock); + waitRouterPackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitRouterPackage.UnpackageBody(byteBlock); + waitRouterPackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + + byteBlock.Reset(); + waitRouterPackage.SwitchId(); + + TouchRpcPackage rpcPackage = waitRouterPackage.Map(); + rpcPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_1200_Invoke_Response, byteBlock); + } + else + { + TouchRpcPackage rpcPackage = new TouchRpcPackage(); + rpcPackage.Unpackage(byteBlock.Seek(2)); + ThreadPool.QueueUserWorkItem(InvokeThis, rpcPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1200_Invoke_Response: + { + try + { + byteBlock.Pos = 2; + TouchRpcPackage rpcPackage = new TouchRpcPackage(); + rpcPackage.UnpackageRouter(byteBlock); + if (IsService && rpcPackage.Route) + { + if (this.TryFindRpcActor(rpcPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1200_Invoke_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + rpcPackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(rpcPackage); + } + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_204_CancelInvoke: + { + try + { + byteBlock.Pos = 2; + CanceledPackage canceledPackage = new CanceledPackage(); + canceledPackage.UnpackageRouter(byteBlock); + if (IsService && canceledPackage.Route) + { + if (this.TryFindRpcActor(canceledPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_204_CancelInvoke, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + canceledPackage.UnpackageBody(byteBlock); + if (m_contextDic.TryGetValue(canceledPackage.Sign, out TouchRpcCallContext context)) + { + context.TokenSource.Cancel(); + } + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 200-299 + + #region 400-499 + + case TouchRpcUtility.P_400_SendStreamToSocketClient_Request://StreamStatusToThis + { + try + { + byteBlock.Pos = 2; + ThreadPool.QueueUserWorkItem(RequestStreamToSocketClient, byteBlock.ReadObject()); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1400_SendStreamToSocketClient_Response://StreamStatusToThis + { + try + { + byteBlock.Pos = 2; + WaitStream waitStream = byteBlock.ReadObject(); + WaitHandlePool.SetRun(waitStream); + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_401_SendStreamToClient://StreamToThis + { + try + { + byteBlock.Pos = 2; + ThreadPool.QueueUserWorkItem(RequestStreamToClient, byteBlock.ReadObject()); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 400-499 + + #region 500-599 + + case TouchRpcUtility.P_500_PullFile_Request: + { + try + { + byteBlock.Pos = 2; + WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage(); + waitFileInfoPackage.UnpackageRouter(byteBlock); + if (IsService && waitFileInfoPackage.Route) + { + if (this.TryRoute(RouteType.PullFile, waitFileInfoPackage)) + { + if (TryFindRpcActor(waitFileInfoPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_500_PullFile_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + waitFileInfoPackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + waitFileInfoPackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + + byteBlock.Reset(); + waitFileInfoPackage.SwitchId(); + waitFileInfoPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_1500_PullFile_Response, byteBlock); + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(RequestPullFile, waitFileInfoPackage); + } + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1500_PullFile_Response: + { + try + { + byteBlock.Pos = 2; + WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage(); + waitFileInfoPackage.UnpackageRouter(byteBlock); + if (IsService && waitFileInfoPackage.Route) + { + if (TryFindRpcActor(waitFileInfoPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1500_PullFile_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitFileInfoPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + + return; + } + case TouchRpcUtility.P_501_BeginPullFile_Request: + { + try + { + byteBlock.Pos = 2; + WaitTransferPackage waitTransferPackage = new WaitTransferPackage(); + waitTransferPackage.UnpackageRouter(byteBlock); + if (IsService && waitTransferPackage.Route) + { + if (TryFindRpcActor(waitTransferPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_501_BeginPullFile_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitTransferPackage.UnpackageBody(byteBlock); + waitTransferPackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + byteBlock.Reset(); + waitTransferPackage.SwitchId(); + waitTransferPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_1501_BeginPullFile_Response, byteBlock); + } + else + { + waitTransferPackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(BeginPullFile, waitTransferPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1501_BeginPullFile_Response: + { + try + { + byteBlock.Pos = 2; + WaitTransferPackage waitTransferPackage = new WaitTransferPackage(); + waitTransferPackage.UnpackageRouter(byteBlock); + if (IsService && waitTransferPackage.Route) + { + if (TryFindRpcActor(waitTransferPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1501_BeginPullFile_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitTransferPackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitTransferPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_502_PushFile_Request: + { + try + { + byteBlock.Pos = 2; + WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage(); + waitFileInfoPackage.UnpackageRouter(byteBlock); + if (IsService && waitFileInfoPackage.Route) + { + if (this.TryRoute(RouteType.PullFile, waitFileInfoPackage)) + { + if (TryFindRpcActor(waitFileInfoPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_502_PushFile_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + waitFileInfoPackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + waitFileInfoPackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + + byteBlock.Reset(); + waitFileInfoPackage.SwitchId(); + waitFileInfoPackage.Package(byteBlock); + this.Send(TouchRpcUtility.P_1502_PushFile_Response, byteBlock); + } + else + { + waitFileInfoPackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(RequestPushFile, waitFileInfoPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1502_PushFile_Response: + { + try + { + byteBlock.Pos = 2; + WaitTransferPackage waitTransferPackage = new WaitTransferPackage(); + waitTransferPackage.UnpackageRouter(byteBlock); + if (IsService && waitTransferPackage.Route) + { + if (TryFindRpcActor(waitTransferPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1502_PushFile_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitTransferPackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitTransferPackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + + return; + } + case TouchRpcUtility.P_509_PushFileAck_Request: + { + try + { + byteBlock.Pos = 2; + WaitPushFileAckPackage waitPushFileAckPackage = new WaitPushFileAckPackage(); + waitPushFileAckPackage.UnpackageRouter(byteBlock); + if (IsService && waitPushFileAckPackage.Route) + { + if (TryFindRpcActor(waitPushFileAckPackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_509_PushFileAck_Request, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitPushFileAckPackage.UnpackageBody(byteBlock); + m_eventArgs.TryAdd((int)waitPushFileAckPackage.Sign, waitPushFileAckPackage); + + EasyTask.DelayRun(10000, waitPushFileAckPackage, (a) => + { + m_eventArgs.TryRemove((int)((WaitPushFileAckPackage)a).Sign, out _); + }); + } + } + catch (System.Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_517_PullSmallFile_Request: + { + try + { + byteBlock.Pos = 2; + var waitSmallFilePackage = new WaitSmallFilePackage(); + waitSmallFilePackage.UnpackageRouter(byteBlock); + if (IsService && waitSmallFilePackage.Route) + { + if (this.TryRoute(RouteType.PullFile, waitSmallFilePackage)) + { + if (this.TryFindRpcActor(waitSmallFilePackage.TargetId, out RpcActor actor)) + { + actor.Send(protocol, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + waitSmallFilePackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + waitSmallFilePackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + byteBlock.Reset(); + waitSmallFilePackage.SwitchId(); + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_1517_PullSmallFile_Response, byteBlock); + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(RequestPullSmallFile, waitSmallFilePackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1517_PullSmallFile_Response: + { + try + { + byteBlock.Pos = 2; + var waitSmallFilePackage = new WaitSmallFilePackage(); + waitSmallFilePackage.UnpackageRouter(byteBlock); + if (IsService && waitSmallFilePackage.Route) + { + if (this.TryFindRpcActor(waitSmallFilePackage.TargetId, out RpcActor actor)) + { + actor.Send(protocol, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitSmallFilePackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_518_PushSmallFile_Request: + { + try + { + byteBlock.Pos = 2; + var waitSmallFilePackage = new WaitSmallFilePackage(); + waitSmallFilePackage.UnpackageRouter(byteBlock); + if (IsService && waitSmallFilePackage.Route) + { + if (this.TryRoute(RouteType.PullFile, waitSmallFilePackage)) + { + if (this.TryFindRpcActor(waitSmallFilePackage.TargetId, out RpcActor actor)) + { + actor.Send(protocol, byteBlock.Buffer, 2, byteBlock.Len - 2); + return; + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + waitSmallFilePackage.Status = TouchSocketStatus.ClientNotFind.ToValue(); + } + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + waitSmallFilePackage.Status = TouchSocketStatus.RoutingNotAllowed.ToValue(); + } + byteBlock.Reset(); + waitSmallFilePackage.SwitchId(); + waitSmallFilePackage.Package(byteBlock); + Send(TouchRpcUtility.P_1518_PushSmallFile_Response, byteBlock); + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + ThreadPool.QueueUserWorkItem(RequestPushSmallFile, waitSmallFilePackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + case TouchRpcUtility.P_1518_PushSmallFile_Response: + { + try + { + byteBlock.Pos = 2; + var waitSmallFilePackage = new WaitSmallFilePackage(); + waitSmallFilePackage.UnpackageRouter(byteBlock); + + if (IsService && waitSmallFilePackage.Route) + { + if (this.TryFindRpcActor(waitSmallFilePackage.TargetId, out RpcActor actor)) + { + actor.Send(TouchRpcUtility.P_1518_PushSmallFile_Response, byteBlock.Buffer, 2, byteBlock.Len - 2); + } + } + else + { + waitSmallFilePackage.UnpackageBody(byteBlock); + WaitHandlePool.SetRun(waitSmallFilePackage); + } + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + return; + } + + #endregion 500-599 + + default: + { + try + { + OnReceived?.Invoke(this, protocol, byteBlock); + } + catch (Exception ex) + { + Logger.Error(this, $"在protocol={protocol}中发生错误。信息:{ex.Message}"); + } + break; + } + } + } + + /// + /// 尝试获取指定Id的RpcActor。一般此方法仅在Service下有效。 + /// + /// + /// + /// + public bool TryFindRpcActor(string targetId, out RpcActor rpcActor) + { + if (targetId == ID) + { + rpcActor = this; + return true; + } + if (OnFindRpcActor?.Invoke(targetId) is RpcActor actor) + { + rpcActor = actor; + return true; + } + + rpcActor = default; + return false; + } + + /// + /// 尝试请求路由,触发路由相关插件。 + /// + /// + /// + /// + public bool TryRoute(RouteType routerType, RouterPackage routerPackage) + { + try + { + PackageRouterEventArgs args = new PackageRouterEventArgs(routerType, routerPackage); + OnRouting?.Invoke(this, args); + return args.IsPermitOperation; + } + catch + { + return false; + } + } + + /// + /// 尝试请求路由,触发路由相关插件。并在路由失败时向中传递消息。 + /// + /// + /// + /// + public bool TryRoute(RouteType routerType, WaitRouterPackage routerPackage) + { + try + { + PackageRouterEventArgs args = new PackageRouterEventArgs(routerType, routerPackage); + OnRouting?.Invoke(this, args); + routerPackage.Message = args.Message; + return args.IsPermitOperation; + } + catch + { + return false; + } + } + + /// + public bool Ping(int timeout = 5000) + { + return PrivatePing(default, timeout); + } + + /// + public bool Ping(string targetId, int timeout = 5000) + { + if (IsService) + { + if (this.TryFindRpcActor(targetId, out RpcActor rpcActor)) + { + return rpcActor.Ping(timeout); + } + return false; + } + return PrivatePing(targetId, timeout); + } + + private bool PrivatePing(string targetId, int timeout) + { + try + { + WaitPingPackage waitPing = new WaitPingPackage + { + TargetId = targetId, + SourceId = ID, + Route = targetId.HasValue() + }; + var wait = WaitHandlePool.GetWaitData(waitPing); + using (ByteBlock byteBlock = new ByteBlock()) + { + waitPing.Package(byteBlock); + Send(TouchRpcUtility.P_2_Ping_Request, byteBlock); + } + + switch (wait.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + { + switch (wait.WaitResult.Status.ToStatus()) + { + case TouchSocketStatus.Success: return true; + default: + return false; + } + } + case WaitDataStatus.Default: + case WaitDataStatus.Overtime: + case WaitDataStatus.Canceled: + case WaitDataStatus.Disposed: + default: + return false; + } + } + catch + { + return false; + } + } + + /// + /// 重新设置ID,并且同步到对端 + /// + /// + /// + public void ResetID(string id) + { + WaitSetID waitSetID = new WaitSetID(ID, id); + + WaitData waitData = WaitHandlePool.GetWaitData(waitSetID); + + ByteBlock byteBlock = new ByteBlock(); + byteBlock.WriteObject(waitSetID); + + Send(TouchRpcUtility.P_1_ResetID_Request, byteBlock.Buffer, 0, byteBlock.Len); + + switch (waitData.Wait(5000)) + { + case WaitDataStatus.SetRunning: + { + if (waitData.WaitResult.Status == 1) + { + ID = id; + } + else + { + throw new Exception(waitData.WaitResult.Message); + } + break; + } + case WaitDataStatus.Overtime: + throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription()); + case WaitDataStatus.Canceled: + break; + + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + + /// + /// 以Fast序列化,发送小(64K)对象。接收方需要将Pos设为2,然后ReadObject即可。 + /// + /// + /// + public void SendFastObject(short protocol, object obj) + { + using ByteBlock byteBlock = new ByteBlock(); + byteBlock.WriteObject(obj, SerializationType.FastBinary); + Send(protocol, byteBlock); + } + + /// + /// 以包发送小(64K)对象。接收方需要将Pos设为2,然后ReadPackage即可。 + /// + /// + /// + public void SendPackage(short protocol, IPackage package) + { + using ByteBlock byteBlock = new ByteBlock(); + package.Package(byteBlock); + Send(protocol, byteBlock); + } + + #region 重写 + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + Caller = null; + OnClose = null; + OnFileTransfered = null; + OnFileTransfering = null; + OnRouting = null; + OnFindRpcActor = null; + OnHandshaked = null; + OnHandshaking = null; + OnReceived = null; + OnResetID = null; + OnStreamTransfered = null; + OnStreamTransfering = null; + OutputSend = null; + WaitHandlePool.SafeDispose(); + Close(nameof(Dispose)); + base.Dispose(disposing); + } + + #endregion 重写 + + #region 协议同步发送 + + /// + /// 发送字节 + /// + /// + /// + /// + /// + public void Send(short protocol, byte[] buffer, int offset, int length) + { + ArraySegment[] transferBytes = new ArraySegment[] + { + new ArraySegment(TouchSocketBitConverter.Default.GetBytes(protocol)), + new ArraySegment(buffer,offset,length) + }; + OutputSend?.Invoke(this, transferBytes); + } + + private void Send(short protocol, ByteBlock byteBlock) + { + Send(protocol, byteBlock.Buffer, 0, byteBlock.Len); + } + + #endregion 协议同步发送 + + #region 协议异步发送 + + /// + /// 异步发送字节 + /// + /// + /// + /// + /// + public Task SendAsync(short protocol, byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(protocol, buffer, offset, length); + }); + } + + #endregion 协议异步发送 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs new file mode 100644 index 000000000..5573f964b --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/RpcActor/Udp/UdpRpcActor.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.TouchRpc +{ + internal class UdpRpcActor : RpcActor + { + private readonly UdpSessionBase m_udpSession; + private readonly EndPoint m_endPoint; + + public int Tick; + + public UdpRpcActor(UdpSessionBase udpSession, EndPoint endPoint, ILog logger) : base(false) + { + OutputSend = RpcActorSend; + m_udpSession = udpSession; + m_endPoint = endPoint; + Logger = logger; + } + + private void RpcActorSend(RpcActor actor, ArraySegment[] transferBytes) + { + m_udpSession.Send(m_endPoint, transferBytes); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs b/src/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs new file mode 100644 index 000000000..bb2504c47 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Stream/StreamInfo.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 流信息 + /// + public struct StreamInfo + { + /// + /// 构造函数 + /// + /// + /// + public StreamInfo(long size, string streamType) + { + Size = size; + StreamType = streamType; + } + + /// + /// 流长度 + /// + public long Size { get; private set; } + + /// + /// 流类型 + /// + public string StreamType { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs b/src/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs new file mode 100644 index 000000000..b839b7c45 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Stream/StreamOperator.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 流传输操作器 + /// + public class StreamOperator : FlowOperator + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs b/src/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs new file mode 100644 index 000000000..1a5dd62f0 --- /dev/null +++ b/src/TouchSocket/Rpc/TouchRpc/Stream/WaitStream.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Rpc.TouchRpc +{ + /// + /// 等待流状态返回 + /// + public class WaitStream : WaitResult + { + /// + /// 流长度 + /// + public long Size { get; set; } + + /// + /// 流类型 + /// + public string StreamType { get; set; } + + /// + /// 元数据 + /// + public Metadata Metadata { get; set; } + + /// + /// 开启的通道标识 + /// + public int ChannelID { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs b/src/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs new file mode 100644 index 000000000..d3dbe115e --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Attribute/OriginAttribute.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// 跨域相关设置 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public sealed class OriginAttribute : RpcActionFilterAttribute + { + /// + /// 允许客户端携带验证信息 + /// + public bool AllowCredentials { get; set; } = true; + + /// + /// 允许跨域的方法。 + /// 默认为“PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH” + /// + public string AllowMethods { get; set; } = "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH"; + + /// + /// 允许跨域的域名 + /// + public string AllowOrigin { get; set; } = "*"; + + /// + /// + /// + /// + /// + /// + public override void Executed(ICallContext callContext, object[] parameters, ref InvokeResult invokeResult) + { + if (callContext is IHttpCallContext httpCallContext && httpCallContext.HttpContext != default) + { + httpCallContext.HttpContext.Response.SetHeader("Access-Control-Allow-Origin", AllowOrigin); + httpCallContext.HttpContext.Response.SetHeader("Access-Control-Allow-Methods", AllowMethods); + httpCallContext.HttpContext.Response.SetHeader("Access-Control-Allow-Credentials", AllowCredentials.ToString().ToLower()); + } + base.Executed(callContext,parameters, ref invokeResult); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs b/src/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs new file mode 100644 index 000000000..998841cfa --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Attribute/RouterAttribute.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// 表示WebApi路由。 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class RouterAttribute : Attribute + { + /// + /// 表示WebApi路由。 + /// 该模板在用于方法时,会覆盖类的使用。 + /// 模板必须由“/”开始,如果没有设置,会自动补齐。 + /// 模板不支持参数约定,仅支持方法路由。 + /// 模板有以下约定: + /// + /// 不区分大小写 + /// 以“[Api]”表示当前类名,如果不包含此字段,则意味着会使用绝对设置 + /// 以“[Action]”表示当前方法名,如果不包含此字段,则意味着会使用绝对设置 + /// + /// + /// + /// + public RouterAttribute(string routeTemple) + { + if (!routeTemple.StartsWith("/")) + { + routeTemple = routeTemple.Insert(0, "/"); + } + RouteTemple = routeTemple; + } + + /// + /// 路由模板。 + /// + public string RouteTemple { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs b/src/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs new file mode 100644 index 000000000..3b02282f8 --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Attribute/WebApiAttribute.cs @@ -0,0 +1,163 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// WebApiAttribute + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class WebApiAttribute : RpcAttribute + { + private readonly HttpMethodType m_method; + + /// + /// 构造函数。 + /// + /// + public WebApiAttribute(HttpMethodType method) + { + m_method = method; + } + + /// + /// + /// + /// + public override Type[] GetGenericInterfaceTypes() + { + return new Type[] { typeof(IWebApiClient) }; + } + + /// + /// 函数类型。 + /// + public HttpMethodType Method => m_method; + + /// + /// + /// + /// + /// + public override string GetInvokenKey(MethodInstance methodInstance) + { + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + i = 1; + } + if (m_method == HttpMethodType.GET) + { + string actionUrl = GetRouteUrls(methodInstance)[0]; + if (methodInstance.ParameterNames.Length > i) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(actionUrl); + stringBuilder.Append("?"); + for (; i < methodInstance.ParameterNames.Length; i++) + { + stringBuilder.Append(methodInstance.ParameterNames[i] + "={&}".Replace("&", i.ToString())); + if (i != methodInstance.ParameterNames.Length - 1) + { + stringBuilder.Append("&"); + } + } + actionUrl = stringBuilder.ToString(); + } + return $"GET:{actionUrl}"; + } + else if (m_method == HttpMethodType.POST) + { + string actionUrl = GetRouteUrls(methodInstance)[0]; + if (methodInstance.ParameterNames.Length > i + 1) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(actionUrl); + stringBuilder.Append("?"); + for (; i < methodInstance.ParameterNames.Length - 1; i++) + { + stringBuilder.Append(methodInstance.ParameterNames[i] + "={&}".Replace("&", i.ToString())); + if (i != methodInstance.ParameterNames.Length - 2) + { + stringBuilder.Append("&"); + } + } + actionUrl = stringBuilder.ToString(); + } + return $"POST:{actionUrl}"; + } + else + { + return base.GetInvokenKey(methodInstance); + } + } + + /// + /// 获取路由路径。 + /// 路由路径的第一个值会被当做调用值。 + /// + /// + /// + public virtual string[] GetRouteUrls(MethodInstance methodInstance) + { + if (methodInstance.GetAttribute() is WebApiAttribute webApiAttribute) + { + List urls = new List(); + + var attrs = methodInstance.Info.GetCustomAttributes(typeof(RouterAttribute), true); + if (attrs.Length > 0) + { + foreach (RouterAttribute item in attrs) + { + string url = item.RouteTemple.ToLower() + .Replace("[api]", methodInstance.ServerType.Name) + .Replace("[action]", webApiAttribute.GetMethodName(methodInstance, false)).ToLower(); + + if (!urls.Contains(url)) + { + urls.Add(url); + } + } + } + else + { + attrs = methodInstance.ServerType.GetCustomAttributes(typeof(RouterAttribute), true); + if (attrs.Length > 0) + { + foreach (RouterAttribute item in attrs) + { + string url = item.RouteTemple.ToLower() + .Replace("[api]", methodInstance.ServerType.Name) + .Replace("[action]", webApiAttribute.GetMethodName(methodInstance, false)).ToLower(); + + if (!urls.Contains(url)) + { + urls.Add(url); + } + } + } + else + { + urls.Add($"/{methodInstance.Info.DeclaringType.Name}/{methodInstance.Name}".ToLower()); + } + } + + return urls.ToArray(); + } + return default; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Common/ActionResult.cs b/src/TouchSocket/Rpc/WebApi/Common/ActionResult.cs new file mode 100644 index 000000000..2e0eb815d --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Common/ActionResult.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// 结果状态 + /// + public class ActionResult + { + /// + /// 状态类型 + /// + public InvokeStatus Status { get; set; } + + /// + /// 消息 + /// + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs b/src/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs new file mode 100644 index 000000000..91dd15f51 --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Common/WebApiCallContext.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.Threading; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// WebApi调用上下文 + /// + internal class WebApiCallContext : IWebApiCallContext + { + private CancellationTokenSource m_tokenSource; + + /// + /// + /// + public object Caller { get; internal set; } + + /// + /// Http上下文 + /// + public HttpContext HttpContext { get; internal set; } + + /// + /// + /// + public MethodInstance MethodInstance { get; internal set; } + + /// + /// + /// + public CancellationTokenSource TokenSource + { + get + { + if (m_tokenSource == null) + { + m_tokenSource = new CancellationTokenSource(); + } + return m_tokenSource; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs b/src/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs new file mode 100644 index 000000000..5d6a24a1b --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Components/WebApiClient.cs @@ -0,0 +1,255 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Rpc.TouchRpc; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// WebApi客户端 + /// + public class WebApiClient : HttpClientBase, IWebApiClient + { + /// + /// 构造函数 + /// + public WebApiClient() + { + m_stringConverter = new StringConverter(); + } + + /// + /// + /// + public Func TryCanInvoke { get; set; } + + private readonly StringConverter m_stringConverter; + + /// + /// 字符串转化器 + /// + public StringConverter StringConverter => m_stringConverter; + + #region RPC调用 + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + string[] strs = method.Split(':'); + if (strs.Length != 2) + { + throw new RpcException("不是有效的url请求。"); + } + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + HttpRequest request = new HttpRequest(); + + switch (strs[0]) + { + case TouchSocketHttpUtility.Get: + { + request.InitHeaders() + .SetHost(RemoteIPHost.Host) + .SetUrl(strs[1].Format(parameters)) + .AsGet(); + break; + } + case TouchSocketHttpUtility.Post: + { + request.InitHeaders() + .SetHost(RemoteIPHost.Host) + .SetUrl(strs[1].Format(parameters)) + .AsPost(); + if (parameters.Length > 0) + { + request.FromJson(parameters[parameters.Length - 1].ToJson()); + } + break; + } + default: + break; + } + + HttpResponse response = RequestContent(request, false, invokeOption.Timeout, invokeOption.Token); + + if (invokeOption.FeedbackType != FeedbackType.WaitInvoke) + { + return default; + } + + if (response.StatusCode == "200") + { + return (T)m_stringConverter.ConvertFrom(response.GetBody(), typeof(T)); + } + else if (response.StatusCode == "422") + { + throw new RpcException(response.GetBody().FromJson().Message); + } + else + { + throw new RpcException(response.StatusMessage); + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + string[] strs = method.Split(':'); + if (strs.Length != 2) + { + throw new RpcException("不是有效的url请求。"); + } + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + HttpRequest request = new HttpRequest(); + + switch (strs[0]) + { + case TouchSocketHttpUtility.Get: + { + request.InitHeaders() + .SetHost(RemoteIPHost.Host) + .SetUrl(strs[1].Format(parameters)) + .AsGet(); + break; + } + case TouchSocketHttpUtility.Post: + { + request.InitHeaders() + .SetHost(RemoteIPHost.Host) + .SetUrl(strs[1].Format(parameters)) + .AsPost(); + if (parameters.Length > 0) + { + request.FromJson(parameters[parameters.Length - 1].ToJson()); + } + break; + } + default: + break; + } + HttpResponse response = RequestContent(request, false, invokeOption.Timeout, invokeOption.Token); + if (invokeOption.FeedbackType != FeedbackType.WaitInvoke) + { + return; + } + + if (response.StatusCode == "200") + { + return; + } + else if (response.StatusCode == "422") + { + throw new RpcException(response.GetBody().FromJson().Message); + } + else + { + throw new RpcException(response.StatusMessage); + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// 函数式调用 + /// + /// 函数名 + /// 参数 + /// Rpc调用设置 + /// + /// + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + Invoke(method, invokeOption, parameters); + }); + } + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// Rpc异常 + /// 其他异常 + /// 服务器返回结果 + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + return Invoke(method, invokeOption, parameters); + }); + } + + #endregion RPC调用 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs b/src/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs new file mode 100644 index 000000000..bbdeee12f --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Config/WebApiConfigExtensions.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Rpc.WebApi; + +namespace TouchSocket.Sockets +{ + /// + /// WebApiConfigExtensions + /// + public static class WebApiConfigExtensions + { + /// + /// 构建WebApiClient类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithWebApiClient(this TouchSocketConfig config) where TClient : IWebApiClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建WebApiClient类客户端,并连接 + /// + /// + /// + public static WebApiClient BuildWithWebApiClient(this TouchSocketConfig config) + { + return BuildWithWebApiClient(config); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs b/src/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs new file mode 100644 index 000000000..de24acc25 --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Enum/HttpMethodType.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Rpc.WebApi +{ + /// + /// 请求函数类型 + /// + public enum HttpMethodType + { + /// + /// 以GET方式。支持调用上下文。 + /// 以该方式时,所有的参数类型必须是基础类型。所有的参数来源均来自url参数。 + /// + GET, + + /// + /// 以Post方式。支持调用上下文。 + /// 以该方式时,可以应对以下情况: + /// + /// 仅有一个参数时,该参数可以为任意类型,且参数来源为Body + /// 当有多个参数时,最后一个参数可以为任意类型,且参数来源为Body,其余参数均必须是基础类型,且来自url参数。 + /// + /// + POST + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs b/src/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs new file mode 100644 index 000000000..0a2b56f23 --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Extensions/WebApiPluginsManagerExtension.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.WebApi; + +namespace TouchSocket.Core +{ + /// + /// WebApiPluginsManagerExtension + /// + public static class WebApiPluginsManagerExtension + { + /// + /// 使用WebApi的插件。仅服务器可用。 + /// + /// + /// + public static WebApiParserPlugin UseWebApi(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs b/src/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs new file mode 100644 index 000000000..17c1ab23a --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Interface/IHttpCallContext.cs @@ -0,0 +1,27 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Http; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// IHttpCallContext + /// + public interface IHttpCallContext : ICallContext + { + /// + /// Http上下文 + /// + HttpContext HttpContext { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs b/src/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs new file mode 100644 index 000000000..ec53726fd --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Interface/IWebApiCallContext.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// IWebApiCallContext + /// + public interface IWebApiCallContext : IHttpCallContext + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs b/src/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs new file mode 100644 index 000000000..f1b714016 --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Interface/IWebApiClient.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Http; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// IWebApiClient + /// + public interface IWebApiClient : IRpcClient, IHttpClient + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs b/src/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs new file mode 100644 index 000000000..9cce74596 --- /dev/null +++ b/src/TouchSocket/Rpc/WebApi/Plugins/WebApiParserPlugin.cs @@ -0,0 +1,354 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.WebApi +{ + /// + /// WebApi解析器 + /// + public class WebApiParserPlugin : HttpPluginBase, IRpcParser + { + private readonly ActionMap m_actionMap; + private readonly StringConverter m_converter; + private RpcStore m_rpcStore; + + /// + /// 构造函数 + /// + public WebApiParserPlugin([DependencyParamterInject(true)] RpcStore rpcStore) + { + m_actionMap = new ActionMap(); + m_converter = new StringConverter(); + rpcStore?.AddRpcParser(GetType().Name, this); + } + + /// + /// 转化器 + /// + public StringConverter Converter => m_converter; + + /// + /// 获取路由映射图 + /// + public ActionMap RouteMap => m_actionMap; + + /// + /// 所属服务器 + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// + /// + /// + /// + protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e) + { + if (m_actionMap.TryGetMethodInstance(e.Context.Request.RelativeURL.ToLower(), out MethodInstance methodInstance)) + { + e.Handled = true; + + InvokeResult invokeResult = new InvokeResult(); + object[] ps = null; + WebApiCallContext callContext = new WebApiCallContext() + { + Caller = client, + HttpContext = e.Context, + MethodInstance = methodInstance + }; + if (methodInstance.IsEnable) + { + try + { + ps = new object[methodInstance.Parameters.Length]; + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + ps[i] = callContext; + i++; + } + if (e.Context.Request.Query == null) + { + for (; i < methodInstance.Parameters.Length; i++) + { + ps[i] = methodInstance.ParameterTypes[i].GetDefault(); + } + } + else + { + for (; i < methodInstance.Parameters.Length; i++) + { + string value = e.Context.Request.Query.Get(methodInstance.ParameterNames[i]); + if (!value.IsNullOrEmpty()) + { + ps[i] = m_converter.ConvertFrom(value, methodInstance.ParameterTypes[i]); + } + else + { + ps[i] = methodInstance.ParameterTypes[i].GetDefault(); + } + } + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + } + else + { + invokeResult.Status = InvokeStatus.UnEnable; + } + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + invokeResult = m_rpcStore.Execute(rpcServer, ps, callContext); + } + + if (e.Context.Response.Responsed) + { + return; + } + HttpResponse httpResponse = e.Context.Response; + switch (invokeResult.Status) + { + case InvokeStatus.Success: + { + httpResponse.FromJson(m_converter.ConvertTo(invokeResult.Result)).SetStatus(); + break; + } + case InvokeStatus.UnFound: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("404"); + break; + } + case InvokeStatus.UnEnable: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("405"); + break; + } + case InvokeStatus.InvocationException: + case InvokeStatus.Exception: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("422"); + break; + } + } + + using (ByteBlock byteBlock = new ByteBlock()) + { + httpResponse.Build(byteBlock); + client.DefaultSend(byteBlock); + } + + if (!e.Context.Request.KeepAlive) + { + client.TryShutdown(SocketShutdown.Both); + } + } + + base.OnGet(client, e); + } + + /// + /// + /// + /// + /// + protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + if (m_actionMap.TryGetMethodInstance(e.Context.Request.RelativeURL.ToLower(), out MethodInstance methodInstance)) + { + e.Handled = true; + + InvokeResult invokeResult = new InvokeResult(); + object[] ps = null; + WebApiCallContext callContext = new WebApiCallContext() + { + Caller = client, + HttpContext = e.Context, + MethodInstance = methodInstance + }; + if (methodInstance.IsEnable) + { + try + { + int index; + ps = new object[methodInstance.Parameters.Length]; + int i = 0; + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + ps[i] = callContext; + i++; + index = methodInstance.Parameters.Length - 2; + } + else + { + index = methodInstance.Parameters.Length - 1; + } + if (e.Context.Request.Query == null) + { + for (; i < methodInstance.Parameters.Length - 1; i++) + { + ps[i] = methodInstance.ParameterTypes[i].GetDefault(); + } + } + else + { + for (; i < methodInstance.Parameters.Length - 1; i++) + { + string value = e.Context.Request.Query.Get(methodInstance.ParameterNames[i]); + if (!value.IsNullOrEmpty()) + { + ps[i] = m_converter.ConvertFrom(value, methodInstance.ParameterTypes[i]); + } + else + { + ps[i] = methodInstance.ParameterTypes[i].GetDefault(); + } + } + } + + if (index >= 0) + { + string str = e.Context.Request.GetBody(); + ps[index] = m_converter.ConvertFrom(str, methodInstance.ParameterTypes[index]); + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + } + else + { + invokeResult.Status = InvokeStatus.UnEnable; + } + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + invokeResult = m_rpcStore.Execute(rpcServer, ps, callContext); + } + + if (e.Context.Response.Responsed) + { + return; + } + HttpResponse httpResponse = e.Context.Response; + switch (invokeResult.Status) + { + case InvokeStatus.Success: + { + httpResponse.FromJson(m_converter.ConvertTo(invokeResult.Result)).SetStatus(); + break; + } + case InvokeStatus.UnFound: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("404", invokeResult.Status.ToString()); + break; + } + case InvokeStatus.UnEnable: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("405", invokeResult.Status.ToString()); + break; + } + case InvokeStatus.InvocationException: + case InvokeStatus.Exception: + { + string jsonString = m_converter.ConvertTo(new ActionResult() { Status = invokeResult.Status, Message = invokeResult.Message }); + httpResponse.FromJson(jsonString).SetStatus("422", invokeResult.Status.ToString()); + break; + } + } + + using (ByteBlock byteBlock = new ByteBlock()) + { + httpResponse.Build(byteBlock); + client.DefaultSend(byteBlock); + } + + if (!e.Context.Request.KeepAlive) + { + client.TryShutdown(SocketShutdown.Both); + } + } + + base.OnPost(client, e); + } + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is WebApiAttribute attribute) + { + string[] actionUrls = attribute.GetRouteUrls(methodInstance); + if (actionUrls != null) + { + foreach (var item in actionUrls) + { + m_actionMap.Add(item, methodInstance); + } + } + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is WebApiAttribute attribute) + { + string[] actionUrls = attribute.GetRouteUrls(methodInstance); + if (actionUrls != null) + { + foreach (var item in actionUrls) + { + m_actionMap.Remove(item); + } + } + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcService) + { + m_rpcStore = rpcService; + } + + #endregion RPC解析器 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs b/src/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs new file mode 100644 index 000000000..5d5da647e --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Attribute/XmlRpcAttribute.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// 适用于XmlRpc的标记 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class XmlRpcAttribute : RpcAttribute + { + /// + /// 适用于XmlRpc的标记. + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + /// + public XmlRpcAttribute(bool methodInvoke = false) + { + MethodInvoke = methodInvoke; + } + + /// + /// 适用于XmlRpc的标记. + /// + /// + public XmlRpcAttribute(string invokenKey) + { + InvokenKey = invokenKey; + } + + /// + /// 是否仅以函数名调用,当为True是,调用时仅需要传入方法名即可。 + /// + public bool MethodInvoke { get; } + + /// + /// + /// + /// + public override Type[] GetGenericInterfaceTypes() + { + return new Type[] { typeof(IXmlRpcClient) }; + } + + /// + /// + /// + /// + /// + public override string GetInvokenKey(MethodInstance methodInstance) + { + if (MethodInvoke) + { + return GetMethodName(methodInstance, false); + } + else + { + return base.GetInvokenKey(methodInstance); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs b/src/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs new file mode 100644 index 000000000..60d0327bf --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Common/XmlDataTool.cs @@ -0,0 +1,259 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections; +using System.Reflection; +using System.Text; +using System.Xml; +using TouchSocket.Core; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.XmlRpc +{ + internal static class XmlDataTool + { + public static object GetValue(XmlNode valueNode, Type type) + { + if (valueNode == null) + { + return type.GetDefault(); + } + switch (valueNode.Name) + { + case "boolean": + { + return bool.Parse(valueNode.InnerText); + } + case "i4": + case "int": + { + return int.Parse(valueNode.InnerText); + } + case "double": + { + return double.Parse(valueNode.InnerText); + } + case "dateTime.iso8601": + { + return DateTime.Parse(valueNode.InnerText); + } + case "base64": + { + return valueNode.InnerText; + } + case "struct": + { + object instance = Activator.CreateInstance(type); + foreach (XmlNode memberNode in valueNode.ChildNodes) + { + string name = memberNode.SelectSingleNode("name").InnerText; + PropertyInfo property = type.GetProperty(name); + property.SetValue(instance, GetValue(memberNode.SelectSingleNode("value").FirstChild, property.PropertyType)); + } + return instance; + } + case "arrays": + case "array": + { + if (type.GetElementType() != null) + { + XmlNode dataNode = valueNode.SelectSingleNode("data"); + Array array = Array.CreateInstance(type.GetElementType(), dataNode.ChildNodes.Count); + + int index = 0; + foreach (XmlNode arrayValueNode in dataNode.ChildNodes) + { + array.SetValue(GetValue(arrayValueNode.FirstChild, type.GetElementType()), index); + index++; + } + return array; + } + else if (type.GetGenericArguments().Length == 1) + { + XmlNode dataNode = valueNode.SelectSingleNode("data"); + IList array = (IList)Activator.CreateInstance(type); + + foreach (XmlNode arrayValueNode in dataNode.ChildNodes) + { + array.Add(GetValue(arrayValueNode.FirstChild, type.GetGenericArguments()[0])); + } + return array; + } + return type.GetDefault(); + } + default: + case "string": + { + return valueNode.InnerText; + } + } + } + + public static HttpRequest CreateRequest(string host, string url, string method, object[] parameters) + { + XmlDocument xml = new XmlDocument(); + + XmlDeclaration xmlDecl = xml.CreateXmlDeclaration("1.0", string.Empty, string.Empty); + xml.AppendChild(xmlDecl); + + XmlElement xmlElement = xml.CreateElement("methodCall"); + xml.AppendChild(xmlElement); + + XmlElement methodNameElement = xml.CreateElement("methodName"); + methodNameElement.InnerText = method; + xmlElement.AppendChild(methodNameElement); + + XmlElement paramsElement = xml.CreateElement("params"); + xmlElement.AppendChild(paramsElement); + + if (parameters != null) + { + foreach (var param in parameters) + { + XmlElement paramElement = xml.CreateElement("param"); + paramsElement.AppendChild(paramElement); + + XmlElement valueElement = xml.CreateElement("value"); + paramElement.AppendChild(valueElement); + + CreateParam(xml, valueElement, param); + } + } + + HttpRequest request = new HttpRequest(); + request.FromXML(xml.OuterXml) + .InitHeaders() + .SetUrl(url) + .SetHost(host) + .AsPost(); + return request; + } + + public static void CreateParam(XmlDocument xml, XmlNode xmlNode, object value) + { + if (value == null) + { + return; + } + if (value is int) + { + XmlElement valueElement = xml.CreateElement("i4"); + valueElement.InnerText = value.ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is bool) + { + XmlElement valueElement = xml.CreateElement("boolean"); + valueElement.InnerText = (value).ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is double) + { + XmlElement valueElement = xml.CreateElement("double"); + valueElement.InnerText = ((double)value).ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is string) + { + XmlElement valueElement = xml.CreateElement("string"); + valueElement.InnerText = value.ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is DateTime) + { + XmlElement valueElement = xml.CreateElement("dateTime.iso8601"); + valueElement.InnerText = ((DateTime)value).ToString(); + xmlNode.AppendChild(valueElement); + } + else if (value is byte[]) + { + XmlElement valueElement = xml.CreateElement("base64"); + string str = Convert.ToBase64String((byte[])value); + valueElement.InnerText = str; + xmlNode.AppendChild(valueElement); + } + else if (typeof(IList).IsAssignableFrom(value.GetType())) + { + IList array = (IList)value; + XmlElement arrayElement; + + arrayElement = xml.CreateElement("array"); + + xmlNode.AppendChild(arrayElement); + + XmlElement dataElememt = xml.CreateElement("data"); + arrayElement.AppendChild(dataElememt); + + foreach (var item in array) + { + XmlElement valueElement = xml.CreateElement("value"); + dataElememt.AppendChild(valueElement); + CreateParam(xml, valueElement, item); + } + } + else + { + XmlElement valueElement = xml.CreateElement("struct"); + xmlNode.AppendChild(valueElement); + + PropertyInfo[] propertyInfos = value.GetType().GetProperties(); + foreach (var propertyInfo in propertyInfos) + { + XmlElement memberElement = xml.CreateElement("member"); + valueElement.AppendChild(memberElement); + + XmlElement nameElement = xml.CreateElement("name"); + nameElement.InnerText = propertyInfo.Name; + memberElement.AppendChild(nameElement); + + XmlElement oValueElement = xml.CreateElement("value"); + memberElement.AppendChild(oValueElement); + + object oValue = propertyInfo.GetValue(value); + CreateParam(xml, oValueElement, oValue); + } + } + } + + public static void CreatResponse(HttpResponse httpResponse, object value) + { + XmlDocument xml = new XmlDocument(); + + XmlDeclaration xmlDecl = xml.CreateXmlDeclaration("1.0", string.Empty, string.Empty); + xml.AppendChild(xmlDecl); + + XmlElement xmlElement = xml.CreateElement("methodResponse"); + + xml.AppendChild(xmlElement); + + XmlElement paramsElement = xml.CreateElement("params"); + xmlElement.AppendChild(paramsElement); + + XmlElement paramElement = xml.CreateElement("param"); + paramsElement.AppendChild(paramElement); + + XmlElement valueElement = xml.CreateElement("value"); + paramElement.AppendChild(valueElement); + + CreateParam(xml, valueElement, value); + + ByteBlock xmlBlock = new ByteBlock(); + xml.Save(xmlBlock); + + string xmlString = Encoding.UTF8.GetString(xmlBlock.Buffer, 0, xmlBlock.Len); + + httpResponse.FromXML(xmlString); + xmlBlock.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs b/src/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs new file mode 100644 index 000000000..0c53566dd --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Common/XmlRpcCallContext.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading; +using TouchSocket.Http; + +namespace TouchSocket.Rpc.XmlRpc +{ + internal class XmlRpcCallContext : IXmlRpcCallContext + { + private CancellationTokenSource m_tokenSource; + + public object Caller { get; internal set; } + + public MethodInstance MethodInstance { get; internal set; } + + public CancellationTokenSource TokenSource + { + get + { + if (m_tokenSource == null) + { + m_tokenSource = new CancellationTokenSource(); + } + return m_tokenSource; + } + } + + /// + /// + /// + public HttpContext HttpContext { get; internal set; } + + public string XmlString { get; internal set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs b/src/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs new file mode 100644 index 000000000..f5b275e25 --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Components/XmlRpcClient.cs @@ -0,0 +1,183 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using System.Xml; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Rpc.TouchRpc; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// XmlRpc客户端 + /// + public class XmlRpcClient : HttpClientBase, IXmlRpcClient + { + private readonly object m_invokeLocker = new object(); + + /// + /// + /// + public Func TryCanInvoke { get; set; } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + lock (m_invokeLocker) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + using (ByteBlock byteBlock = new ByteBlock(BufferLength)) + { + HttpRequest request = XmlDataTool.CreateRequest(RemoteIPHost.Host, RemoteIPHost.GetUrlPath(), method, parameters); + + HttpResponse response = RequestContent(request, invokeOption.FeedbackType == FeedbackType.OnlySend, invokeOption.Timeout, invokeOption.Token); + if (invokeOption.FeedbackType != FeedbackType.WaitInvoke) + { + return default; + } + + if (response.StatusCode != "200") + { + throw new Exception(response.StatusMessage); + } + else + { + XmlDocument xml = new XmlDocument(); + xml.LoadXml(response.GetBody()); + XmlNode paramNode = xml.SelectSingleNode("methodResponse/params/param"); + if (paramNode != null) + { + return (T)XmlDataTool.GetValue(paramNode.FirstChild.FirstChild, typeof(T)); + } + return default; + } + } + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types) + { + lock (m_invokeLocker) + { + if (invokeOption == default) + { + invokeOption = InvokeOption.WaitInvoke; + } + + using (ByteBlock byteBlock = new ByteBlock(BufferLength)) + { + HttpRequest request = XmlDataTool.CreateRequest(RemoteIPHost.Host, RemoteIPHost.GetUrlPath(), method, parameters); + var response = RequestContent(request, invokeOption.FeedbackType == FeedbackType.OnlySend, invokeOption.Timeout, invokeOption.Token); + if (invokeOption.FeedbackType != FeedbackType.WaitInvoke) + { + return; + } + if (response.StatusCode != "200") + { + throw new Exception(response.StatusMessage); + } + } + } + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// Rpc调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public T Invoke(string method, IInvokeOption invokeOption, params object[] parameters) + { + return Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// 函数式调用 + /// + /// 函数名 + /// 参数 + /// Rpc调用设置 + /// + /// + /// + /// + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + Invoke(method, invokeOption, parameters); + }); + } + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// Rpc调用设置 + /// 调用超时 + /// 序列化异常 + /// Rpc异常 + /// 其他异常 + /// 服务器返回结果 + public Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters) + { + return EasyTask.Run(() => + { + return Invoke(method, invokeOption, parameters); + }); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs b/src/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs new file mode 100644 index 000000000..617b39a19 --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Config/XmlRpcConfigExtensions.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; +using TouchSocket.Rpc.XmlRpc; + +namespace TouchSocket.Sockets +{ + /// + /// XmlRpcConfigExtensions + /// + public static class XmlRpcConfigExtensions + { + /// + /// 构建XmlRpcClient类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithXmlRpcClient(this TouchSocketConfig config) where TClient : IXmlRpcClient + { + TClient client = config.Container.Resolve(); + client.Setup(config); + client.Connect(); + return client; + } + + /// + /// 构建XmlRpcClient类客户端,并连接 + /// + /// + /// + public static XmlRpcClient BuildWithXmlRpcClient(this TouchSocketConfig config) + { + return BuildWithXmlRpcClient(config); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs b/src/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs new file mode 100644 index 000000000..2db28034c --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Extensions/XmlRpcPluginsManagerExtension.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.XmlRpc; + +namespace TouchSocket.Core +{ + /// + /// XmlRpcPluginsManagerExtension + /// + public static class XmlRpcPluginsManagerExtension + { + /// + /// 使用XmlRpc的插件。仅服务器可用。 + /// + /// + /// + public static XmlRpcParserPlugin UseXmlRpc(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs b/src/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs new file mode 100644 index 000000000..957ef4268 --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcCallContext.cs @@ -0,0 +1,27 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Rpc.WebApi; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// IXmlRpcCallContext + /// + public interface IXmlRpcCallContext : IHttpCallContext + { + /// + /// XmlRpc的调用字符串。 + /// + string XmlString { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs b/src/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs new file mode 100644 index 000000000..50e9e6bf9 --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Interface/IXmlRpcClient.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Http; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// IWebApiClient + /// + public interface IXmlRpcClient : IRpcClient, IHttpClient + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs b/src/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs new file mode 100644 index 000000000..f09ca5991 --- /dev/null +++ b/src/TouchSocket/Rpc/XmlRpc/Plugins/XmlRpcParserPlugin.cs @@ -0,0 +1,217 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using System.Xml; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; + +namespace TouchSocket.Rpc.XmlRpc +{ + /// + /// XmlRpc解析器 + /// + public class XmlRpcParserPlugin : HttpPluginBase, IRpcParser + { + private readonly ActionMap m_actionMap; + private RpcStore m_rpcStore; + private string m_xmlRpcUrl = "/xmlrpc"; + + /// + /// 构造函数 + /// + public XmlRpcParserPlugin([DependencyParamterInject(true)] RpcStore rpcStore) + { + m_actionMap = new ActionMap(); + rpcStore?.AddRpcParser(GetType().Name, this); + } + + /// + /// XmlRpc调用 + /// + public ActionMap ActionMap => m_actionMap; + + /// + /// 所属服务器 + /// + public RpcStore RpcStore => m_rpcStore; + + /// + /// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。 + /// + public string XmlRpcUrl + { + get => m_xmlRpcUrl; + set => m_xmlRpcUrl = string.IsNullOrEmpty(value) ? "/" : value; + } + + #region RPC解析器 + + void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is XmlRpcAttribute attribute) + { + m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); + } + } + } + + void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) + { + foreach (var methodInstance in methodInstances) + { + if (methodInstance.GetAttribute() is XmlRpcAttribute attribute) + { + m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); + } + } + } + + void IRpcParser.SetRpcStore(RpcStore rpcService) + { + m_rpcStore = rpcService; + } + + #endregion RPC解析器 + + /// + /// 当挂载在时,匹配Url然后响应。当设置为null或空时,会全部响应。 + /// + /// + /// + public XmlRpcParserPlugin SetXmlRpcUrl(string xmlRpcUrl) + { + XmlRpcUrl = xmlRpcUrl; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) + { + if (m_xmlRpcUrl == "/" || e.Context.Request.UrlEquals(m_xmlRpcUrl)) + { + e.Handled = true; + + XmlDocument xml = new XmlDocument(); + string xmlstring = e.Context.Request.GetBody(); + xml.LoadXml(xmlstring); + XmlNode methodName = xml.SelectSingleNode("methodCall/methodName"); + string actionKey = methodName.InnerText; + + object[] ps = null; + InvokeResult invokeResult = new InvokeResult(); + XmlRpcCallContext callContext = null; + + if (m_actionMap.TryGetMethodInstance(actionKey, out MethodInstance methodInstance)) + { + if (methodInstance.IsEnable) + { + try + { + callContext = new XmlRpcCallContext() + { + Caller = client, + HttpContext = e.Context, + MethodInstance = methodInstance, + XmlString = xmlstring + }; + ps = new object[methodInstance.ParameterNames.Length]; + XmlNode paramsNode = xml.SelectSingleNode("methodCall/params"); + if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) + { + ps[0] = callContext; + int index = 1; + foreach (XmlNode paramNode in paramsNode.ChildNodes) + { + XmlNode valueNode = paramNode.FirstChild.FirstChild; + ps[index] = (XmlDataTool.GetValue(valueNode, methodInstance.ParameterTypes[index])); + index++; + } + } + else + { + int index = 0; + foreach (XmlNode paramNode in paramsNode.ChildNodes) + { + XmlNode valueNode = paramNode.FirstChild.FirstChild; + ps[index] = (XmlDataTool.GetValue(valueNode, methodInstance.ParameterTypes[index])); + index++; + } + } + } + catch (Exception ex) + { + invokeResult.Status = InvokeStatus.Exception; + invokeResult.Message = ex.Message; + } + } + else + { + invokeResult.Status = InvokeStatus.UnEnable; + invokeResult.Message = "服务不可用"; + } + } + else + { + invokeResult.Status = InvokeStatus.UnFound; + invokeResult.Message = "没有找到这个服务。"; + } + + if (invokeResult.Status == InvokeStatus.Ready) + { + IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); + if (rpcServer is ITransientRpcServer transientRpcServer) + { + transientRpcServer.CallContext = callContext; + } + invokeResult = m_rpcStore.Execute(rpcServer, ps, callContext); + } + + HttpResponse httpResponse = e.Context.Response; + + ByteBlock byteBlock = new ByteBlock(); + + if (invokeResult.Status == InvokeStatus.Success) + { + XmlDataTool.CreatResponse(httpResponse, invokeResult.Result); + } + else + { + httpResponse.StatusCode = "201"; + httpResponse.StatusMessage = invokeResult.Message; + } + try + { + httpResponse.Answer(); + } + finally + { + byteBlock.Dispose(); + } + + if (!e.Context.Request.KeepAlive) + { + client.TryShutdown(SocketShutdown.Both); + } + } + base.OnPost(client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/BaseSocket.cs b/src/TouchSocket/Sockets/BaseSocket.cs new file mode 100644 index 000000000..d16cc7292 --- /dev/null +++ b/src/TouchSocket/Sockets/BaseSocket.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 通讯基类 + /// + public abstract class BaseSocket : DependencyObject, ISocket + { + /// + /// 通讯基类 + /// + public BaseSocket() + { + SyncRoot = new object(); + } + + private int m_bufferLength; + + /// + /// 数据交互缓存池限制,min=1024 byte + /// + public virtual int BufferLength + { + get => m_bufferLength; + set + { + if (value < 1024) + { + value = 1024 * 10; + } + m_bufferLength = value; + } + } + + /// + /// 同步根。 + /// + protected object SyncRoot; + + /// + /// 日志记录器 + /// + public ILog Logger { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/DelaySender.cs b/src/TouchSocket/Sockets/Common/DelaySender.cs new file mode 100644 index 000000000..ec9989d28 --- /dev/null +++ b/src/TouchSocket/Sockets/Common/DelaySender.cs @@ -0,0 +1,204 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 延迟发送器 + /// + public sealed class DelaySender : DisposableObject + { + private readonly ReaderWriterLockSlim m_lockSlim; + private readonly Action m_onError; + private readonly IntelligentDataQueue m_queueDatas; + private readonly Socket m_socket; + private readonly Timer m_timer; + private volatile bool m_sending; + + /// + /// 延迟发送器 + /// + /// + /// + /// + public DelaySender(Socket socket, int queueLength, Action onError) + { + m_socket = socket; + m_onError = onError; + m_queueDatas = new IntelligentDataQueue(queueLength); + m_lockSlim = new ReaderWriterLockSlim(); + m_timer = new Timer(TimerRun, null, 10, 10); + } + + /// + /// 延迟包最大尺寸,默认1024*512字节。 + /// + public int DelayLength { get; set; } = 1024 * 512; + + /// + /// 是否处于发送状态 + /// + public bool Sending + { + get + { + using (new ReadLock(m_lockSlim)) + { + return m_sending; + } + } + + private set + { + using (new WriteLock(m_lockSlim)) + { + m_sending = value; + } + } + } + + /// + /// 发送 + /// + public void Send(QueueDataBytes dataBytes) + { + m_queueDatas.Enqueue(dataBytes); + if (SwitchToRun()) + { + ThreadPool.QueueUserWorkItem(BeginSend); + } + } + + /// + /// 释放 + /// + /// + protected override void Dispose(bool disposing) + { + m_timer.SafeDispose(); + m_queueDatas.Clear(); + base.Dispose(disposing); + } + + private void BeginSend(object o) + { + try + { + byte[] buffer = BytePool.Default.GetByteCore(DelayLength); + while (!DisposedValue) + { + try + { + if (TryGet(buffer, out QueueDataBytes asyncByte)) + { + m_socket.AbsoluteSend(asyncByte.Buffer, asyncByte.Offset, asyncByte.Length); + } + else + { + break; + } + } + catch (Exception ex) + { + m_onError?.Invoke(ex); + break; + } + } + BytePool.Default.Recycle(buffer); + Sending = false; + } + catch + { + } + } + + private bool SwitchToRun() + { + using (new WriteLock(m_lockSlim)) + { + if (m_sending) + { + return false; + } + else + { + m_sending = true; + return true; + } + } + } + + private void TimerRun(object state) + { + if (SwitchToRun()) + { + BeginSend(null); + } + } + + private bool TryGet(byte[] buffer, out QueueDataBytes asyncByteDe) + { + int len = 0; + int surLen = buffer.Length; + while (true) + { + if (m_queueDatas.TryPeek(out QueueDataBytes asyncB)) + { + if (surLen > asyncB.Length) + { + if (m_queueDatas.TryDequeue(out QueueDataBytes asyncByte)) + { + Array.Copy(asyncByte.Buffer, asyncByte.Offset, buffer, len, asyncByte.Length); + len += asyncByte.Length; + surLen -= asyncByte.Length; + } + } + else if (asyncB.Length > buffer.Length) + { + if (len > 0) + { + break; + } + else + { + asyncByteDe = asyncB; + return true; + } + } + else + { + break; + } + } + else + { + if (len > 0) + { + break; + } + else + { + asyncByteDe = default; + return false; + } + } + } + asyncByteDe = new QueueDataBytes(buffer, 0, len); + return true; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/IPHost.cs b/src/TouchSocket/Sockets/Common/IPHost.cs new file mode 100644 index 000000000..57d67938e --- /dev/null +++ b/src/TouchSocket/Sockets/Common/IPHost.cs @@ -0,0 +1,214 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; + +namespace TouchSocket.Sockets +{ + /// + /// IP解析映射 + /// + /// 支持端口,ip,域名等。具体格式如下: + /// + /// 端口:直接按入参,该操作一般在监听时使用。 + /// ip:按127.0.0.1:7789入参。 + /// 域名:按tcp://127.0.0.1:7789、或者http://baidu.com入参。 + /// + /// + /// + public class IPHost + { + /// + /// IP解析映射 + /// + /// 支持端口,ip,域名等。具体格式如下: + /// + /// 端口:直接按入参,该操作一般在监听时使用。 + /// ip:按127.0.0.1:7789入参。 + /// 域名:按tcp://127.0.0.1:7789、或者http://baidu.com入参。 + /// + /// + /// + /// + public IPHost(string host) + { + if (TouchSocketUtility.IsURL(host)) + { + IsUri = true; + Uri = new Uri(host); + if (Uri.Port > 0) + { + Host = $"{Uri.Host}:{Uri.Port}"; + } + else + { + Host = Uri.Host; + } + if (TouchSocketUtility.IsIPv4(Uri.Host) || TouchSocketUtility.IsIPV6(Uri.Host)) + { + Analysis(Uri.Host, Uri.Port.ToString()); + } + else + { + if (HostNameToIP(Uri.Host, out IPAddress[] addresses)) + { + Analysis(addresses[0].ToString(), Uri.Port.ToString()); + } + } + } + else + { + Host = host; + int r = host.LastIndexOf(":"); + string ip = host.Substring(0, r); + Analysis(ip, host.Substring(r + 1, host.Length - (r + 1))); + } + } + + /// + /// 从IPAddress和端口号 + /// + /// + /// + public IPHost(IPAddress iPAddress, int port) : this($"{iPAddress}:{port}") + { + } + + /// + /// 从端口号创建。 + /// + /// + public IPHost(int port) : this($"0.0.0.0:{port}") + { + } + + /// + /// 寻址方案 + /// + public AddressFamily AddressFamily { get; private set; } + + /// + /// 终结点 + /// + public IPEndPoint EndPoint { get; private set; } + + /// + /// 具有端口信息的host + /// + public string Host { get; private set; } + + /// + /// IP + /// + public string IP { get; private set; } + + /// + /// 是否为Uri + /// + public bool IsUri { get; private set; } + + /// + /// 端口号 + /// + public int Port { get; private set; } + + /// + /// 统一资源标识 + /// + public Uri Uri { get; private set; } + + /// + /// 解析一个组的地址。 + /// + /// + /// + public static IPHost[] ParseIPHosts(string[] strs) + { + List iPs = new List(); + foreach (var item in strs) + { + iPs.Add(new IPHost(item)); + } + return iPs.ToArray(); + } + + /// + /// 获取Url全路径 + /// + /// + public string GetUrlPath() + { + if (IsUri) + { + return Uri.PathAndQuery; + } + return default; + } + + /// + /// 返回EndPoint字符串 + /// + /// + public override string ToString() + { + return EndPoint == null ? null : EndPoint.ToString(); + } + + private static bool HostNameToIP(string hostname, out IPAddress[] address) + { + try + { + IPHostEntry hostInfo = Dns.GetHostEntry(hostname); + address = hostInfo.AddressList; + if (address.Length > 0) + { + return true; + } + + return false; + } + catch + { + address = null; + return false; + } + } + + private void Analysis(string ip, string port) + { + try + { + int portNum = int.Parse(port); + IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), portNum); + if (ip.Contains(":")) + { + AddressFamily = AddressFamily.InterNetworkV6; + } + else + { + AddressFamily = AddressFamily.InterNetwork; + } + EndPoint = endPoint; + IP = ip; + Port = portNum; + } + catch (Exception ex) + { + throw new Exception($"IPHost初始化失败,信息:{ex.Message}", ex); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/KeepAliveValue.cs b/src/TouchSocket/Sockets/Common/KeepAliveValue.cs new file mode 100644 index 000000000..98bfb6dda --- /dev/null +++ b/src/TouchSocket/Sockets/Common/KeepAliveValue.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Runtime.InteropServices; + +namespace TouchSocket.Sockets +{ + /// + /// 保活机制 + /// + public class KeepAliveValue + { + /// + /// 保活机制 + /// + public byte[] KeepAliveTime + { + get + { + uint dummy = 0; + byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3]; + BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0); + BitConverter.GetBytes(Interval).CopyTo(inOptionValues, Marshal.SizeOf(dummy)); + BitConverter.GetBytes(AckInterval).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2); + return inOptionValues; + } + } + + /// + /// 是否启用保活。默认为True。 + /// + public bool Enable { get; set; } = true; + + /// + /// 发送间隔,默认20*1000ms + /// + public uint Interval { get; set; } = 20 * 1000; + + /// + /// 确认间隔,默认2*1000ms + /// + public uint AckInterval { get; set; } = 2 * 1000; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/NetworkMonitor.cs b/src/TouchSocket/Sockets/Common/NetworkMonitor.cs new file mode 100644 index 000000000..71424da27 --- /dev/null +++ b/src/TouchSocket/Sockets/Common/NetworkMonitor.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; + +namespace TouchSocket.Sockets +{ + /// + /// 网络监听器 + /// + public class NetworkMonitor + { + /// + /// 构造函数 + /// + /// + /// + public NetworkMonitor(IPHost iPHost, Socket socket) + { + this.iPHost = iPHost; + this.socket = socket ?? throw new ArgumentNullException(nameof(socket)); + } + + private readonly IPHost iPHost; + + /// + /// 监听地址组 + /// + public IPHost IPHost => iPHost; + + private readonly Socket socket; + + /// + /// Socket组件 + /// + public Socket Socket => socket; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/Options/ClientSslOption.cs b/src/TouchSocket/Sockets/Common/Options/ClientSslOption.cs new file mode 100644 index 000000000..1cf6d7203 --- /dev/null +++ b/src/TouchSocket/Sockets/Common/Options/ClientSslOption.cs @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Security.Cryptography.X509Certificates; + +namespace TouchSocket.Sockets +{ + /// + /// 客户端Ssl验证 + /// + public class ClientSslOption : SslOption + { + /// + /// 构造函数 + /// + public ClientSslOption() + { + X509Store store = new X509Store(StoreName.Root); + store.Open(OpenFlags.ReadWrite); + ClientCertificates = store.Certificates; + store.Close(); + } + + private string targetHost; + + /// + /// 目标Host + /// + public string TargetHost + { + get => targetHost; + set => targetHost = value; + } + + private X509CertificateCollection clientCertificates; + + /// + /// 验证组合 + /// + public X509CertificateCollection ClientCertificates + { + get => clientCertificates; + set => clientCertificates = value; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs b/src/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs new file mode 100644 index 000000000..e266b16fe --- /dev/null +++ b/src/TouchSocket/Sockets/Common/Options/DelaySenderOption.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// DelaySenderOption + /// + public class DelaySenderOption + { + /// + /// 延迟队列最大尺寸,默认1024*1024*10字节。 + /// + public int QueueLength { get; set; } = 1024 * 1024 * 10; + + /// + /// 延迟包最大尺寸,默认1024*512字节。 + /// + public int DelayLength { get; set; } = 1024 * 512; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs b/src/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs new file mode 100644 index 000000000..3e75ddb17 --- /dev/null +++ b/src/TouchSocket/Sockets/Common/Options/ServiceSslOption.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Security.Cryptography.X509Certificates; + +namespace TouchSocket.Sockets +{ + /// + /// 服务器Ssl设置 + /// + public class ServiceSslOption : SslOption + { + private X509Certificate certificate; + + /// + /// 证书 + /// + public X509Certificate Certificate + { + get => certificate; + set => certificate = value; + } + + private bool clientCertificateRequired; + + /// + /// 该值指定是否向客户端请求证书用于进行身份验证。 请注意,这只是一个请求 - 如果没有提供任何证书,服务器仍然可接受连接请求 + /// + public bool ClientCertificateRequired + { + get => clientCertificateRequired; + set => clientCertificateRequired = value; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/Options/SslOption.cs b/src/TouchSocket/Sockets/Common/Options/SslOption.cs new file mode 100644 index 000000000..bb0fcc8a6 --- /dev/null +++ b/src/TouchSocket/Sockets/Common/Options/SslOption.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net.Security; +using System.Security.Authentication; + +namespace TouchSocket.Sockets +{ + /// + /// Ssl配置 + /// + public abstract class SslOption + { + private SslProtocols sslProtocols; + + /// + /// 协议版本 + /// + public SslProtocols SslProtocols + { + get => sslProtocols; + set => sslProtocols = value; + } + + private bool checkCertificateRevocation; + + /// + /// 该值指定身份验证期间是否检查证书吊销列表 + /// + public bool CheckCertificateRevocation + { + get => checkCertificateRevocation; + set => checkCertificateRevocation = value; + } + + /// + /// SSL验证回调。 + /// + public RemoteCertificateValidationCallback CertificateValidationCallback { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/Protocol.cs b/src/TouchSocket/Sockets/Common/Protocol.cs new file mode 100644 index 000000000..09e173928 --- /dev/null +++ b/src/TouchSocket/Sockets/Common/Protocol.cs @@ -0,0 +1,132 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 协议类 + /// + public struct Protocol + { + /// + /// 值 + /// + private readonly string value; + + /// + /// 表示无协议 + /// + public static readonly Protocol None = new Protocol(); + + /// + /// 获取http协议 + /// + public static readonly Protocol Http = new Protocol("http"); + + /// + /// TCP协议 + /// + public static readonly Protocol TCP = new Protocol("tcp"); + + /// + /// UDP协议 + /// + public static readonly Protocol UDP = new Protocol("udp"); + + /// + /// 获取WebSocket协议 + /// + public static readonly Protocol WebSocket = new Protocol("ws"); + + /// + /// 表示 + /// + /// 值 + public Protocol(string value) + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentNullException(); + } + this.value = value; + } + + /// + /// 转换为字符串 + /// + /// + public override string ToString() + { + if (string.IsNullOrEmpty(value)) + { + return "None"; + } + return value; + } + + /// + /// 获取哈希码 + /// + /// + public override int GetHashCode() + { + if (value == null) + { + return string.Empty.GetHashCode(); + } + return value.ToLower().GetHashCode(); + } + + /// + /// 比较是否和目标相等 + /// + /// 目标 + /// + public override bool Equals(object obj) + { + if (obj is Protocol) + { + return GetHashCode() == obj.GetHashCode(); + } + return false; + } + + /// + /// 等于 + /// + /// + /// + /// + public static bool operator ==(Protocol a, Protocol b) + { + if (string.IsNullOrEmpty(a.value) && string.IsNullOrEmpty(b.value)) + { + return true; + } + return string.Equals(a.value, b.value, StringComparison.OrdinalIgnoreCase); + } + + /// + /// 不等于 + /// + /// + /// + /// + public static bool operator !=(Protocol a, Protocol b) + { + var state = a == b; + return !state; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/SocketCliectCollection.cs b/src/TouchSocket/Sockets/Common/SocketCliectCollection.cs new file mode 100644 index 000000000..e16d94257 --- /dev/null +++ b/src/TouchSocket/Sockets/Common/SocketCliectCollection.cs @@ -0,0 +1,156 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; + +namespace TouchSocket.Sockets +{ + /// + /// 客户端集合 + /// + [DebuggerDisplay("Count={Count}")] + public sealed class SocketClientCollection + { + private readonly ConcurrentDictionary m_tokenDic = new ConcurrentDictionary(); + + /// + /// 数量 + /// + public int Count => m_tokenDic.Count; + + /// + /// 获取SocketClient + /// + /// + /// + public ISocketClient this[string id] + { + get + { + TryGetSocketClient(id, out ISocketClient t); + return t; + } + } + + /// + /// 获取所有的客户端 + /// + /// + public IEnumerable GetClients() + { + return m_tokenDic.Values; + } + + /// + /// 获取ID集合 + /// + /// + public IEnumerable GetIDs() + { + return m_tokenDic.Keys; + } + + /// + /// 根据ID判断SocketClient是否存在 + /// + /// + /// + public bool SocketClientExist(string id) + { + if (string.IsNullOrEmpty(id)) + { + return false; + } + + if (m_tokenDic.ContainsKey(id)) + { + return true; + } + return false; + } + + /// + /// 尝试获取实例 + /// + /// + /// + /// + public bool TryGetSocketClient(string id, out ISocketClient socketClient) + { + if (string.IsNullOrEmpty(id)) + { + socketClient = null; + return false; + } + + return m_tokenDic.TryGetValue(id, out socketClient); + } + + /// + /// 尝试获取实例 + /// + /// + /// + /// + /// + public bool TryGetSocketClient(string id, out TClient socketClient) where TClient : ISocketClient + { + if (string.IsNullOrEmpty(id)) + { + socketClient = default; + return false; + } + + if (m_tokenDic.TryGetValue(id, out ISocketClient client)) + { + socketClient = (TClient)client; + return true; + } + socketClient = default; + return false; + } + + internal bool TryAdd(ISocketClient socketClient) + { + return m_tokenDic.TryAdd(socketClient.ID, socketClient); + } + + internal bool TryRemove(string id, out ISocketClient socketClient) + { + if (string.IsNullOrEmpty(id)) + { + socketClient = null; + return false; + } + return m_tokenDic.TryRemove(id, out socketClient); + } + + internal bool TryRemove(string id, out TClient socketClient) where TClient : ISocketClient + { + if (string.IsNullOrEmpty(id)) + { + socketClient = default; + return false; + } + + if (m_tokenDic.TryRemove(id, out ISocketClient client)) + { + socketClient = (TClient)client; + return true; + } + socketClient = default; + return false; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Common/TouchSocketUtility.cs b/src/TouchSocket/Sockets/Common/TouchSocketUtility.cs new file mode 100644 index 000000000..63e581a85 --- /dev/null +++ b/src/TouchSocket/Sockets/Common/TouchSocketUtility.cs @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Text.RegularExpressions; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TouchSocketUtility + /// + public class TouchSocketUtility + { + /// + /// 判断输入的字符串是否是一个超链接 + /// + /// + /// + public static bool IsURL(string input) + { + string pattern = @"^[a-zA-Z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$?"; + Regex regex = new Regex(pattern); + return regex.IsMatch(input); + } + + /// + /// 判断输入的字符串是否是表示一个IP地址 + /// + /// 被比较的字符串 + /// 是IP地址则为True + public static bool IsIPv4(string input) + { + try + { + string[] IPs = input.Split('.'); + Regex regex = new Regex(@"^\d+$"); + for (int i = 0; i < IPs.Length; i++) + { + if (!regex.IsMatch(IPs[i])) + { + return false; + } + if (Convert.ToUInt16(IPs[i]) > 255) + { + return false; + } + } + return true; + } + catch + { + return false; + } + } + + /// + /// 判断输入的字符串是否是合法的IPV6 地址 + /// + /// + /// + public static bool IsIPV6(string input) + { + string pattern = ""; + string temp = input; + string[] strs = temp.Split(':'); + if (strs.Length > 8) + { + return false; + } + int count = StringExtension.HitStringCount(input, "::"); + if (count > 1) + { + return false; + } + else if (count == 0) + { + pattern = @"^([\da-f]{1,4}:){7}[\da-f]{1,4}$"; + + Regex regex = new Regex(pattern); + return regex.IsMatch(input); + } + else + { + pattern = @"^([\da-f]{1,4}:){0,5}::([\da-f]{1,4}:){0,5}[\da-f]{1,4}$"; + Regex regex1 = new Regex(pattern); + return regex1.IsMatch(input); + } + } + + /// + /// 大数据边界 + /// + public const int BigDataBoundary = 1024 * 64; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/Factory/ClientFactory.cs b/src/TouchSocket/Sockets/Components/Factory/ClientFactory.cs new file mode 100644 index 000000000..440cf73d8 --- /dev/null +++ b/src/TouchSocket/Sockets/Components/Factory/ClientFactory.cs @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Client工厂 + /// + public abstract class ClientFactory : DisposableObject where TClient : IClient + { + /// + /// Client工厂 + /// + public ClientFactory() + { + this.MainConfig = new TouchSocketConfig(); + } + + /// + /// 已创建的客户端安全列表,一般不要直接操作。 + /// + public ConcurrentList CreatedClients { get; } = new ConcurrentList(); + + /// + /// 空闲客户端的安全队列,一般不要直接操作。 + /// + public ConcurrentQueue FreeClients { get; } = new ConcurrentQueue(); + + /// + /// 主通信客户端。 + /// + public abstract TClient MainClient { get; } + + /// + /// 主客户端配置 + /// + /// + public virtual TouchSocketConfig MainConfig { get; } + + /// + /// 最大客户端数量。默认10。 + /// + public int MaxCount { get; set; } = 10; + + /// + /// 池中维护的最小客户端数量。默认0。 + /// + public int MinCount { get; set; } + + /// + /// 检验主通信状态。最好在每次操作时都调用。 + /// + /// 如果状态异常,是否进行再次初始化 + /// + public abstract Result CheckStatus(bool tryInit = true); + + /// + /// 清理池中的所有客户端。 + /// + /// + public int Clear() + { + int count = 0; + foreach (var item in this.CreatedClients) + { + count++; + DisposeClient(item); + } + FreeClients.Clear(); + return count; + } + + /// + /// 释放客户端最后的调用。 + /// + /// + public abstract void DisposeClient(TClient client); + + /// + /// 获取空闲可用的客户端数量。 + /// + public abstract int GetAvailableCount(); + + /// + /// 获取用于传输的客户端。在此处返回的结果,必须完成基本初始化,例如连接等。 + /// + /// + /// + public abstract TClient GetTransferClient(TimeSpan waitTime); + + /// + /// 判断客户端是不是存活状态。 + /// + /// + /// + public abstract bool IsAlive(TClient client); + + /// + /// 释放使用完成的客户端 + /// + /// + public abstract void ReleaseTransferClient(TClient client); + + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + DisposeClient(MainClient); + this.Clear(); + } + + /// + /// 获取用于传输的客户端配置 + /// + /// + protected abstract TouchSocketConfig GetTransferConfig(); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs b/src/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs new file mode 100644 index 000000000..1158c46f9 --- /dev/null +++ b/src/TouchSocket/Sockets/Components/Factory/TcpClientFactory.cs @@ -0,0 +1,273 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 适用于Tcp客户端的连接工厂。 + /// + /// + public class TcpClientFactory : ClientFactory where TClient : ITcpClient, new() + { + private readonly TClient m_mainClient = new TClient(); + + private readonly SingleTimer m_singleTimer; + + private bool first = true; + + /// + /// 适用于Tcp客户端的连接工厂。 + /// + public TcpClientFactory() + { + m_singleTimer = new SingleTimer(1000, () => + { + List list = new List(); + foreach (var item in this.CreatedClients) + { + if (!this.IsAlive(item)) + { + list.Add(item); + } + } + + foreach (var item in list) + { + this.DisposeClient(item); + } + + if (IsAlive(this.MainClient)) + { + if (this.CreatedClients.Count < this.MinCount) + { + try + { + this.CreateTransferClient(); + } + catch + { + } + } + } + }); + } + + /// + /// 连接超时设定 + /// + public TimeSpan ConnectTimeout { get; set; } = TimeSpan.FromSeconds(5); + + /// + public override TClient MainClient { get => m_mainClient; } + + /// + /// 获取传输的客户端配置 + /// + public Func OnGetTransferConfig { get; set; } + + /// + public override Result CheckStatus(bool tryInit = true) + { + lock (this.m_singleTimer) + { + try + { + if (!IsAlive(m_mainClient)) + { + if (!tryInit) + { + return Result.UnknownFail; + } + if (first) + { + OnMainClientSetuping(); + MainClient.Setup(this.MainConfig); + first = false; + } + MainClient.Close(); + MainClient.Connect((int)this.ConnectTimeout.TotalMilliseconds); + } + return Result.Success; + } + catch (Exception ex) + { + return new Result(ex); + } + } + } + + /// + /// 在主客户端加载配置之前 + /// + protected virtual void OnMainClientSetuping() + { + + } + + /// + public override void DisposeClient(TClient client) + { + client.TryShutdown(); + client.SafeDispose(); + this.CreatedClients.Remove(client); + } + + /// + /// 获取可以使用的客户端数量。 + /// + /// 注意:该值不一定是的长度,当已创建数量小于设定的最大值时,也会累加未创建的值。 + /// + /// + /// + public override int GetAvailableCount() + { + return Math.Max(0, this.MaxCount - this.CreatedClients.Count) + this.FreeClients.Count; + } + + /// + /// 获取一个空闲的连接对象,如果等待超出设定的时间,则会创建新的连接。 + /// + /// 指定毫秒数 + /// + /// + /// + public TClient GetTransferClient(int waitTime) + { + return this.GetTransferClient(TimeSpan.FromMilliseconds(waitTime)); + } + + /// + /// 获取一个空闲的连接对象,如果等待超出1秒的时间,则会创建新的连接。 + /// + /// + /// + /// + public TClient GetTransferClient() + { + return this.GetTransferClient(TimeSpan.FromSeconds(1)); + } + + /// + /// 获取一个空闲的连接对象,如果等待超出设定的时间,则会创建新的连接。 + /// + /// + /// + /// + /// + public override TClient GetTransferClient(TimeSpan waitTime) + { + while (FreeClients.TryDequeue(out var client)) + { + if (IsAlive(client)) + { + return client; + } + else + { + DisposeClient(client); + } + } + + if (this.CreatedClients.Count > MaxCount) + { + if (SpinWait.SpinUntil(Wait, waitTime)) + { + return GetTransferClient(waitTime); + } + } + + var clientRes = CreateTransferClient(); + return clientRes; + } + + /// + public override bool IsAlive(TClient client) + { + return client.Online; + } + + /// + /// 归还使用完的连接。 + /// + /// 首先内部会判定存活状态,如果不再活动状态,会直接调用。 + /// 其次会计算是否可以进入缓存队列,如果队列数量超出,也会直接调用 + /// + /// + /// + public override void ReleaseTransferClient(TClient client) + { + if ((object)client == (object)MainClient) + { + return; + } + if (!IsAlive(client)) + { + DisposeClient(client); + return; + } + if (FreeClients.Count < MaxCount) + { + FreeClients.Enqueue(client); + } + else + { + DisposeClient(client); + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + this.m_singleTimer.SafeDispose(); + base.Dispose(disposing); + } + + /// + protected override TouchSocketConfig GetTransferConfig() + { + return OnGetTransferConfig?.Invoke(); + } + + private TClient CreateTransferClient() + { + TClient client = new TClient(); + client.Setup(this.GetTransferConfig()); + client.Connect((int)ConnectTimeout.TotalMilliseconds); + this.CreatedClients.Add(client); + return client; + } + + private bool Wait() + { + if (FreeClients.Count > 0) + { + return true; + } + return false; + } + } + + /// + /// 适用于基于的连接工厂。 + /// + public class TcpClientFactory : TcpClientFactory + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/NAT/NATService.cs b/src/TouchSocket/Sockets/Components/NAT/NATService.cs new file mode 100644 index 000000000..96606cad2 --- /dev/null +++ b/src/TouchSocket/Sockets/Components/NAT/NATService.cs @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP端口转发服务器 + /// + public class NATService : TcpService + { + /// + /// + /// + /// + protected override NATSocketClient GetClientInstence() + { + var client = base.GetClientInstence(); + client.m_internalDis = OnTargetClientDisconnected; + client.m_internalTargetClientRev = OnTargetClientReceived; + return client; + } + + /// + /// 在NAT服务器收到数据时。 + /// + /// + /// + /// + /// 需要转发的数据。 + protected virtual byte[] OnNATReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + return byteBlock?.ToArray(); + } + + /// + /// + /// + /// + /// + /// + protected override sealed void OnReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + var data = OnNATReceived(socketClient, byteBlock, requestInfo); + if (data != null) + { + socketClient.SendToTargetClient(data, 0, data.Length); + } + } + + /// + /// 当目标客户端断开。 + /// + /// + /// + /// + protected virtual void OnTargetClientDisconnected(NATSocketClient socketClient, ITcpClient tcpClient, DisconnectEventArgs e) + { + } + + /// + /// 在目标客户端收到数据时。 + /// + /// + /// + /// + /// + /// + protected virtual byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + return byteBlock?.ToArray(); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs b/src/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs new file mode 100644 index 000000000..dabb1a6fb --- /dev/null +++ b/src/TouchSocket/Sockets/Components/NAT/NATSocketClient.cs @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 端口转发辅助 + /// + public class NATSocketClient : SocketClient + { + internal Action m_internalDis; + internal Func m_internalTargetClientRev; + private readonly ConcurrentList m_targetClients = new ConcurrentList(); + + /// + /// 添加转发客户端。 + /// + /// 配置文件 + /// 当完成配置,但是还未连接时回调。 + /// + public ITcpClient AddTargetClient(TouchSocketConfig config, Action setupAction = default) + { + TcpClient tcpClient = new TcpClient(); + tcpClient.Disconnected += TcpClient_Disconnected; + tcpClient.Received += TcpClient_Received; + tcpClient.Setup(config); + setupAction?.Invoke(tcpClient); + tcpClient.Connect(); + + m_targetClients.Add(tcpClient); + return tcpClient; + } + + /// + /// 添加转发客户端。 + /// + /// 配置文件 + /// 当完成配置,但是还未连接时回调。 + /// + public Task AddTargetClientAsync(TouchSocketConfig config, Action setupAction = default) + { + return EasyTask.Run(() => + { + return AddTargetClient(config, setupAction); + }); + } + + /// + /// 获取所有目标客户端 + /// + /// + public ITcpClient[] GetTargetClients() + { + return m_targetClients.ToArray(); + } + + /// + /// 发送数据到全部转发端。 + /// + /// + /// + /// + public void SendToTargetClient(byte[] buffer, int offset, int length) + { + foreach (var socket in m_targetClients) + { + try + { + socket.Send(buffer, offset, length); + } + catch + { + } + } + } + + /// + /// + /// + /// + protected override void OnDisconnected(DisconnectEventArgs e) + { + foreach (var client in m_targetClients) + { + client.TryShutdown(); + client.SafeDispose(); + } + base.OnDisconnected(e); + } + + private void TcpClient_Disconnected(ITcpClientBase client, DisconnectEventArgs e) + { + client.SafeDispose(); + m_targetClients.Remove((ITcpClient)client); + m_internalDis?.Invoke(this, (ITcpClient)client, e); + } + + private void TcpClient_Received(TcpClient client, ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (DisposedValue) + { + return; + } + + try + { + var data = m_internalTargetClientRev?.Invoke(this, client, byteBlock, requestInfo); + if (data != null) + { + if (Online) + { + this.Send(data); + } + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/TCP/SocketClient.cs b/src/TouchSocket/Sockets/Components/TCP/SocketClient.cs new file mode 100644 index 000000000..80f3f8daf --- /dev/null +++ b/src/TouchSocket/Sockets/Components/TCP/SocketClient.cs @@ -0,0 +1,965 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// 服务器辅助类 + /// + [DebuggerDisplay("ID={ID},IPAdress={IP}:{Port}")] + public class SocketClient : BaseSocket, ISocketClient + { + /// + /// 构造函数 + /// + public SocketClient() + { + Protocol = Protocol.TCP; + } + + #region 变量 + + internal string m_id; + internal ReceiveType m_receiveType; + internal TcpServiceBase m_service; + internal bool m_usePlugin; + private DataHandlingAdapter m_adapter; + private DelaySender m_delaySender; + private Socket m_mainSocket; + + //private int m_maxPackageSize; + private bool m_online; + + private bool m_useDelaySender; + private Stream m_workStream; + + #endregion 变量 + + #region 属性 + + /// + public bool IsClient => false; + + /// + /// + /// + public bool CanSend => m_online; + + /// + /// + /// + public virtual bool CanSetDataHandlingAdapter => true; + + /// + /// + /// + public TouchSocketConfig Config { get; internal set; } + + /// + /// + /// + public IContainer Container => Config?.Container; + + /// + /// + /// + public DataHandlingAdapter DataHandlingAdapter => m_adapter; + + /// + /// 用于索引的ID + /// + public string ID => m_id; + + /// + /// + /// + public string IP { get; private set; } + + /// + /// + /// + public Socket MainSocket => m_mainSocket; + + /// + /// + /// + public bool Online => m_online; + + /// + /// + /// + public IPluginsManager PluginsManager => Config?.PluginsManager; + + /// + /// + /// + public int Port { get; private set; } + + /// + /// + /// + public Protocol Protocol { get; set; } + + /// + /// + /// + public ReceiveType ReceiveType => m_receiveType; + + /// + /// + /// + public TcpServiceBase Service => m_service; + + /// + /// + /// + public bool UsePlugin => m_usePlugin; + + /// + /// + /// + public bool UseSsl { get; private set; } + + #endregion 属性 + + #region 事件&委托 + + /// + /// + /// + public DisconnectEventHandler Disconnected { get; set; } + + /// + /// + /// + public DisconnectEventHandler Disconnecting { get; set; } + + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + protected virtual void OnDisconnecting(DisconnectEventArgs e) + { + try + { + Disconnecting?.Invoke(this, e); + } + catch (Exception ex) + { + Logger.Log(LogType.Error, this, $"在事件{nameof(Disconnecting)}中发生错误。", ex); + } + } + /// + /// 当客户端完整建立TCP连接,如果覆盖父类方法,则不会触发插件。 + /// + /// + protected virtual void OnConnected(TouchSocketEventArgs e) + { + m_service.OnInternalConnected(this, e); + } + + /// + /// 客户端正在连接,如果覆盖父类方法,则不会触发插件。 + /// + protected virtual void OnConnecting(OperationEventArgs e) + { + m_service.OnInternalConnecting(this, e); + } + + /// + /// 在延迟发生错误 + /// + /// + protected virtual void OnDelaySenderError(Exception ex) + { + Logger.Log(LogType.Error, this, "发送错误", ex); + } + + /// + /// 客户端已断开连接,如果从Connecting中拒绝连接,则不会触发。如果覆盖父类方法,则不会触发插件。 + /// + /// + protected virtual void OnDisconnected(DisconnectEventArgs e) + { + Disconnected?.Invoke(this, e); + } + + /// + /// 当初始化完成时,执行在之前。 + /// + protected virtual void OnInitialized() + { + } + + private void PrivateOnDisconnected(DisconnectEventArgs e) + { + if (m_usePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnDisconnected), this, e)) + { + return; + } + OnDisconnected(e); + if (!e.Handled) + { + m_service.OnInternalDisconnected(this, e); + } + } + + private void PrivateOnDisconnecting(DisconnectEventArgs e) + { + if (m_usePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnDisconnecting), this, e)) + { + return; + } + OnDisconnecting(e); + if (!e.Handled) + { + m_service.OnInternalDisconnecting(this, e); + } + } + #endregion 事件&委托 + + /// + /// + /// + public DateTime LastReceivedTime { get; private set; } + + /// + /// + /// + public DateTime LastSendTime { get; private set; } + + /// + /// + /// + public Func OnHandleRawBuffer { get; set; } + + /// + /// + /// + public Func OnHandleReceivedData { get; set; } + + /// + /// + /// + public string ServiceIP { get; private set; } + + /// + /// + /// + public int ServicePort { get; private set; } + + /// + public virtual void Close() + { + Close($"主动调用{nameof(Close)}"); + } + + /// + public virtual void Close(string msg) + { + if (this.m_online) + { + var args = new DisconnectEventArgs(true, msg) + { + IsPermitOperation = true + }; + PrivateOnDisconnecting(args); + if (this.DisposedValue || args.IsPermitOperation) + { + BreakOut(msg, true); + } + } + } + + /// + /// + /// + /// + public Stream GetStream() + { + if (m_workStream == null) + { + m_workStream = new NetworkStream(m_mainSocket, true); + } + return m_workStream; + } + + /// + /// 直接重置内部ID。 + /// + /// + protected void DirectResetID(string newId) + { + if (string.IsNullOrEmpty(newId)) + { + throw new ArgumentException($"“{nameof(newId)}”不能为 null 或空。", nameof(newId)); + } + + if (m_id == newId) + { + return; + } + string oldId = m_id; + if (Service.SocketClients.TryRemove(m_id, out SocketClient socketClient)) + { + socketClient.m_id = newId; + if (Service.SocketClients.TryAdd(socketClient)) + { + if (m_usePlugin) + { + IDChangedEventArgs e = new IDChangedEventArgs(oldId, newId); + PluginsManager.Raise(nameof(ITcpPlugin.OnIDChanged), socketClient, e); + } + return; + } + else + { + socketClient.m_id = oldId; + if (Service.SocketClients.TryAdd(socketClient)) + { + throw new Exception("ID重复"); + } + else + { + socketClient.Close("修改新ID时操作失败,且回退旧ID时也失败。"); + } + } + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(oldId)); + } + } + + /// + /// + /// + /// + /// + /// + /// + public virtual void ResetID(string newId) + { + DirectResetID(newId); + } + + /// + /// + /// + /// + public virtual void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + if (!CanSetDataHandlingAdapter) + { + throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。"); + } + + SetAdapter(adapter); + } + + internal void BeginReceive(ReceiveType receiveType) + { + try + { + if (receiveType == ReceiveType.Auto) + { + SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs(); + eventArgs.Completed += EventArgs_Completed; + ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength); + eventArgs.UserToken = byteBlock; + eventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity); + if (!m_mainSocket.ReceiveAsync(eventArgs)) + { + ProcessReceived(eventArgs); + } + } + } + catch (Exception ex) + { + BreakOut(ex.Message, false); + } + } + + internal void BeginReceiveSsl(ReceiveType receiveType, ServiceSslOption sslOption) + { + SslStream sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(m_mainSocket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(m_mainSocket, false), false); + sslStream.AuthenticateAsServer(sslOption.Certificate, sslOption.ClientCertificateRequired, sslOption.SslProtocols, sslOption.CheckCertificateRevocation); + m_workStream = sslStream; + UseSsl = true; + if (receiveType == ReceiveType.Auto) + { + BeginSsl(); + } + } + + internal void InternalConnected(TouchSocketEventArgs e) + { + m_online = true; + + if (Config.GetValue(TouchSocketConfigExtension.DelaySenderProperty) is DelaySenderOption senderOption) + { + m_useDelaySender = true; + m_delaySender.SafeDispose(); + m_delaySender = new DelaySender(m_mainSocket, senderOption.QueueLength, OnDelaySenderError) + { + DelayLength = senderOption.DelayLength + }; + } + + if (m_usePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnConnected), this, e)) + { + return; + } + + OnConnected(e); + } + + internal void InternalConnecting(OperationEventArgs e) + { + if (m_usePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnConnecting), this, e)) + { + return; + } + OnConnecting(e); + } + + internal void InternalInitialized() + { + LastReceivedTime = DateTime.Now; + LastSendTime = DateTime.Now; + OnInitialized(); + } + + internal void SetSocket(Socket mainSocket) + { + m_mainSocket = mainSocket ?? throw new ArgumentNullException(nameof(mainSocket)); + IP = mainSocket.RemoteEndPoint.GetIP(); + Port = mainSocket.RemoteEndPoint.GetPort(); + ServiceIP = mainSocket.LocalEndPoint.GetIP(); + ServicePort = mainSocket.LocalEndPoint.GetPort(); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (this.m_online) + { + var args = new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"); + PrivateOnDisconnecting(args); + } + Config = default; + m_adapter.SafeDispose(); + m_adapter = default; + BreakOut($"{nameof(Dispose)}主动断开", true); + base.Dispose(disposing); + } + + /// + /// 处理已接收到的数据。 + /// 根据不同的数据处理适配器,会传递不同的数据 + /// + /// 以二进制流形式传递 + /// 以解析的数据对象传递 + protected virtual void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + } + + /// + /// 当即将发送时,如果覆盖父类方法,则不会触发插件。 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 返回值表示是否允许发送 + protected virtual bool HandleSendingData(byte[] buffer, int offset, int length) + { + if (m_usePlugin) + { + SendingEventArgs args = new SendingEventArgs(buffer, offset, length); + PluginsManager.Raise(nameof(ITcpPlugin.OnSendingData), this, args); + if (args.IsPermitOperation) + { + return true; + } + return false; + } + return true; + } + + + /// + /// 设置适配器,该方法不会检验的值。 + /// + /// + protected void SetAdapter(DataHandlingAdapter adapter) + { + if (adapter is null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + if (Config != null) + { + if (Config.GetValue(TouchSocketConfigExtension.MaxPackageSizeProperty) is int v1) + { + adapter.MaxPackageSize = v1; + } + if (Config.GetValue(TouchSocketConfigExtension.CacheTimeoutProperty) != TimeSpan.Zero) + { + adapter.CacheTimeout = Config.GetValue(TouchSocketConfigExtension.CacheTimeoutProperty); + } + if (Config.GetValue(TouchSocketConfigExtension.CacheTimeoutEnableProperty) is bool v2) + { + adapter.CacheTimeoutEnable = v2; + } + if (Config.GetValue(TouchSocketConfigExtension.UpdateCacheTimeWhenRevProperty) is bool v3) + { + adapter.UpdateCacheTimeWhenRev = v3; + } + } + + adapter.OnLoaded(this); + adapter.ReceivedCallBack = PrivateHandleReceivedData; + adapter.SendCallBack = DefaultSend; + m_adapter = adapter; + } + + private void BeginSsl() + { + if (!DisposedValue) + { + ByteBlock byteBlock = new ByteBlock(BufferLength); + try + { + m_workStream.BeginRead(byteBlock.Buffer, 0, byteBlock.Capacity, EndSsl, byteBlock); + } + catch (System.Exception ex) + { + byteBlock.Dispose(); + BreakOut(ex.Message, false); + } + } + } + + private void BreakOut(string msg, bool manual) + { + lock (this.SyncRoot) + { + if (m_online) + { + m_online = false; + this.TryShutdown(); + m_mainSocket.SafeDispose(); + m_delaySender.SafeDispose(); + m_adapter.SafeDispose(); + m_service?.SocketClients.TryRemove(m_id, out _); + PrivateOnDisconnected(new DisconnectEventArgs(manual, msg)); + Disconnected = null; + } + base.Dispose(true); + } + } + + private void EndSsl(IAsyncResult result) + { + ByteBlock byteBlock = (ByteBlock)result.AsyncState; + try + { + int r = m_workStream.EndRead(result); + if (r == 0) + { + BreakOut("远程终端主动关闭", false); + } + byteBlock.SetLength(r); + + HandleBuffer(byteBlock); + BeginSsl(); + } + catch (Exception ex) + { + byteBlock.Dispose(); + BreakOut(ex.Message, false); + } + } + + private void EventArgs_Completed(object sender, SocketAsyncEventArgs e) + { + try + { + ProcessReceived(e); + } + catch (Exception ex) + { + e.SafeDispose(); + BreakOut(ex.Message, false); + } + } + + private void HandleBuffer(ByteBlock byteBlock) + { + try + { + LastReceivedTime = DateTime.Now; + if (OnHandleRawBuffer?.Invoke(byteBlock) == false) + { + return; + } + if (UsePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnReceivingData), this, new ByteBlockEventArgs(byteBlock))) + { + return; + } + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + Logger.Error(this, TouchSocketStatus.NullDataAdapter.GetDescription()); + return; + } + m_adapter.ReceivedInput(byteBlock); + } + catch (System.Exception ex) + { + Logger.Log(LogType.Error, this, "在处理数据时发生错误", ex); + } + finally + { + byteBlock.Dispose(); + } + } + + private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false) + { + return; + } + + if (m_usePlugin) + { + ReceivedDataEventArgs args = new ReceivedDataEventArgs(byteBlock, requestInfo); + PluginsManager.Raise(nameof(ITcpPlugin.OnReceivedData), this, args); + if (args.Handled) + { + return; + } + } + + HandleReceivedData(byteBlock, requestInfo); + + m_service.OnInternalReceivedData(this, byteBlock, requestInfo); + } + + + private void ProcessReceived(SocketAsyncEventArgs e) + { + if (DisposedValue) + { + e.SafeDispose(); + } + else + { + if (e.SocketError == SocketError.Success && e.BytesTransferred > 0) + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + HandleBuffer(byteBlock); + try + { + ByteBlock newByteBlock = new ByteBlock(BufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Capacity); + + if (!m_mainSocket.ReceiveAsync(e)) + { + ProcessReceived(e); + } + } + catch (Exception ex) + { + BreakOut(ex.Message, false); + } + } + else + { + e.SafeDispose(); + BreakOut("远程主机主动断开连接", false); + } + } + } + + #region 发送 + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void DefaultSend(byte[] buffer, int offset, int length) + { + if (!m_online) + { + throw new NotConnectedException(TouchSocketStatus.NotConnected.GetDescription()); + } + if (HandleSendingData(buffer, offset, length)) + { + if (UseSsl) + { + m_workStream.Write(buffer, offset, length); + } + else + { + if (m_useDelaySender && length < TouchSocketUtility.BigDataBoundary) + { + m_delaySender.Send(new QueueDataBytes(buffer, offset, length)); + } + else + { + m_mainSocket.AbsoluteSend(buffer, offset, length); + } + } + LastSendTime = DateTime.Now; + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public Task DefaultSendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + DefaultSend(buffer, offset, length); + }); + } + + #region 同步发送 + + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(IRequestInfo requestInfo) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + if (!m_adapter.CanSendRequestInfo) + { + throw new NotSupportedException($"当前适配器不支持对象发送。"); + } + m_adapter.SendInput(requestInfo); + } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(byte[] buffer, int offset, int length) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + m_adapter.SendInput(buffer, offset, length); + } + + /// + /// + /// + /// + public virtual void Send(IList> transferBytes) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + if (m_adapter.CanSplicingSend) + { + m_adapter.SendInput(transferBytes); + } + else + { + ByteBlock byteBlock = new ByteBlock(BufferLength); + try + { + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + m_adapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + } + + #endregion 同步发送 + + #region 异步发送 + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(buffer, offset, length); + }); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(IRequestInfo requestInfo) + { + return EasyTask.Run(() => + { + Send(requestInfo); + }); + } + + /// + /// + /// + /// + public virtual Task SendAsync(IList> transferBytes) + { + return EasyTask.Run(() => + { + Send(transferBytes); + }); + } + + #endregion 异步发送 + + #region ID发送 + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public void Send(string id, byte[] buffer, int offset, int length) + { + m_service.Send(id, buffer, offset, length); + } + + /// + /// + /// + /// + /// + public void Send(string id, IRequestInfo requestInfo) + { + m_service.Send(id, requestInfo); + } + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public Task SendAsync(string id, byte[] buffer, int offset, int length) + { + return m_service.SendAsync(id, buffer, offset, length); + } + + /// + /// + /// + /// + /// + public Task SendAsync(string id, IRequestInfo requestInfo) + { + return m_service.SendAsync(id, requestInfo); + } + + #endregion ID发送 + + #endregion 发送 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/TCP/TcpClient.cs b/src/TouchSocket/Sockets/Components/TCP/TcpClient.cs new file mode 100644 index 000000000..a6490e763 --- /dev/null +++ b/src/TouchSocket/Sockets/Components/TCP/TcpClient.cs @@ -0,0 +1,1098 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// 简单TCP客户端 + /// + public class TcpClient : TcpClientBase + { + /// + /// 接收到数据 + /// + public ReceivedEventHandler Received { get; set; } + + /// + /// 接收数据 + /// + /// + /// + protected override void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + Received?.Invoke(this, byteBlock, requestInfo); + base.HandleReceivedData(byteBlock, requestInfo); + } + } + + /// + /// TCP客户端 + /// + [System.Diagnostics.DebuggerDisplay("{IP}:{Port}")] + public class TcpClientBase : BaseSocket, ITcpClient + { + /// + /// 构造函数 + /// + public TcpClientBase() + { + Protocol = Protocol.TCP; + } + + #region 变量 + + private DelaySender m_delaySender; + private TouchSocketConfig m_config; + private DataHandlingAdapter m_adapter; + private Socket m_mainSocket; + private bool m_online; + private ReceiveType m_receiveType; + private bool m_useDelaySender; + private bool m_usePlugin; + private Stream m_workStream; + private IPHost m_remoteIPHost; + + #endregion 变量 + + #region 事件 + + /// + /// 成功连接到服务器 + /// + public MessageEventHandler Connected { get; set; } + + /// + /// 准备连接的时候,此时已初始化Socket,但是并未建立Tcp连接 + /// + public ConnectingEventHandler Connecting { get; set; } + + /// + /// 断开连接。在客户端未设置连接状态时,不会触发 + /// + public DisconnectEventHandler Disconnected { get; set; } + + /// + /// + /// + public DisconnectEventHandler Disconnecting { get; set; } + + private void PrivateOnConnected(MsgEventArgs e) + { + if (m_usePlugin) + { + PluginsManager.Raise(nameof(ITcpPlugin.OnConnected), this, e); + if (e.Handled) + { + return; + } + } + OnConnected(e); + } + + /// + /// 已经建立Tcp连接 + /// + /// + protected virtual void OnConnected(MsgEventArgs e) + { + try + { + Connected?.Invoke(this, e); + } + catch (System.Exception ex) + { + Logger.Log(LogType.Error, this, $"在事件{nameof(Connected)}中发生错误。", ex); + } + } + + private void PrivateOnConnecting(ConnectingEventArgs e) + { + LastReceivedTime = DateTime.Now; + LastSendTime = DateTime.Now; + if (CanSetDataHandlingAdapter) + { + SetDataHandlingAdapter(Config.GetValue>(TouchSocketConfigExtension.DataHandlingAdapterProperty).Invoke()); + } + if (m_usePlugin) + { + PluginsManager.Raise(nameof(ITcpPlugin.OnConnecting), this, e); + if (e.Handled) + { + return; + } + } + OnConnecting(e); + } + + /// + /// 准备连接的时候,此时已初始化Socket,但是并未建立Tcp连接 + /// + /// + protected virtual void OnConnecting(ConnectingEventArgs e) + { + try + { + Connecting?.Invoke(this, e); + } + catch (Exception ex) + { + Logger.Log(LogType.Error, this, $"在事件{nameof(this.OnConnecting)}中发生错误。", ex); + } + } + + private void PrivateOnDisconnected(DisconnectEventArgs e) + { + if (m_usePlugin) + { + PluginsManager.Raise(nameof(ITcpPlugin.OnDisconnected), this, e); + if (e.Handled) + { + return; + } + } + OnDisconnected(e); + } + + /// + /// 断开连接。在客户端未设置连接状态时,不会触发 + /// + /// + protected virtual void OnDisconnected(DisconnectEventArgs e) + { + try + { + Disconnected?.Invoke(this, e); + } + catch (Exception ex) + { + Logger.Log(LogType.Error, this, $"在事件{nameof(Disconnected)}中发生错误。", ex); + } + } + + private void PrivateOnDisconnecting(DisconnectEventArgs e) + { + if (m_usePlugin) + { + PluginsManager.Raise(nameof(ITcpPlugin.OnDisconnecting), this, e); + if (e.Handled) + { + return; + } + } + OnDisconnecting(e); + } + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + protected virtual void OnDisconnecting(DisconnectEventArgs e) + { + try + { + Disconnecting?.Invoke(this, e); + } + catch (Exception ex) + { + Logger.Log(LogType.Error, this, $"在事件{nameof(Disconnecting)}中发生错误。", ex); + } + } + + #endregion 事件 + + #region 属性 + + /// + /// + /// + public DateTime LastReceivedTime { get; private set; } + + /// + /// + /// + public DateTime LastSendTime { get; private set; } + + /// + /// 处理未经过适配器的数据。返回值表示是否继续向下传递。 + /// + public Func OnHandleRawBuffer { get; set; } + + /// + /// 处理经过适配器后的数据。返回值表示是否继续向下传递。 + /// + public Func OnHandleReceivedData { get; set; } + + /// + /// + /// + public IContainer Container => m_config?.Container; + + /// + /// + /// + public virtual bool CanSetDataHandlingAdapter => true; + + /// + /// 客户端配置 + /// + public TouchSocketConfig Config => m_config; + + /// + /// 数据处理适配器 + /// + public DataHandlingAdapter DataHandlingAdapter => m_adapter; + + /// + /// IP地址 + /// + public string IP { get; private set; } + + /// + /// 主通信器 + /// + public Socket MainSocket => m_mainSocket; + + /// + /// + /// + public bool CanSend => m_online; + + /// + /// + /// + public bool Online => m_online; + + /// + /// + /// + public IPluginsManager PluginsManager => m_config?.PluginsManager; + + /// + /// 端口号 + /// + public int Port { get; private set; } + + /// + /// + /// + public ReceiveType ReceiveType => m_receiveType; + + /// + /// 是否已启用插件 + /// + public bool UsePlugin => m_usePlugin; + + /// + /// + /// + public bool UseSsl { get; private set; } + + /// + /// + /// + public Protocol Protocol { get; set; } + + /// + /// + /// + public IPHost RemoteIPHost => m_remoteIPHost; + + /// + public bool IsClient => true; + + #endregion 属性 + + #region 断开操作 + + /// + /// + /// + public virtual void Close() + { + Close($"{nameof(Close)}主动断开"); + } + + /// + /// 中断终端,传递中断消息。 + /// + /// + public virtual void Close(string msg) + { + if (this.m_online) + { + var args = new DisconnectEventArgs(true, msg) + { + IsPermitOperation = true + }; + PrivateOnDisconnecting(args); + if (this.DisposedValue || args.IsPermitOperation) + { + BreakOut(msg, true); + } + } + } + + private void BreakOut(string msg, bool manual) + { + lock (this.SyncRoot) + { + if (m_online) + { + m_online = false; + this.TryShutdown(); + m_mainSocket.SafeDispose(); + m_delaySender.SafeDispose(); + m_workStream.SafeDispose(); + m_adapter.SafeDispose(); + PrivateOnDisconnected(new DisconnectEventArgs(manual, msg)); + } + } + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (this.m_online) + { + var args = new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"); + PrivateOnDisconnecting(args); + } + PluginsManager.Clear(); + m_config = default; + m_adapter.SafeDispose(); + m_adapter = default; + BreakOut($"{nameof(Dispose)}主动断开", true); + base.Dispose(disposing); + } + + #endregion 断开操作 + + /// + /// 建立Tcp的连接。 + /// + /// + /// + /// + /// + /// + protected void TcpConnect(int timeout) + { + lock (SyncRoot) + { + if (m_online) + { + return; + } + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + if (m_config == null) + { + throw new ArgumentNullException("配置文件不能为空。"); + } + IPHost iPHost = m_config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + if (iPHost == null) + { + throw new ArgumentNullException("iPHost不能为空。"); + } + if (m_mainSocket != null) + { + m_mainSocket.Dispose(); + } + m_mainSocket = CreateSocket(iPHost); + + ConnectingEventArgs args = new ConnectingEventArgs(m_mainSocket); + PrivateOnConnecting(args); + if (timeout == 5000) + { + m_mainSocket.Connect(iPHost.EndPoint); + m_online = true; + LoadSocketAndReadIpPort(); + + if (m_config.GetValue(TouchSocketConfigExtension.DelaySenderProperty) is DelaySenderOption senderOption) + { + m_useDelaySender = true; + m_delaySender.SafeDispose(); + m_delaySender = new DelaySender(m_mainSocket, senderOption.QueueLength, OnDelaySenderError) + { + DelayLength = senderOption.DelayLength + }; + } + + BeginReceive(); + PrivateOnConnected(new MsgEventArgs("连接成功")); + } + else + { + var result = m_mainSocket.BeginConnect(iPHost.EndPoint, null, null); + if (result.AsyncWaitHandle.WaitOne(timeout)) + { + if (m_mainSocket.Connected) + { + m_mainSocket.EndConnect(result); + m_online = true; + LoadSocketAndReadIpPort(); + + if (m_config.GetValue(TouchSocketConfigExtension.DelaySenderProperty) is DelaySenderOption senderOption) + { + m_useDelaySender = true; + m_delaySender.SafeDispose(); + m_delaySender = new DelaySender(m_mainSocket, senderOption.QueueLength, OnDelaySenderError) + { + DelayLength = senderOption.DelayLength + }; + } + + BeginReceive(); + PrivateOnConnected(new MsgEventArgs("连接成功")); + return; + } + else + { + m_mainSocket.SafeDispose(); + throw new Exception("异步已完成,但是socket并未在连接状态,可能发生了绑定端口占用的错误。"); + } + } + m_mainSocket.SafeDispose(); + throw new TimeoutException(); + } + } + } + + /// + /// 请求连接到服务器。 + /// + public virtual ITcpClient Connect(int timeout = 5000) + { + TcpConnect(timeout); + return this; + } + + /// + /// 异步连接服务器 + /// + public Task ConnectAsync(int timeout = 5000) + { + return EasyTask.Run(() => + { + return Connect(timeout); + }); + } + + /// + /// + /// + /// + public Stream GetStream() + { + if (m_workStream == null) + { + m_workStream = new NetworkStream(m_mainSocket, true); + } + return m_workStream; + } + + /// + /// 设置数据处理适配器 + /// + /// + public virtual void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + if (!CanSetDataHandlingAdapter) + { + throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。"); + } + + SetAdapter(adapter); + } + + /// + /// + /// + /// + /// + public ITcpClient Setup(string ipHost) + { + TouchSocketConfig config = new TouchSocketConfig(); + config.SetRemoteIPHost(new IPHost(ipHost)); + return Setup(config); + } + + /// + /// 配置服务器 + /// + /// + /// + public ITcpClient Setup(TouchSocketConfig config) + { + m_config = config; + if (config.IsUsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config)); + } + LoadConfig(m_config); + if (UsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config)); + } + return this; + } + + private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false) + { + return; + } + if (m_usePlugin) + { + ReceivedDataEventArgs args = new ReceivedDataEventArgs(byteBlock, requestInfo); + PluginsManager.Raise(nameof(ITcpPlugin.OnReceivedData), this, args); + if (args.Handled) + { + return; + } + } + + HandleReceivedData(byteBlock, requestInfo); + } + + /// + /// 处理已接收到的数据。 + /// + /// 以二进制流形式传递 + /// 以解析的数据对象传递 + protected virtual void HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + } + + /// + /// 当即将发送时,如果覆盖父类方法,则不会触发插件。 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 返回值表示是否允许发送 + protected virtual bool HandleSendingData(byte[] buffer, int offset, int length) + { + if (m_usePlugin) + { + SendingEventArgs args = new SendingEventArgs(buffer, offset, length); + PluginsManager.Raise(nameof(ITcpPlugin.OnSendingData), this, args); + if (args.IsPermitOperation) + { + return true; + } + return false; + } + return true; + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TouchSocketConfig config) + { + if (config == null) + { + throw new Exception("配置文件为空"); + } + m_remoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty); + m_receiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty); + m_usePlugin = config.IsUsePlugin; + Logger = Container.Resolve(); + if (config.GetValue(TouchSocketConfigExtension.SslOptionProperty) != null) + { + UseSsl = true; + } + } + + /// + /// 在延迟发生错误 + /// + /// + protected virtual void OnDelaySenderError(Exception ex) + { + Logger.Log(LogType.Error, this, "发送错误", ex); + } + + /// + /// 设置适配器,该方法不会检验的值。 + /// + /// + protected void SetAdapter(DataHandlingAdapter adapter) + { + if (adapter is null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + if (Config != null) + { + if (Config.GetValue(TouchSocketConfigExtension.MaxPackageSizeProperty) is int v1) + { + adapter.MaxPackageSize = v1; + } + if (Config.GetValue(TouchSocketConfigExtension.CacheTimeoutProperty) != TimeSpan.Zero) + { + adapter.CacheTimeout = Config.GetValue(TouchSocketConfigExtension.CacheTimeoutProperty); + } + if (Config.GetValue(TouchSocketConfigExtension.CacheTimeoutEnableProperty) is bool v2) + { + adapter.CacheTimeoutEnable = v2; + } + if (Config.GetValue(TouchSocketConfigExtension.UpdateCacheTimeWhenRevProperty) is bool v3) + { + adapter.UpdateCacheTimeWhenRev = v3; + } + } + + adapter.OnLoaded(this); + adapter.ReceivedCallBack = PrivateHandleReceivedData; + adapter.SendCallBack = DefaultSend; + m_adapter = adapter; + } + + private void BeginReceive() + { + m_workStream.SafeDispose(); + if (UseSsl) + { + ClientSslOption sslOption = (ClientSslOption)m_config.GetValue(TouchSocketConfigExtension.SslOptionProperty); + SslStream sslStream = (sslOption.CertificateValidationCallback != null) ? new SslStream(new NetworkStream(m_mainSocket, false), false, sslOption.CertificateValidationCallback) : new SslStream(new NetworkStream(m_mainSocket, false), false); + if (sslOption.ClientCertificates == null) + { + sslStream.AuthenticateAsClient(sslOption.TargetHost); + } + else + { + sslStream.AuthenticateAsClient(sslOption.TargetHost, sslOption.ClientCertificates, sslOption.SslProtocols, sslOption.CheckCertificateRevocation); + } + m_workStream = sslStream; + if (m_receiveType != ReceiveType.None) + { + BeginSsl(); + } + } + else + { + if (m_receiveType == ReceiveType.Auto) + { + SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs(); + eventArgs.Completed += EventArgs_Completed; + + ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength); + eventArgs.UserToken = byteBlock; + eventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Buffer.Length); + if (!m_mainSocket.ReceiveAsync(eventArgs)) + { + ProcessReceived(eventArgs); + } + } + } + } + + private void BeginSsl() + { + ByteBlock byteBlock = new ByteBlock(BufferLength); + try + { + m_workStream.BeginRead(byteBlock.Buffer, 0, byteBlock.Capacity, EndSsl, byteBlock); + } + catch (Exception ex) + { + byteBlock.Dispose(); + BreakOut(ex.Message, false); + } + } + + private void EndSsl(IAsyncResult result) + { + ByteBlock byteBlock = (ByteBlock)result.AsyncState; + try + { + int r = m_workStream.EndRead(result); + if (r == 0) + { + BreakOut("远程终端主动关闭", false); + } + byteBlock.SetLength(r); + HandleBuffer(byteBlock); + BeginSsl(); + } + catch (System.Exception ex) + { + byteBlock.Dispose(); + BreakOut(ex.Message, false); + } + } + + private Socket CreateSocket(IPHost iPHost) + { + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + socket.ReceiveBufferSize = BufferLength; + socket.SendBufferSize = BufferLength; +#if NET45_OR_GREATER + KeepAliveValue keepAliveValue = m_config.GetValue(TouchSocketConfigExtension.KeepAliveValueProperty); + if (keepAliveValue.Enable) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + socket.IOControl(IOControlCode.KeepAliveValues, keepAliveValue.KeepAliveTime, null); + } +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + KeepAliveValue keepAliveValue = m_config.GetValue(TouchSocketConfigExtension.KeepAliveValueProperty); + if (keepAliveValue.Enable) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + socket.IOControl(IOControlCode.KeepAliveValues, keepAliveValue.KeepAliveTime, null); + } + } +#endif + socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, m_config.GetValue(TouchSocketConfigExtension.NoDelayProperty)); + if (m_config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) != null) + { + if (m_config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty)) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + socket.Bind(m_config.GetValue(TouchSocketConfigExtension.BindIPHostProperty).EndPoint); + } + return socket; + } + + private void EventArgs_Completed(object sender, SocketAsyncEventArgs e) + { + try + { + ProcessReceived(e); + } + catch (System.Exception ex) + { + e.Dispose(); + BreakOut(ex.Message, false); + } + } + + /// + /// 处理数据 + /// + private void HandleBuffer(ByteBlock byteBlock) + { + try + { + LastReceivedTime = DateTime.Now; + if (OnHandleRawBuffer?.Invoke(byteBlock) == false) + { + return; + } + if (DisposedValue) + { + return; + } + if (UsePlugin && PluginsManager.Raise(nameof(ITcpPlugin.OnReceivingData), this, new ByteBlockEventArgs(byteBlock))) + { + return; + } + if (m_adapter == null) + { + Logger.Error(this, TouchSocketStatus.NullDataAdapter.GetDescription()); + return; + } + m_adapter.ReceivedInput(byteBlock); + } + catch (Exception ex) + { + Logger.Log(LogType.Error, this, "在处理数据时发生错误", ex); + } + finally + { + byteBlock.Dispose(); + } + } + + #region 发送 + + #region 同步发送 + + /// + /// + /// + /// + /// + /// + /// + public void Send(IRequestInfo requestInfo) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + if (!m_adapter.CanSendRequestInfo) + { + throw new NotSupportedException($"当前适配器不支持对象发送。"); + } + m_adapter.SendInput(requestInfo); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(byte[] buffer, int offset, int length) + { + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + m_adapter.SendInput(buffer, offset, length); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(IList> transferBytes) + { + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + + if (m_adapter.CanSplicingSend) + { + m_adapter.SendInput(transferBytes); + } + else + { + ByteBlock byteBlock = BytePool.Default.GetByteBlock(BufferLength); + try + { + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + m_adapter.SendInput(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + } + + #endregion 同步发送 + + #region 异步发送 + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(buffer, offset, length); + }); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(IRequestInfo requestInfo) + { + return EasyTask.Run(() => + { + Send(requestInfo); + }); + } + + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(IList> transferBytes) + { + return EasyTask.Run(() => + { + Send(transferBytes); + }); + } + + #endregion 异步发送 + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void DefaultSend(byte[] buffer, int offset, int length) + { + if (!m_online) + { + throw new NotConnectedException(TouchSocketStatus.NotConnected.GetDescription()); + } + if (HandleSendingData(buffer, offset, length)) + { + if (UseSsl) + { + m_workStream.Write(buffer, offset, length); + } + else + { + if (m_useDelaySender && length < TouchSocketUtility.BigDataBoundary) + { + m_delaySender.Send(new QueueDataBytes(buffer, offset, length)); + } + else + { + m_mainSocket.AbsoluteSend(buffer, offset, length); + } + } + + LastSendTime = DateTime.Now; + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public Task DefaultSendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + DefaultSend(buffer, offset, length); + }); + } + + #endregion 发送 + + private void LoadSocketAndReadIpPort() + { + if (m_mainSocket == null) + { + IP = null; + Port = -1; + return; + } + + string ipport; + if (m_mainSocket.Connected && m_mainSocket.RemoteEndPoint != null) + { + ipport = m_mainSocket.RemoteEndPoint.ToString(); + } + else if (m_mainSocket.IsBound && m_mainSocket.LocalEndPoint != null) + { + ipport = m_mainSocket.LocalEndPoint.ToString(); + } + else + { + return; + } + + int r = ipport.LastIndexOf(":"); + IP = ipport.Substring(0, r); + Port = Convert.ToInt32(ipport.Substring(r + 1, ipport.Length - (r + 1))); + } + + private void ProcessReceived(SocketAsyncEventArgs e) + { + if (!m_online) + { + e.Dispose(); + return; + } + if (e.SocketError == SocketError.Success && e.BytesTransferred > 0) + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + HandleBuffer(byteBlock); + try + { + ByteBlock newByteBlock = BytePool.Default.GetByteBlock(BufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length); + + if (!MainSocket.ReceiveAsync(e)) + { + ProcessReceived(e); + } + } + catch (System.Exception ex) + { + e.Dispose(); + BreakOut(ex.Message, false); + } + } + else + { + e.Dispose(); + BreakOut("远程终端主动关闭", false); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/TCP/TcpService.cs b/src/TouchSocket/Sockets/Components/TCP/TcpService.cs new file mode 100644 index 000000000..b68d65695 --- /dev/null +++ b/src/TouchSocket/Sockets/Components/TCP/TcpService.cs @@ -0,0 +1,723 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Threading; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// TCP泛型服务器,由客户自己指定类型。 + /// + public class TcpService : TcpServiceBase, ITcpService where TClient : SocketClient + { + /// + /// 构造函数 + /// + public TcpService() + { + m_socketClients = new SocketClientCollection(); + m_getDefaultNewID = () => + { + return Interlocked.Increment(ref m_nextId).ToString(); + }; + } + + #region 变量 + + private readonly SocketClientCollection m_socketClients; + private int m_backlog; + private TouchSocketConfig m_config; + private Func m_getDefaultNewID; + private int m_maxCount; + private NetworkMonitor[] m_monitors; + private long m_nextId; + private ReceiveType m_receiveType; + private ServerState m_serverState; + private bool m_usePlugin; + private bool m_useSsl; + + #endregion 变量 + + #region 属性 + + /// + /// 获取服务器配置 + /// + public override TouchSocketConfig Config => m_config; + + /// + /// + /// + public override IContainer Container => Config?.Container; + + /// + /// + /// + public override Func GetDefaultNewID => m_getDefaultNewID; + + /// + /// + /// + public override int MaxCount => m_maxCount; + + /// + /// + /// + public override NetworkMonitor[] Monitors => m_monitors; + + /// + /// + /// + public override IPluginsManager PluginsManager => Config?.PluginsManager; + + /// + /// + /// + public override string ServerName => Config?.GetValue(TouchSocketConfigExtension.ServerNameProperty); + + /// + /// + /// + public override ServerState ServerState => m_serverState; + + /// + /// + /// + public override SocketClientCollection SocketClients => m_socketClients; + + /// + /// + /// + public override bool UsePlugin => m_usePlugin; + + /// + /// + /// + public override bool UseSsl => m_useSsl; + + #endregion 属性 + + #region 事件 + + /// + /// 用户连接完成 + /// + public TouchSocketEventHandler Connected { get; set; } + + /// + /// 有用户连接的时候 + /// + public OperationEventHandler Connecting { get; set; } + + /// + /// 有用户断开连接 + /// + public DisconnectEventHandler Disconnected { get; set; } + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + public DisconnectEventHandler Disconnecting { get; set; } + + /// + /// 当客户端ID被修改时触发。 + /// + public IDChangedEventHandler IDChanged { get; set; } + + /// + /// + /// + /// + /// + protected override sealed void OnClientConnected(ISocketClient socketClient, TouchSocketEventArgs e) + { + OnConnected((TClient)socketClient, e); + } + + /// + /// + /// + /// + /// + protected override sealed void OnClientConnecting(ISocketClient socketClient, OperationEventArgs e) + { + OnConnecting((TClient)socketClient, e); + } + + /// + /// + /// + /// + /// + protected override sealed void OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e) + { + OnDisconnected((TClient)socketClient, e); + } + + /// + /// + /// + /// + /// + protected override sealed void OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e) + { + OnDisconnecting((TClient)socketClient, e); + } + + /// + /// + /// + /// + /// + /// + protected override sealed void OnClientReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + OnReceived((TClient)socketClient, byteBlock, requestInfo); + } + + /// + /// 客户端连接完成,覆盖父类方法将不会触发事件。 + /// + /// + /// + protected virtual void OnConnected(TClient socketClient, TouchSocketEventArgs e) + { + Connected?.Invoke(socketClient, e); + } + + /// + /// 客户端请求连接,覆盖父类方法将不会触发事件。 + /// + /// + /// + protected virtual void OnConnecting(TClient socketClient, OperationEventArgs e) + { + Connecting?.Invoke(socketClient, e); + } + + /// + /// 客户端断开连接,覆盖父类方法将不会触发事件。 + /// + /// + /// + protected virtual void OnDisconnected(TClient socketClient, DisconnectEventArgs e) + { + Disconnected?.Invoke(socketClient, e); + } + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + /// + protected virtual void OnDisconnecting(TClient socketClient, DisconnectEventArgs e) + { + Disconnecting?.Invoke(socketClient, e); + } + + /// + /// 当收到适配器数据。 + /// + /// + /// + /// + protected virtual void OnReceived(TClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + } + + #endregion 事件 + + /// + /// + /// + public override void Clear() + { + string[] ids = GetIDs(); + foreach (var item in ids) + { + if (TryGetSocketClient(item, out TClient client)) + { + client.Dispose(); + } + } + } + + /// + /// 获取当前在线的所有客户端 + /// + /// + public TClient[] GetClients() + { + var clients = m_socketClients.GetClients().ToArray(); + + TClient[] clients1 = new TClient[clients.Length]; + for (int i = 0; i < clients.Length; i++) + { + clients1[i] = (TClient)clients[i]; + } + return clients1; + } + + /// + /// + /// + /// + /// + /// + /// + public override void ResetID(string oldID, string newID) + { + if (string.IsNullOrEmpty(oldID)) + { + throw new ArgumentException($"“{nameof(oldID)}”不能为 null 或空。", nameof(oldID)); + } + + if (string.IsNullOrEmpty(newID)) + { + throw new ArgumentException($"“{nameof(newID)}”不能为 null 或空。", nameof(newID)); + } + + if (oldID == newID) + { + return; + } + if (m_socketClients.TryGetSocketClient(oldID, out TClient socketClient)) + { + socketClient.ResetID(newID); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(oldID)); + } + } + + /// + /// + /// + /// + public override IService Setup(TouchSocketConfig config) + { + m_config = config; + if (config.IsUsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config)); + } + LoadConfig(m_config); + if (UsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config)); + } + Container.RegisterTransient(); + return this; + } + + /// + /// + /// + /// + public override IService Setup(int port) + { + TouchSocketConfig serviceConfig = new TouchSocketConfig(); + serviceConfig.SetListenIPHosts(new IPHost[] { new IPHost(port) }); + return Setup(serviceConfig); + } + + /// + /// + /// + /// + /// + public override bool SocketClientExist(string id) + { + return SocketClients.SocketClientExist(id); + } + + /// + /// + /// + /// + /// + /// + public override IService Start() + { + try + { + IPHost[] iPHosts = Config.GetValue(TouchSocketConfigExtension.ListenIPHostsProperty); + if (iPHosts == null || iPHosts.Length == 0) + { + throw new Exception("IPHosts为空,无法绑定"); + } + switch (m_serverState) + { + case ServerState.None: + { + BeginListen(iPHosts); + break; + } + case ServerState.Running: + { + return this; + } + case ServerState.Stopped: + { + BeginListen(iPHosts); + break; + } + case ServerState.Disposed: + { + throw new Exception("无法重新利用已释放对象"); + } + } + m_serverState = ServerState.Running; + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + return this; + } + catch (Exception ex) + { + m_serverState = ServerState.Exception; + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message=ex.Message }); + } + throw; + } + } + + /// + /// + /// + public override IService Stop() + { + if (m_monitors != null) + { + foreach (var item in m_monitors) + { + item.Socket?.Dispose(); + } + } + m_monitors = null; + + Clear(); + + m_serverState = ServerState.Stopped; + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStoped), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + return this; + } + + /// + /// 尝试获取TClient + /// + /// ID + /// TClient + /// + public bool TryGetSocketClient(string id, out TClient socketClient) + { + return m_socketClients.TryGetSocketClient(id, out socketClient); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (!DisposedValue) + { + if (disposing) + { + if (m_monitors != null) + { + foreach (var item in m_monitors) + { + item.Socket?.Dispose(); + } + m_monitors = null; + } + Clear(); + m_serverState = ServerState.Disposed; + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStoped), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + PluginsManager.Clear(); + } + } + + base.Dispose(disposing); + } + + /// + /// 初始化客户端实例,默认实现为 + /// + /// + protected virtual TClient GetClientInstence() + { + return Container.Resolve(); + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TouchSocketConfig config) + { + if (config == null) + { + throw new Exception("配置文件为空"); + } + if (config.GetValue(TouchSocketConfigExtension.GetDefaultNewIDProperty) is Func fun) + { + m_getDefaultNewID = fun; + } + m_usePlugin = config.IsUsePlugin; + m_maxCount = config.GetValue(TouchSocketConfigExtension.MaxCountProperty); + m_backlog = config.GetValue(TouchSocketConfigExtension.BacklogProperty); + BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty); + m_receiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty); + + Logger ??= Container.Resolve(); + if (config.GetValue(TouchSocketConfigExtension.SslOptionProperty) != null) + { + m_useSsl = true; + } + } + + /// + /// 在验证Ssl发送错误时。 + /// + /// + protected virtual void OnAuthenticatingError(System.Exception ex) + { + } + + /// + /// 在Socket初始化对象后,Bind之前调用。 + /// 可用于设置Socket参数。 + /// 父类方法可覆盖。 + /// + /// + protected virtual void PreviewBind(Socket socket) + { + } + + private void Args_Completed(object sender, SocketAsyncEventArgs e) + { + if (e.LastOperation == SocketAsyncOperation.Accept) + { + OnAccepted(e); + } + } + + private void BeginListen(IPHost[] iPHosts) + { + int threadCount = Config.GetValue(TouchSocketConfigExtension.ThreadCountProperty); + if (threadCount > 0) + { + while (!ThreadPool.SetMinThreads(threadCount, threadCount)) + { + if (--threadCount <= 10) + { + break; + } + } + } + + List networkMonitors = new List(); + foreach (var iPHost in iPHosts) + { + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp) + { + ReceiveBufferSize = BufferLength, + SendBufferSize = BufferLength + }; + if (m_config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty)) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + PreviewBind(socket); + socket.Bind(iPHost.EndPoint); + socket.Listen(m_backlog); + + networkMonitors.Add(new NetworkMonitor(iPHost, socket)); + } + + m_monitors = networkMonitors.ToArray(); + foreach (var networkMonitor in m_monitors) + { + SocketAsyncEventArgs e = new SocketAsyncEventArgs + { + UserToken = networkMonitor.Socket + }; + e.Completed += Args_Completed; + if (!networkMonitor.Socket.AcceptAsync(e)) + { + OnAccepted(e); + } + } + } + + private void OnAccepted(SocketAsyncEventArgs e) + { + if (!DisposedValue) + { + if (e.SocketError == SocketError.Success && e.AcceptSocket != null) + { + Socket socket = e.AcceptSocket; + socket.ReceiveBufferSize = BufferLength; + socket.SendBufferSize = BufferLength; + if (SocketClients.Count < m_maxCount) + { + SocketInit(socket); + } + else + { + socket.SafeDispose(); + Logger.Warning(this, "连接客户端数量已达到设定最大值"); + } + } + e.AcceptSocket = null; + + try + { + if (!((Socket)e.UserToken).AcceptAsync(e)) + { + OnAccepted(e); + } + } + catch + { + e.Dispose(); + return; + } + } + } + + private void SetClientConfiguration(SocketClient client) + { + client.m_usePlugin = m_usePlugin; + client.Config = m_config; + client.m_service = this; + client.Logger = Container.Resolve(); + client.m_receiveType = m_receiveType; + client.BufferLength = BufferLength; + if (client.CanSetDataHandlingAdapter) + { + client.SetDataHandlingAdapter(Config.GetValue(TouchSocketConfigExtension.DataHandlingAdapterProperty).Invoke()); + } + } + + private void SocketInit(Socket socket) + { + try + { + if (Config.GetValue(TouchSocketConfigExtension.NoDelayProperty)) + { + socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + } + TClient client = GetClientInstence(); + SetClientConfiguration(client); + client.SetSocket(socket); + client.InternalInitialized(); + + OperationEventArgs args = new OperationEventArgs + { + ID = GetDefaultNewID() + }; + client.InternalConnecting(args);//Connecting + if (args.IsPermitOperation) + { + client.m_id = args.ID; + if (SocketClients.TryAdd(client)) + { + client.InternalConnected(new MsgEventArgs("客户端成功连接")); + if (!client.MainSocket.Connected) + { + return; + } + if (m_useSsl) + { + try + { + client.BeginReceiveSsl(m_receiveType, (ServiceSslOption)m_config.GetValue(TouchSocketConfigExtension.SslOptionProperty)); + } + catch (System.Exception ex) + { + OnAuthenticatingError(ex); + return; + } + } + else + { + client.BeginReceive(m_receiveType); + } + } + else + { + throw new Exception($"ID={client.m_id}重复"); + } + } + else + { + socket.SafeDispose(); + } + } + catch (Exception ex) + { + socket.SafeDispose(); + Logger.Log(LogType.Error, this, "接收新连接错误", ex); + } + } + } + + /// + /// TCP服务器 + /// + public class TcpService : TcpService + { + /// + /// 处理数据 + /// + public ReceivedEventHandler Received { get; set; } + + /// + /// + /// + /// + /// + /// + protected override void OnReceived(SocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + Received?.Invoke(socketClient, byteBlock, requestInfo); + base.OnReceived(socketClient, byteBlock, requestInfo); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs b/src/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs new file mode 100644 index 000000000..c0c79ddc4 --- /dev/null +++ b/src/TouchSocket/Sockets/Components/TCP/TcpServiceBase.cs @@ -0,0 +1,289 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// Tcp服务器基类 + /// + public abstract class TcpServiceBase : BaseSocket, ITcpService + { + /// + /// + /// + public abstract TouchSocketConfig Config { get; } + + /// + /// + /// + public abstract IContainer Container { get; } + + /// + /// + /// + public int Count => SocketClients.Count; + + /// + /// + /// + public abstract NetworkMonitor[] Monitors { get; } + + /// + /// 插件管理器 + /// + public abstract IPluginsManager PluginsManager { get; } + + /// + /// + /// + public abstract string ServerName { get; } + + /// + /// + /// + public abstract ServerState ServerState { get; } + + /// + /// + /// + public abstract SocketClientCollection SocketClients { get; } + + /// + /// + /// + public abstract bool UseSsl { get; } + + /// + /// + /// + public abstract Func GetDefaultNewID { get; } + + /// + /// + /// + public abstract int MaxCount { get; } + + /// + /// + /// + public abstract bool UsePlugin { get; } + + /// + /// + /// + public abstract void Clear(); + + /// + /// + /// + /// + public string[] GetIDs() + { + return SocketClients.GetIDs().ToArray(); + } + + /// + /// + /// + /// + /// + public abstract void ResetID(string oldID, string newID); + + /// + /// + /// + /// + /// + public abstract IService Setup(TouchSocketConfig serverConfig); + + /// + /// + /// + /// + /// + public abstract IService Setup(int port); + + /// + /// + /// + /// + public abstract IService Start(); + + /// + /// + /// + /// + public abstract IService Stop(); + + internal void OnInternalConnected(ISocketClient socketClient, TouchSocketEventArgs e) + { + OnClientConnected(socketClient, e); + } + + internal void OnInternalConnecting(ISocketClient socketClient, OperationEventArgs e) + { + OnClientConnecting(socketClient, e); + } + + internal void OnInternalDisconnected(ISocketClient socketClient, DisconnectEventArgs e) + { + OnClientDisconnected(socketClient, e); + } + + internal void OnInternalDisconnecting(ISocketClient socketClient, DisconnectEventArgs e) + { + OnClientDisconnecting(socketClient, e); + } + + internal void OnInternalReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo) + { + OnClientReceivedData(socketClient, byteBlock, requestInfo); + } + + /// + /// 客户端连接完成 + /// + /// + /// + protected abstract void OnClientConnected(ISocketClient socketClient, TouchSocketEventArgs e); + + /// + /// 客户端请求连接 + /// + /// + /// + protected abstract void OnClientConnecting(ISocketClient socketClient, OperationEventArgs e); + + /// + /// 客户端断开连接 + /// + /// + /// + protected abstract void OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e); + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + /// + protected abstract void OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e); + + /// + /// 收到数据时 + /// + /// + /// + /// + protected abstract void OnClientReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo); + + #region ID发送 + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public void Send(string id, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(id, out ISocketClient client)) + { + client.Send(buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + /// + /// + /// + /// + public void Send(string id, IRequestInfo requestInfo) + { + if (SocketClients.TryGetSocketClient(id, out ISocketClient client)) + { + client.Send(requestInfo); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public Task SendAsync(string id, byte[] buffer, int offset, int length) + { + if (SocketClients.TryGetSocketClient(id, out ISocketClient client)) + { + return client.SendAsync(buffer, offset, length); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + /// + /// + /// + /// + public Task SendAsync(string id, IRequestInfo requestInfo) + { + if (SocketClients.TryGetSocketClient(id, out ISocketClient client)) + { + return client.SendAsync(requestInfo); + } + else + { + throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(id)); + } + } + + /// + /// + /// + /// + /// + public abstract bool SocketClientExist(string id); + + #endregion ID发送 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Components/UDP/UdpSession.cs b/src/TouchSocket/Sockets/Components/UDP/UdpSession.cs new file mode 100644 index 000000000..1390ae994 --- /dev/null +++ b/src/TouchSocket/Sockets/Components/UDP/UdpSession.cs @@ -0,0 +1,861 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + /// + /// 简单UDP会话。 + /// + public class UdpSession : UdpSessionBase + { + /// + /// 当收到数据时 + /// + public UdpReceivedEventHandler Received { get; set; } + + /// + /// + /// + /// + /// + /// + protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + Received?.Invoke(remoteEndPoint, byteBlock, requestInfo); + } + } + + /// + /// UDP基类服务器。 + /// + public class UdpSessionBase : BaseSocket, IUdpSession, IPluginObject + { + private readonly ConcurrentList m_socketAsyncs; + private TouchSocketConfig m_config; + private UdpDataHandlingAdapter m_adapter; + private NetworkMonitor m_monitor; + private IPHost m_remoteIPHost; + private ServerState m_serverState; + private bool m_usePlugin; + + /// + /// 构造函数 + /// + public UdpSessionBase() + { + m_socketAsyncs = new ConcurrentList(); + Protocol = Protocol.UDP; + Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + socket.ReceiveBufferSize = BufferLength; + socket.SendBufferSize = BufferLength; + m_monitor = new NetworkMonitor(null, socket); + } + + /// + /// 处理未经过适配器的数据。返回值表示是否继续向下传递。 + /// + public Func OnHandleRawBuffer { get; set; } + + /// + /// 处理经过适配器后的数据。返回值表示是否继续向下传递。 + /// + public Func OnHandleReceivedData { get; set; } + + /// + /// + /// + public bool CanSend => m_serverState == ServerState.Running; + + /// + /// + /// + public virtual bool CanSetDataHandlingAdapter => true; + + /// + /// 获取配置 + /// + public TouchSocketConfig Config => m_config; + + /// + /// + /// + public IContainer Container => m_config?.Container; + + /// + /// + /// + public DateTime LastReceivedTime { get; private set; } + + /// + /// + /// + public DateTime LastSendTime { get; private set; } + + /// + /// 数据处理适配器 + /// + public UdpDataHandlingAdapter DataHandlingAdapter => m_adapter; + + /// + /// 监听器 + /// + public NetworkMonitor Monitor => m_monitor; + + /// + /// + /// + public IPluginsManager PluginsManager => m_config?.PluginsManager; + + /// + /// + /// + public virtual Protocol Protocol { get; set; } + + /// + /// 默认远程节点 + /// + public IPHost RemoteIPHost => m_remoteIPHost; + + /// + /// 服务器名称 + /// + public string ServerName => Config?.GetValue(TouchSocketConfigExtension.ServerNameProperty); + + /// + /// 获取服务器状态 + /// + public ServerState ServerState => m_serverState; + + /// + /// 是否已启用插件 + /// + public bool UsePlugin => m_usePlugin; + + /// + /// 退出组播 + /// + /// + public void DropMulticastGroup(IPAddress multicastAddr) + { + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + if (multicastAddr is null) + { + throw new ArgumentNullException(nameof(multicastAddr)); + } + + if (m_monitor.Socket.AddressFamily == AddressFamily.InterNetwork) + { + MulticastOption optionValue = new MulticastOption(multicastAddr); + m_monitor.Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, optionValue); + } + else + { + IPv6MulticastOption optionValue2 = new IPv6MulticastOption(multicastAddr); + m_monitor.Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.DropMembership, optionValue2); + } + } + + /// + /// 加入组播。 + /// 组播地址为 224.0.0.0 ~ 239.255.255.255,其中 224.0.0.0~224.255.255.255 不建议在用户程序中使用,因为它们一般都有特殊用途。 + /// + /// + public void JoinMulticastGroup(IPAddress multicastAddr) + { + if (multicastAddr is null) + { + throw new ArgumentNullException(nameof(multicastAddr)); + } + if (DisposedValue) + { + throw new ObjectDisposedException(GetType().FullName); + } + + if (m_monitor.Socket.AddressFamily == AddressFamily.InterNetwork) + { + MulticastOption optionValue = new MulticastOption(multicastAddr); + m_monitor.Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, optionValue); + } + else + { + IPv6MulticastOption optionValue2 = new IPv6MulticastOption(multicastAddr); + m_monitor.Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, optionValue2); + } + } + + /// + /// 设置数据处理适配器 + /// + /// + public virtual void SetDataHandlingAdapter(UdpDataHandlingAdapter adapter) + { + if (!CanSetDataHandlingAdapter) + { + throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。"); + } + + SetAdapter(adapter); + } + + /// + /// + /// + /// + /// + public IService Setup(TouchSocketConfig config) + { + m_config = config; + if (config.IsUsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config)); + } + LoadConfig(m_config); + if (UsePlugin) + { + PluginsManager.Raise(nameof(IConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config)); + } + return this; + } + + /// + /// 通过端口配置 + /// + /// + public IService Setup(int port) + { + TouchSocketConfig serverConfig = new TouchSocketConfig(); + serverConfig.SetBindIPHost(new IPHost(port)); + return Setup(serverConfig); + } + + /// + /// 启动服务 + /// + public IService Start() + { + try + { + if (m_serverState == ServerState.Disposed) + { + throw new Exception("无法重新利用已释放对象"); + } + + switch (m_serverState) + { + case ServerState.None: + { + if (m_config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) is IPHost iPHost) + { + BeginReceive(iPHost); + } + + break; + } + case ServerState.Running: + return this; + + case ServerState.Stopped: + { + if (m_config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) is IPHost iPHost) + { + BeginReceive(iPHost); + } + break; + } + case ServerState.Disposed: + { + throw new Exception("无法再次利用已释放对象"); + } + } + + m_serverState = ServerState.Running; + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + return this; + } + catch (Exception ex) + { + m_serverState = ServerState.Exception; + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message = ex.Message }) ; + } + throw; + } + + } + + /// + /// 停止服务器 + /// + public IService Stop() + { + m_monitor?.Socket.Dispose(); + m_monitor = null; + m_serverState = ServerState.Stopped; + foreach (var item in m_socketAsyncs) + { + item.SafeDispose(); + } + m_socketAsyncs.Clear(); + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + return this; + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + if (!this.DisposedValue) + { + if (disposing) + { + m_monitor?.Socket.Dispose(); + m_monitor = null; + m_serverState = ServerState.Disposed; + foreach (var item in m_socketAsyncs) + { + item.SafeDispose(); + } + m_socketAsyncs.Clear(); + + if (UsePlugin) + { + PluginsManager.Raise(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default)); + } + } + } + base.Dispose(disposing); + } + + /// + /// 处理已接收到的数据。 + /// + /// + /// 以二进制流形式传递 + /// 以解析的数据对象传递 + protected virtual void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + } + + /// + /// 当即将发送时,如果覆盖父类方法,则不会触发插件。 + /// + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 返回值表示是否允许发送 + protected virtual bool HandleSendingData(EndPoint endPoint, byte[] buffer, int offset, int length) + { + return true; + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TouchSocketConfig config) + { + if (config == null) + { + throw new Exception("配置文件为空"); + } + Logger = Container.Resolve(); + m_remoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty); + BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty); + m_usePlugin = config.IsUsePlugin; + + if (CanSetDataHandlingAdapter) + { + SetDataHandlingAdapter(Config.GetValue(TouchSocketConfigExtension.UdpDataHandlingAdapterProperty).Invoke()); + } + } + + /// + /// 在Socket初始化对象后,Bind之前调用。 + /// 可用于设置Socket参数。 + /// 父类方法可覆盖。 + /// + /// + protected virtual void PreviewBind(Socket socket) + { + } + + /// + /// 设置适配器,该方法不会检验的值。 + /// + /// + protected void SetAdapter(UdpDataHandlingAdapter adapter) + { + if (adapter is null) + { + throw new ArgumentNullException(nameof(adapter)); + } + + if (adapter.m_owner != null) + { + throw new Exception("此适配器已被其他终端使用,请重新创建对象。"); + } + + if (Config != null) + { + if (Config.GetValue(TouchSocketConfigExtension.MaxPackageSizeProperty) is int v1) + { + adapter.MaxPackageSize = v1; + } + } + adapter.m_owner = this; + adapter.ReceivedCallBack = PrivateHandleReceivedData; + adapter.SendCallBack = DefaultSend; + m_adapter = adapter; + } + + private void BeginReceive(IPHost iPHost) + { + int threadCount = Config.GetValue(TouchSocketConfigExtension.ThreadCountProperty); + threadCount = threadCount < 0 ? 1 : threadCount; + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Dgram, ProtocolType.Udp) + { + ReceiveBufferSize = BufferLength, + SendBufferSize = BufferLength, + EnableBroadcast = m_config.GetValue(TouchSocketConfigExtension.EnableBroadcastProperty) + }; + if (m_config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty)) + { + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + PreviewBind(socket); + socket.Bind(iPHost.EndPoint); + + m_monitor = new NetworkMonitor(iPHost, socket); + + switch (m_config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty)) + { + case ReceiveType.Auto: + { +#if NET45_OR_GREATER||NET5_0_OR_GREATER + for (int i = 0; i < threadCount; i++) + { + SocketAsyncEventArgs eventArg = new SocketAsyncEventArgs(); + m_socketAsyncs.Add(eventArg); + eventArg.Completed += IO_Completed; + ByteBlock byteBlock = new ByteBlock(BufferLength); + eventArg.UserToken = byteBlock; + eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity); + eventArg.RemoteEndPoint = iPHost.EndPoint; + if (!socket.ReceiveFromAsync(eventArg)) + { + ProcessReceive(socket, eventArg); + } + } +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + for (int i = 0; i < threadCount; i++) + { + SocketAsyncEventArgs eventArg = new SocketAsyncEventArgs(); + m_socketAsyncs.Add(eventArg); + eventArg.Completed += IO_Completed; + ByteBlock byteBlock = new ByteBlock(BufferLength); + eventArg.UserToken = byteBlock; + eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity); + eventArg.RemoteEndPoint = iPHost.EndPoint; + if (!socket.ReceiveFromAsync(eventArg)) + { + ProcessReceive(socket, eventArg); + } + } + } + else + { + Thread thread = new Thread(Received); + thread.IsBackground = true; + thread.Start(); + } +#endif + break; + } + default: + throw new Exception("UDP中只支持Auto模式"); + } + } + + private void Received() + { + while (true) + { + ByteBlock byteBlock = new ByteBlock(); + try + { + EndPoint endPoint = m_monitor.IPHost.EndPoint; + int r = m_monitor.Socket.ReceiveFrom(byteBlock.Buffer, ref endPoint); + byteBlock.SetLength(r); + HandleBuffer(endPoint, byteBlock); + } + catch (Exception ex) + { + byteBlock.Dispose(); + Logger.Log(LogType.Error, this, ex.Message, ex); + break; + } + } + } + + private void HandleBuffer(EndPoint endPoint, ByteBlock byteBlock) + { + try + { + LastReceivedTime = DateTime.Now; + if (OnHandleRawBuffer?.Invoke(byteBlock) == false) + { + return; + } + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + Logger.Error(this, TouchSocketStatus.NullDataAdapter.GetDescription()); + return; + } + m_adapter.ReceivedInput(endPoint, byteBlock); + } + catch (Exception ex) + { + Logger.Log(LogType.Error, this, "在处理数据时发生错误", ex); + } + finally + { + byteBlock.Dispose(); + } + } + + private void IO_Completed(object sender, SocketAsyncEventArgs e) + { + ProcessReceive((Socket)sender, e); + } + + private void PrivateHandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + if (OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false) + { + return; + } + + if (m_usePlugin) + { + UdpReceivedDataEventArgs args = new UdpReceivedDataEventArgs(remoteEndPoint, byteBlock, requestInfo); + PluginsManager.Raise(nameof(IUdpSessionPlugin.OnReceivedData), this, args); + if (args.Handled) + { + return; + } + } + HandleReceivedData(remoteEndPoint, byteBlock, requestInfo); + } + + #region 向默认远程同步发送 + + /// + /// 向默认终结点发送 + /// + /// + /// + /// + public virtual void Send(byte[] buffer, int offset, int length) + { + if (m_remoteIPHost == null) + { + throw new Exception("默认终结点为空"); + } + Send(m_remoteIPHost.EndPoint, buffer, offset, length); + } + + /// + /// + /// + /// + /// + /// + public virtual void Send(IRequestInfo requestInfo) + { + if (DisposedValue) + { + return; + } + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + if (!m_adapter.CanSendRequestInfo) + { + throw new NotSupportedException($"当前适配器不支持对象发送。"); + } + m_adapter.SendInput(requestInfo); + } + + #endregion 向默认远程同步发送 + + #region 向默认远程异步发送 + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(buffer, offset, length); + }); + } + + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(IRequestInfo requestInfo) + { + return EasyTask.Run(() => + { + Send(requestInfo); + }); + } + + #endregion 向默认远程异步发送 + + #region 向设置的远程同步发送 + + /// + /// 向设置的远程同步发送 + /// + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(EndPoint remoteEP, byte[] buffer, int offset, int length) + { + m_adapter.SendInput(remoteEP, buffer, offset, length); + } + + #endregion 向设置的远程同步发送 + + #region 向设置的远程异步发送 + + /// + /// 向设置的远程异步发送 + /// + /// + /// + /// + /// + /// + /// + /// + public virtual Task SendAsync(EndPoint remoteEP, byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + Send(remoteEP, buffer, offset, length); + }); + } + + #endregion 向设置的远程异步发送 + + private void ProcessReceive(Socket socket, SocketAsyncEventArgs e) + { + if (m_serverState == ServerState.Running && e.SocketError == SocketError.Success) + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + + HandleBuffer(e.RemoteEndPoint, byteBlock); + + ByteBlock newByteBlock = new ByteBlock(BufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length); + + try + { + if (!socket.ReceiveFromAsync(e)) + { + ProcessReceive(socket, e); + } + } + catch (System.Exception ex) + { + Logger.Log(LogType.Error, this, ex.Message, ex); + } + } + } + + #region DefaultSend + + /// + /// + /// + /// + /// + /// + public void DefaultSend(byte[] buffer, int offset, int length) + { + DefaultSend(m_remoteIPHost.EndPoint, buffer, offset, length); + } + + /// + /// + /// + /// + /// + /// + /// + public void DefaultSend(EndPoint endPoint, byte[] buffer, int offset, int length) + { + if (HandleSendingData(endPoint, buffer, offset, length)) + { + if (CanSend) + { + m_monitor.Socket.SendTo(buffer, offset, length, SocketFlags.None, endPoint); + } + + LastSendTime = DateTime.Now; + } + } + + #endregion DefaultSend + + #region DefaultSendAsync + + /// + /// + /// + /// + /// + /// + public Task DefaultSendAsync(byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + DefaultSend(buffer, offset, length); + }); + } + + /// + /// + /// + /// + /// + /// + /// + public Task DefaultSendAsync(EndPoint endPoint, byte[] buffer, int offset, int length) + { + return EasyTask.Run(() => + { + DefaultSend(buffer, offset, length); + }); + } + + #endregion DefaultSendAsync + + #region 组合发送 + + /// + /// + /// + /// + public void Send(IList> transferBytes) + { + Send(m_remoteIPHost.EndPoint, transferBytes); + } + + /// + /// + /// + /// + /// + public void Send(EndPoint endPoint, IList> transferBytes) + { + if (m_adapter == null) + { + throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription()); + } + + if (!m_adapter.CanSplicingSend) + { + throw new NotSupportedException("该适配器不支持拼接发送"); + } + m_adapter.SendInput(endPoint, transferBytes); + } + + /// + /// + /// + /// + public Task SendAsync(IList> transferBytes) + { + return EasyTask.Run(() => + { + Send(transferBytes); + }); + } + + /// + /// + /// + /// + /// + public Task SendAsync(EndPoint endPoint, IList> transferBytes) + { + return EasyTask.Run(() => + { + Send(endPoint, transferBytes); + }); + } + + #endregion 组合发送 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs b/src/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs new file mode 100644 index 000000000..bf4ae4256 --- /dev/null +++ b/src/TouchSocket/Sockets/Config/TouchSocketConfigExtension.cs @@ -0,0 +1,618 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Security.Authentication; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TouchSocketConfigBuilder配置扩展 + /// + public static class TouchSocketConfigExtension + { + #region 数据 + + /// + /// 接收缓存容量,默认1024*64,其作用有两个: + /// + /// 指示单次可接受的最大数据量 + /// 指示常规申请内存块的长度 + /// + /// 所需类型 + /// + public static readonly DependencyProperty BufferLengthProperty = + DependencyProperty.Register("BufferLength", typeof(TouchSocketConfigExtension), 1024 * 64); + + /// + /// 数据处理适配器,默认为获取 + /// 所需类型 + /// + public static readonly DependencyProperty> DataHandlingAdapterProperty = DependencyProperty>.Register("DataHandlingAdapter", typeof(TouchSocketConfigExtension), (Func)(() => { return new NormalDataHandlingAdapter(); })); + + /// + /// 接收类型,默认为 + /// 为自动接收数据,然后主动触发。 + /// 为不投递IO接收申请,用户可通过,获取到流以后,自己处理接收。注意:连接端不会感知主动断开 + /// 所需类型 + /// + public static readonly DependencyProperty ReceiveTypeProperty = DependencyProperty.Register("ReceiveType", typeof(TouchSocketConfigExtension), ReceiveType.Auto); + + /// + /// 数据处理适配器,默认为获取 + /// 所需类型 + /// + public static readonly DependencyProperty> UdpDataHandlingAdapterProperty = DependencyProperty>.Register("UdpDataHandlingAdapter", typeof(TouchSocketConfigExtension), (Func)(() => { return new NormalUdpDataHandlingAdapter(); })); + + /// + /// 接收缓存容量,默认1024*64,其作用有两个: + /// + /// 指示单次可接受的最大数据量 + /// 指示常规申请内存块的长度 + /// + /// + /// + /// + /// + public static TouchSocketConfig SetBufferLength(this TouchSocketConfig config, int value) + { + config.SetValue(BufferLengthProperty, value); + return config; + } + + /// + /// 设置(Tcp系)数据处理适配器。 + /// + /// + /// + /// + public static TouchSocketConfig SetDataHandlingAdapter(this TouchSocketConfig config, Func value) + { + config.SetValue(DataHandlingAdapterProperty, value); + return config; + } + + /// + /// 接收类型,默认为 + /// 为自动接收数据,然后主动触发。 + /// 为不投递IO接收申请,用户可通过,获取到流以后,自己处理接收。注意:连接端不会感知主动断开 + /// + /// + /// + /// + public static TouchSocketConfig SetReceiveType(this TouchSocketConfig config, ReceiveType value) + { + config.SetValue(ReceiveTypeProperty, value); + return config; + } + + /// + /// 设置(Udp系)数据处理适配器。 + /// + /// + /// + /// + public static TouchSocketConfig SetUdpDataHandlingAdapter(this TouchSocketConfig config, Func value) + { + config.SetValue(UdpDataHandlingAdapterProperty, value); + return config; + } + + #endregion 数据 + + #region ServiceBase + + /// + /// 服务名称,用于标识,无实际意义,所需类型 + /// + public static readonly DependencyProperty ServerNameProperty = DependencyProperty.Register("ServerName", typeof(TouchSocketConfigExtension), "TouchSocketServer"); + + /// + /// 多线程数量。默认-1缺省。 + /// TCP模式中,该值等效于 + /// UDP模式中,该值为重叠IO并发数 + /// 所需类型 + /// + public static readonly DependencyProperty ThreadCountProperty = DependencyProperty.Register("ThreadCount", typeof(TouchSocketConfigExtension), -1); + + /// + /// 服务名称,用于标识,无实际意义 + /// + /// + /// + /// + public static TouchSocketConfig SetServerName(this TouchSocketConfig config, string value) + { + config.SetValue(ServerNameProperty, value); + return config; + } + + /// + /// 多线程数量,默认为-1缺省,实际上在tcp中相当于值10,udp中相当于1。 + /// TCP模式中,该值等效于 + /// UDP模式中,该值为重叠IO并发数 + /// + /// + /// + /// + public static TouchSocketConfig SetThreadCount(this TouchSocketConfig config, int value) + { + config.SetValue(ThreadCountProperty, value); + return config; + } + + #endregion ServiceBase + + #region 适配器配置 + + /// + /// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于 + /// + public static readonly DependencyProperty CacheTimeoutEnableProperty = DependencyProperty.Register("CacheTimeoutEnable", typeof(TouchSocketConfigExtension), null); + + /// + /// 适配器数据包缓存启用。默认为缺省(null),如果有正常值会在设置适配器时,直接作用于 + /// + /// + /// + /// + public static TouchSocketConfig SetCacheTimeoutEnable(this TouchSocketConfig config, bool value) + { + config.SetValue(CacheTimeoutEnableProperty, value); + return config; + } + + /// + /// 适配器数据包缓存时长。默认为缺省()。当该值有效时会在设置适配器时,直接作用于 + /// + public static readonly DependencyProperty CacheTimeoutProperty = DependencyProperty.Register("CacheTimeout", typeof(TouchSocketConfigExtension), TimeSpan.Zero); + + /// + /// 适配器数据包缓存时长。默认为缺省()。当该值有效时会在设置适配器时,直接作用于 + /// + /// + /// + /// + public static TouchSocketConfig SetCacheTimeout(this TouchSocketConfig config, TimeSpan value) + { + config.SetValue(CacheTimeoutProperty, value); + return config; + } + + /// + /// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于 + /// + public static readonly DependencyProperty UpdateCacheTimeWhenRevProperty = DependencyProperty.Register("UpdateCacheTimeWhenRev", typeof(TouchSocketConfigExtension), null); + + /// + /// 适配器数据包缓存策略。默认缺省(null),当该值有效时会在设置适配器时,直接作用于 + /// + /// + /// + /// + public static TouchSocketConfig SetUpdateCacheTimeWhenRev(this TouchSocketConfig config, bool value) + { + config.SetValue(UpdateCacheTimeWhenRevProperty, value); + return config; + } + + /// + /// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于 + /// + public static readonly DependencyProperty MaxPackageSizeProperty = DependencyProperty.Register("MaxPackageSize", typeof(TouchSocketConfigExtension), null); + + /// + /// 适配器数据包最大值。默认缺省(null),当该值有效时会在设置适配器时,直接作用于 + /// + /// + /// + /// + public static TouchSocketConfig SetMaxPackageSize(this TouchSocketConfig config, int value) + { + config.SetValue(MaxPackageSizeProperty, value); + return config; + } + + #endregion 适配器配置 + + #region TcpClient + + /// + /// TCP固定端口绑定, + /// 所需类型 + /// + public static readonly DependencyProperty BindIPHostProperty = DependencyProperty.Register("BindIPHost", typeof(TouchSocketConfigExtension), null); + + /// + /// 在Socket配置KeepAlive属性,这个是操作tcp底层的,如果你对底层不了解,建议不要动。 + /// 所需类型 + /// + public static readonly DependencyProperty KeepAliveValueProperty = DependencyProperty.Register("KeepAliveValue", typeof(TouchSocketConfigExtension), new KeepAliveValue()); + + /// + /// 设置Socket不使用Delay算法, + /// 所需类型 + /// + public static readonly DependencyProperty NoDelayProperty = DependencyProperty.Register("NoDelay", typeof(TouchSocketConfigExtension), false); + + /// + /// 远程目标地址,所需类型 + /// + public static readonly DependencyProperty RemoteIPHostProperty = DependencyProperty.Register("RemoteIPHost", typeof(TouchSocketConfigExtension), null); + + /// + /// Ssl配置,为Null时则不启用 + /// 所需类型 + /// + public static readonly DependencyProperty SslOptionProperty = DependencyProperty.Register("SslOption", typeof(TouchSocketConfigExtension), null); + + /// + /// 是否使用延迟合并发送。默认null。不开启 + /// 所需类型 + /// + public static readonly DependencyProperty DelaySenderProperty = DependencyProperty.Register("DelaySender", typeof(TouchSocketConfigExtension), null); + + /// + /// 使用默认配置延迟合并发送。 + /// 所需类型 + /// + /// + /// + /// + public static TouchSocketConfig UseDelaySender(this TouchSocketConfig config, DelaySenderOption option = default) + { + if (option == default) + { + option = new DelaySenderOption(); + } + config.SetValue(DelaySenderProperty, option); + return config; + } + + /// + /// 固定端口绑定。 + /// 中表示本地监听地址 + /// 中表示固定客户端端口号。 + /// + /// + /// + /// + public static TouchSocketConfig SetBindIPHost(this TouchSocketConfig config, IPHost value) + { + config.SetValue(BindIPHostProperty, value); + return config; + } + + /// + /// 固定端口绑定。 + /// 中表示本地监听地址 + /// 中表示固定客户端端口号。 + /// + /// + /// + /// + public static TouchSocketConfig SetBindIPHost(this TouchSocketConfig config, int value) + { + config.SetValue(BindIPHostProperty, new IPHost(value)); + return config; + } + + /// + /// 固定端口绑定。 + /// 中表示本地监听地址 + /// 中表示固定客户端端口号。 + /// + /// + /// + /// + public static TouchSocketConfig SetBindIPHost(this TouchSocketConfig config, string value) + { + config.SetValue(BindIPHostProperty, new IPHost(value)); + return config; + } + + /// + /// 设置客户端Ssl配置,为Null时则不启用。 + /// + /// + /// + /// + public static TouchSocketConfig SetClientSslOption(this TouchSocketConfig config, ClientSslOption value) + { + config.SetValue(SslOptionProperty, value); + return config; + } + + /// + /// 在Socket的KeepAlive属性。 + /// 注意:这个是操作tcp底层的,如果你对底层不了解,建议不要动。 + /// + /// + /// + /// + public static TouchSocketConfig SetKeepAliveValue(this TouchSocketConfig config, KeepAliveValue value) + { + config.SetValue(KeepAliveValueProperty, value); + return config; + } + + /// + /// 设置远程目标地址。在中,表示默认发送时的目标地址。 + /// + /// + /// + /// + public static TouchSocketConfig SetRemoteIPHost(this TouchSocketConfig config, IPHost value) + { + config.SetValue(RemoteIPHostProperty, value); + if (value.IsUri) + { + if (value.Uri.Scheme.Equals("https", StringComparison.CurrentCultureIgnoreCase) + || value.Uri.Scheme.Equals("wss", StringComparison.CurrentCultureIgnoreCase)) + { + config.SetClientSslOption(new ClientSslOption() { TargetHost = value.Host, SslProtocols = SslProtocols.Tls12 }); + } + } + return config; + } + + /// + /// 设置远程目标地址。在中,表示默认发送时的目标地址。 + /// + /// + /// + /// + public static TouchSocketConfig SetRemoteIPHost(this TouchSocketConfig config, string value) + { + return SetRemoteIPHost(config, new IPHost(value)); + } + + /// + /// 设置Socket的NoDelay属性,默认false。 + /// + /// + /// + public static TouchSocketConfig UseNoDelay(this TouchSocketConfig config) + { + config.SetValue(NoDelayProperty, true); + return config; + } + + #endregion TcpClient + + #region TcpService + + /// + /// 挂起连接队列的最大长度,所需类型 + /// + public static readonly DependencyProperty BacklogProperty = DependencyProperty.Register("Backlog", typeof(TouchSocketConfigExtension), 100); + + /// + /// 设置默认ID的获取方式,所需类型 + /// + public static readonly DependencyProperty> GetDefaultNewIDProperty = DependencyProperty>.Register("GetDefaultNewID", typeof(TouchSocketConfigExtension), null); + + /// + /// 服务器负责监听的地址组。所需类型数组 + /// + public static readonly DependencyProperty ListenIPHostsProperty = DependencyProperty.Register("ListenIPHosts", typeof(TouchSocketConfigExtension), null); + + /// + /// 最大可连接数,默认为10000,所需类型 + /// + public static readonly DependencyProperty MaxCountProperty = DependencyProperty.Register("MaxCount", typeof(TouchSocketConfigExtension), 10000); + + /// + /// 端口复用,默认为false,所需类型 + /// + public static readonly DependencyProperty ReuseAddressProperty = DependencyProperty.Register("ReuseAddress", typeof(TouchSocketConfigExtension), false); + + /// + /// 启用端口复用。 + /// 该配置可在服务器、或客户端在监听端口时,运行监听同一个端口。可以一定程度缓解端口来不及释放的问题 + /// + /// + /// + public static TouchSocketConfig UseReuseAddress(this TouchSocketConfig config) + { + config.SetValue(ReuseAddressProperty, true); + return config; + } + + /// + /// 挂起连接队列的最大长度,默认100。 + /// + /// + /// + /// + public static TouchSocketConfig SetBacklog(this TouchSocketConfig config, int value) + { + config.SetValue(BacklogProperty, value); + return config; + } + + /// + /// 设置清理无数据交互的SocketClient,默认60*1000 ms。如果不想清除,可使用-1 + /// + /// + /// + /// + [Obsolete("该操作已被弃用,请使用CheckClearPlugin插件,或者在插件中,配置UseCheckClear。", true)] + public static TouchSocketConfig SetClearInterval(this TouchSocketConfig config, int value) + { + throw new NotImplementedException(); + } + + /// + /// 清理统计类型。 + /// 为在收到数据时,刷新统计,如果一直有数据接收,则不会被主动清理断开 + /// 为在发送数据时,刷新统计,如果一直有数据发送,则不会被主动清理断开 + /// 二者可叠加使用。 + /// + /// + /// + /// + [Obsolete("该操作已被弃用,请使用CheckClearPlugin插件,或者在插件中,配置UseCheckClear。", true)] + public static TouchSocketConfig SetClearType(this TouchSocketConfig config, CheckClearType value) + { + throw new NotImplementedException(); + } + + /// + /// 设置默认ID的获取方式。仅服务器生效。 + /// + /// + /// + /// + public static TouchSocketConfig SetGetDefaultNewID(this TouchSocketConfig config, Func value) + { + config.SetValue(GetDefaultNewIDProperty, value); + return config; + } + + /// + /// 服务器负责监听的地址组。 + /// + /// + /// + /// + public static TouchSocketConfig SetListenIPHosts(this TouchSocketConfig config, IPHost[] value) + { + config.SetValue(ListenIPHostsProperty, value); + return config; + } + + /// + /// 最大可连接数,默认为10000。 + /// + /// + /// + /// + public static TouchSocketConfig SetMaxCount(this TouchSocketConfig config, int value) + { + config.SetValue(MaxCountProperty, value); + return config; + } + + /// + /// 设置客户端Ssl配置,为Null时则不启用。 + /// + /// + /// + /// + public static TouchSocketConfig SetServiceSslOption(this TouchSocketConfig config, ServiceSslOption value) + { + config.SetValue(SslOptionProperty, value); + return config; + } + + #endregion TcpService + + #region UDP + + /// + /// 该值指定 System.Net.Sockets.Socket可以发送或接收广播数据包。 + /// + public static readonly DependencyProperty EnableBroadcastProperty = DependencyProperty.Register("EnableBroadcast", typeof(TouchSocketConfigExtension), false); + + /// + /// 该值指定 System.Net.Sockets.Socket可以发送或接收广播数据包。 + /// + /// + /// + public static TouchSocketConfig UseBroadcast(this TouchSocketConfig config) + { + config.SetValue(EnableBroadcastProperty, true); + return config; + } + + #endregion UDP + + #region 创建 + + /// + /// 构建Tcp类客户端,并连接 + /// + /// + /// + /// + public static TClient BuildWithTcpClient(this TouchSocketConfig config) where TClient : ITcpClient + { + TClient service = config.Container.Resolve(); + service.Setup(config); + service.Connect(); + return service; + } + + /// + /// 构建Tcp类客户端,并连接 + /// + /// + /// + public static TcpClient BuildWithTcpClient(this TouchSocketConfig config) + { + return BuildWithTcpClient(config); + } + + /// + /// 构建Tcp类服务器,并启动。 + /// + /// + /// + /// + public static TService BuildWithTcpService(this TouchSocketConfig config) where TService : ITcpService + { + TService service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建Tcp类服务器,并启动。 + /// + /// + /// + public static TcpService BuildWithTcpService(this TouchSocketConfig config) + { + return BuildWithTcpService(config); + } + + /// + /// 构建UDP类,并启动。 + /// + /// + /// + /// + public static TSession BuildWithUdpSession(this TouchSocketConfig config) where TSession : IUdpSession + { + TSession service = config.Container.Resolve(); + service.Setup(config); + service.Start(); + return service; + } + + /// + /// 构建UDP类,并启动。 + /// + /// + /// + public static UdpSession BuildWithUdpSession(this TouchSocketConfig config) + { + return BuildWithUdpSession(config); + } + + #endregion 创建 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs new file mode 100644 index 000000000..50a514f42 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/CacheDataHandlingAdapter.cs @@ -0,0 +1,102 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// CacheDataHandlingAdapter + /// + public abstract class CacheDataHandlingAdapter : DataHandlingAdapter + { + /// + /// 缓存数据,如果需要手动释放,请先判断,然后到调用后,再置空; + /// + protected ByteBlock m_cacheByteBlock; + + /// + /// 将数据缓存起来 + /// + /// + /// + /// + protected void Cache(byte[] buffer, int offset, int length) + { + m_cacheByteBlock ??= new ByteBlock(length); + m_cacheByteBlock.Write(buffer, offset, length); + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + } + + /// + /// + /// + protected override void Reset() + { + m_cacheByteBlock.SafeDispose(); + m_cacheByteBlock = null; + } + + /// + /// 获取当前缓存, + /// 如果缓存超时,或者不存在,均会返回false。 + /// 如果获取成功,则会清空内部缓存。 + /// + /// + protected bool TryGetCache(out byte[] buffer) + { + if (m_cacheByteBlock == null) + { + buffer = null; + return false; + } + if (DateTime.Now - LastCacheTime > CacheTimeout) + { + m_cacheByteBlock.SafeDispose(); + m_cacheByteBlock = null; + buffer = null; + return false; + } + buffer = m_cacheByteBlock.ToArray(); + m_cacheByteBlock.SafeDispose(); + m_cacheByteBlock = null; + return true; + } + + /// + /// 获取缓存,注意:获取的ByteBlock需要手动释放。 + /// + /// + /// + protected bool TryGetCache(out ByteBlock byteBlock) + { + if (m_cacheByteBlock == null) + { + byteBlock = null; + return false; + } + if (DateTime.Now - LastCacheTime > CacheTimeout) + { + m_cacheByteBlock.SafeDispose(); + m_cacheByteBlock = null; + byteBlock = null; + return false; + } + byteBlock = m_cacheByteBlock; + return true; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs new file mode 100644 index 000000000..0caa4c804 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomBetweenAndDataHandlingAdapter.cs @@ -0,0 +1,172 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 区间数据包处理适配器,支持以任意字符、字节数组起始与结尾的数据包。 + /// + public abstract class CustomBetweenAndDataHandlingAdapter : CustomDataHandlingAdapter where TBetweenAndRequestInfo : class, IBetweenAndRequestInfo + { + /// + /// 起始字符,不可以为null,可以为0长度 + /// + public abstract byte[] StartCode { get; } + + /// + /// 即使找到了终止因子,也不会结束,默认0 + /// + public int MinSize { get; set; } + + /// + /// 结束字符,不可以为null,不可以为0长度,必须具有有效值。 + /// + public abstract byte[] EndCode { get; } + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TBetweenAndRequestInfo request, ref int tempCapacity) + { + if (beCached) + { + int len; + int pos = byteBlock.Pos; + while (true) + { + int indexEnd = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, EndCode); + if (indexEnd == -1) + { + byteBlock.Pos = pos; + return FilterResult.Cache; + } + + len = indexEnd - EndCode.Length - pos + 1; + if (len >= MinSize) + { + break; + } + byteBlock.Pos += len + EndCode.Length; + } + + byteBlock.Pos = pos; + request.OnParsingBody(byteBlock.ToArray(pos, len)); + byteBlock.Pos += len; + + if (request.OnParsingEndCode(byteBlock.ToArray(byteBlock.Pos, EndCode.Length))) + { + byteBlock.Pos += EndCode.Length; + return FilterResult.Success; + } + else + { + byteBlock.Pos += EndCode.Length; + return FilterResult.GoOn; + } + } + else + { + TBetweenAndRequestInfo requestInfo = GetInstance(); + + int indexStart = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, StartCode); + if (indexStart == -1) + { + return FilterResult.Cache; + } + if (!requestInfo.OnParsingStartCode(byteBlock.ToArray(byteBlock.Pos, StartCode.Length))) + { + byteBlock.Pos += StartCode.Length; + return FilterResult.GoOn; + } + byteBlock.Pos += StartCode.Length; + request = requestInfo; + + int len; + int pos = byteBlock.Pos; + while (true) + { + int indexEnd = byteBlock.Buffer.IndexOfFirst(byteBlock.Pos, byteBlock.CanReadLen, EndCode); + if (indexEnd == -1) + { + byteBlock.Pos = pos; + return FilterResult.Cache; + } + + len = indexEnd - EndCode.Length - pos + 1; + if (len >= MinSize) + { + break; + } + byteBlock.Pos += len + EndCode.Length; + } + + byteBlock.Pos = pos; + request.OnParsingBody(byteBlock.ToArray(pos, len)); + byteBlock.Pos += len; + + if (request.OnParsingEndCode(byteBlock.ToArray(byteBlock.Pos, EndCode.Length))) + { + byteBlock.Pos += EndCode.Length; + return FilterResult.Success; + } + else + { + byteBlock.Pos += EndCode.Length; + return FilterResult.GoOn; + } + } + } + + /// + /// 获取泛型实例。 + /// + /// + protected abstract TBetweenAndRequestInfo GetInstance(); + } + + /// + /// 区间类型的适配器数据模型接口。 + /// + public interface IBetweenAndRequestInfo : IRequestInfo + { + /// + /// 当解析到起始字符时。 + /// + /// + /// + bool OnParsingStartCode(byte[] startCode); + + /// + /// 当解析数据体。 + /// 在此方法中,您必须手动保存Body内容 + /// + /// + void OnParsingBody(byte[] body); + + /// + /// 当解析到起始字符时。 + /// + /// + /// + bool OnParsingEndCode(byte[] endCode); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs new file mode 100644 index 000000000..a206d8309 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomBigFixedHeaderDataHandlingAdapter.cs @@ -0,0 +1,169 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 大数据用户自定义固定包头解析器,使用该适配器时,接收方收到的数据中,将为null,同时将实现为TFixedHeaderRequestInfo。 + /// + public abstract class CustomBigFixedHeaderDataHandlingAdapter : CustomDataHandlingAdapter + where TFixedHeaderRequestInfo : class, IBigFixedHeaderRequestInfo + { + /// + /// 固定包头的长度。 + /// + public abstract int HeaderLength { get; } + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TFixedHeaderRequestInfo request, ref int tempCapacity) + { + if (beCached) + { + while (m_surLen > 0 && byteBlock.CanRead) + { + int r = (int)Math.Min(m_surLen, byteBlock.CanReadLength); + try + { + request.OnAppendBody(byteBlock.Buffer, byteBlock.Pos, r); + m_surLen -= r; + byteBlock.Pos += r; + if (m_surLen == 0) + { + if (request.OnFinished()) + { + return FilterResult.Success; + } + request = null; + return FilterResult.GoOn; + } + } + catch (Exception ex) + { + OnError(ex.Message, false, true); + } + } + return FilterResult.GoOn; + } + else + { + if (HeaderLength > byteBlock.CanReadLen) + { + return FilterResult.Cache; + } + + TFixedHeaderRequestInfo requestInfo = GetInstance(); + byteBlock.Read(out byte[] header, HeaderLength); + if (requestInfo.OnParsingHeader(header)) + { + request = requestInfo; + if (requestInfo.BodyLength == 0) + { + if (requestInfo.OnFinished()) + { + return FilterResult.Success; + } + request = null; + return FilterResult.GoOn; + } + m_surLen = request.BodyLength; + + while (m_surLen > 0 && byteBlock.CanRead) + { + int r = (int)Math.Min(m_surLen, byteBlock.CanReadLength); + try + { + request.OnAppendBody(byteBlock.Buffer, byteBlock.Pos, r); + m_surLen -= r; + byteBlock.Pos += r; + if (m_surLen == 0) + { + if (request.OnFinished()) + { + return FilterResult.Success; + } + request = null; + return FilterResult.GoOn; + } + } + catch (Exception ex) + { + OnError(ex.Message, false, true); + } + } + return FilterResult.GoOn; + } + else + { + return FilterResult.GoOn; + } + } + } + + private long m_surLen; + + /// + /// 获取泛型实例。 + /// + /// + protected abstract TFixedHeaderRequestInfo GetInstance(); + } + + /// + /// 用户自定义固定包头请求 + /// + public interface IBigFixedHeaderRequestInfo : IRequestInfo + { + /// + /// 数据体长度 + /// + long BodyLength { get; } + + /// + /// 当收到数据,由框架封送固定协议头。 + /// 您需要在此函数中,解析自己的固定包头,并且对赋值后续数据的长度,然后返回True。 + /// 如果返回false,则意味着放弃本次解析 + /// + /// + /// + bool OnParsingHeader(byte[] header); + + /// + /// 当收到数据,由框架封送数据。 + /// 您需要将有效数据自行保存。该方法可能会多次调用。 + /// + /// + /// + /// + /// 是否成功有效 + void OnAppendBody(byte[] buffer, int offset, int length); + + /// + /// 当完成数据接收时调用。 + /// 当返回False时,将不会把该对象向Received传递。 + /// + /// 是否成功有效 + bool OnFinished(); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs new file mode 100644 index 000000000..d28297a45 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomDataHandlingAdapter.cs @@ -0,0 +1,200 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 用户自定义数据处理适配器,使用该适配器时,接收方收到的数据中,将为null, + /// 同时将实现为TRequest,发送数据直接发送。 + /// 此处设计思路借鉴SuperSocket。 + /// + public abstract class CustomDataHandlingAdapter : DataHandlingAdapter where TRequest : class, IRequestInfo + { + /// + /// 缓存数据,如果需要手动释放,请先判断,然后到调用后,再置空; + /// + protected ByteBlock TempByteBlock; + + /// + /// 缓存对象。 + /// + protected TRequest TempRequest; + + private bool m_needReset; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// 默认不支持拼接发送 + /// + public override bool CanSplicingSend => false; + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected abstract FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TRequest request, ref int tempCapacity); + + /// + /// 成功执行接收以后。 + /// + /// + protected virtual void OnReceivedSuccess(TRequest request) + { + } + + /// + /// 即将执行。 + /// + /// + /// 返回值标识是否继续执行 + protected virtual bool OnReceivingSuccess(TRequest request) + { + return true; + } + + /// + /// + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (m_needReset || CacheTimeoutEnable && DateTime.Now - LastCacheTime > CacheTimeout) + { + Reset(); + m_needReset = false; + } + if (TempByteBlock == null) + { + Single(byteBlock, false); + } + else + { + TempByteBlock.Write(byteBlock.Buffer, 0, byteBlock.Len); + ByteBlock block = TempByteBlock; + TempByteBlock = null; + Single(block, true); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + } + + /// + /// + /// + /// 数据 + /// 偏移 + /// 长度 + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + GoSend(buffer, offset, length); + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。 + } + + /// + /// + /// + protected override void Reset() + { + TempByteBlock.SafeDispose(); + TempByteBlock = null; + TempRequest = default; + m_needReset = true; + } + + private void Single(ByteBlock byteBlock, bool temp) + { + byteBlock.Pos = 0; + while (byteBlock.Pos < byteBlock.Len) + { + if (m_needReset) + { + return; + } + int tempCapacity = 1024 * 64; + FilterResult filterResult = Filter(byteBlock, TempRequest != null, ref TempRequest, ref tempCapacity); + switch (filterResult) + { + case FilterResult.Success: + if (OnReceivingSuccess(TempRequest)) + { + GoReceived(null, TempRequest); + OnReceivedSuccess(TempRequest); + } + TempRequest = default; + break; + + case FilterResult.Cache: + if (byteBlock.CanReadLen > 0) + { + if (temp) + { + TempByteBlock = new ByteBlock(tempCapacity); + TempByteBlock.Write(byteBlock.Buffer, byteBlock.Pos, byteBlock.CanReadLen); + byteBlock.Dispose(); + } + else + { + TempByteBlock = new ByteBlock(tempCapacity); + TempByteBlock.Write(byteBlock.Buffer, byteBlock.Pos, byteBlock.CanReadLen); + } + + if (TempByteBlock.Len > MaxPackageSize) + { + OnError("缓存的数据长度大于设定值的情况下未收到解析信号"); + } + } + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + return; + + case FilterResult.GoOn: + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs new file mode 100644 index 000000000..4c55c3af1 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomFixedHeaderDataHandlingAdapter.cs @@ -0,0 +1,127 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 用户自定义固定包头解析器,使用该适配器时,接收方收到的数据中,将为null,同时将实现为TFixedHeaderRequestInfo。 + /// + public abstract class CustomFixedHeaderDataHandlingAdapter : CustomDataHandlingAdapter where TFixedHeaderRequestInfo : class, IFixedHeaderRequestInfo + { + /// + /// 固定包头的长度。 + /// + public abstract int HeaderLength { get; } + + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TFixedHeaderRequestInfo request, ref int tempCapacity) + { + if (beCached) + { + if (request.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象 + { + return FilterResult.Cache; + } + + byteBlock.Read(out byte[] body, request.BodyLength); + if (request.OnParsingBody(body)) + { + return FilterResult.Success; + } + else + { + request = default;//放弃所有解析 + return FilterResult.GoOn; + } + } + else + { + if (HeaderLength > byteBlock.CanReadLen) + { + return FilterResult.Cache; + } + + TFixedHeaderRequestInfo requestInfo = GetInstance(); + byteBlock.Read(out byte[] header, HeaderLength); + if (requestInfo.OnParsingHeader(header)) + { + request = requestInfo; + if (requestInfo.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象 + { + return FilterResult.Cache; + } + + byteBlock.Read(out byte[] body, requestInfo.BodyLength); + if (requestInfo.OnParsingBody(body)) + { + return FilterResult.Success; + } + else + { + request = default;//放弃所有解析 + return FilterResult.GoOn; + } + } + else + { + return FilterResult.GoOn; + } + } + } + + /// + /// 获取泛型实例。 + /// + /// + protected abstract TFixedHeaderRequestInfo GetInstance(); + } + + /// + /// 用户自定义固定包头请求 + /// + public interface IFixedHeaderRequestInfo : IRequestInfo + { + /// + /// 数据体长度 + /// + int BodyLength { get; } + + /// + /// 当收到数据,由框架封送固定协议头。 + /// 您需要在此函数中,解析自己的固定包头,并且对赋值后续数据的长度,然后返回True。 + /// 如果返回false,则意味着放弃本次解析 + /// + /// + /// + bool OnParsingHeader(byte[] header); + + /// + /// 当收到数据,由框架封送有效载荷数据。 + /// 如果返回false,意味着放弃本次解析的所有数据,包括已经解析完成的Header + /// + /// 载荷数据 + /// 是否成功有效 + bool OnParsingBody(byte[] body); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs new file mode 100644 index 000000000..6abf70037 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Custom/CustomUnfixedHeaderDataHandlingAdapter.cs @@ -0,0 +1,117 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 用户自定义固定包头解析器,使用该适配器时,接收方收到的数据中,将为null,同时将实现为TUnfixedHeaderRequestInfo。 + /// + public abstract class CustomUnfixedHeaderDataHandlingAdapter : CustomDataHandlingAdapter where TUnfixedHeaderRequestInfo : class, IUnfixedHeaderRequestInfo + { + /// + /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 + /// 当不满足解析条件时,请返回,此时会保存的数据 + /// 当数据部分异常时,请移动到指定位置,然后返回 + /// 当完全满足解析条件时,请返回最后将移至指定位置。 + /// + /// 字节块 + /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 + /// 对象。 + /// 缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。 + /// + protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref TUnfixedHeaderRequestInfo request, ref int tempCapacity) + { + if (beCached) + { + if (request.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象 + { + return FilterResult.Cache; + } + + byteBlock.Read(out byte[] body, request.BodyLength); + if (request.OnParsingBody(body)) + { + return FilterResult.Success; + } + else + { + request = default;//放弃所有解析 + return FilterResult.GoOn; + } + } + else + { + TUnfixedHeaderRequestInfo requestInfo = GetInstance(); + if (requestInfo.OnParsingHeader(byteBlock)) + { + request = requestInfo; + if (requestInfo.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象 + { + return FilterResult.Cache; + } + + byteBlock.Read(out byte[] body, requestInfo.BodyLength); + if (requestInfo.OnParsingBody(body)) + { + return FilterResult.Success; + } + else + { + request = default;//放弃所有解析 + return FilterResult.GoOn; + } + } + else + { + return FilterResult.Cache; + } + } + } + + /// + /// 获取泛型实例。 + /// + /// + protected abstract TUnfixedHeaderRequestInfo GetInstance(); + } + + /// + /// 用户自定义不固定包头请求 + /// + public interface IUnfixedHeaderRequestInfo : IRequestInfo + { + /// + /// 数据体长度 + /// + int BodyLength { get; } + + /// + /// 当收到数据,由框架封送数据,您需要在此函数中,解析自己的数据包头。 + /// 如果满足包头的解析,请返回True,并且递增整个包头的长度到,然后赋值 + /// 如果返回false,意味着缓存剩余数据,此时如果仅仅是因为长度不足,则不必修改其他。 + /// 但是如果是因为数据错误,则需要修改到正确位置,如果都不正确,则设置等于 + /// + /// + /// 是否满足解析包头 + bool OnParsingHeader(ByteBlock byteBlock); + + /// + /// 当收到数据,由框架封送有效载荷数据。 + /// 如果返回false,意味着放弃本次解析的所有数据,包括已经解析完成的Header + /// + /// 载荷数据 + /// 是否成功有效 + bool OnParsingBody(byte[] body); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs new file mode 100644 index 000000000..3fefceecb --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/DataHandlingAdapter.cs @@ -0,0 +1,219 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 数据处理适配器 + /// + public abstract class DataHandlingAdapter : DisposableObject + { + private ITcpClientBase m_client; + + /// + /// 最后缓存的时间 + /// + protected DateTime LastCacheTime { get; set; } + + /// + /// 是否在收到数据时,即刷新缓存时间。默认true。 + /// + /// 当设为true时,将弱化的作用,只要一直有数据,则缓存不会过期。 + /// 当设为false时,则在的时效内。必须完成单个缓存的数据。 + /// + /// + public bool UpdateCacheTimeWhenRev { get; set; } = true; + + /// + /// 缓存超时时间。默认1秒。 + /// + public TimeSpan CacheTimeout { get; set; } = TimeSpan.FromSeconds(1); + + /// + /// 是否启用缓存超时。默认true。 + /// + public bool CacheTimeoutEnable { get; set; } = true; + + /// + /// 当插件在被第一次加载时调用。 + /// + /// + /// 此适配器已被其他终端使用,请重新创建对象。 + public virtual void OnLoaded(ITcpClientBase client) + { + if (m_client != null) + { + throw new Exception("此适配器已被其他终端使用,请重新创建对象。"); + } + m_client = client; + } + + /// + /// 拼接发送 + /// + public abstract bool CanSplicingSend { get; } + + /// + /// 是否允许发送对象。 + /// + public abstract bool CanSendRequestInfo { get; } + + /// + /// 获取或设置适配器能接收的最大数据包长度。 + /// + public int MaxPackageSize { get; set; } = 1024 * 1024 * 10; + + /// + /// 适配器拥有者。 + /// + public ITcpClientBase Client => m_client; + + /// + /// 当接收数据处理完成后,回调该函数执行接收 + /// + public Action ReceivedCallBack { get; set; } + + /// + /// 当接收数据处理完成后,回调该函数执行发送 + /// + public Action SendCallBack { get; set; } + + /// + /// 收到数据的切入点,该方法由框架自动调用。 + /// + /// + public void ReceivedInput(ByteBlock byteBlock) + { + try + { + PreviewReceived(byteBlock); + } + catch (Exception ex) + { + OnError(ex.Message); + } + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + /// + /// + public void SendInput(byte[] buffer, int offset, int length) + { + PreviewSend(buffer, offset, length); + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + public void SendInput(IList> transferBytes) + { + PreviewSend(transferBytes); + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + public void SendInput(IRequestInfo requestInfo) + { + PreviewSend(requestInfo); + } + + /// + /// 处理已经经过预先处理后的数据 + /// + /// 以二进制形式传递 + /// 以解析实例传递 + protected void GoReceived(ByteBlock byteBlock, IRequestInfo requestInfo) + { + ReceivedCallBack.Invoke(byteBlock, requestInfo); + } + + /// + /// 发送已经经过预先处理后的数据 + /// + /// + /// + /// + protected void GoSend(byte[] buffer, int offset, int length) + { + SendCallBack.Invoke(buffer, offset, length); + } + + /// + /// 在解析时发生错误。 + /// + /// 错误异常 + /// 是否调用 + /// 是否记录日志 + protected virtual void OnError(string error, bool reset = true, bool log = true) + { + if (reset) + { + Reset(); + } + if (log && m_client != null && m_client.Logger != null) + { + m_client.Logger.Error(error); + } + } + + /// + /// 当接收到数据后预先处理数据,然后调用处理数据 + /// + /// + protected abstract void PreviewReceived(ByteBlock byteBlock); + + /// + /// 当发送数据前预先处理数据 + /// + /// 数据 + /// 偏移 + /// 长度 + protected abstract void PreviewSend(byte[] buffer, int offset, int length); + + /// + /// 当发送数据前预先处理数据 + /// + /// + protected abstract void PreviewSend(IRequestInfo requestInfo); + + /// + /// 组合发送预处理数据, + /// 当属性SplicingSend实现为True时,系统才会调用该方法。 + /// + /// 代发送数据组合 + protected abstract void PreviewSend(IList> transferBytes); + + /// + /// 重置解析器到初始状态,一般在被触发时,由返回值指示是否调用。 + /// + protected abstract void Reset(); + + /// + /// 该方法被触发时,一般说明已经断开连接。 + /// + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs new file mode 100644 index 000000000..7c64601b8 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/JsonStringDataHandlingAdapter.cs @@ -0,0 +1,154 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +//using TouchSocket.Core; +//using System.Collections.Generic; +//using System.Text; +//using System.Text.RegularExpressions; + +//namespace TouchSocket.Sockets +//{ +// /// +// /// Json字符串数据处理解析器(该解析器由网友"明月"提供) +// /// +// public class JsonStringDataHandlingAdapter : CustomDataHandlingAdapter +// { +// private ByteBlock Temp; + +// /// +// /// +// /// +// public override bool CanSplicingSend => false; + +// /// +// /// 预解析 +// /// +// /// +// protected override void PreviewReceived(ByteBlock byteBlock) +// { +// byte[] buffer = byteBlock.Buffer; +// int length = byteBlock.Len; + +// //Console.WriteLine("----------------接收的新数据-------------------"); +// if (Temp != null) +// { +// Temp.Write(byteBlock.Buffer, 0, length); +// buffer = Temp.Buffer; +// length = (int)Temp.Length; +// } + +// string msg = Encoding.UTF8.GetString(buffer, 0, length); +// if (msg.Contains("}{")) +// { +// //Console.WriteLine("----------------发生粘包-------------------"); +// string[] mes = Regex.Split(msg, "}{"); +// for (int i = 0; i < mes.Length; i++) +// { +// string str = mes[i]; +// if (i == 0) +// { +// str += "}"; +// } +// else if (i == mes.Length - 1) +// { +// str = "{" + str; +// int start = StringCount(str, "{"); +// int end = StringCount(str, "}"); +// if (start == end) +// { +// if (Temp != null) +// { +// Temp = null; +// } +// } +// else +// { +// byte[] surPlus = Encoding.UTF8.GetBytes(str); + +// if (Temp != null) +// { +// Temp = null; +// } +// //Temp = BytePool.GetByteBlock(1024*1024*10); +// Temp = BytePool.GetByteBlock(length); + +// Temp.Write(surPlus); +// //Console.WriteLine("----------------数据不完整-------------------"); +// break; +// } +// } +// else +// { +// str = "{" + str + "}"; +// } +// //Console.WriteLine(str); +// PreviewHandle(str); +// } +// } +// else if (msg[0] == '{' && msg[1] == '}') +// { +// Temp = null; +// PreviewHandle(msg); +// } +// else +// { +// if (Temp == null) +// { +// Temp = BytePool.GetByteBlock(length); +// Temp.Write(byteBlock.Buffer, 0, length); +// } + +// Temp.Write(byteBlock.Buffer, 0, length); +// } +// } + +// /// +// /// 预发送封装 +// /// +// /// +// /// +// /// +// /// +// protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync) +// { +// this.GoSend(buffer, offset, length, isAsync); +// } + +// private int StringCount(string source, string match) +// { +// int count = 0; +// if (source.Contains(match)) +// { +// string temp = source.Replace(match, ""); +// count = (source.Length - temp.Length) / match.Length; +// } +// return count; +// } + +// private void PreviewHandle(string msg) +// { +// GoReceived(null, msg); +// } + +// protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref JsonRequestInfo request, ref int tempCapacity) +// { +// } +// } + +// /// +// /// json解析 +// /// +// public class JsonRequestInfo:IRequestInfo +// { +// } +//} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs new file mode 100644 index 000000000..7cfffc2c4 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/NormalDataHandlingAdapter.cs @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 普通TCP数据处理器,该适配器不对数据做任何处理。 + /// + public class NormalDataHandlingAdapter : DataHandlingAdapter + { + /// + /// + /// + public override bool CanSplicingSend => false; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// 当接收到数据时处理数据 + /// + /// 数据流 + protected override void PreviewReceived(ByteBlock byteBlock) + { + GoReceived(byteBlock, null); + } + + /// + /// + /// + /// 数据 + /// 偏移 + /// 长度 + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + GoSend(buffer, offset, length); + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + throw new System.NotImplementedException();//因为设置了不支持拼接发送,所以该方法可以不实现。 + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs new file mode 100644 index 000000000..770aef0a8 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Package/FixedHeaderPackageAdapter.cs @@ -0,0 +1,347 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 固定包头数据包处理适配器,支持Byte、UShort、Int三种类型作为包头。使用大小端设置。 + /// + public class FixedHeaderPackageAdapter : DataHandlingAdapter + { + private byte[] m_agreementTempBytes; + private int m_surPlusLength = 0; + + //包剩余长度 + private ByteBlock m_tempByteBlock; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// 设置包头类型,默认为int + /// + public FixedHeaderType FixedHeaderType { get; set; } = FixedHeaderType.Int; + + /// + /// 获取或设置包数据的最小值(默认为0) + /// + public int MinPackageSize { get; set; } = 0; + + /// + /// 当接收到数据时处理数据 + /// + /// 数据流 + protected override void PreviewReceived(ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + + if (CacheTimeoutEnable && DateTime.Now - LastCacheTime > CacheTimeout) + { + Reset(); + } + + if (m_agreementTempBytes != null) + { + SeamPackage(buffer, r); + } + else if (m_tempByteBlock == null) + { + SplitPackage(buffer, 0, r); + } + else + { + if (m_surPlusLength == r) + { + m_tempByteBlock.Write(buffer, 0, m_surPlusLength); + PreviewHandle(m_tempByteBlock); + m_tempByteBlock = null; + m_surPlusLength = 0; + } + else if (m_surPlusLength < r) + { + m_tempByteBlock.Write(buffer, 0, m_surPlusLength); + PreviewHandle(m_tempByteBlock); + m_tempByteBlock = null; + SplitPackage(buffer, m_surPlusLength, r); + } + else + { + m_tempByteBlock.Write(buffer, 0, r); + m_surPlusLength -= r; + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + } + } + } + + /// + /// 当发送数据前处理数据 + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + if (length < MinPackageSize) + { + throw new Exception("发送数据小于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + if (length > MaxPackageSize) + { + throw new Exception("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + ByteBlock byteBlock = null; + byte[] lenBytes = null; + + switch (FixedHeaderType) + { + case FixedHeaderType.Byte: + { + byte dataLen = (byte)(length - offset); + byteBlock = new ByteBlock(dataLen + 1); + lenBytes = new byte[] { dataLen }; + break; + } + case FixedHeaderType.Ushort: + { + ushort dataLen = (ushort)(length - offset); + byteBlock = new ByteBlock(dataLen + 2); + lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen); + break; + } + case FixedHeaderType.Int: + { + int dataLen = length - offset; + byteBlock = new ByteBlock(dataLen + 4); + lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen); + break; + } + } + + try + { + byteBlock.Write(lenBytes); + byteBlock.Write(buffer, offset, length); + GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + if (transferBytes.Count == 0) + { + return; + } + + int length = 0; + foreach (var item in transferBytes) + { + length += item.Count; + } + + if (length < MinPackageSize) + { + throw new Exception("发送数据小于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + if (length > MaxPackageSize) + { + throw new Exception("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + ByteBlock byteBlock = null; + byte[] lenBytes = null; + + switch (FixedHeaderType) + { + case FixedHeaderType.Byte: + { + byte dataLen = (byte)length; + byteBlock = new ByteBlock(dataLen + 1); + lenBytes = new byte[] { dataLen }; + break; + } + case FixedHeaderType.Ushort: + { + ushort dataLen = (ushort)length; + byteBlock = new ByteBlock(dataLen + 2); + lenBytes = TouchSocketBitConverter.Default.GetBytes(dataLen); + break; + } + case FixedHeaderType.Int: + { + byteBlock = new ByteBlock(length + 4); + lenBytes = TouchSocketBitConverter.Default.GetBytes(length); + break; + } + } + + try + { + byteBlock.Write(lenBytes); + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + m_agreementTempBytes = null; + m_surPlusLength = default; + m_tempByteBlock?.Dispose(); + m_tempByteBlock = null; + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// 缝合包 + /// + /// + /// + private void SeamPackage(byte[] buffer, int r) + { + ByteBlock byteBlock = new ByteBlock(r + m_agreementTempBytes.Length); + byteBlock.Write(m_agreementTempBytes); + byteBlock.Write(buffer, 0, r); + r += m_agreementTempBytes.Length; + m_agreementTempBytes = null; + SplitPackage(byteBlock.Buffer, 0, r); + byteBlock.Dispose(); + } + + /// + /// 分解包 + /// + /// + /// + /// + private void SplitPackage(byte[] dataBuffer, int index, int r) + { + while (index < r) + { + if (r - index <= (byte)FixedHeaderType) + { + m_agreementTempBytes = new byte[r - index]; + Array.Copy(dataBuffer, index, m_agreementTempBytes, 0, m_agreementTempBytes.Length); + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + return; + } + int length = 0; + + switch (FixedHeaderType) + { + case FixedHeaderType.Byte: + length = dataBuffer[index]; + break; + + case FixedHeaderType.Ushort: + length = TouchSocketBitConverter.Default.ToUInt16(dataBuffer, index); + break; + + case FixedHeaderType.Int: + length = TouchSocketBitConverter.Default.ToInt32(dataBuffer, index); + break; + } + + if (length < 0) + { + throw new Exception("接收数据长度错误,已放弃接收"); + } + else if (length < MinPackageSize) + { + throw new Exception("接收数据长度小于设定值,已放弃接收"); + } + else if (length > MaxPackageSize) + { + throw new Exception("接收数据长度大于设定值,已放弃接收"); + } + + int recedSurPlusLength = r - index - (byte)FixedHeaderType; + if (recedSurPlusLength >= length) + { + ByteBlock byteBlock = new ByteBlock(length); + byteBlock.Write(dataBuffer, index + (byte)FixedHeaderType, length); + PreviewHandle(byteBlock); + m_surPlusLength = 0; + } + else//半包 + { + m_tempByteBlock = new ByteBlock(length); + m_surPlusLength = length - recedSurPlusLength; + m_tempByteBlock.Write(dataBuffer, index + (byte)FixedHeaderType, recedSurPlusLength); + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + } + index += (length + (byte)FixedHeaderType); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs new file mode 100644 index 000000000..069feb16f --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Package/FixedSizePackageAdapter.cs @@ -0,0 +1,224 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 固定长度数据包处理适配器。 + /// + public class FixedSizePackageAdapter : DataHandlingAdapter + { + /// + /// 包剩余长度 + /// + private int m_surPlusLength = 0; + + /// + /// 临时包 + /// + private ByteBlock m_tempByteBlock; + + /// + /// 构造函数 + /// + /// 数据包的长度 + public FixedSizePackageAdapter(int fixedSize) + { + FixedSize = fixedSize; + } + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// 获取已设置的数据包的长度 + /// + public int FixedSize { get; private set; } + + /// + /// 预处理 + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (CacheTimeoutEnable && DateTime.Now - LastCacheTime > CacheTimeout) + { + Reset(); + } + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + if (m_tempByteBlock == null) + { + SplitPackage(buffer, 0, r); + } + else + { + if (m_surPlusLength == r) + { + m_tempByteBlock.Write(buffer, 0, m_surPlusLength); + PreviewHandle(m_tempByteBlock); + m_tempByteBlock = null; + m_surPlusLength = 0; + } + else if (m_surPlusLength < r) + { + m_tempByteBlock.Write(buffer, 0, m_surPlusLength); + PreviewHandle(m_tempByteBlock); + m_tempByteBlock = null; + SplitPackage(buffer, m_surPlusLength, r); + } + else + { + m_tempByteBlock.Write(buffer, 0, r); + m_surPlusLength -= r; + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + } + } + } + + /// + /// 预处理 + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + int dataLen = length - offset; + if (dataLen > FixedSize) + { + throw new OverlengthException("发送的数据包长度大于FixedSize"); + } + ByteBlock byteBlock = new ByteBlock(FixedSize); + + byteBlock.Write(buffer, offset, length); + for (int i = (int)byteBlock.Position; i < FixedSize; i++) + { + byteBlock.Buffer[i] = 0; + } + byteBlock.SetLength(FixedSize); + try + { + GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + int length = 0; + foreach (var item in transferBytes) + { + length += item.Count; + } + + if (length > FixedSize) + { + throw new OverlengthException("发送的数据包长度大于FixedSize"); + } + ByteBlock byteBlock = new ByteBlock(FixedSize); + + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + + Array.Clear(byteBlock.Buffer, byteBlock.Pos, FixedSize); + byteBlock.SetLength(FixedSize); + try + { + GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + m_tempByteBlock.SafeDispose(); + m_tempByteBlock = null; + m_surPlusLength = 0; + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + + private void SplitPackage(byte[] dataBuffer, int index, int r) + { + while (index < r) + { + if (r - index >= FixedSize) + { + ByteBlock byteBlock = new ByteBlock(FixedSize); + byteBlock.Write(dataBuffer, index, FixedSize); + PreviewHandle(byteBlock); + m_surPlusLength = 0; + } + else//半包 + { + m_tempByteBlock = new ByteBlock(FixedSize); + m_surPlusLength = FixedSize - (r - index); + m_tempByteBlock.Write(dataBuffer, index, r - index); + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + } + index += FixedSize; + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs new file mode 100644 index 000000000..a7fbd2a29 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Package/TerminatorPackageAdapter.cs @@ -0,0 +1,254 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Text; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 终止字符数据包处理适配器,支持以任意字符、字节数组结尾的数据包。 + /// + public class TerminatorPackageAdapter : DataHandlingAdapter + { + private int m_minSize = 0; + + private bool m_reserveTerminatorCode; + + private ByteBlock m_tempByteBlock; + + private readonly byte[] m_terminatorCode; + + /// + /// 构造函数 + /// + /// + public TerminatorPackageAdapter(string terminator) : this(0, Encoding.UTF8.GetBytes(terminator)) + { + } + + /// + /// 构造函数 + /// + /// + /// + public TerminatorPackageAdapter(string terminator, Encoding encoding) + : this(0, encoding.GetBytes(terminator)) + { + } + + /// + /// 构造函数 + /// + /// + /// + public TerminatorPackageAdapter(int minSize, byte[] terminatorCode) + { + m_minSize = minSize; + m_terminatorCode = terminatorCode; + } + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// 即使找到了终止因子,也不会结束,默认0 + /// + public int MinSize + { + get => m_minSize; + set => m_minSize = value; + } + + /// + /// 保留终止因子 + /// + public bool ReserveTerminatorCode + { + get => m_reserveTerminatorCode; + set => m_reserveTerminatorCode = value; + } + + /// + /// 预处理 + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (CacheTimeoutEnable && DateTime.Now - LastCacheTime > CacheTimeout) + { + Reset(); + } + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + if (m_tempByteBlock != null) + { + m_tempByteBlock.Write(buffer, 0, r); + buffer = m_tempByteBlock.Buffer; + r = (int)m_tempByteBlock.Position; + } + + List indexes = buffer.IndexOfInclude(0, r, m_terminatorCode); + if (indexes.Count == 0) + { + if (r > MaxPackageSize) + { + Reset(); + Client?.Logger.Error("在已接收数据大于设定值的情况下未找到终止因子,已放弃接收"); + } + else if (m_tempByteBlock == null) + { + m_tempByteBlock = new ByteBlock(r * 2); + m_tempByteBlock.Write(buffer, 0, r); + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + } + } + else + { + int startIndex = 0; + foreach (int lastIndex in indexes) + { + int length; + if (m_reserveTerminatorCode) + { + length = lastIndex - startIndex + 1; + } + else + { + length = lastIndex - startIndex - m_terminatorCode.Length + 1; + } + + ByteBlock packageByteBlock = new ByteBlock(length); + packageByteBlock.Write(buffer, startIndex, length); + + string mes = Encoding.UTF8.GetString(packageByteBlock.Buffer, 0, (int)packageByteBlock.Position); + + PreviewHandle(packageByteBlock); + startIndex = lastIndex + 1; + } + Reset(); + if (startIndex < r) + { + m_tempByteBlock = new ByteBlock((r - startIndex) * 2); + m_tempByteBlock.Write(buffer, startIndex, r - startIndex); + if (UpdateCacheTimeWhenRev) + { + LastCacheTime = DateTime.Now; + } + } + } + } + + /// + /// 预处理 + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length) + { + if (length > MaxPackageSize) + { + throw new Exception("发送的数据长度大于适配器设定的最大值,接收方可能会抛弃。"); + } + int dataLen = length - offset + m_terminatorCode.Length; + ByteBlock byteBlock = new ByteBlock(dataLen); + byteBlock.Write(buffer, offset, length); + byteBlock.Write(m_terminatorCode); + + try + { + GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IList> transferBytes) + { + int length = 0; + foreach (var item in transferBytes) + { + length += item.Count; + } + if (length > MaxPackageSize) + { + throw new Exception("发送的数据长度大于适配器设定的最大值,接收方可能会抛弃。"); + } + int dataLen = length + m_terminatorCode.Length; + ByteBlock byteBlock = new ByteBlock(dataLen); + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + + byteBlock.Write(m_terminatorCode); + + try + { + GoSend(byteBlock.Buffer, 0, byteBlock.Len); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + m_tempByteBlock.SafeDispose(); + m_tempByteBlock = null; + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs new file mode 100644 index 000000000..56ab6895a --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/PipelineDataHandlingAdapter.cs @@ -0,0 +1,159 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Pipeline读取管道 + /// + public abstract class Pipeline : BlockReadStream, IRequestInfo + { + /// + /// Pipeline读取管道 + /// + /// + protected Pipeline(ITcpClientBase client) + { + Client = client; + } + + /// + /// 当前支持此管道的客户端。 + /// + public ITcpClientBase Client { get; set; } + } + + /// + /// 管道数据处理适配器。 + /// 使用该适配器后,将为. + /// + public class PipelineDataHandlingAdapter : NormalDataHandlingAdapter + { + private byte[] m_buffer; + private InternalPipeline m_pipeline; + + private Task m_task; + + /// + /// 管道数据处理适配器。 + /// 使用该适配器后,将为. + /// + public PipelineDataHandlingAdapter() + { + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + m_pipeline.SafeDispose(); + base.Dispose(disposing); + } + + /// + /// + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + if (m_pipeline == null || !m_pipeline.Enable) + { + m_task?.Wait(); + m_pipeline = new InternalPipeline(Client); + m_task = EasyTask.Run(() => + { + try + { + GoReceived(default, m_pipeline); + if (m_pipeline.CanReadLen > 0) + { + m_buffer = new byte[m_pipeline.CanReadLen]; + m_pipeline.Read(m_buffer, 0, m_buffer.Length); + } + } + catch + { + } + finally + { + m_pipeline.SafeDispose(); + } + }); + } + if (m_buffer != null) + { + m_pipeline.InternalInput(m_buffer, 0, m_buffer.Length); + m_buffer = null; + } + m_pipeline.InternalInput(byteBlock.Buffer, 0, byteBlock.Len); + } + } + + internal class InternalPipeline : Pipeline + { + private readonly object m_locker = new object(); + + private bool m_disposedValue; + + /// + /// Pipeline读取管道 + /// + /// + public InternalPipeline(ITcpClientBase client) : base(client) + { + ReadTimeout = 60 * 1000; + } + + public override bool CanRead => Enable; + + public override bool CanWrite => Client.CanSend; + + public bool Enable + { + get + { + lock (m_locker) + { + return !m_disposedValue; + } + } + } + + public override void Flush() + { + } + + public override void Write(byte[] buffer, int offset, int count) + { + Client.DefaultSend(buffer, offset, count); + } + + internal void InternalInput(byte[] buffer, int offset, int length) + { + Input(buffer, offset, length); + } + + protected override void Dispose(bool disposing) + { + lock (m_locker) + { + m_disposedValue = true; + base.Dispose(disposing); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs b/src/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs new file mode 100644 index 000000000..bb1afcc83 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Test/DataAdapterTester.cs @@ -0,0 +1,368 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 数据处理适配器测试 + /// + public class DataAdapterTester : IDisposable + { + private readonly IntelligentDataQueue asyncBytes; + private readonly Thread sendThread; + private DataHandlingAdapter adapter; + private int bufferLength; + private int count; + private bool dispose; + private int expectedCount; + private Action receivedCallBack; + private Stopwatch stopwatch; + private int timeout; + + private DataAdapterTester() + { + asyncBytes = new IntelligentDataQueue(1024 * 1024 * 10); + sendThread = new Thread(BeginSend); + sendThread.IsBackground = true; + sendThread.Name = "DataAdapterTesterThread"; + sendThread.Start(); + } + + /// + /// 获取测试器 + /// + /// 待测试适配器 + /// 收到数据回调 + /// 缓存数据长度 + /// + public static DataAdapterTester CreateTester(DataHandlingAdapter adapter, int bufferLength = 1024, Action receivedCallBack = default) + { + DataAdapterTester tester = new DataAdapterTester(); + tester.adapter = adapter; + tester.bufferLength = bufferLength; + adapter.SendCallBack = tester.SendCallback; + adapter.ReceivedCallBack = tester.OnReceived; + tester.receivedCallBack = receivedCallBack; + return tester; + } + + /// + /// 释放 + /// + public void Dispose() + { + dispose = true; + } + + /// + /// 模拟测试运行发送 + /// + /// + /// + /// + /// 测试次数 + /// 期待测试次数 + /// 超时 + /// + public TimeSpan Run(byte[] buffer, int offset, int length, int testCount, int expectedCount, int timeout) + { + count = 0; + this.expectedCount = expectedCount; + this.timeout = timeout; + stopwatch = new Stopwatch(); + stopwatch.Start(); + EasyTask.Run(() => + { + for (int i = 0; i < testCount; i++) + { + adapter.SendInput(buffer, offset, length); + } + }); + + if (SpinWait.SpinUntil(() => count == this.expectedCount, this.timeout)) + { + stopwatch.Stop(); + return stopwatch.Elapsed; + } + throw new TimeoutException(); + } + + /// + /// 模拟发送 + /// + /// + /// 测试次数 + /// 期待测试次数 + /// 超时 + public TimeSpan Run(byte[] buffer, int testCount, int expectedCount, int timeout) + { + return Run(buffer, 0, buffer.Length, testCount, expectedCount, timeout); + } + + private void BeginSend() + { + while (!dispose) + { + if (tryGet(out List byteBlocks)) + { + foreach (var block in byteBlocks) + { + try + { + adapter.ReceivedInput(block); + } + finally + { + block.Dispose(); + } + } + } + else + { + Thread.Sleep(1); + } + } + } + + private void OnReceived(ByteBlock byteBlock, IRequestInfo requestInfo) + { + count++; + receivedCallBack?.Invoke(byteBlock, requestInfo); + } + + private void SendCallback(byte[] buffer, int offset, int length) + { + QueueDataBytes asyncByte = new QueueDataBytes(new byte[length], 0, length); + Array.Copy(buffer, offset, asyncByte.Buffer, 0, length); + asyncBytes.Enqueue(asyncByte); + } + + private bool tryGet(out List byteBlocks) + { + byteBlocks = new List(); + ByteBlock block = null; + while (true) + { + if (asyncBytes.TryDequeue(out QueueDataBytes asyncByte)) + { + if (block == null) + { + block = BytePool.Default.GetByteBlock(bufferLength); + byteBlocks.Add(block); + } + int surLen = bufferLength - block.Pos; + if (surLen < asyncByte.Length)//不能完成写入 + { + block.Write(asyncByte.Buffer, asyncByte.Offset, surLen); + int offset = surLen; + while (offset < asyncByte.Length) + { + block = Write(asyncByte, ref offset); + byteBlocks.Add(block); + } + + if (byteBlocks.Count > 10) + { + break; + } + } + else//本次能完成写入 + { + block.Write(asyncByte.Buffer, asyncByte.Offset, asyncByte.Length); + if (byteBlocks.Count > 10) + { + break; + } + } + } + else + { + if (byteBlocks.Count > 0) + { + break; + } + else + { + return false; + } + } + } + return true; + } + + private ByteBlock Write(QueueDataBytes transferByte, ref int offset) + { + ByteBlock block = BytePool.Default.GetByteBlock(bufferLength, true); + int len = Math.Min(transferByte.Length - offset, bufferLength); + block.Write(transferByte.Buffer, offset, len); + offset += len; + + return block; + } + } + + /// + /// Udp数据处理适配器测试 + /// + public class UdpDataAdapterTester : IDisposable + { + private readonly IntelligentDataQueue asyncBytes; + private UdpDataHandlingAdapter adapter; + private int count; + private bool dispose; + private int expectedCount; + private Action receivedCallBack; + private Stopwatch stopwatch; + private int timeout; + + private UdpDataAdapterTester(int multiThread) + { + asyncBytes = new IntelligentDataQueue(1024 * 1024 * 10); + for (int i = 0; i < multiThread; i++) + { + EasyTask.Run(BeginSend); + } + } + + /// + /// 获取测试器 + /// + /// 待测试适配器 + /// 并发多线程数量 + /// 收到数据回调 + /// + public static UdpDataAdapterTester CreateTester(UdpDataHandlingAdapter adapter, int multiThread, Action receivedCallBack = default) + { + UdpDataAdapterTester tester = new UdpDataAdapterTester(multiThread); + tester.adapter = adapter; + adapter.SendCallBack = tester.SendCallback; + adapter.ReceivedCallBack = tester.OnReceived; + tester.receivedCallBack = receivedCallBack; + return tester; + } + + /// + /// 释放 + /// + public void Dispose() + { + dispose = true; + } + + /// + /// 模拟测试运行发送 + /// + /// + /// + /// + /// 测试次数 + /// 期待测试次数 + /// 超时 + /// + public TimeSpan Run(byte[] buffer, int offset, int length, int testCount, int expectedCount, int timeout) + { + count = 0; + this.expectedCount = expectedCount; + this.timeout = timeout; + stopwatch = new Stopwatch(); + stopwatch.Start(); + EasyTask.Run(() => + { + for (int i = 0; i < testCount; i++) + { + adapter.SendInput(null, buffer, offset, length); + } + }); + if (SpinWait.SpinUntil(() => count == this.expectedCount, this.timeout)) + { + stopwatch.Stop(); + return stopwatch.Elapsed; + } + + throw new TimeoutException(); + } + + /// + /// 模拟发送 + /// + /// + /// 测试次数 + /// 期待测试次数 + /// 超时 + public TimeSpan Run(byte[] buffer, int testCount, int expectedCount, int timeout) + { + return Run(buffer, 0, buffer.Length, testCount, expectedCount, timeout); + } + + private void BeginSend() + { + while (!dispose) + { + if (tryGet(out List byteBlocks)) + { + foreach (var block in byteBlocks) + { + try + { + adapter.ReceivedInput(null, block); + } + finally + { + block.Dispose(); + } + } + } + else + { + Thread.Sleep(1); + } + } + } + + private void OnReceived(EndPoint endPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + receivedCallBack?.Invoke(byteBlock, requestInfo); + Interlocked.Increment(ref count); + } + + private void SendCallback(EndPoint endPoint, byte[] buffer, int offset, int length) + { + QueueDataBytes asyncByte = new QueueDataBytes(new byte[length], 0, length); + Array.Copy(buffer, offset, asyncByte.Buffer, 0, length); + asyncBytes.Enqueue(asyncByte); + } + + private bool tryGet(out List byteBlocks) + { + byteBlocks = new List(); + + while (asyncBytes.TryDequeue(out QueueDataBytes asyncByte)) + { + ByteBlock block = new ByteBlock(asyncByte.Length); + block.Write(asyncByte.Buffer, asyncByte.Offset, asyncByte.Length); + byteBlocks.Add(block); + } + if (byteBlocks.Count > 0) + { + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs new file mode 100644 index 000000000..dcf98d7a2 --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Udp/NormalUdpDataHandlingAdapter.cs @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Net; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 常规UDP数据处理适配器 + /// + public class NormalUdpDataHandlingAdapter : UdpDataHandlingAdapter + { + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + /// + /// + protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + GoReceived(remoteEndPoint, byteBlock, null); + } + + /// + /// + /// + /// + /// + /// + /// + protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length) + { + GoSend(endPoint, buffer, offset, length); + } + + /// + /// + /// + /// + /// + protected override void PreviewSend(EndPoint endPoint, IList> transferBytes) + { + int length = 0; + foreach (var item in transferBytes) + { + length += item.Count; + } + + if (length > MaxPackageSize) + { + throw new OverlengthException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + using (ByteBlock byteBlock = new ByteBlock(length)) + { + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + GoSend(endPoint, byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new System.NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs new file mode 100644 index 000000000..92a75495e --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Udp/UdpDataHandlingAdapter.cs @@ -0,0 +1,182 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Net; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Udp数据处理适配器 + /// + public abstract class UdpDataHandlingAdapter + { + internal IUdpSession m_owner; + + /// + /// 是否允许发送对象。 + /// + public abstract bool CanSendRequestInfo { get; } + + /// + /// 拼接发送 + /// + public abstract bool CanSplicingSend { get; } + + /// + /// 获取或设置适配器能接收的最大数据包长度。默认1024*1024 Byte。 + /// + public int MaxPackageSize { get; set; } = 1024 * 1024; + + /// + /// 适配器拥有者。 + /// + public IUdpSession Owner => m_owner; + + /// + /// 当接收数据处理完成后,回调该函数执行接收 + /// + public Action ReceivedCallBack { get; set; } + + /// + /// 当接收数据处理完成后,回调该函数执行发送 + /// + public Action SendCallBack { get; set; } + + /// + /// 收到数据的切入点,该方法由框架自动调用。 + /// + /// + /// + public void ReceivedInput(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + try + { + PreviewReceived(remoteEndPoint, byteBlock); + } + catch (Exception ex) + { + OnError(ex.Message); + } + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + public void SendInput(IRequestInfo requestInfo) + { + PreviewSend(requestInfo); + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + /// + /// + /// + public void SendInput(EndPoint endPoint, byte[] buffer, int offset, int length) + { + PreviewSend(endPoint, buffer, offset, length); + } + + /// + /// 发送数据的切入点,该方法由框架自动调用。 + /// + /// + /// + public void SendInput(EndPoint endPoint, IList> transferBytes) + { + PreviewSend(endPoint, transferBytes); + } + + /// + /// 处理已经经过预先处理后的数据 + /// + /// + /// 以二进制形式传递 + /// 以解析实例传递 + protected void GoReceived(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo) + { + ReceivedCallBack.Invoke(remoteEndPoint, byteBlock, requestInfo); + } + + /// + /// 发送已经经过预先处理后的数据 + /// + /// + /// + /// + /// + protected void GoSend(EndPoint endPoint, byte[] buffer, int offset, int length) + { + SendCallBack.Invoke(endPoint, buffer, offset, length); + } + + /// + /// 在解析时发生错误。 + /// + /// 错误异常 + /// 是否调用 + /// 是否记录日志 + protected virtual void OnError(string error, bool reset = true, bool log = true) + { + if (reset) + { + Reset(); + } + if (log && m_owner != null && m_owner.Logger != null) + { + m_owner.Logger.Error(error); + } + } + + /// + /// 当接收到数据后预先处理数据,然后调用处理数据 + /// + /// + /// + protected abstract void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock); + + /// + /// 当发送数据前预先处理数据 + /// + /// + protected abstract void PreviewSend(IRequestInfo requestInfo); + + /// + /// 当发送数据前预先处理数据 + /// + /// + /// 数据 + /// 偏移 + /// 长度 + protected abstract void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length); + + /// + /// 组合发送预处理数据, + /// 当属性SplicingSend实现为True时,系统才会调用该方法。 + /// + /// + /// 代发送数据组合 + protected abstract void PreviewSend(EndPoint endPoint, IList> transferBytes); + + /// + /// 重置解析器到初始状态,一般在被触发时,由返回值指示是否调用。 + /// + protected abstract void Reset(); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs new file mode 100644 index 000000000..dc19651ae --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Udp/UdpKcpPackageAdapter.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// UdpKcpPackageAdapter + /// + public class UdpKcpPackageAdapter : NormalUdpDataHandlingAdapter + { + /// + protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + base.PreviewReceived(remoteEndPoint, byteBlock); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs b/src/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs new file mode 100644 index 000000000..67473f2eb --- /dev/null +++ b/src/TouchSocket/Sockets/DataAdapter/Udp/UdpPackageAdapter.cs @@ -0,0 +1,388 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Net; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// UDP数据帧 + /// + public struct UdpFrame + { + /// + /// Crc校验 + /// + public byte[] Crc { get; set; } + + /// + /// 数据 + /// + public byte[] Data { get; set; } + + /// + /// 是否为终结帧 + /// + public bool FIN { get; set; } + + /// + /// 数据ID + /// + public long ID { get; set; } + + /// + /// 帧序号 + /// + public ushort SN { get; set; } + + /// + /// 解析 + /// + /// + /// + /// + /// + public bool Parse(byte[] buffer, int offset, int length) + { + if (length > 11) + { + ID = TouchSocketBitConverter.Default.ToInt64(buffer, offset); + SN = TouchSocketBitConverter.Default.ToUInt16(buffer, 8 + offset); + FIN = buffer[10 + offset].GetBit(7) == 1; + if (FIN) + { + if (length > 13) + { + Data = new byte[length - 13]; + } + else + { + Data = new byte[0]; + } + Crc = new byte[2] { buffer[length - 2], buffer[length - 1] }; + } + else + { + Data = new byte[length - 11]; + } + + Array.Copy(buffer, 11, Data, 0, Data.Length); + return true; + } + return false; + } + } + + /// + /// UDP数据包 + /// + [System.Diagnostics.DebuggerDisplay("Count={Count}")] + public class UdpPackage + { + private readonly ConcurrentQueue m_frames; + private readonly Timer m_timer; + private int m_count; + private int m_length; + + private int m_mtu; + + /// + /// 构造函数 + /// + /// + /// + /// + public UdpPackage(long id, int timeout, ConcurrentDictionary revStore) + { + ID = id; + m_frames = new ConcurrentQueue(); + m_timer = new Timer((o) => + { + if (revStore.TryRemove(ID, out UdpPackage udpPackage)) + { + udpPackage.m_frames.Clear(); + } + }, null, timeout, Timeout.Infinite); + } + + /// + /// 当前长度 + /// + public int Count => m_count; + + /// + /// Crc + /// + public byte[] Crc { get; private set; } + + /// + /// 包唯一标识 + /// + public long ID { get; } + + /// + /// 是否已完成 + /// + public bool IsComplated => TotalCount > 0 ? (TotalCount == m_count ? true : false) : false; + + /// + /// 当前数据长度 + /// + public int Length => m_length; + + /// + /// MTU + /// + public int MTU => m_mtu + 11; + + /// + /// 总长度,在收到最后一帧之前,为-1。 + /// + public int TotalCount { get; private set; } = -1; + + /// + /// 添加帧 + /// + /// + public void Add(UdpFrame frame) + { + Interlocked.Increment(ref m_count); + + if (frame.FIN) + { + TotalCount = frame.SN + 1; + Crc = frame.Crc; + } + Interlocked.Add(ref m_length, frame.Data.Length); + if (frame.SN == 0) + { + m_mtu = frame.Data.Length; + } + m_frames.Enqueue(frame); + } + + /// + /// 获得数据 + /// + /// + /// + public bool TryGetData(ByteBlock byteBlock) + { + while (m_frames.TryDequeue(out UdpFrame frame)) + { + byteBlock.Pos = frame.SN * m_mtu; + byteBlock.Write(frame.Data); + } + + if (byteBlock.Len != Length) + { + return false; + } + var crc = TouchSocket.Core.Crc.Crc16(byteBlock.Buffer, 0, byteBlock.Len); + if (crc[0] != Crc[0] || crc[1] != Crc[1]) + { + return false; + } + + return true; + } + } + + /// + /// UDP数据包的适配器 + /// + public class UdpPackageAdapter : UdpDataHandlingAdapter + { + private readonly SnowflakeIDGenerator m_iDGenerator; + private readonly ConcurrentDictionary revStore; + private int m_mtu = 1472; + + /// + /// 构造函数 + /// + public UdpPackageAdapter() + { + revStore = new ConcurrentDictionary(); + m_iDGenerator = new SnowflakeIDGenerator(4); + } + + /// + /// + /// + public override bool CanSendRequestInfo => false; + + /// + /// + /// + public override bool CanSplicingSend => true; + + /// + /// 最大传输单元 + /// + public int MTU + { + get => m_mtu + 11; + set => m_mtu = value > 11 ? value : 1472; + } + + /// + /// 接收超时时间,默认5000ms + /// + public int Timeout { get; set; } = 5000; + + /// + /// + /// + /// + /// + protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + UdpFrame udpFrame = new UdpFrame(); + if (udpFrame.Parse(byteBlock.Buffer, 0, byteBlock.Len)) + { + UdpPackage udpPackage = revStore.GetOrAdd(udpFrame.ID, (i) => new UdpPackage(i, Timeout, revStore)); + udpPackage.Add(udpFrame); + if (udpPackage.Length > MaxPackageSize) + { + revStore.TryRemove(udpPackage.ID, out _); + m_owner?.Logger.Error("数据长度大于设定的最大值。"); + return; + } + if (udpPackage.IsComplated) + { + if (revStore.TryRemove(udpPackage.ID, out _)) + { + using (ByteBlock block = new ByteBlock(udpPackage.Length)) + { + if (udpPackage.TryGetData(block)) + { + GoReceived(remoteEndPoint, block, null); + } + } + } + } + } + } + + /// + /// + /// + /// + /// + /// + /// + protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length) + { + if (length > MaxPackageSize) + { + throw new OverlengthException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + long id = m_iDGenerator.NextID(); + int off = 0; + int surLen = length; + int freeRoom = m_mtu - 11; + ushort sn = 0; + /*|********|**|*|n|*/ + /*|********|**|*|**|*/ + while (surLen > 0) + { + byte[] data = new byte[m_mtu]; + Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(id), 0, data, 0, 8); + Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(sn++), 0, data, 8, 2); + if (surLen > freeRoom)//有余 + { + Buffer.BlockCopy(buffer, off, data, 11, freeRoom); + off += freeRoom; + surLen -= freeRoom; + GoSend(endPoint, data, 0, m_mtu); + } + else if (surLen + 2 <= freeRoom)//结束且能容纳Crc + { + byte flag = 0; + data[10] = flag.SetBit(7, 1);//设置终结帧 + + Buffer.BlockCopy(buffer, off, data, 11, surLen); + Buffer.BlockCopy(Crc.Crc16(buffer, offset, length), 0, data, 11 + surLen, 2); + + GoSend(endPoint, data, 0, surLen + 11 + 2); + + off += surLen; + surLen -= surLen; + } + else//结束但不能容纳Crc + { + Buffer.BlockCopy(buffer, off, data, 11, surLen); + GoSend(endPoint, data, 0, surLen + 11); + off += surLen; + surLen -= surLen; + + byte[] finData = new byte[13]; + Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(id), 0, finData, 0, 8); + Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(sn++), 0, finData, 8, 2); + byte flag = 0; + finData[10] = flag.SetBit(7, 1); + Buffer.BlockCopy(Crc.Crc16(buffer, offset, length), 0, finData, 11, 2); + GoSend(endPoint, finData, 0, finData.Length); + } + } + } + + /// + /// + /// + /// + /// + protected override void PreviewSend(EndPoint endPoint, IList> transferBytes) + { + int length = 0; + foreach (var item in transferBytes) + { + length += item.Count; + } + + if (length > MaxPackageSize) + { + throw new OverlengthException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + using (ByteBlock byteBlock = new ByteBlock(length)) + { + foreach (var item in transferBytes) + { + byteBlock.Write(item.Array, item.Offset, item.Count); + } + PreviewSend(endPoint, byteBlock.Buffer, 0, byteBlock.Len); + } + } + + /// + /// + /// + /// + protected override void PreviewSend(IRequestInfo requestInfo) + { + throw new NotImplementedException(); + } + + /// + /// + /// + protected override void Reset() + { + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/DelegateCollection.cs b/src/TouchSocket/Sockets/DelegateCollection.cs new file mode 100644 index 000000000..97bc06849 --- /dev/null +++ b/src/TouchSocket/Sockets/DelegateCollection.cs @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net; +using TouchSocket.Core; +using TouchSocket.Sockets; + +/// +/// 显示信息 +/// +/// +/// +public delegate void MessageEventHandler(TClient client, MsgEventArgs e); + +/// +/// 普通通知 +/// +/// +/// +/// +public delegate void TouchSocketEventHandler(TClient client, TouchSocketEventArgs e); + +/// +/// ID修改通知 +/// +/// +/// +/// +public delegate void IDChangedEventHandler(TClient client, IDChangedEventArgs e); + +/// +/// Connecting +/// +/// +/// +/// +public delegate void ConnectingEventHandler(TClient client, ConnectingEventArgs e); + +/// +/// 客户端断开连接 +/// +/// +/// +/// +public delegate void DisconnectEventHandler(TClient client, DisconnectEventArgs e); + +/// +/// 正在连接事件 +/// +/// +/// +/// +public delegate void OperationEventHandler(TClient client, OperationEventArgs e); + +/// +/// 插件数据 +/// +/// +/// +public delegate void PluginReceivedEventHandler(TClient client, ReceivedDataEventArgs e); + +/// +/// 普通数据 +/// +/// +/// +/// +public delegate void ReceivedEventHandler(TClient client, ByteBlock byteBlock, IRequestInfo requestInfo); + +/// +/// UDP接收 +/// +/// +/// +/// +public delegate void UdpReceivedEventHandler(EndPoint endpoint, ByteBlock byteBlock, IRequestInfo requestInfo); \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Enum/CheckClearType.cs b/src/TouchSocket/Sockets/Enum/CheckClearType.cs new file mode 100644 index 000000000..a35f9e396 --- /dev/null +++ b/src/TouchSocket/Sockets/Enum/CheckClearType.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// 检查清理类型 + /// + public enum CheckClearType + { + /// + /// 仅统计发送 + /// + OnlySend, + + /// + /// 仅统计接收 + /// + OnlyReceive, + + /// + /// 全部 + /// + All + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Enum/FilterResult.cs b/src/TouchSocket/Sockets/Enum/FilterResult.cs new file mode 100644 index 000000000..4a6b6eff3 --- /dev/null +++ b/src/TouchSocket/Sockets/Enum/FilterResult.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 过滤结果 + /// + public enum FilterResult + { + /// + /// 缓存后续所有数据。 + /// + Cache, + + /// + /// 操作成功 + /// + Success, + + /// + /// 继续操作,一般原因是本次数据有部分无效,但已经调整了属性,所以继续后续解析。 + /// 或者想放弃当前数据的操作,直接设置相等即可。 + /// + GoOn + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Enum/FixedHeaderType.cs b/src/TouchSocket/Sockets/Enum/FixedHeaderType.cs new file mode 100644 index 000000000..5a9a0511f --- /dev/null +++ b/src/TouchSocket/Sockets/Enum/FixedHeaderType.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 固定包头类型 + /// + public enum FixedHeaderType : byte + { + /// + /// 以1Byte标识长度,最长接收255 + /// + Byte = 1, + + /// + /// 以2Byte标识长度,最长接收65535 + /// + Ushort = 2, + + /// + /// 以4Byte标识长度,最长接收2147483647 + /// + Int = 4 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Enum/ReceiveType.cs b/src/TouchSocket/Sockets/Enum/ReceiveType.cs new file mode 100644 index 000000000..61f858ea8 --- /dev/null +++ b/src/TouchSocket/Sockets/Enum/ReceiveType.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 接收类型 + /// + public enum ReceiveType : byte + { + /// + /// 该模式下会自动接收数据,然后主动触发。 + /// + Auto, + + /// + /// 在该模式下,不会投递接收申请,用户可通过,获取到流以后,自己处理接收。 + /// 注意:连接端不会感知主动断开 + /// + None + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Enum/ServerState.cs b/src/TouchSocket/Sockets/Enum/ServerState.cs new file mode 100644 index 000000000..57206b90d --- /dev/null +++ b/src/TouchSocket/Sockets/Enum/ServerState.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 服务器状态 + /// + public enum ServerState + { + /// + /// 无状态,指示为初建 + /// + None, + + /// + /// 正在运行 + /// + Running, + + /// + /// 运行遇到异常 + /// + Exception, + + /// + /// 已停止 + /// + Stopped, + + /// + /// 已释放 + /// + Disposed + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs new file mode 100644 index 000000000..07c18213c --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/ByteBlockEventArgs.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 字节事件 + /// + public class ByteBlockEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + public ByteBlockEventArgs(ByteBlock byteBlock) + { + ByteBlock = byteBlock; + } + + /// + /// 数据块 + /// + public ByteBlock ByteBlock { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs new file mode 100644 index 000000000..1ebcd57f2 --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/BytesEventArgs.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 字节事件 + /// + public class BytesEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + public BytesEventArgs(byte[] data) + { + ReceivedDataBytes = data; + } + + /// + /// 字节数组 + /// + public byte[] ReceivedDataBytes { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs new file mode 100644 index 000000000..fa7c749df --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/ConfigEventArgs.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// ConfigEventArgs + /// + public class ConfigEventArgs : TouchSocketEventArgs + { + /// + /// 实例化2ConfigEventArgs + /// + /// + public ConfigEventArgs(TouchSocketConfig config) + { + Config = config; + } + + /// + /// 具体配置 + /// + public TouchSocketConfig Config { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs new file mode 100644 index 000000000..295c2d7e8 --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/ConnectingEventArgs.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Net.Sockets; + +namespace TouchSocket.Sockets +{ + /// + /// ClientConnectingEventArgs + /// + [Obsolete("此类已被弃用,请使用ConnectingEventArgs代替", true)] + public class ClientConnectingEventArgs : OperationEventArgs + { + + } + /// + /// 客户端连接事件。 + /// + public class ConnectingEventArgs : OperationEventArgs + { + private readonly Socket socket; + + /// + /// 构造函数 + /// + /// + public ConnectingEventArgs(Socket socket) + { + this.socket = socket; + } + + /// + /// 新初始化的通信器 + /// + public Socket Socket => socket; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs new file mode 100644 index 000000000..90cde6ca9 --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/DisconnectEventArgs.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 断开连接事件参数 + /// + public class DisconnectEventArgs : MsgEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public DisconnectEventArgs(bool manual, string mes) : base(mes) + { + Manual = manual; + } + + /// + /// 是否为主动行为。 + /// + public bool Manual { get; private set; } + } + + /// + /// ClientDisconnectedEventArgs + /// + [Obsolete("该类型已被弃用,请使用DisconnectEventArgs替代。", true)] + public class ClientDisconnectedEventArgs : MsgEventArgs + { + + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs new file mode 100644 index 000000000..ad266e7b2 --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/IDChangedEventArgs.cs @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// IDChangedEventArgs + /// + public class IDChangedEventArgs : TouchSocketEventArgs + { + /// + /// IDChangedEventArgs + /// + /// + /// + public IDChangedEventArgs(string oldID, string newID) + { + OldID = oldID; + NewID = newID; + } + + /// + /// 旧ID + /// + public string OldID { get; private set; } + + /// + /// 新ID + /// + public string NewID { get; private set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs new file mode 100644 index 000000000..c8f00afa6 --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/MsgEventArgs.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 消息事件 + /// + public class MsgEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + public MsgEventArgs(string mes) + { + Message = mes; + } + + /// + /// 构造函数 + /// + public MsgEventArgs() + { + } + + /// + /// 消息 + /// + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs new file mode 100644 index 000000000..990d3caff --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/OperationEventArgs.cs @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// ClientOperationEventArgs + /// + [Obsolete("此类已被弃用,请使用OperationEventArgs代替", true)] + public class ClientOperationEventArgs : TouchSocketEventArgs + { + + } + /// + /// Client消息操作事件 + /// + public class OperationEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + public OperationEventArgs() + { + IsPermitOperation = true; + } + + /// + /// 客户端ID + /// + public string ID { get; set; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs new file mode 100644 index 000000000..57c74d366 --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/ReceivedDataEventArgs.cs @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 插件处理事件 + /// + public class ReceivedDataEventArgs : ByteBlockEventArgs + { + /// + /// 构造函数 + /// + /// + /// + public ReceivedDataEventArgs(ByteBlock byteBlock, IRequestInfo requestInfo) : base(byteBlock) + { + RequestInfo = requestInfo; + } + + /// + /// 对象载体 + /// + public IRequestInfo RequestInfo { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs new file mode 100644 index 000000000..e3ec4716b --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/SendingEventArgs.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 发送事件 + /// + public class SendingEventArgs : TouchSocketEventArgs + { + /// + /// 构造函数 + /// + /// + /// + /// + public SendingEventArgs(byte[] buffer, int offset, int length) + { + Buffer = buffer; + Offset = offset; + Length = length; + IsPermitOperation = true; + } + + /// + /// 数据缓存区,该属性获取来自于内存池,所以最好不要引用该对象,可以同步使用该对象 + /// + public byte[] Buffer { get; } + + /// + /// 缓存偏移 + /// + public int Offset { get; } + + /// + /// 数据长度 + /// + public int Length { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs new file mode 100644 index 000000000..0f693769d --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/ServiceStateEventArgs.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 服务器状态事件参数 + /// + public class ServiceStateEventArgs: MsgEventArgs + { + /// + /// 服务器状态事件参数 + /// + /// + /// + public ServiceStateEventArgs(ServerState serverState,Exception exception) + { + ServerState = serverState; + Exception = exception; + } + + /// + /// 服务器状态 + /// + public ServerState ServerState { get; } + + /// + /// 异常类 + /// + public Exception Exception { get; } + } +} diff --git a/src/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs b/src/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs new file mode 100644 index 000000000..b836dca07 --- /dev/null +++ b/src/TouchSocket/Sockets/EventArgs/UdpReceivedDataEventArgs.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Net; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Udp接收消息 + /// + public class UdpReceivedDataEventArgs : ReceivedDataEventArgs + { + /// + /// 构造函数 + /// + /// + /// + /// + public UdpReceivedDataEventArgs(EndPoint endPoint, ByteBlock byteBlock, IRequestInfo requestInfo) : base(byteBlock, requestInfo) + { + EndPoint = endPoint; + } + + /// + /// 接收终结点 + /// + public EndPoint EndPoint { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs b/src/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs new file mode 100644 index 000000000..9457e751b --- /dev/null +++ b/src/TouchSocket/Sockets/Exceptions/ClientNotFindException.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 没有找到ID对应的客户端 + /// + [Serializable] + public class ClientNotFindException : Exception + { + /// + /// 构造函数 + /// + public ClientNotFindException() + { } + + /// + /// 构造函数 + /// + /// + public ClientNotFindException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public ClientNotFindException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected ClientNotFindException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Exceptions/NotConnectedException.cs b/src/TouchSocket/Sockets/Exceptions/NotConnectedException.cs new file mode 100644 index 000000000..b9e009823 --- /dev/null +++ b/src/TouchSocket/Sockets/Exceptions/NotConnectedException.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 未连接异常 + /// + [Serializable] + public class NotConnectedException : Exception + { + /// + /// 构造函数 + /// + public NotConnectedException() + { } + + /// + /// 构造函数 + /// + /// + public NotConnectedException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public NotConnectedException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected NotConnectedException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Exceptions/OverlengthException.cs b/src/TouchSocket/Sockets/Exceptions/OverlengthException.cs new file mode 100644 index 000000000..f19618373 --- /dev/null +++ b/src/TouchSocket/Sockets/Exceptions/OverlengthException.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; + +namespace TouchSocket.Sockets +{ + /// + /// 超长异常 + /// + [Serializable] + public class OverlengthException : Exception + { + /// + /// 构造函数 + /// + public OverlengthException() + { } + + /// + /// 构造函数 + /// + /// + public OverlengthException(string message) : base(message) { } + + /// + /// 构造函数 + /// + /// + /// + public OverlengthException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// 构造函数 + /// + /// + /// + protected OverlengthException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Extensions/ClientExtension.cs b/src/TouchSocket/Sockets/Extensions/ClientExtension.cs new file mode 100644 index 000000000..cadb918f4 --- /dev/null +++ b/src/TouchSocket/Sockets/Extensions/ClientExtension.cs @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 客户端扩展类 + /// + public static class ClientExtension + { + /// + /// 获取相关信息。格式: + ///IPPort=IP:Port,ID=id,Protocol=Protocol + /// + /// + /// + /// + public static string GetInfo(this T client) where T : ISocketClient + { + return $"IP&Port={client.IP}:{client.Port},ID={client.ID},Protocol={client.Protocol}"; + } + + /// + /// 获取服务器中,除自身以外的所有客户端id + /// + /// + /// + /// + public static IEnumerable GetOtherIDs(this T client) where T : ISocketClient + { + return client.Service.GetIDs().Where(id => id != client.ID); + } + + /// + /// 获取最后活动时间。即的最近值。 + /// + /// + /// + /// + public static DateTime GetLastActiveTime(this T client) where T : IClient + { + return client.LastSendTime > client.LastReceivedTime ? client.LastSendTime : client.LastReceivedTime; + } + + /// + /// 安全性发送关闭报文 + /// + /// + /// + /// + public static bool TryShutdown(this T client, SocketShutdown how = SocketShutdown.Both) where T : ITcpClientBase + { + try + { + if (!client.MainSocket.Connected) + { + return false; + } + client?.MainSocket?.Shutdown(how); + return true; + } + catch + { + } + + return false; + } + + /// + /// 安全性关闭。不会抛出异常。 + /// + /// + /// + /// + public static void SafeClose(this T client, string msg) where T : ITcpClientBase + { + try + { + client.Close(msg); + } + catch + { + } + } + + /// + /// 获取IP和端口。 + /// + /// + /// + /// + public static string GetIPPort(this T client) where T : ITcpClientBase + { + return $"{client.IP}:{client.Port}"; + } + + #region 连接 + + /// + /// 尝试连接。不会抛出异常。 + /// + /// + /// + /// + /// + public static Result TryConnect(this TClient client, int timeout = 5000) where TClient : ITcpClient + { + try + { + client.Connect(timeout); + return new Result(ResultCode.Success); + } + catch (Exception ex) + { + return new Result(ResultCode.Exception, ex.Message); + } + } + + /// + /// 尝试连接。不会抛出异常。 + /// + /// + /// + /// + /// + public static async Task TryConnectAsync(this TClient client, int timeout = 5000) where TClient : ITcpClient + { + try + { + await client.ConnectAsync(timeout); + return new Result(ResultCode.Success); + } + catch (Exception ex) + { + return new Result(ResultCode.Exception, ex.Message); + } + } + + #endregion 连接 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Extensions/SenderExtension.cs b/src/TouchSocket/Sockets/Extensions/SenderExtension.cs new file mode 100644 index 000000000..b2b410e3a --- /dev/null +++ b/src/TouchSocket/Sockets/Extensions/SenderExtension.cs @@ -0,0 +1,353 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// SenderExtension + /// + public static class SenderExtension + { + #region ISend + + /// + /// 同步发送数据。 + /// + /// + /// + /// + public static void Send(this TClient client, byte[] buffer) where TClient : ISender + { + client.Send(buffer, 0, buffer.Length); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + public static void Send(this TClient client, ByteBlock byteBlock) where TClient : ISender + { + client.Send(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + public static void Send(this TClient client, string value) where TClient : ISender + { + client.Send(Encoding.UTF8.GetBytes(value)); + } + + /// + /// 异步发送数据。 + /// + /// + /// + /// + public static Task SendAsync(this TClient client, byte[] buffer) where TClient : ISender + { + return client.SendAsync(buffer, 0, buffer.Length); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + public static Task SendAsync(this TClient client, string value) where TClient : ISender + { + return client.SendAsync(Encoding.UTF8.GetBytes(value)); + } + + #endregion ISend + + #region IDefaultSender + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + public static void DefaultSend(this TClient client, string value) where TClient : IDefaultSender + { + client.DefaultSend(Encoding.UTF8.GetBytes(value)); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + public static void DefaultSend(this TClient client, byte[] buffer) where TClient : IDefaultSender + { + client.DefaultSend(buffer, 0, buffer.Length); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + public static void DefaultSend(this TClient client, ByteBlock byteBlock) where TClient : IDefaultSender + { + client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + public static Task DefaultSendAsync(this TClient client, string value) where TClient : IDefaultSender + { + return client.DefaultSendAsync(Encoding.UTF8.GetBytes(value)); + } + + /// + /// 异步发送数据。 + /// + /// + /// + /// + public static Task DefaultSendAsync(this TClient client, byte[] buffer) where TClient : IDefaultSender + { + return client.DefaultSendAsync(buffer, 0, buffer.Length); + } + + #endregion IDefaultSender + + #region IIDSender + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + /// + public static void Send(this TClient client, string id, string value) where TClient : IIDSender + { + client.Send(id, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + /// + public static void Send(this TClient client, string id, byte[] buffer) where TClient : IIDSender + { + client.Send(id, buffer, 0, buffer.Length); + } + + /// + /// 同步发送数据。 + /// + /// + /// + /// + /// + public static void Send(this TClient client, string id, ByteBlock byteBlock) where TClient : IIDSender + { + client.Send(id, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + /// + public static Task SendAsync(this TClient client, string id, string value) where TClient : IIDSender + { + return client.SendAsync(id, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 异步发送数据。 + /// + /// + /// + /// + /// + public static Task SendAsync(this TClient client, string id, byte[] buffer) where TClient : IIDSender + { + return client.SendAsync(id, buffer, 0, buffer.Length); + } + + #endregion IIDSender + + #region IUdpDefaultSender + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + /// + public static void DefaultSend(this TClient client, EndPoint endPoint, string value) where TClient : IUdpDefaultSender + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + client.DefaultSend(endPoint, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 绕过适配器,直接发送字节流 + /// + /// + /// 目的终结点 + /// 数据区 + /// 发送数据超长 + /// 其他异常 + public static void DefaultSend(this TClient client, EndPoint endPoint, byte[] buffer) + where TClient : IUdpDefaultSender + { + client.DefaultSend(endPoint, buffer, 0, buffer.Length); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + /// + public static Task DefaultSendAsync(this TClient client, EndPoint endPoint, string value) where TClient : IUdpDefaultSender + { + return client.DefaultSendAsync(endPoint, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 绕过适配器,直接发送字节流 + /// + /// + /// 目的终结点 + /// 数据缓存区 + /// 发送数据超长 + /// 其他异常 + public static Task DefaultSendAsync(this TClient client, EndPoint endPoint, byte[] buffer) + where TClient : IUdpDefaultSender + { + return client.DefaultSendAsync(endPoint, buffer, 0, buffer.Length); + } + + /// + /// 绕过适配器,直接发送字节流 + /// + /// + /// 目的终结点 + /// + /// 发送数据超长 + /// 其他异常 + public static Task DefaultSendAsync(this TClient client, EndPoint endPoint, ByteBlock byteBlock) + where TClient : IUdpDefaultSender + { + return client.DefaultSendAsync(endPoint, byteBlock.Buffer, 0, byteBlock.Len); + } + + #endregion IUdpDefaultSender + + #region IUdpClientSender + + /// + /// 以UTF-8的编码同步发送字符串。 + /// + /// + /// + /// + /// + public static void Send(this TClient client, EndPoint endPoint, string value) where TClient : IUdpClientSender + { + client.Send(endPoint, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 发送字节流 + /// + /// + /// 目的终结点 + /// 数据区 + /// 发送数据超长 + /// 其他异常 + public static void Send(this TClient client, EndPoint endPoint, byte[] buffer) + where TClient : IUdpClientSender + { + client.Send(endPoint, buffer, 0, buffer.Length); + } + + /// + /// 发送字节流 + /// + /// + /// 目的终结点 + /// 数据区 + /// 发送数据超长 + /// 其他异常 + public static void Send(this TClient client, EndPoint endPoint, ByteBlock byteBlock) + where TClient : IUdpClientSender + { + client.Send(endPoint, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 以UTF-8的编码异步发送字符串。 + /// + /// + /// + /// + /// + public static Task SendAsync(this TClient client, EndPoint endPoint, string value) where TClient : IUdpClientSender + { + return client.SendAsync(endPoint, Encoding.UTF8.GetBytes(value)); + } + + /// + /// 发送字节流 + /// + /// + /// 目的终结点 + /// 数据缓存区 + /// 发送数据超长 + /// 其他异常 + public static Task SendAsync(this TClient client, EndPoint endPoint, byte[] buffer) + where TClient : IUdpClientSender + { + return client.SendAsync(endPoint, buffer, 0, buffer.Length); + } + + #endregion IUdpClientSender + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Extensions/SocketExtension.cs b/src/TouchSocket/Sockets/Extensions/SocketExtension.cs new file mode 100644 index 000000000..fb621aba8 --- /dev/null +++ b/src/TouchSocket/Sockets/Extensions/SocketExtension.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; + +namespace TouchSocket.Sockets +{ + /// + /// SocketExtension + /// + public static class SocketExtension + { + /// + /// 会使用同步锁,保证所有数据上缓存区。 + /// + /// + /// + /// + /// + public static void AbsoluteSend(this Socket socket, byte[] buffer, int offset, int length) + { + lock (socket) + { + while (length > 0) + { + int r = socket.Send(buffer, offset, length, SocketFlags.None); + if (r == 0 && length > 0) + { + throw new Exception("发送数据不完全"); + } + offset += r; + length -= r; + } + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs b/src/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs new file mode 100644 index 000000000..17fa303f7 --- /dev/null +++ b/src/TouchSocket/Sockets/Extensions/SocketPluginsManagerExtension.cs @@ -0,0 +1,138 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Sockets; + +namespace TouchSocket.Core +{ + /// + /// IPluginsManagerExtension + /// + public static class SocketPluginsManagerExtension + { + /// + /// 使用断线重连。 + /// 该效果仅客户端在完成首次连接,且为被动断开时有效。 + /// + /// + /// 成功回调函数 + /// 尝试重连次数,设为-1时则永远尝试连接 + /// 是否输出日志。 + /// 失败时,停留时间 + /// + public static IPluginsManager UseReconnection(this IPluginsManager pluginsManager, int tryCount = 10, + bool printLog = false, int sleepTime = 1000, Action successCallback = null) + { + bool first = true; + var reconnectionPlugin = new ReconnectionPlugin(client => + { + int tryT = tryCount; + while (tryCount < 0 || tryT-- > 0) + { + try + { + if (client.Online) + { + return true; + } + else + { + if (first) Thread.Sleep(1000); + first = false; + client.Connect(); + first = true; + } + successCallback?.Invoke(client); + return true; + } + catch (Exception ex) + { + if (printLog) + { + client.Logger.Log(LogType.Error, client, "断线重连失败。", ex); + } + Thread.Sleep(sleepTime); + } + } + return true; + }); + + pluginsManager.Add(reconnectionPlugin); + return pluginsManager; + } + + /// + /// 检查连接客户端活性插件。 + /// 当在设置的周期内,没有接收/发送任何数据,则判定该客户端掉线。执行清理。默认配置:60秒为一个周期,同时检测发送和接收。 + /// 仅服务器适用。 + /// + /// + /// + public static CheckClearPlugin UseCheckClear(this IPluginsManager pluginsManager) + { + return pluginsManager.Add(); + } + + /// + /// 使用断线重连。 + /// 该效果仅客户端在完成首次连接,且为被动断开时有效。 + /// + /// + /// 失败时间隔时间 + /// 失败时回调(参数依次为:客户端,本轮尝试重连次数,异常信息)。如果回调为null或者返回false,则终止尝试下次连接。 + /// 成功连接时回调。 + /// + public static IPluginsManager UseReconnection(this IPluginsManager pluginsManager, int sleepTime, + Func failCallback, + Action successCallback) + { + bool first = true; + var reconnectionPlugin = new ReconnectionPlugin(client => + { + int tryT = 0; + while (true) + { + try + { + if (client.Online) + { + return true; + } + else + { + if (first) Thread.Sleep(1000); + first = false; + client.Connect(); + first = true; + } + + successCallback?.Invoke(client); + return true; + } + catch (Exception ex) + { + Thread.Sleep(sleepTime); + if (failCallback?.Invoke(client, ++tryT, ex) != true) + { + return true; + } + } + } + }); + + pluginsManager.Add(reconnectionPlugin); + return pluginsManager; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/IClient.cs b/src/TouchSocket/Sockets/Interface/IClient.cs new file mode 100644 index 000000000..f3c149f09 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/IClient.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 终端接口 + /// + public interface IClient : IDependencyObject, IDisposable + { + /// + /// 处理未经过适配器的数据。返回值表示是否继续向下传递。 + /// + Func OnHandleRawBuffer { get; set; } + + /// + /// 处理经过适配器后的数据。返回值表示是否继续向下传递。 + /// + Func OnHandleReceivedData { get; set; } + + /// + /// 日志记录器 + /// + ILog Logger { get; } + + /// + /// 终端协议 + /// + Protocol Protocol { get; set; } + + /// + /// 简单IOC容器 + /// + IContainer Container { get; } + + /// + /// 最后一次接收到数据的时间 + /// + DateTime LastReceivedTime { get; } + + /// + /// 最后一次发送数据的时间 + /// + DateTime LastSendTime { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/INATSocketClient.cs b/src/TouchSocket/Sockets/Interface/INATSocketClient.cs new file mode 100644 index 000000000..c93cf80b6 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/INATSocketClient.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// INATSocketClient + /// + public interface INATSocketClient : ISocketClient + { + /// + /// 添加转发客户端。 + /// + /// 配置文件 + /// 当完成配置,但是还未连接时回调。 + /// + ITcpClient AddTargetClient(TouchSocketConfig config, Action setupAction = null); + + /// + /// 添加转发客户端。 + /// + /// 配置文件 + /// 当完成配置,但是还未连接时回调。 + /// + Task AddTargetClientAsync(TouchSocketConfig config, Action setupAction = null); + + /// + /// 获取所有目标客户端 + /// + /// + ITcpClient[] GetTargetClients(); + + /// + /// 发送数据到全部转发端。 + /// + /// + /// + /// + void SendToTargetClient(byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/IRequestInfo.cs b/src/TouchSocket/Sockets/Interface/IRequestInfo.cs new file mode 100644 index 000000000..b2a180a57 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/IRequestInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 请求解析对象接口。 + ///此处接口设计借鉴SuperSocket,只为大家更好理解 + /// + public interface IRequestInfo + { + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/IClientSender.cs b/src/TouchSocket/Sockets/Interface/ISender/IClientSender.cs new file mode 100644 index 000000000..a154a7908 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/IClientSender.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 客户端发送接口 + /// + public interface IClientSender : ISender, IRequsetInfoSender + { + /// + /// 同步组合发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 组合数据 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(IList> transferBytes); + + /// + /// 异步组合发送数据。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 组合数据 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(IList> transferBytes); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs b/src/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs new file mode 100644 index 000000000..6e1fd6f88 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/IDefaultSender.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 具有直接发送功能 + /// + public interface IDefaultSender + { + /// + /// 绕过适配器,直接发送字节流 + /// + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void DefaultSend(byte[] buffer, int offset, int length); + + /// + /// 绕过适配器,直接发送字节流 + /// + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task DefaultSendAsync(byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs b/src/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs new file mode 100644 index 000000000..6b167c2e4 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/IIDRequsetInfoSender.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// IIDRequsetInfoSender + /// + public interface IIDRequsetInfoSender + { + /// + /// 同步发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// + /// 解析对象 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(string id, IRequestInfo requestInfo); + + /// + /// 异步发送数据。 + /// 时,如果使用独立线程发送,则不会触发异常。 + /// 时,相当于 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// + /// 解析对象 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(string id, IRequestInfo requestInfo); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/IIDSender.cs b/src/TouchSocket/Sockets/Interface/ISender/IIDSender.cs new file mode 100644 index 000000000..cec500803 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/IIDSender.cs @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 通过ID发送 + /// + public interface IIDSender + { + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 数据 + /// 偏移 + /// 长度 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + void Send(string id, byte[] buffer, int offset, int length); + + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 数据 + /// 偏移 + /// 长度 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + Task SendAsync(string id, byte[] buffer, int offset, int length); + + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 数据对象 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + void Send(string id, IRequestInfo requestInfo); + + /// + /// 向对应ID的客户端发送 + /// + /// 目标ID + /// 数据对象 + /// 未连接异常 + /// 未找到ID对应的客户端 + /// 其他异常 + Task SendAsync(string id, IRequestInfo requestInfo); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs b/src/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs new file mode 100644 index 000000000..6734f411c --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/IRequsetInfoSender.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// IRequsetInfoSend + /// + public interface IRequsetInfoSender + { + /// + /// 同步发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 解析对象 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(IRequestInfo requestInfo); + + /// + /// 异步发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 解析对象 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(IRequestInfo requestInfo); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/ISender.cs b/src/TouchSocket/Sockets/Interface/ISender/ISender.cs new file mode 100644 index 000000000..0a77a5835 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/ISender.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 具有发送功能的接口 + /// + public interface ISender : ISenderBase + { + /// + /// 同步发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(byte[] buffer, int offset, int length); + + /// + /// 异步发送数据。 + /// 时,如果使用独立线程发送,则不会触发异常。 + /// 时,相当于 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs b/src/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs new file mode 100644 index 000000000..6b6ca33bc --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/ISenderBase.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace TouchSocket.Sockets +{ + /// + /// 具有发送动作的基类。 + /// + public interface ISenderBase + { + /// + /// 表示对象能否顺利执行发送操作。 + /// 由于高并发,当该值为True时,也不一定完全能执行。 + /// + bool CanSend { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs b/src/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs new file mode 100644 index 000000000..22a6c5aa3 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/IUdpClientSender.cs @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 具有Udp终结点的发送 + /// + public interface IUdpClientSender : ISender + { + /// + /// 同步组合发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 远程终结点 + /// 组合数据 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void Send(EndPoint endPoint, IList> transferBytes); + + /// + /// 异步组合发送数据。 + /// 时,如果使用独立线程发送,则不会触发异常。 + /// 时,相当于 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 远程终结点 + /// 组合数据 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task SendAsync(EndPoint endPoint, IList> transferBytes); + + /// + /// 同步组合发送数据。 + /// 内部已经封装Ssl和发送长度检测,即:调用完成即表示数据全部发送完毕。 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 远程终结点 + /// + /// + /// + /// 发送数据超长 + /// 其他异常 + void Send(EndPoint endPoint, byte[] buffer, int offset, int length); + + /// + /// 异步组合发送数据。 + /// 时,如果使用独立线程发送,则不会触发异常。 + /// 时,相当于 + /// 该发送会经过适配器封装,具体封装内容由适配器决定。 + /// + /// 远程终结点 + /// + /// + /// + /// 发送数据超长 + /// 其他异常 + Task SendAsync(EndPoint endPoint, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs b/src/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs new file mode 100644 index 000000000..60b6eb34f --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/IUdpDefaultSender.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Net; +using System.Threading.Tasks; + +namespace TouchSocket.Sockets +{ + /// + /// 具有直接发送功能 + /// + public interface IUdpDefaultSender : ISenderBase + { + /// + /// 绕过适配器,直接发送字节流 + /// + /// 目的终结点 + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + void DefaultSend(EndPoint endPoint, byte[] buffer, int offset, int length); + + /// + /// 绕过适配器,直接发送字节流 + /// + /// 目的终结点 + /// 数据缓存区 + /// 偏移量 + /// 数据长度 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + Task DefaultSendAsync(EndPoint endPoint, byte[] buffer, int offset, int length); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs b/src/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs new file mode 100644 index 000000000..07f2c8c92 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISender/IWaitSender.cs @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 发送等待接口 + /// + public interface IWaitSender : ISenderBase + { + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 发送流中的有效数据 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/IService.cs b/src/TouchSocket/Sockets/Interface/IService.cs new file mode 100644 index 000000000..b26ee4a36 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/IService.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 服务器接口 + /// + public interface IService : IDisposable + { + /// + /// 服务器状态 + /// + ServerState ServerState { get; } + + /// + /// 获取服务器配置 + /// + TouchSocketConfig Config { get; } + + /// + /// 名称 + /// + string ServerName { get; } + + /// + /// 配置服务器 + /// + /// 配置 + /// + /// 设置的服务实例 + IService Setup(TouchSocketConfig serverConfig); + + /// + /// 配置服务器 + /// + /// + /// + /// 设置的服务实例 + IService Setup(int port); + + /// + /// 启动 + /// + /// + /// + /// + /// 设置的服务实例 + IService Start(); + + /// + /// 停止 + /// + /// + /// 设置的服务实例 + IService Stop(); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISocket.cs b/src/TouchSocket/Sockets/Interface/ISocket.cs new file mode 100644 index 000000000..440ca468c --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISocket.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Socket基接口 + /// + public interface ISocket : IDisposable + { + /// + /// 数据交互缓存池限制 + /// + int BufferLength { get; } + + /// + /// 日志记录器 + /// + ILog Logger { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ISocketClient.cs b/src/TouchSocket/Sockets/Interface/ISocketClient.cs new file mode 100644 index 000000000..ec88d716f --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ISocketClient.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// 服务器辅助类接口 + /// + public interface ISocketClient : ITcpClientBase, IClientSender, IIDSender, IIDRequsetInfoSender + { + /// + /// 重新设置ID + /// + /// + void ResetID(string newID); + + /// + /// 用于索引的ID + /// + string ID { get; } + + /// + /// 包含此辅助类的主服务器类 + /// + TcpServiceBase Service { get; } + + /// + /// 接收此客户端的服务器IP地址 + /// + string ServiceIP { get; } + + /// + /// 接收此客户端的服务器端口 + /// + int ServicePort { get; } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ITcpClient.cs b/src/TouchSocket/Sockets/Interface/ITcpClient.cs new file mode 100644 index 000000000..4635b1164 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ITcpClient.cs @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP客户端终端接口 + /// + public interface ITcpClient : ITcpClientBase, IClientSender, IPluginObject + { + /// + /// 成功连接到服务器 + /// + MessageEventHandler Connected { get; set; } + + /// + /// 准备连接的时候 + /// + ConnectingEventHandler Connecting { get; set; } + + /// + /// 远程IPHost。 + /// + IPHost RemoteIPHost { get; } + + /// + /// 连接服务器 + /// + /// + /// + ITcpClient Connect(int timeout = 5000); + + /// + /// 异步连接服务器 + /// + /// + /// + Task ConnectAsync(int timeout = 5000); + + /// + /// 配置服务器 + /// + /// + /// + ITcpClient Setup(TouchSocketConfig config); + + /// + /// 配置服务器 + /// + /// + /// + ITcpClient Setup(string ipHost); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ITcpClientBase.cs b/src/TouchSocket/Sockets/Interface/ITcpClientBase.cs new file mode 100644 index 000000000..067e3b9d0 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ITcpClientBase.cs @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System.IO; +using System.Net.Security; +using System.Net.Sockets; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP终端基础接口。 + /// + /// 注意:该接口并不仅表示客户端。也实现了该接口。 + /// + /// + public interface ITcpClientBase : IClient, ISender, IDefaultSender, IPluginObject, IRequsetInfoSender + { + /// + /// 缓存池大小 + /// + int BufferLength { get; } + + /// + /// 是否允许自由调用进行赋值。 + /// + bool CanSetDataHandlingAdapter { get; } + + /// + /// 客户端配置 + /// + TouchSocketConfig Config { get; } + + /// + /// 数据处理适配器 + /// + DataHandlingAdapter DataHandlingAdapter { get; } + + /// + /// 断开连接 + /// + DisconnectEventHandler Disconnected { get; set; } + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + DisconnectEventHandler Disconnecting { get; set; } + /// + /// IP地址 + /// + string IP { get; } + + /// + /// 表示是否为客户端。 + /// + bool IsClient { get; } + /// + /// 主通信器 + /// + Socket MainSocket { get; } + + /// + /// 判断是否在线 + /// 该属性仅表示TCP状态是否在线 + /// + bool Online { get; } + + /// + /// 端口号 + /// + int Port { get; } + + /// + /// 接收模式 + /// + public ReceiveType ReceiveType { get; } + + /// + /// 使用Ssl加密 + /// + bool UseSsl { get; } + + + /// + /// 中断终端 + /// + void Close(); + + /// + /// 中断终端,传递中断消息 + /// + /// + void Close(string msg); + + /// + /// 获取流,在正常模式下为,在Ssl模式下为。 + /// + /// + Stream GetStream(); + + /// + /// 设置数据处理适配器 + /// + /// + void SetDataHandlingAdapter(DataHandlingAdapter adapter); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/ITcpService.cs b/src/TouchSocket/Sockets/Interface/ITcpService.cs new file mode 100644 index 000000000..41f7b4c56 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/ITcpService.cs @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP系列服务器接口 + /// + public interface ITcpService : ITcpService where TClient : ISocketClient + { + /// + /// 用户连接完成 + /// + TouchSocketEventHandler Connected { get; set; } + + /// + /// 有用户连接的时候 + /// + OperationEventHandler Connecting { get; set; } + + /// + /// 有用户断开连接 + /// + DisconnectEventHandler Disconnected { get; set; } + + /// + /// 尝试获取TClient + /// + /// ID + /// TClient + /// + bool TryGetSocketClient(string id, out TClient socketClient); + } + + /// + /// TCP服务器接口 + /// + public interface ITcpService : IService, IIDSender, IIDRequsetInfoSender, IPluginObject + { + /// + /// 当前在线客户端数量 + /// + int Count { get; } + + /// + /// 获取默认新ID。 + /// + Func GetDefaultNewID { get; } + + /// + /// 获取最大可连接数 + /// + int MaxCount { get; } + + /// + /// 网络监听集合 + /// + NetworkMonitor[] Monitors { get; } + + /// + /// 获取当前连接的所有客户端 + /// + SocketClientCollection SocketClients { get; } + + /// + /// 使用Ssl加密 + /// + bool UseSsl { get; } + + /// + /// 清理当前已连接的所有客户端 + /// + void Clear(); + + /// + /// 获取当前在线的所有ID集合 + /// + /// + string[] GetIDs(); + + /// + /// 重置ID + /// + /// + /// + /// + /// + void ResetID(string oldID, string newID); + + /// + /// 根据ID判断SocketClient是否存在 + /// + /// + /// + bool SocketClientExist(string id); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/IUdpSession.cs b/src/TouchSocket/Sockets/Interface/IUdpSession.cs new file mode 100644 index 000000000..71a10bae5 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/IUdpSession.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// UDP会话 + /// + public interface IUdpSession : IService, IClient, IClientSender, IUdpClientSender, IDefaultSender, IUdpDefaultSender + { + /// + /// 插件管理器 + /// + IPluginsManager PluginsManager { get; } + + /// + /// 缓存池大小 + /// + int BufferLength { get; } + + /// + /// 是否允许自由调用进行赋值。 + /// + bool CanSetDataHandlingAdapter { get; } + + /// + /// 数据处理适配器 + /// + UdpDataHandlingAdapter DataHandlingAdapter { get; } + + /// + /// 设置数据处理适配器 + /// + /// + void SetDataHandlingAdapter(UdpDataHandlingAdapter adapter); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs b/src/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs new file mode 100644 index 000000000..eb2a3c9f9 --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/Plugins/IConfigPlugin.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 当配置Config时触发。 + /// + public interface IConfigPlugin : IPlugin + { + /// + /// 当载入配置时 + /// + /// + /// + [AsyncRaiser] + void OnLoadingConfig(object sender, ConfigEventArgs e); + + /// + /// 当载入配置时 + /// + /// + /// + Task OnLoadingConfigAsync(object sender, ConfigEventArgs e); + + /// + /// 当完成配置载入时 + /// + /// + /// + [AsyncRaiser] + void OnLoadedConfig(object sender, ConfigEventArgs e); + + /// + /// 当完成配置载入时 + /// + /// + /// + /// + Task OnLoadedConfigAsync(object sender, ConfigEventArgs e); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs b/src/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs new file mode 100644 index 000000000..edd6676ab --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/Plugins/IServicePlugin.cs @@ -0,0 +1,48 @@ +using TouchSocket.Core; +using System.Threading.Tasks; +using System; + +namespace TouchSocket.Sockets +{ + /// + /// IServicePlugin + /// + public interface IServicePlugin : IPlugin + { + /// + /// 当服务器执行后时。 + /// + /// 注意:此处并不表示服务器成功启动,具体状态请看 + /// + /// + /// + /// + [AsyncRaiser] + void OnStarted(object sender, ServiceStateEventArgs e); + + /// + /// 当服务器执行后时。 + /// + /// 注意:此处并不表示服务器成功启动,具体状态请看 + /// + /// + /// + /// + Task OnStartedAsync(object sender, ServiceStateEventArgs e); + + /// + /// 当服务器调用或者时 + /// + /// + /// + [AsyncRaiser] + void OnStoped(object sender, ServiceStateEventArgs e); + + /// + /// 当服务器调用或者时 + /// + /// + /// + Task OnStopedAsync(object sender, ServiceStateEventArgs e); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs b/src/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs new file mode 100644 index 000000000..483e5925a --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/Plugins/ITcpPlugin.cs @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Tcp系插件接口 + /// + public interface ITcpPlugin : IPlugin + { + /// + /// 客户端连接成功后触发 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnConnected(ITcpClientBase client, TouchSocketEventArgs e); + + /// + /// 客户端连接成功后触发 + /// + /// + /// + /// + Task OnConnectedAsync(ITcpClientBase client, TouchSocketEventArgs e); + + /// + ///在即将完成连接时触发。 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnConnecting(ITcpClientBase client, OperationEventArgs e); + + /// + /// 在即将完成连接时触发。 + /// + /// + /// + /// + Task OnConnectingAsync(ITcpClientBase client, OperationEventArgs e); + + /// + /// 会话断开后触发 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e); + + /// + /// 会话断开后触发 + /// + /// + /// + /// + Task OnDisconnectedAsync(ITcpClientBase client, DisconnectEventArgs e); + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnDisconnecting(ITcpClientBase client, DisconnectEventArgs e); + + /// + /// 即将断开连接(仅主动断开时有效)。 + /// + /// 当主动调用Close断开时,可通过终止断开行为。 + /// + /// + /// + /// + /// + Task OnDisconnectingAsync(ITcpClientBase client, DisconnectEventArgs e); + + /// + /// 当Client的ID被更改后触发 + /// + /// + /// + [AsyncRaiser] + void OnIDChanged(ITcpClientBase client, IDChangedEventArgs e); + + /// + /// 当Client的ID被更改后触发 + /// + /// + /// + /// + Task OnIDChangedAsync(ITcpClientBase client, IDChangedEventArgs e); + + /// + /// 在收到数据时触发 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e); + + /// + /// 在收到数据时触发 + /// + /// + /// + /// + Task OnReceivedDataAsync(ITcpClientBase client, ReceivedDataEventArgs e); + + /// + /// 在刚收到数据时触发,即在适配器之前。 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnReceivingData(ITcpClientBase client, ByteBlockEventArgs e); + + /// + /// 在刚收到数据时触发,即在适配器之前。 + /// + /// + /// + /// + Task OnReceivingDataAsync(ITcpClientBase client, ByteBlockEventArgs e); + + /// + /// 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnSendingData(ITcpClientBase client, SendingEventArgs e); + + /// + /// 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 + /// + /// + /// + /// + Task OnSendingDataAsync(ITcpClientBase client, SendingEventArgs e); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs b/src/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs new file mode 100644 index 000000000..4f451397a --- /dev/null +++ b/src/TouchSocket/Sockets/Interface/Plugins/IUdpSessionPlugin.cs @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// Udp会话插件 + /// + public interface IUdpSessionPlugin : IPlugin + { + /// + /// 在收到数据时触发 + /// + /// 客户端 + /// 参数 + [AsyncRaiser] + void OnReceivedData(IUdpSession client, UdpReceivedDataEventArgs e); + + /// + /// 在收到数据时触发 + /// + /// + /// + /// + Task OnReceivedDataAsync(IUdpSession client, UdpReceivedDataEventArgs e); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs b/src/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs new file mode 100644 index 000000000..b28e759f6 --- /dev/null +++ b/src/TouchSocket/Sockets/Plugins/CheckClearPlugin.cs @@ -0,0 +1,116 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 检查清理连接插件。服务器适用。 + /// + [SingletonPlugin] + public class CheckClearPlugin : TcpPluginBase + { + private ITcpService m_service; + private Thread m_thread; + + /// + /// 清理统计类型。默认为:。当设置为时, + /// 则只检验发送方向是否有数据流动。没有的话则会断开连接。 + /// + public CheckClearType CheckClearType { get; set; } = CheckClearType.All; + + /// + /// 获取或设置清理无数据交互的Client,默认60秒。 + /// + public TimeSpan Duration { get; set; } = TimeSpan.FromSeconds(60); + + /// + /// 清理统计类型。默认为:。当设置为时, + /// 则只检验发送方向是否有数据流动。没有的话则会断开连接。 + /// + /// + /// + public CheckClearPlugin SetCheckClearType(CheckClearType clearType) + { + CheckClearType = clearType; + return this; + } + + /// + /// 设置清理无数据交互的Client,默认60秒。 + /// + /// + /// + public CheckClearPlugin SetDuration(TimeSpan timeSpan) + { + if (timeSpan == TimeSpan.Zero || timeSpan == TimeSpan.MaxValue || timeSpan == TimeSpan.MinValue) + { + throw new InvalidTimeZoneException("设置的时间必须为有效值。"); + } + Duration = timeSpan; + return this; + } + + /// + protected override void OnLoadedConfig(object sender, ConfigEventArgs e) + { + if (sender is ITcpService service) + { + m_service = service; + m_thread = new Thread(ClearThread); + m_thread.IsBackground = true; + m_thread.Start(); + } + base.OnLoadedConfig(sender, e); + } + + private void ClearThread(object obj) + { + while (true) + { + if (m_service.ServerState == ServerState.Disposed || DisposedValue) + { + return; + } + foreach (var client in m_service.SocketClients.GetClients()) + { + if (CheckClearType == CheckClearType.OnlyReceive) + { + if (DateTime.Now - client.LastReceivedTime > Duration) + { + client.SafeClose("超时无数据Receive交互,主动断开连接"); + } + } + else if (CheckClearType == CheckClearType.OnlySend) + { + if (DateTime.Now - client.LastSendTime > Duration) + { + client.SafeClose("超时无数据Send交互,主动断开连接"); + } + } + else + { + if (DateTime.Now - client.GetLastActiveTime() > Duration) + { + client.SafeClose("超时无数据交互,主动断开连接"); + } + } + } + + Thread.Sleep(1000); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs b/src/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs new file mode 100644 index 000000000..a4a296f3b --- /dev/null +++ b/src/TouchSocket/Sockets/Plugins/ReconnectionPlugin.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 重连插件 + /// + [SingletonPlugin] + public sealed class ReconnectionPlugin : TcpPluginBase where TClient : class, ITcpClient + { + private readonly Func m_tryCon; + + /// + /// 初始化一个重连插件 + /// + /// 无论如何,只要返回True,则结束本轮尝试 + public ReconnectionPlugin(Func tryCon) + { + Order = int.MinValue; + m_tryCon = tryCon; + } + + /// + /// + /// + /// + /// + protected override void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + base.OnDisconnected(client, e); + + if (client is ITcpClient tcpClient) + { + if (e.Manual) + { + return; + } + EasyTask.Run(() => + { + while (true) + { + try + { + if (m_tryCon.Invoke((TClient)tcpClient)) + { + break; + } + } + catch + { + } + } + }); + } + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Plugins/ServicePlugin.cs b/src/TouchSocket/Sockets/Plugins/ServicePlugin.cs new file mode 100644 index 000000000..696b0df50 --- /dev/null +++ b/src/TouchSocket/Sockets/Plugins/ServicePlugin.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// ServicePlugin + /// + public class ServicePlugin : PluginBase, IServicePlugin + { + /// + protected virtual void OnStarted(TService sender, ServiceStateEventArgs e) + { + + } + + /// + protected virtual Task OnStartedAsync(TService sender, ServiceStateEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + protected virtual void OnStoped(TService sender, ServiceStateEventArgs e) + { + + } + + /// + protected virtual Task OnStopedAsync(TService sender, ServiceStateEventArgs e) + { + return EasyTask.CompletedTask; + } + + void IServicePlugin.OnStarted(object sender, ServiceStateEventArgs e) + { + this.OnStarted((TService)sender, e); + } + + Task IServicePlugin.OnStartedAsync(object sender, ServiceStateEventArgs e) + { + return this.OnStartedAsync((TService)sender, e); + } + + void IServicePlugin.OnStoped(object sender, ServiceStateEventArgs e) + { + this.OnStoped((TService)sender, e); + } + + Task IServicePlugin.OnStopedAsync(object sender, ServiceStateEventArgs e) + { + return this.OnStopedAsync((TService)sender, e); + } + } + + /// + /// TcpServicePlugin + /// + public class TcpServicePlugin : ServicePlugin + { + + } + + /// + /// UdpServicePlugin + /// + public class UdpServicePlugin : ServicePlugin + { + + } +} diff --git a/src/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs b/src/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs new file mode 100644 index 000000000..7d101863d --- /dev/null +++ b/src/TouchSocket/Sockets/Plugins/TcpCommandLinePlugin.cs @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// TCP命令行插件。 + /// + public abstract class TcpCommandLinePlugin : TcpPluginBase + { + private readonly Dictionary m_pairs = new Dictionary(); + private ILog m_logger; + + /// + /// TCP命令行插件。 + /// + /// + /// + protected TcpCommandLinePlugin(ILog logger) + { + m_logger = logger ?? throw new ArgumentNullException(nameof(logger)); + Converter = new StringConverter(); + var ms = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(a => a.Name.EndsWith("Command")); + foreach (var item in ms) + { + m_pairs.Add(item.Name.Replace("Command", string.Empty), new Method(item)); + } + } + + /// + /// 字符串转换器,默认支持基础类型和Json。可以自定义。 + /// + public StringConverter Converter { get; } + + /// + /// 是否返回执行异常。 + /// + public bool ReturnException { get; set; } = true; + + /// + /// 当有执行异常时,不返回异常。 + /// + /// + public TcpCommandLinePlugin NoReturnException() + { + ReturnException = false; + return this; + } + + /// + /// + /// + /// + /// + protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + try + { + string[] strs = e.ByteBlock.ToString().Split(' '); + if (strs.Length > 0 && m_pairs.TryGetValue(strs[0], out Method method)) + { + var ps = method.Info.GetParameters(); + object[] os = new object[ps.Length]; + int index = 0; + for (int i = 0; i < ps.Length; i++) + { + if (ps[i].ParameterType.IsInterface && typeof(ITcpClientBase).IsAssignableFrom(ps[i].ParameterType)) + { + os[i] = client; + } + else + { + os[i] = Converter.ConvertFrom(strs[index + 1], ps[i].ParameterType); + index++; + } + } + e.Handled = true; + + try + { + object result = method.Invoke(this, os); + if (method.HasReturn) + { + client.Send(Converter.ConvertTo(result)); + } + } + catch (Exception ex) + { + if (ReturnException) + { + client.Send(ex.Message); + } + } + } + } + catch (Exception ex) + { + m_logger.Log(LogType.Error, this, ex.Message, ex); + } + base.OnReceivedData(client, e); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Plugins/TcpPluginBase.cs b/src/TouchSocket/Sockets/Plugins/TcpPluginBase.cs new file mode 100644 index 000000000..d31578e18 --- /dev/null +++ b/src/TouchSocket/Sockets/Plugins/TcpPluginBase.cs @@ -0,0 +1,325 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 插件实现基类 + /// + public abstract class TcpPluginBase : TcpPluginBase + { + } + + /// + /// 插件实现基类 + /// + public abstract class TcpPluginBase : PluginBase, ITcpPlugin, IConfigPlugin + { + void ITcpPlugin.OnConnected(ITcpClientBase client, TouchSocketEventArgs e) + { + OnConnected((TClient)client, e); + } + + Task ITcpPlugin.OnConnectedAsync(ITcpClientBase client, TouchSocketEventArgs e) + { + return OnConnectedAsync((TClient)client, e); + } + + void ITcpPlugin.OnConnecting(ITcpClientBase client, OperationEventArgs e) + { + OnConnecting((TClient)client, e); + } + + Task ITcpPlugin.OnConnectingAsync(ITcpClientBase client, OperationEventArgs e) + { + return OnConnectingAsync((TClient)client, e); + } + + void ITcpPlugin.OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + OnDisconnected((TClient)client, e); + } + + Task ITcpPlugin.OnDisconnectedAsync(ITcpClientBase client, DisconnectEventArgs e) + { + return OnDisconnectedAsync((TClient)client, e); + } + + void ITcpPlugin.OnIDChanged(ITcpClientBase client, IDChangedEventArgs e) + { + OnIDChanged((TClient)client, e); + } + + Task ITcpPlugin.OnIDChangedAsync(ITcpClientBase client, IDChangedEventArgs e) + { + return OnIDChangedAsync((TClient)client, e); + } + + void IConfigPlugin.OnLoadedConfig(object sender, ConfigEventArgs e) + { + OnLoadedConfig(sender, e); + } + + Task IConfigPlugin.OnLoadedConfigAsync(object sender, ConfigEventArgs e) + { + return OnLoadedConfigAsync(sender, e); + } + + void IConfigPlugin.OnLoadingConfig(object sender, ConfigEventArgs e) + { + OnLoadingConfig(sender, e); + } + + Task IConfigPlugin.OnLoadingConfigAsync(object sender, ConfigEventArgs e) + { + return OnLoadingConfigAsync(sender, e); + } + + void ITcpPlugin.OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e) + { + OnReceivedData((TClient)client, e); + } + + Task ITcpPlugin.OnReceivedDataAsync(ITcpClientBase client, ReceivedDataEventArgs e) + { + return OnReceivedDataAsync((TClient)client, e); + } + + void ITcpPlugin.OnReceivingData(ITcpClientBase client, ByteBlockEventArgs e) + { + OnReceivingData((TClient)client, e); + } + + Task ITcpPlugin.OnReceivingDataAsync(ITcpClientBase client, ByteBlockEventArgs e) + { + return OnReceivingDataAsync((TClient)client, e); + } + + void ITcpPlugin.OnSendingData(ITcpClientBase client, SendingEventArgs e) + { + OnSending((TClient)client, e); + } + + Task ITcpPlugin.OnSendingDataAsync(ITcpClientBase client, SendingEventArgs e) + { + return OnSendingDataAsync((TClient)client, e); + } + + void ITcpPlugin.OnDisconnecting(ITcpClientBase client, DisconnectEventArgs e) + { + this.OnDisconnecting((TClient)client,e) ; + } + + Task ITcpPlugin.OnDisconnectingAsync(ITcpClientBase client, DisconnectEventArgs e) + { + return this.OnDisconnectingAsync((TClient)client, e); + } + #region 虚函数实现 + + /// + protected virtual void OnDisconnecting(TClient client, DisconnectEventArgs e) + { + + } + + /// + protected virtual Task OnDisconnectingAsync(TClient client, DisconnectEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 成功建立连接 + /// + /// + /// + protected virtual void OnConnected(TClient client, TouchSocketEventArgs e) + { + } + + /// + /// 客户端连接成功后触发 + /// + /// + /// + /// + protected virtual Task OnConnectedAsync(TClient client, TouchSocketEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在请求连接时 + /// + /// + /// + protected virtual void OnConnecting(TClient client, OperationEventArgs e) + { + } + + /// + /// 在即将完成连接时触发。 + /// + /// + /// + /// + protected virtual Task OnConnectingAsync(TClient client, OperationEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在断开连接时 + /// + /// + /// + protected virtual void OnDisconnected(TClient client, DisconnectEventArgs e) + { + } + + /// + /// 会话断开后触发 + /// + /// + /// + /// + protected virtual Task OnDisconnectedAsync(TClient client, DisconnectEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当Client的ID被更改后触发 + /// + /// + /// + protected virtual void OnIDChanged(TClient client, TouchSocketEventArgs e) + { + } + + /// + /// 当Client的ID被更改后触发 + /// + /// + /// + /// + protected virtual Task OnIDChangedAsync(TClient client, TouchSocketEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当载入配置时 + /// + /// + /// + protected virtual void OnLoadedConfig(object sender, ConfigEventArgs e) + { + } + + /// + /// 当完成配置载入时 + /// + /// + /// + /// + protected virtual Task OnLoadedConfigAsync(object sender, ConfigEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当完成配置载入时 + /// + /// + /// + protected virtual void OnLoadingConfig(object sender, ConfigEventArgs e) + { + } + + /// + /// 当载入配置时 + /// + /// + /// + /// + protected virtual Task OnLoadingConfigAsync(object sender, ConfigEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在收到数据时触发 + /// + /// 客户端 + /// 参数,当设置e.Handled=true时,终止向下传递 + protected virtual void OnReceivedData(TClient client, ReceivedDataEventArgs e) + { + } + + /// + /// 在收到数据时触发 + /// + /// + /// + /// + protected virtual Task OnReceivedDataAsync(TClient client, ReceivedDataEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 在刚收到数据时触发,即在适配器之前。 + /// + /// 客户端 + /// 参数 + protected virtual void OnReceivingData(TClient client, ByteBlockEventArgs e) + { + } + + /// + /// 在刚收到数据时触发,即在适配器之前。 + /// + /// + /// + /// + protected virtual Task OnReceivingDataAsync(TClient client, ByteBlockEventArgs e) + { + return EasyTask.CompletedTask; + } + + /// + /// 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 + /// + /// 客户端 + /// 参数,当设置e.IsPermitOperation=false时,中断发送。 + protected virtual void OnSending(TClient client, SendingEventArgs e) + { + } + + /// + /// 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 + /// + /// + /// + /// + protected virtual Task OnSendingDataAsync(TClient client, SendingEventArgs e) + { + return EasyTask.CompletedTask; + } + + #endregion 虚函数实现 + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs b/src/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs new file mode 100644 index 000000000..bb9ee1380 --- /dev/null +++ b/src/TouchSocket/Sockets/Plugins/UdpSessionPluginBase.cs @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// UdpSessionPluginBase + /// + public class UdpSessionPluginBase : UdpSessionPluginBase + { + } + + /// + /// Udp插件实现类 + /// + public class UdpSessionPluginBase : DisposableObject, IUdpSessionPlugin + { + /// + /// + /// + public ILog Logger { get; set; } + + /// + /// + /// + public int Order { get; set; } + + /// + /// + /// + public IPluginsManager PluginsManager { get; set; } + + /// + /// + /// + /// + /// + void IUdpSessionPlugin.OnReceivedData(IUdpSession client, UdpReceivedDataEventArgs e) + { + OnReceivedData((TSession)client, e); + } + + Task IUdpSessionPlugin.OnReceivedDataAsync(IUdpSession client, UdpReceivedDataEventArgs e) + { + return OnReceivedDataAsync((TSession)client, e); + } + + /// + /// 收到数据 + /// + /// + /// + protected virtual void OnReceivedData(TSession client, UdpReceivedDataEventArgs e) + { + } + + /// + /// 在收到数据时触发 + /// + /// + /// + /// + protected virtual Task OnReceivedDataAsync(TSession client, UdpReceivedDataEventArgs e) + { + return EasyTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs b/src/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs new file mode 100644 index 000000000..05be84833 --- /dev/null +++ b/src/TouchSocket/Sockets/WaitingClient/IWaitingClient.cs @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// 等待型客户端。 + /// + public interface IWaitingClient : IWaitSender where TClient : IClient, IDefaultSender, ISender + { + /// + /// 等待设置。 + /// + public WaitingOptions WaitingOptions { get; set; } + + /// + /// 客户端终端 + /// + TClient Client { get; } + + + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 发送流中的有效数据 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default); + + /// + /// 异步发送 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + Task SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default); + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/WaitingClient/ResponsedData.cs b/src/TouchSocket/Sockets/WaitingClient/ResponsedData.cs new file mode 100644 index 000000000..4a9152a10 --- /dev/null +++ b/src/TouchSocket/Sockets/WaitingClient/ResponsedData.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// 响应数据。 + /// + public struct ResponsedData + { + private readonly byte[] m_data; + private readonly IRequestInfo m_requestInfo; + + /// + /// 构造函数 + /// + /// + /// + public ResponsedData(byte[] data, IRequestInfo requestInfo) + { + m_data = data; + m_requestInfo = requestInfo; + } + + /// + /// 数据 + /// + public byte[] Data => m_data; + + /// + /// RequestInfo + /// + public IRequestInfo RequestInfo => m_requestInfo; + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/WaitingClient/WaitingClient.cs b/src/TouchSocket/Sockets/WaitingClient/WaitingClient.cs new file mode 100644 index 000000000..1ea1c6803 --- /dev/null +++ b/src/TouchSocket/Sockets/WaitingClient/WaitingClient.cs @@ -0,0 +1,363 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Resources; + +namespace TouchSocket.Sockets +{ + internal class WaitingClient : IWaitingClient where TClient : IClient, IDefaultSender, ISender + { + private readonly WaitData m_waitData; + + private volatile bool breaked; + + public WaitingClient(TClient client, WaitingOptions waitingOptions) + { + Client = client ?? throw new ArgumentNullException(nameof(client)); + m_waitData = new WaitData(); + WaitingOptions = waitingOptions; + } + + public bool CanSend + { + get + { + if (Client is ITcpClientBase tcpClient) + { + return tcpClient.Online; + } + else if (Client is IUdpSession) + { + return true; + } + else + { + return false; + } + } + } + + public TClient Client { get; private set; } + + public WaitingOptions WaitingOptions { get; set; } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default) + { + lock (this) + { + try + { + breaked = false; + m_waitData.Reset(); + + if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) + { + tcpClient.Disconnected += this.OnDisconnected; + } + + if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) + { + Client.OnHandleReceivedData += OnHandleReceivedData; + } + else + { + Client.OnHandleRawBuffer += OnHandleRawBuffer; + } + + if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter) + { + Client.Send(buffer, offset, length); + } + else + { + Client.DefaultSend(buffer, offset, length); + } + + m_waitData.SetCancellationToken(token); + switch (m_waitData.Wait(timeout)) + { + case WaitDataStatus.SetRunning: + return m_waitData.WaitResult; + + case WaitDataStatus.Overtime: + throw new TimeoutException(); + case WaitDataStatus.Canceled: + { + if (this.WaitingOptions.ThrowBreakException && this.breaked) + { + throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。"); + } + return default; + } + case WaitDataStatus.Default: + case WaitDataStatus.Disposed: + default: + throw new Exception(TouchSocketStatus.UnknownError.GetDescription()); + } + } + finally + { + if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) + { + tcpClient.Disconnected -= this.OnDisconnected; + } + + if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) + { + Client.OnHandleReceivedData -= OnHandleReceivedData; + } + else + { + Client.OnHandleRawBuffer -= OnHandleRawBuffer; + } + } + } + } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenResponse(buffer, 0, buffer.Length, timeout, token); + } + + /// + /// 发送流中的有效数据 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, timeout, token); + } + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenResponse(buffer, offset, length, timeout, token); + }); + } + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenResponse(buffer, timeout, token); + }); + } + + /// + /// 异步发送 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenResponse(byteBlock, timeout, token); + }); + } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenResponse(buffer, offset, length, timeout, token).Data; + } + + /// + /// 发送字节流 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenReturn(buffer, 0, buffer.Length, timeout, token); + } + + /// + /// 发送流中的有效数据 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default) + { + return SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, timeout, token); + } + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 偏移 + /// 长度 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenReturn(buffer, offset, length, timeout, token); + }); + } + + /// + /// 异步发送 + /// + /// 数据缓存区 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenReturn(buffer, timeout, token); + }); + } + + /// + /// 异步发送 + /// + /// 数据块载体 + /// 超时时间 + /// 取消令箭 + /// 客户端没有连接 + /// 发送数据超长 + /// 其他异常 + /// 返回的数据 + public Task SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default) + { + return EasyTask.Run(() => + { + return SendThenReturn(byteBlock, timeout, token); + }); + } + + private void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e) + { + breaked = true; + this.m_waitData.Cancel(); + } + + private bool OnHandleRawBuffer(ByteBlock byteBlock) + { + ResponsedData responsedData = new ResponsedData(byteBlock.ToArray(), null); + return !m_waitData.Set(responsedData); + } + + /// + /// + /// + /// + /// + private bool OnHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo) + { + ResponsedData responsedData; + if (byteBlock != null) + { + responsedData = new ResponsedData(byteBlock.ToArray(), requestInfo); + } + else + { + responsedData = new ResponsedData(null, requestInfo); + } + + return !m_waitData.Set(responsedData); + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs b/src/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs new file mode 100644 index 000000000..744dd32e4 --- /dev/null +++ b/src/TouchSocket/Sockets/WaitingClient/WaitingClientExtension.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; +using TouchSocket.Core; + +namespace TouchSocket.Sockets +{ + /// + /// WaitingClientExtensions + /// + public static class WaitingClientExtension + { + /// + /// 获取可等待的客户端。 + /// + /// + /// + /// + /// + public static IWaitingClient GetWaitingClient(this TClient client, WaitingOptions waitingOptions) where TClient : IClient, IDefaultSender, ISender + { + WaitingClient waitingClient = new WaitingClient(client, waitingOptions); + return waitingClient; + } + } +} \ No newline at end of file diff --git a/src/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs b/src/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs new file mode 100644 index 000000000..e4498c123 --- /dev/null +++ b/src/TouchSocket/Sockets/WaitingClient/WaitingOptions.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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首页:https://www.yuque.com/rrqm/touchsocket/index +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace TouchSocket.Sockets +{ + /// + /// 等待设置 + /// + public class WaitingOptions + { + /// + /// 当Client为Tcp系时。是否在断开连接时以异常返回结果。 + /// + public bool ThrowBreakException { get; set; } = true; + + /// + /// 当Client为Tcp系时。是否在断开连接时立即触发结果。默认会返回null。当时,会触发异常。 + /// + public bool BreakTrigger { get; set; } + + /// + /// 适配器筛选 + /// + public AdapterFilter AdapterFilter { get; set; } = AdapterFilter.AllAdapter; + } + + /// + /// 适配器筛选 + /// + public enum AdapterFilter + { + /// + /// 发送和接收都经过适配器 + /// + AllAdapter, + + /// + /// 发送经过适配器,接收不经过 + /// + SendAdapter, + + /// + /// 发送不经过适配器,接收经过 + /// + WaitAdapter, + + /// + /// 全都不经过适配器。 + /// + NoneAll + } +} \ No newline at end of file diff --git a/src/TouchSocket/TouchSocket.csproj b/src/TouchSocket/TouchSocket.csproj new file mode 100644 index 000000000..cfbb6786a --- /dev/null +++ b/src/TouchSocket/TouchSocket.csproj @@ -0,0 +1,96 @@ + + + net45;netstandard2.0;netcoreapp3.1;net7.0 + logo.ico + True + D:\MyStore\13_Doc\Keys\TouchSocket.snk + 1.2.3 + 8.0 + 若汝棋茗 + Copyright © 2023 若汝棋茗 + tcp,udp,socket,ssl,rpc,http,https,websocket,rpc,xmlrpc,jsonrpc,webapi + 这是一个轻量级的、支持插件的综合网络通信库。基础通信功能包含Tcp、Udp、Ssl、Rpc、Http等。其中http服务器支持WebSocket、静态网页、XmlRpc、WebApi、JsonRpc等扩展插件。和自定义协议的TouchRpc,支持Ssl加密、异步调用、权限管理、错误状态返回、服务回调、分布式调用等。在空载函数执行时,10万次调用仅3.8秒,在不返回状态时,仅0.9秒。 + +This is a lightweight, plug-in - enabled comprehensive network communication library. Basic communication functions include Tcp, Udp, Ssl, Rpc, and Http. HTTP server supports WebSocket, static web page, XmlRpc, WebApi, JsonRpc and other extension plug-ins. And custom protocol TouchRpc, support Ssl encryption, asynchronous call, permission management, error status return, service callback, distributed call, etc. It takes 3.8 seconds for 100,000 calls when the no-load function is executing, and 0.9 seconds when the state is not returned. + +说明文档:http://rrqm_home.gitee.io/touchsocket + https://gitee.com/rrqm_home/touchsocket + + logo.png + 若汝棋茗 + true + true + LICENSE.txt + + + + bin\Debug\netstandard2.0\TouchSocket.xml + + true + + + + bin\Release\netstandard2.0\TouchSocket.xml + + true + + + + bin\Debug\net45\TouchSocket.xml + + TRACE;DEBUG + true + false + + + + bin\Release\net45\TouchSocket.xml + + true + + + + bin\Debug\net7.0\TouchSocket.xml + + true + + + + bin\Release\net7.0\TouchSocket.xml + + true + + + + bin\Debug\netcoreapp3.1\TouchSocket.xml + + true + + + + bin\Release\netcoreapp3.1\TouchSocket.xml + + true + + + + + True + + + + True + + + + + + + + + + + + + + diff --git a/src/TouchSocket/logo.ico b/src/TouchSocket/logo.ico new file mode 100644 index 000000000..7b33dcf65 Binary files /dev/null and b/src/TouchSocket/logo.ico differ diff --git a/src/TouchSocket/logo.png b/src/TouchSocket/logo.png new file mode 100644 index 000000000..d4199b5c3 Binary files /dev/null and b/src/TouchSocket/logo.png differ