V5.5.0正式版
341
.gitignore
vendored
Normal file
@@ -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
|
||||
201
LICENSE
Normal file
@@ -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.
|
||||
397
README.md
Normal file
@@ -0,0 +1,397 @@
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p align="center">
|
||||
<img src="https://ftp.bmp.ovh/imgs/2021/06/351eeccfadc07014.png" width = "100" height = "100" alt="图片名称" align=center />
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://www.nuget.org/packages/RRQMSocket/)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
[](https://www.nuget.org/packages/RRQMSocket/)
|
||||
[](https://gitee.com/dotnetchina/RRQMSocket/stargazers)
|
||||
[](https://gitee.com/dotnetchina/RRQMSocket/members)
|
||||
<a href="https://jq.qq.com/?_wv=1027&k=gN7UL4fw">
|
||||
<img src="https://img.shields.io/badge/QQ群-234762506-red" alt="QQ">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
|
||||
合抱之木,生于毫末;九层之台,起于垒土。
|
||||
|
||||
</div>
|
||||
<div align="center">
|
||||
<img src="https://i.bmp.ovh/imgs/2021/06/0bb09b575906f48b.png" alt="图片名称" align=center />
|
||||
</div>
|
||||
|
||||
## 💿描述
|
||||
| 名称 |描述|
|
||||
|---|---|
|
||||
|[](https://www.nuget.org/packages/RRQMSocket/)| **RRQMSocket**是一个整合性的、超轻量级的、可以免费商用使用的网络通信服务框架。<br>它具有 **高并发连接** 、 **高并发处理** 、 **事件订阅** 、 **插件式扩展** 、<br> **多线程处理** 、 **内存池** 、 **对象池** 等特点,<br>让使用者能够更加简单的、快速的搭建网络框架。|
|
||||
|[](https://www.nuget.org/packages/RRQMSocketFramework/)| **RRQMSocketFramework**是RRQMSocket系列的企业版,<br>两者在功能上几乎没有区别,但是RRQMSocketFramework无任何依赖,<br>且可以提供专属的定制功能。后续也会加入企业已定制的优秀功能,希望大家多多支持。|
|
||||
| [](https://www.nuget.org/packages/RRQMSocket.FileTransfer/) | RRQMSocket.FileTransfer是一个高性能的文件传输框架,<br>您可以用它传输**任意大小**的文件,它可以完美支持**上传下载混合式队列传输**、<br>**断点续传**、 **快速上传** 、**传输限速**、**获取文件信息**、**删除文件**等。<br>在实时测试中,它的传输速率可达500Mb/s。 |
|
||||
|[](https://www.nuget.org/packages/RRQMSocket.RPC/) |RPC是一个超轻量、高性能、可扩展的微服务管理平台框架,<br>目前已完成开发**RRQMRPC**、**XmlRpc**、**JsonRpc**、**WebApi**部分。<br> **RRQMRPC**部分使用RRQM专属协议,支持客户端**异步调用**,<br>服务端**异步触发**、以及**out**和**ref**关键字,**函数回调**等。<br>在调用效率上也是非常强悍,在调用空载函数,且返回状态时,<br>**10w**次调用仅用时**3.8**秒,不返回状态用时**0.9**秒。<br>其他协议调用性能详看性能评测。|
|
||||
|[](https://www.nuget.org/packages/RRQMSocket.RPC.WebApi/)| WebApi是一个扩展于RRQMSocket.RPC的WebApi组件,<br>可以通过该组件创建WebApi服务解析器,让桌面端、Web端、移动端可以跨语言调用RPC函数。<br>功能支持路由、Get传参、Post传参等。|
|
||||
|[](https://www.nuget.org/packages/RRQMSocket.RPC.XmlRpc/)| XmlRpc是一个扩展于RRQMSocket.RPC的XmlRpc组件,<br>可以通过该组件创建XmlRpc服务解析器,完美支持XmlRpc数据类型,类型嵌套,<br>Array等,也能与CookComputing.XmlRpcV2完美对接。不限Web,Android等平台。|
|
||||
| [](https://www.nuget.org/packages/RRQMSocket.RPC.JsonRpc/)| JsonRpc是一个扩展于RRQMSocket.RPC的JsonRpc组件,<br>可以通过该组件创建JsonRpc服务解析器,支持JsonRpc全部功能,可与Web,Android等平台无缝对接。|
|
||||
| [](https://www.nuget.org/packages/RRQMSocket.Http/) | RRQMSocket.Http是一个能够简单解析Http的服务组件,<br>能够快速响应Http服务请求。|
|
||||
|
||||
|
||||
## 🖥支持环境
|
||||
- .NET Framework4.5及以上。
|
||||
- .NET Core3.1及以上。
|
||||
- .NET Standard2.0及以上。
|
||||
|
||||
## 🥪支持框架
|
||||
- WPF
|
||||
- Winform
|
||||
- Blazor
|
||||
- Xamarin
|
||||
- Mono
|
||||
- Unity
|
||||
- 其他(即所有C#系)
|
||||
|
||||
## 🌴RRQMSocket特点速览
|
||||
|
||||
#### 对象池
|
||||
|
||||
对象池在RRQMSocket有很多应用,最主要的两个就是**连接对象池**和**处理对象池**。连接对象池就是当客户端成功连接时,首先会去连接对象池中找SocketClient,然后没有的话,才会创建。如果哪个客户端掉线了,它的SocketClient就会被回收。
|
||||
|
||||
然后就是处理对象池,在RRQMSocket中,接收数据的线程和IOCP内核线程是分开的(也可以设置拥塞接收),也就是比如说客户端给服务器发送了1w条数据,但是服务器收到后处理起来很慢,那传统的iocp肯定会放慢接收速率,然后通知客户端的tcp窗口,发生拥塞,然后让客户端暂缓发送。但是在RRQMSocket中会把收到的数据通过队列全都存起来,首先不影响iocp的接收,同时再分配线程去处理收到的报文信息,这样就相当于一个“泄洪湖泊”,能很大程度的提高处理数据的能力。
|
||||
|
||||
#### 多线程
|
||||
|
||||
由于有**处理对象池**的存在,使多线程处理变得简单。在客户端连接完成时,会自动分配该客户端辅助类(TcpSocketClient)的消息处理逻辑线程,假如服务器线程数量为10,则第一个连接的客户端会被分配到0号线程中,第二个连接将被分配到1号线程中,以此类推,循环分配。当某个客户端收到数据时,会将数据排入当前线程所独自拥有的队列当中,并唤醒线程执行。
|
||||
|
||||
#### 传统IOCP和RRQMSocket
|
||||
|
||||
RRQMSocket的IOCP和传统也不一样,就以微软官方示例为例,使用MemoryBuffer开辟一块内存,均分,然后给每个会话分配一个区接收,等收到数据后,再**复制**源数据,然后把复制的数据进行处理。而RRQMSocket是每次接收之前,从内存池拿一个可用内存块,然后**直接用于接收**,等收到数据以后,直接就把这个内存块抛出处理,这样就避免了**复制操作**,虽然只是细小的设计,但是在传输**1000w**次**64kb**的数据时,性能相差了**10倍**。
|
||||
|
||||
#### 数据处理适配器
|
||||
|
||||
相信大家都使用过其他的Socket产品,例如HPSocket,SuperSocket等,那么RRQMSocket在设计时也是借鉴了其他产品的优秀设计理念,数据处理适配器就是其中之一,但和其他产品的设计不同的是,RRQMSocket的适配器功能更加强大,它不仅可以提前解析数据包,还可以解析数据对象。例如:可以使用固定包头对数据进行预处理,从而解决数据分包、粘包的问题。也可以直接解析HTTP协议,经过适配器处理后传回一个HttpRequest对象等。
|
||||
|
||||
#### 粘包、分包解决
|
||||
|
||||
在RRQMSocket中处理TCP粘包、分包问题是非常简单的。只需要更改不同的**数据处理适配器**即可。例如:使用**固定包头**,只需要给SocketClient和TcpClient配置注入**FixedHeaderDataHandlingAdapter**的实例即可。同样对应的处理器也有**固定长度** 、 **终止字符分割** 等。
|
||||
|
||||
#### 兼容性与适配
|
||||
|
||||
RRQMSocket提供多种框架模型,能够完全兼容基于TCP、UDP协议的所有协议。例如:TcpService与TcpClient,其基础功能和Socket一模一样,只是增强了框架的**坚固性**和**并发性**,将**连接**和**接收数据**通过事件的形式抛出,让使用者能够更加友好的使用。
|
||||
|
||||
其次,RRQMSocket也提供了一些特定的服务器和客户端,如TokenService和TokenClient,这两个就必须配套使用,不然在验证Token时会被主动断开。
|
||||
|
||||
## 🔗联系作者
|
||||
|
||||
- [CSDN博客主页](https://blog.csdn.net/qq_40374647)
|
||||
- [哔哩哔哩视频](https://space.bilibili.com/94253567)
|
||||
- [源代码仓库主页](https://gitee.com/RRQM_Home)
|
||||
- 交流QQ群:234762506
|
||||
|
||||
## 🍻RRQM系产品
|
||||
|
||||
| 名称| 版本(Nuget Version)|下载(Nuget Download)| 描述 |
|
||||
|------|----------|-------------|-------|
|
||||
| [RRQMCore](https://gitee.com/RRQM_OS/RRQMCore) | [](https://www.nuget.org/packages/RRQMCore/) | [](https://www.nuget.org/packages/RRQMCore/) | RRQMCore是为RRQM系提供基础服务功能的库,其中包含:**内存池**、**对象池**、**等待逻辑池**、**AppMessenger**、**3DES加密**、**Xml快速存储**、**运行时间测量器**、**文件快捷操作**、**高性能序列化器**、**规范日志接口**等。 |
|
||||
| [RRQMMVVM](https://gitee.com/RRQM_OS/RRQMMVVM) | [](https://www.nuget.org/packages/RRQMMVVM/) | [](https://www.nuget.org/packages/RRQMMVVM/) | RRQMMVVM是超轻简的MVVM框架,但是麻雀虽小,五脏俱全。|
|
||||
| [RRQMSkin](https://gitee.com/RRQM_OS/RRQMSkin) | [](https://www.nuget.org/packages/RRQMSkin/) | [](https://www.nuget.org/packages/RRQMSkin/) | RRQMSkin是WPF的控件样式库,其中包含: **无边框窗体** 、 **圆角窗体** 、 **水波纹按钮** 、 **输入提示筛选框** 、 **控件拖动效果** 、**圆角图片框**、 **弧形文字** 、 **扇形元素** 、 **指针元素** 、 **饼图** 、 **时钟** 、 **速度表盘** 等。|
|
||||
|
||||
## 一、TCP框架
|
||||
|
||||
#### 1.1 说明
|
||||
|
||||
TCP框架是RRQMSocket最基础的框架,它定制了后继成员的创建、管理,维护、使用等一系列的规则,让使用者无需关心连接、掉线、失活检测、多线程安全等问题,能够专注于数据处理。
|
||||
|
||||
#### 1.2 安装
|
||||
|
||||
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
|
||||
|
||||
```CSharp
|
||||
Install-Package RRQMSocket
|
||||
```
|
||||
|
||||
#### 1.3 特点
|
||||
|
||||
- 简单易用。
|
||||
- 多线程。
|
||||
- **多地址监听**(可以一次性监听多个IP及端口)
|
||||
- 适配器预处理,一键式解决**分包**、**粘包**、对象解析(如HTTP,Json)等。
|
||||
- 超简单的同步发送、异步发送、接收等操作。
|
||||
- 基于事件驱动,让每一步操作尽在掌握。
|
||||
- 高性能(服务器每秒可接收200w条信息)
|
||||
- **独立线程内存池**(每个线程拥有自己的内存池)
|
||||
|
||||
#### 1.4 应用场景
|
||||
|
||||
- C/S服务器开发。
|
||||
- 制造业自动化控制服务器。
|
||||
- 物联网数据采集服务器。
|
||||
- 游戏服务器开发。
|
||||
|
||||
#### 1.5 API文档
|
||||
|
||||
[RRQMSocket API文档](https://gitee.com/RRQM_OS/RRQM/wikis/pages?sort_id=3984527&doc_id=1402901)
|
||||
|
||||
#### 1.6 Demo
|
||||
|
||||
[RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
|
||||
|
||||
## 二、Token框架
|
||||
|
||||
#### 2.1 说明
|
||||
|
||||
TokenService框架是RRQMSocket提供的派生自TcpService的基础框架,它在TCP基础之上,通过验证Token的方式,可以规范、筛选连接者。这样可以很大程度的**保护服务器**不疲于非法连接者的攻击。
|
||||
|
||||
#### 2.2 安装
|
||||
|
||||
工具➨Nuegt包管理器 ➨ 程序包管理器控制台
|
||||
|
||||
```CSharp
|
||||
Install-Package RRQMSocket
|
||||
```
|
||||
|
||||
#### 2.3 特点
|
||||
|
||||
- **规范**、**筛选**连接者,保护服务器。
|
||||
- 客户端与服务器必须**配套**使用。
|
||||
|
||||
#### 2.4 应用场景
|
||||
|
||||
- C/S服务器开发。
|
||||
- 制造业自动化控制服务器。
|
||||
- 游戏服务器开发。
|
||||
|
||||
#### 2.5 API文档
|
||||
|
||||
[RRQMSocket API文档](https://gitee.com/RRQM_OS/RRQM/wikis/pages?sort_id=3984517&doc_id=1402901)
|
||||
|
||||
#### 2.6 Demo
|
||||
|
||||
[RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
|
||||
|
||||
## 三、Protocol框架
|
||||
|
||||
#### 3.1 说明
|
||||
|
||||
ProtocolService框架是RRQMSocket提供的派生自TokenService的基础框架,它在Token基础之上,提供**协议+数据**的形式发送,其中还包括**协议冲突检测**、**协议数据占位**等。
|
||||
|
||||
#### 3.2 安装
|
||||
|
||||
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
|
||||
|
||||
```CSharp
|
||||
Install-Package RRQMSocket
|
||||
```
|
||||
|
||||
#### 3.3 特点
|
||||
|
||||
- 支持**ID同步**。
|
||||
- 快捷**协议发送**。
|
||||
|
||||
#### 3.4 应用场景
|
||||
|
||||
- C/S服务器开发。
|
||||
- 制造业自动化控制服务器。
|
||||
- 游戏服务器开发。
|
||||
|
||||
#### 3.5 API文档
|
||||
|
||||
[RRQMSocket API文档](https://gitee.com/RRQM_OS/RRQM/wikis/pages?sort_id=3984517&doc_id=1402901)
|
||||
|
||||
#### 3.6 Demo
|
||||
|
||||
[RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
|
||||
|
||||
## 四、RPCService框架
|
||||
|
||||
#### 4.1 说明
|
||||
|
||||
RPCService框架是所有远程过程调用的微服务调用管理平台,在该平台的托管下,使多种协议、多种序列化方式调用成为可能。目前可使用RRQMRPC、WebApi、XmlRpc、JsonRpc共同调用。
|
||||
|
||||
#### 4.2 RPC解析器
|
||||
|
||||
**说明:** RPCService仅仅是对调用的服务进行管理和维护,并不参与实质性的通信过程。实际上由于通信协议、序列化方式的不同,需要创建相对应的解析器才能完成调用操作。
|
||||
|
||||
#### 4.3 RPC解析器之RRQMRPC
|
||||
|
||||
##### 4.3.1 说明
|
||||
|
||||
RRQMRPC是基于Protocol框架、固定包头解析的远程调用框架,也是RRQM中性能最强悍、使用最简单、功能最强大的RPC框架。
|
||||
|
||||
##### 4.3.2 特点
|
||||
|
||||
- 支持**自定义**类型参数。
|
||||
- 支持具有**默认值**的参数设定。
|
||||
- 支持**out、ref** 关键字参数。
|
||||
- 支持服务器**回调客户端** 。
|
||||
- 支持**客户端**之间**相互调用**。
|
||||
- 支持TCP、UDP等不同的协议调用相同服务。
|
||||
- 支持异步调用。
|
||||
- 支持权限管理,让非法调用死在萌芽时期。
|
||||
- 支持**静态织入调用**,**静态编译调用**,也支持**方法名+参数**调用。
|
||||
- 支持**调用配置**(类似MQTT的AtMostOnce,AtLeastOnce,ExactlyOnce)。
|
||||
- **支持EventBus**(企业版支持)。
|
||||
- 支持**自定义序列化**。
|
||||
- **全异常反馈** ,服务器调用状态会完整的反馈到客户端(可以设置不反馈)。
|
||||
- 高性能,在保证送达但不返回的情况下,10w次调用用时0.8s,在返回的情况下,用时3.9s。
|
||||
|
||||
##### 4.3.3 安装
|
||||
|
||||
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
|
||||
|
||||
```CSharp
|
||||
Install-Package RRQMSocket.RPC
|
||||
```
|
||||
|
||||
##### 4.3.4 RRQMRPC性能测试
|
||||
|
||||
**说明:**
|
||||
图一、图二、图三分别为`UDP无反馈调用`、`TCP有反馈调用`、`TCP连接池有反馈调用`。调用次数均为10w次,调用性能非常nice。在无反馈中,吞吐量达14.28w,在有反馈中达2.72w。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
#### 4.4 RPC解析器之WebApi
|
||||
|
||||
##### 4.4.1 说明
|
||||
|
||||
使用WebApi解析器,就可以在RPCService中通过WebApi的调用方式直接调用服务。
|
||||
|
||||
##### 4.4.2 特点
|
||||
|
||||
- 高性能,100个客户端,10w次调用,仅用时17s。
|
||||
- **全异常反馈** 。
|
||||
- 支持大部分路由规则。
|
||||
- 支持js、Android等调用。
|
||||
|
||||
##### 4.4.3 安装
|
||||
|
||||
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
|
||||
|
||||
```CSharp
|
||||
Install-Package RRQMSocket.RPC.WebApi
|
||||
```
|
||||
|
||||
#### 4.5 RPC解析器之XmlRpc
|
||||
|
||||
##### 4.5.1 说明
|
||||
|
||||
使用XmlRpc解析器,就可以在RPCService中通过XmlRpc的调用方式直接调用服务,客户端可以使用**CookComputing.XmlRpcV2**进行对接。
|
||||
|
||||
##### 4.5.2 特点
|
||||
|
||||
- **异常反馈** 。
|
||||
- 支持自定义类型。
|
||||
- 支持类型嵌套。
|
||||
- 支持Array及自定义Array嵌套。
|
||||
- 支持js、Android等调用。
|
||||
|
||||
##### 4.5.3 安装
|
||||
|
||||
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
|
||||
|
||||
```CSharp
|
||||
Install-Package RRQMSocket.RPC.XmlRpc
|
||||
```
|
||||
|
||||
#### 4.6 RPC解析器之JsonRpc
|
||||
|
||||
##### 4.6.1 说明
|
||||
|
||||
使用JsonRpc解析器,就可以在RPCService中通过Json字符串直接调用服务。
|
||||
|
||||
##### 4.6.2 特点
|
||||
|
||||
- **异常反馈** 。
|
||||
- 支持自定义类型。
|
||||
- 支持类型嵌套。
|
||||
- 支持js、Android等调用。
|
||||
|
||||
##### 4.6.3 安装
|
||||
|
||||
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
|
||||
|
||||
```CSharp
|
||||
Install-Package RRQMSocket.RPC.JsonRpc
|
||||
```
|
||||
|
||||
#### 4.7 API文档
|
||||
|
||||
[RRQMSocket API文档](https://gitee.com/RRQM_OS/RRQM/wikis/pages?sort_id=3984517&doc_id=1402901)
|
||||
|
||||
#### 4.8 Demo
|
||||
|
||||
[RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
|
||||
|
||||
## 五、文件传输框架
|
||||
|
||||
#### 5.1 说明
|
||||
|
||||
RRQMSocket.FileTransfer是一个高性能的文件传输框架,由于它派生自RRQMRPC,所以也具备RPC的全部特性。
|
||||
|
||||
#### 5.2 特点
|
||||
|
||||
- 简单易用。
|
||||
- 多线程处理。
|
||||
- 高性能,传输速度可达**500Mb/s**。
|
||||
- 超简单的**传输限速**设置,1k-10Gb 无级调节。
|
||||
- 超简单的传输速度、传输进度获取。
|
||||
- 随心所欲的暂停、继续、停止传输。
|
||||
- 系统化的权限管理,让敏感文件只允许**私有化下载**。
|
||||
- **RPC交互**,让客户端和服务器交流不延迟。
|
||||
- 基于**事件驱动**,让每一步操作尽在掌握。
|
||||
- 可视化的文件块流,可以实现像迅雷一样的**填充式进度条**。
|
||||
- 超简单的**断点续传**设置,为大文件传输保驾护航。
|
||||
- 无状态上传断点续传设置,让同一个文件,在不同客户端之间**接力上传**。
|
||||
- **断网续传**(企业版支持)
|
||||
- 已经上传的文件,再次上传时,可实现**快速上传**。
|
||||
- 极少的GC释放。
|
||||
|
||||
#### 5.3 安装
|
||||
|
||||
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
|
||||
|
||||
```CSharp
|
||||
Install-Package RRQMSocket.FileTransfer
|
||||
```
|
||||
|
||||
#### 5.4 Demo示例
|
||||
|
||||
**Demo位置:** [RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
|
||||
|
||||
#### 5.5 性能测试
|
||||
|
||||
**说明:** 可以看到,图一正在上传一个Window的系统镜像文件,大约4.2Gb,传输速度已达到346Mb/s,这是因为服务器和客户端在同一电脑上,磁盘性能限制导致的。其次,GC基本上没有释放,性能非常强悍,图二是下载文件,性能依旧非常强悍。
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## 致谢
|
||||
|
||||
谢谢大家对我的支持,如果还有其他问题,请加群QQ:234762506讨论。
|
||||
|
||||
|
||||
## 💕 支持本项目
|
||||
您的支持就是我不懈努力的动力。
|
||||
|
||||
#### 爱心赞助名单(以下排名只按照打赏时间顺序)
|
||||
|
||||
1. Bobo Joker(200¥)
|
||||
2. UnitySir(66¥)
|
||||
3. Coffee(100¥)
|
||||
4. Ninety(50¥)
|
||||
5. *琼(100¥)
|
||||
6. **安(5¥)
|
||||
|
||||
#### 商业采购名单(以下排名只按照商业采购时间顺序)
|
||||
1.凯斯得****有限公司
|
||||
|
||||
<img src="https://images.gitee.com/uploads/images/2021/0330/234046_7662fb8c_8553710.png" width = "600" height = "400" alt="图片名称" align=center />
|
||||
|
||||
40
RRQMSocket.FileTransfer/Common/FileBlock.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件块
|
||||
/// </summary>
|
||||
public class FileBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件快索引
|
||||
/// </summary>
|
||||
public int Index { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件流位置
|
||||
/// </summary>
|
||||
public long Position { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件块长度
|
||||
/// </summary>
|
||||
public long UnitLength { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求状态
|
||||
/// </summary>
|
||||
public RequestStatus RequestStatus { get; internal set; }
|
||||
}
|
||||
}
|
||||
80
RRQMSocket.FileTransfer/Common/FileHashGenerator.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.IO;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件Hash校验
|
||||
/// </summary>
|
||||
public static class FileHashGenerator
|
||||
{
|
||||
private static FileHashType fileCheckType;
|
||||
|
||||
/// <summary>
|
||||
/// 文件
|
||||
/// </summary>
|
||||
public static FileHashType FileCheckType
|
||||
{
|
||||
get { return fileCheckType; }
|
||||
set { fileCheckType = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件Hash
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetFileHash(string path)
|
||||
{
|
||||
using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
return GetFileHash(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件Hash
|
||||
/// </summary>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetFileHash(FileStream fileStream)
|
||||
{
|
||||
HashAlgorithm hash;
|
||||
switch (fileCheckType)
|
||||
{
|
||||
case FileHashType.MD5:
|
||||
hash = MD5.Create();
|
||||
break;
|
||||
|
||||
case FileHashType.SHA1:
|
||||
hash = SHA1.Create();
|
||||
break;
|
||||
|
||||
case FileHashType.SHA256:
|
||||
hash = SHA256.Create();
|
||||
break;
|
||||
|
||||
case FileHashType.SHA512:
|
||||
hash = SHA512.Create();
|
||||
break;
|
||||
|
||||
default:
|
||||
hash = null;
|
||||
break;
|
||||
}
|
||||
return FileControler.GetStreamHash(fileStream, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
250
RRQMSocket.FileTransfer/Common/FileStreamPool.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件流池
|
||||
/// </summary>
|
||||
public static class FileStreamPool
|
||||
{
|
||||
internal static ConcurrentDictionary<string, RRQMStream> pathStream = new ConcurrentDictionary<string, RRQMStream>();
|
||||
private readonly static object locker = new object();
|
||||
private static ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();
|
||||
|
||||
internal static bool CheckAllFileBlockFinished(string path)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (!pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (stream.StreamType == StreamOperationType.Read)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (var block in stream.Blocks)
|
||||
{
|
||||
if (block.RequestStatus != RequestStatus.Finished)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DisposeReadStream(string path)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
if (Interlocked.Decrement(ref stream.reference) == 0)
|
||||
{
|
||||
if (pathStream.TryRemove(path, out stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DisposeWriteStream(string path, bool finished)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
if (Interlocked.Decrement(ref stream.reference) == 0)
|
||||
{
|
||||
if (pathStream.TryRemove(path, out stream))
|
||||
{
|
||||
if (finished)
|
||||
{
|
||||
stream.FinishStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool GetFreeFileBlock(string path, out FileBlock fileBlock, out string mes)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (!pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
mes = "没有此路径的写入信息";
|
||||
fileBlock = null;
|
||||
return false;
|
||||
}
|
||||
if (stream.StreamType == StreamOperationType.Read)
|
||||
{
|
||||
mes = "该路径的流为只读";
|
||||
fileBlock = null;
|
||||
return false;
|
||||
}
|
||||
foreach (var block in stream.Blocks)
|
||||
{
|
||||
if (block.RequestStatus == RequestStatus.Hovering)
|
||||
{
|
||||
block.RequestStatus = RequestStatus.InProgress;
|
||||
fileBlock = block;
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
fileBlock = null;
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool LoadReadStream(ref UrlFileInfo urlFileInfo, out string mes)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (pathStream.TryGetValue(urlFileInfo.FilePath, out stream))
|
||||
{
|
||||
Interlocked.Increment(ref stream.reference);
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RRQMStream.CreateReadStream(out stream, ref urlFileInfo, out mes))
|
||||
{
|
||||
Interlocked.Increment(ref stream.reference);
|
||||
pathStream.TryAdd(urlFileInfo.FilePath, stream);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool LoadWriteStream(ref ProgressBlockCollection blocks, bool onlySearch, out string mes)
|
||||
{
|
||||
RRQMStream stream;
|
||||
string rrqmPath = blocks.UrlFileInfo.SaveFullPath + ".rrqm";
|
||||
if (!pathStream.TryGetValue(rrqmPath, out stream))
|
||||
{
|
||||
if (RRQMStream.CreateWriteStream(out stream, ref blocks, out mes))
|
||||
{
|
||||
Interlocked.Increment(ref stream.reference);
|
||||
mes = null;
|
||||
return pathStream.TryAdd(rrqmPath, stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (onlySearch)
|
||||
{
|
||||
blocks = stream.Blocks;
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
mes = "该文件流正在被其他客户端拥有";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool ReadFile(string path, out string mes, long beginPosition, ByteBlock byteBlock, int offset, int length)
|
||||
{
|
||||
lockSlim.EnterReadLock();
|
||||
try
|
||||
{
|
||||
if (pathStream.TryGetValue(path, out RRQMStream stream))
|
||||
{
|
||||
stream.FileStream.Position = beginPosition;
|
||||
|
||||
if (byteBlock.Buffer.Length < length + offset)
|
||||
{
|
||||
byteBlock.SetBuffer(new byte[length + offset]);
|
||||
}
|
||||
|
||||
int r = stream.FileStream.Read(byteBlock.Buffer, offset, length);
|
||||
if (r == length)
|
||||
{
|
||||
byteBlock.Position = offset + length;
|
||||
byteBlock.SetLength(offset + length);
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mes = "没有找到该路径下的流文件";
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mes = ex.Message;
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
lockSlim.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SaveProgressBlockCollection(string path)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
stream.SaveProgressBlockCollection();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RRQMException("没有找到该路径下的流文件");
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool WriteFile(string path, out string mes, out RRQMStream stream, long streamPosition, byte[] buffer, int offset, int length)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
stream.FileStream.Position = streamPosition;
|
||||
stream.FileStream.Write(buffer, offset, length);
|
||||
stream.FileStream.Flush();
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
mes = "未找到该路径下的流";
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mes = ex.Message;
|
||||
stream = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Exceptions;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件传输错误码映射
|
||||
/// </summary>
|
||||
public class FileTransferErrorExceptionMapping : ErrorExceptionMapping
|
||||
{
|
||||
private static FileTransferErrorExceptionMapping _instance = new FileTransferErrorExceptionMapping();
|
||||
|
||||
/// <summary>
|
||||
/// 默认实例
|
||||
/// </summary>
|
||||
public static FileTransferErrorExceptionMapping Default { get => _instance; }
|
||||
}
|
||||
}
|
||||
20
RRQMSocket.FileTransfer/Common/FileWaitResult.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Run;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
internal class FileWaitResult : WaitResult
|
||||
{
|
||||
public PBCollectionTemp PBCollectionTemp { get; set; }
|
||||
}
|
||||
}
|
||||
64
RRQMSocket.FileTransfer/Common/PBCollectionTemp.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 临时序列化
|
||||
/// </summary>
|
||||
public class PBCollectionTemp
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息
|
||||
/// </summary>
|
||||
public UrlFileInfo UrlFileInfo { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 块集合
|
||||
/// </summary>
|
||||
public List<FileBlock> Blocks { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 从文件块转换
|
||||
/// </summary>
|
||||
/// <param name="progressBlocks"></param>
|
||||
/// <returns></returns>
|
||||
public static PBCollectionTemp GetFromProgressBlockCollection(ProgressBlockCollection progressBlocks)
|
||||
{
|
||||
if (progressBlocks == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
PBCollectionTemp collectionTemp = new PBCollectionTemp();
|
||||
collectionTemp.UrlFileInfo = progressBlocks.UrlFileInfo;
|
||||
collectionTemp.Blocks = new List<FileBlock>();
|
||||
collectionTemp.Blocks.AddRange(progressBlocks);
|
||||
return collectionTemp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为ProgressBlockCollection
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ProgressBlockCollection ToPBCollection()
|
||||
{
|
||||
ProgressBlockCollection progressBlocks = new ProgressBlockCollection();
|
||||
progressBlocks.UrlFileInfo = this.UrlFileInfo;
|
||||
if (this.Blocks != null)
|
||||
{
|
||||
progressBlocks.AddRange(this.Blocks);
|
||||
}
|
||||
return progressBlocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
106
RRQMSocket.FileTransfer/Common/ProgressBlockCollection.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件进度块集合
|
||||
/// </summary>
|
||||
public class ProgressBlockCollection : ReadOnlyList<FileBlock>
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息
|
||||
/// </summary>
|
||||
public UrlFileInfo UrlFileInfo { get; internal set; }
|
||||
|
||||
private static int blockLength = 1024 * 1024 * 10;
|
||||
|
||||
/// <summary>
|
||||
/// 分块长度,min=1024*1024*5
|
||||
/// </summary>
|
||||
public static int BlockLength
|
||||
{
|
||||
get { return blockLength; }
|
||||
set
|
||||
{
|
||||
if (value < 1024 * 1024 * 5)
|
||||
{
|
||||
value = 1024 * 1024 * 5;
|
||||
}
|
||||
blockLength = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
internal void Save(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
byte[] buffer = SerializeConvert.RRQMBinarySerialize(this, true);
|
||||
using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
{
|
||||
fileStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
internal static ProgressBlockCollection Read(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(path))
|
||||
{
|
||||
byte[] buffer = new byte[stream.Length];
|
||||
stream.Read(buffer, 0, buffer.Length);
|
||||
return SerializeConvert.RRQMBinaryDeserialize<ProgressBlockCollection>(buffer, 0);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal static ProgressBlockCollection CreateProgressBlockCollection(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
ProgressBlockCollection blocks = new ProgressBlockCollection();
|
||||
blocks.UrlFileInfo = urlFileInfo;
|
||||
long position = 0;
|
||||
long surLength = urlFileInfo.FileLength;
|
||||
int index = 0;
|
||||
while (surLength > 0)
|
||||
{
|
||||
FileBlock block = new FileBlock();
|
||||
block.Index = index++;
|
||||
block.RequestStatus = RequestStatus.Hovering;
|
||||
block.Position = position;
|
||||
block.UnitLength = surLength > blockLength ? blockLength : surLength;
|
||||
blocks.Add(block);
|
||||
position += block.UnitLength;
|
||||
surLength -= block.UnitLength;
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
157
RRQMSocket.FileTransfer/Common/RRQMStream.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
internal class RRQMStream
|
||||
{
|
||||
internal int reference;
|
||||
|
||||
private ProgressBlockCollection blocks;
|
||||
|
||||
private FileStream fileStream;
|
||||
private string rrqmPath;
|
||||
private StreamOperationType streamType;
|
||||
|
||||
private UrlFileInfo urlFileInfo;
|
||||
|
||||
private RRQMStream()
|
||||
{
|
||||
}
|
||||
|
||||
public ProgressBlockCollection Blocks { get { return blocks; } }
|
||||
|
||||
public FileStream FileStream
|
||||
{
|
||||
get { return fileStream; }
|
||||
}
|
||||
|
||||
public StreamOperationType StreamType
|
||||
{
|
||||
get { return streamType; }
|
||||
}
|
||||
|
||||
public UrlFileInfo UrlFileInfo { get => urlFileInfo; }
|
||||
|
||||
internal static bool CreateReadStream(out RRQMStream stream, ref UrlFileInfo urlFileInfo, out string mes)
|
||||
{
|
||||
stream = new RRQMStream();
|
||||
try
|
||||
{
|
||||
stream.streamType = StreamOperationType.Read;
|
||||
stream.fileStream = File.OpenRead(urlFileInfo.FilePath);
|
||||
urlFileInfo.FileLength = stream.fileStream.Length;
|
||||
stream.urlFileInfo = urlFileInfo;
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
stream.Dispose();
|
||||
stream = null;
|
||||
mes = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool CreateWriteStream(out RRQMStream stream, ref ProgressBlockCollection blocks, out string mes)
|
||||
{
|
||||
stream = new RRQMStream();
|
||||
stream.rrqmPath = blocks.UrlFileInfo.SaveFullPath + ".rrqm";
|
||||
stream.urlFileInfo = blocks.UrlFileInfo;
|
||||
stream.streamType = StreamOperationType.Write;
|
||||
try
|
||||
{
|
||||
if (blocks.UrlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume) && File.Exists(stream.rrqmPath))
|
||||
{
|
||||
stream.fileStream = new FileStream(stream.rrqmPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
||||
int blocksLength = (int)(stream.fileStream.Length - blocks.UrlFileInfo.FileLength);
|
||||
if (blocksLength > 0)
|
||||
{
|
||||
stream.fileStream.Position = blocks.UrlFileInfo.FileLength;
|
||||
byte[] buffer = new byte[blocksLength];
|
||||
stream.fileStream.Read(buffer, 0, buffer.Length);
|
||||
try
|
||||
{
|
||||
PBCollectionTemp readBlocks = SerializeConvert.RRQMBinaryDeserialize<PBCollectionTemp>(buffer);
|
||||
if (readBlocks.UrlFileInfo != null && blocks.UrlFileInfo != null && readBlocks.UrlFileInfo.FileHash != null)
|
||||
{
|
||||
if (readBlocks.UrlFileInfo.FileHash == blocks.UrlFileInfo.FileHash)
|
||||
{
|
||||
stream.blocks = blocks = readBlocks.ToPBCollection();
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
stream.fileStream.Dispose();
|
||||
}
|
||||
stream.blocks = blocks;
|
||||
if (File.Exists(stream.rrqmPath))
|
||||
{
|
||||
File.Delete(stream.rrqmPath);
|
||||
}
|
||||
stream.fileStream = new FileStream(stream.rrqmPath, FileMode.Create, FileAccess.ReadWrite);
|
||||
stream.SaveProgressBlockCollection();
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mes = ex.Message;
|
||||
stream.Dispose();
|
||||
stream = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool FinishStream()
|
||||
{
|
||||
this.fileStream.SetLength(this.urlFileInfo.FileLength);
|
||||
this.fileStream.Flush();
|
||||
UrlFileInfo info = this.urlFileInfo;
|
||||
this.Dispose();
|
||||
if (File.Exists(info.SaveFullPath))
|
||||
{
|
||||
File.Delete(info.SaveFullPath);
|
||||
}
|
||||
File.Move(info.SaveFullPath + ".rrqm", info.SaveFullPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
this.blocks = null;
|
||||
this.urlFileInfo = null;
|
||||
if (this.fileStream != null)
|
||||
{
|
||||
this.fileStream.Dispose();
|
||||
this.fileStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SaveProgressBlockCollection()
|
||||
{
|
||||
byte[] dataBuffer = SerializeConvert.RRQMBinarySerialize(PBCollectionTemp.GetFromProgressBlockCollection(blocks), true);
|
||||
this.fileStream.Position = this.urlFileInfo.FileLength;
|
||||
this.fileStream.WriteAsync(dataBuffer, 0, dataBuffer.Length);
|
||||
this.fileStream.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
93
RRQMSocket.FileTransfer/Common/ReadOnlyList.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 只读
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
|
||||
public class ReadOnlyList<T> : IEnumerable<T>
|
||||
{
|
||||
private List<T> list = new List<T>();
|
||||
|
||||
internal void Add(T block)
|
||||
{
|
||||
list.Add(block);
|
||||
}
|
||||
|
||||
internal void AddRange(IEnumerable<T> collection)
|
||||
{
|
||||
list.AddRange(collection);
|
||||
}
|
||||
|
||||
internal void Remove(T block)
|
||||
{
|
||||
list.Remove(block);
|
||||
}
|
||||
|
||||
internal void RemoveAt(int index)
|
||||
{
|
||||
list.RemoveAt(index);
|
||||
}
|
||||
|
||||
internal void RemoveAll(Predicate<T> match)
|
||||
{
|
||||
list.RemoveAll(match);
|
||||
}
|
||||
|
||||
internal void RemoveRange(int index, int range)
|
||||
{
|
||||
list.RemoveRange(index, range);
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
list.Clear();
|
||||
}
|
||||
|
||||
internal void Insert(int index, T item)
|
||||
{
|
||||
list.Insert(index, item);
|
||||
}
|
||||
|
||||
internal void InsertRange(int index, IEnumerable<T> collection)
|
||||
{
|
||||
list.InsertRange(index, collection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回迭代器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return this.list.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.list.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public T this[int index] { get { return list[index]; } }
|
||||
}
|
||||
}
|
||||
22
RRQMSocket.FileTransfer/Common/Speed.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal class Speed
|
||||
{
|
||||
internal static long downloadSpeed;
|
||||
internal static long uploadSpeed;
|
||||
}
|
||||
}
|
||||
92
RRQMSocket.FileTransfer/Common/TransferCollection.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输集合
|
||||
/// </summary>
|
||||
public class TransferCollection : IEnumerable<UrlFileInfo>
|
||||
{
|
||||
internal TransferCollection()
|
||||
{
|
||||
list = new List<UrlFileInfo>();
|
||||
}
|
||||
|
||||
internal event RRQMMessageEventHandler OnCollectionChanged;
|
||||
|
||||
private List<UrlFileInfo> list;
|
||||
|
||||
/// <summary>
|
||||
/// 返回一个循环访问集合的枚举器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<UrlFileInfo> GetEnumerator()
|
||||
{
|
||||
return list.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return list.GetEnumerator();
|
||||
}
|
||||
|
||||
internal void Add(UrlFileInfo fileInfo)
|
||||
{
|
||||
this.list.Add(fileInfo);
|
||||
Task.Run(() =>
|
||||
{
|
||||
OnCollectionChanged?.Invoke(null, new MesEventArgs("添加"));
|
||||
});
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
this.list.Clear();
|
||||
Task.Run(() =>
|
||||
{
|
||||
OnCollectionChanged?.Invoke(null, new MesEventArgs("清空"));
|
||||
});
|
||||
}
|
||||
|
||||
internal bool Remove(UrlFileInfo fileInfo)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
OnCollectionChanged?.Invoke(null, new MesEventArgs("移除"));
|
||||
});
|
||||
return this.list.Remove(fileInfo);
|
||||
}
|
||||
|
||||
internal bool GetFirst(out UrlFileInfo fileInfo)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (this.list.Count > 0)
|
||||
{
|
||||
fileInfo = this.list[0];
|
||||
this.list.RemoveAt(0);
|
||||
Task.Run(() =>
|
||||
{
|
||||
OnCollectionChanged?.Invoke(null, new MesEventArgs("进入传输"));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
203
RRQMSocket.FileTransfer/Common/TransferFileHashDictionary.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输文件Hash暂存字典
|
||||
/// </summary>
|
||||
public static class TransferFileHashDictionary
|
||||
{
|
||||
private static ConcurrentDictionary<string, UrlFileInfo> fileHashAndInfo = new ConcurrentDictionary<string, UrlFileInfo>();
|
||||
private static ConcurrentDictionary<string, UrlFileInfo> filePathAndInfo = new ConcurrentDictionary<string, UrlFileInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// 字典存储文件Hash的最大数量,默认为10000
|
||||
/// </summary>
|
||||
public static int MaxCount { get; set; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// 添加文件信息
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="breakpointResume"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlFileInfo AddFile(string filePath, bool breakpointResume = true)
|
||||
{
|
||||
UrlFileInfo urlFileInfo = new UrlFileInfo();
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
urlFileInfo.FilePath = filePath;
|
||||
urlFileInfo.FileLength = stream.Length;
|
||||
urlFileInfo.FileName = Path.GetFileName(filePath);
|
||||
if (breakpointResume)
|
||||
{
|
||||
urlFileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
|
||||
}
|
||||
}
|
||||
AddFile(urlFileInfo);
|
||||
return urlFileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加文件信息
|
||||
/// </summary>
|
||||
/// <param name="urlFileInfo"></param>
|
||||
public static void AddFile(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
if (urlFileInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
filePathAndInfo.AddOrUpdate(urlFileInfo.FilePath, urlFileInfo, (key, oldValue) =>
|
||||
{
|
||||
return urlFileInfo;
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(urlFileInfo.FileHash))
|
||||
{
|
||||
fileHashAndInfo.AddOrUpdate(urlFileInfo.FileHash, urlFileInfo, (key, oldValue) =>
|
||||
{
|
||||
return urlFileInfo;
|
||||
});
|
||||
}
|
||||
|
||||
if (filePathAndInfo.Count > MaxCount)
|
||||
{
|
||||
foreach (var item in filePathAndInfo.Keys)
|
||||
{
|
||||
if (filePathAndInfo.TryRemove(item, out _))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fileHashAndInfo.Count > MaxCount)
|
||||
{
|
||||
foreach (var item in fileHashAndInfo.Keys)
|
||||
{
|
||||
if (fileHashAndInfo.TryRemove(item, out _))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除全部
|
||||
/// </summary>
|
||||
public static void ClearDictionary()
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
filePathAndInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件信息
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="urlFileInfo"></param>
|
||||
/// <param name="breakpointResume"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetFileInfo(string filePath, out UrlFileInfo urlFileInfo, bool breakpointResume)
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (filePathAndInfo.ContainsKey(filePath))
|
||||
{
|
||||
urlFileInfo = filePathAndInfo[filePath];
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
if (urlFileInfo.FileLength == stream.Length)
|
||||
{
|
||||
if (breakpointResume && urlFileInfo.FileHash == null)
|
||||
{
|
||||
urlFileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
|
||||
AddFile(urlFileInfo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过FileHash获取文件信息
|
||||
/// </summary>
|
||||
/// <param name="fileHash"></param>
|
||||
/// <param name="urlFileInfo"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetFileInfoFromHash(string fileHash, out UrlFileInfo urlFileInfo)
|
||||
{
|
||||
if (fileHashAndInfo == null)
|
||||
{
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(fileHash))
|
||||
{
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileHashAndInfo.TryGetValue(fileHash, out urlFileInfo))
|
||||
{
|
||||
if (urlFileInfo.FileHash == fileHash)
|
||||
{
|
||||
if (File.Exists(urlFileInfo.FilePath))
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(urlFileInfo.FilePath))
|
||||
{
|
||||
if (urlFileInfo.FileLength == stream.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Remove(string filePath)
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return filePathAndInfo.TryRemove(filePath, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
166
RRQMSocket.FileTransfer/Common/UrlFileInfo.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息类
|
||||
/// </summary>
|
||||
public class UrlFileInfo
|
||||
{
|
||||
private string saveFullPath = string.Empty;
|
||||
|
||||
private int timeout = 30 * 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 文件哈希值
|
||||
/// </summary>
|
||||
public string FileHash { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件大小
|
||||
/// </summary>
|
||||
public long FileLength { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string FileName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
public string FilePath { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 传输标识
|
||||
/// </summary>
|
||||
public TransferFlags Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 携带消息
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 存放目录
|
||||
/// </summary>
|
||||
public string SaveFullPath
|
||||
{
|
||||
get { return saveFullPath; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
value = string.Empty;
|
||||
}
|
||||
saveFullPath = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 超时时间,默认30*1000 ms
|
||||
/// </summary>
|
||||
public int Timeout
|
||||
{
|
||||
get { return timeout; }
|
||||
set { timeout = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求传输类型
|
||||
/// </summary>
|
||||
public TransferType TransferType { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成下载请求必要信息
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="flags"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlFileInfo CreateDownload(string path, TransferFlags flags)
|
||||
{
|
||||
UrlFileInfo fileInfo = new UrlFileInfo();
|
||||
fileInfo.FilePath = path;
|
||||
fileInfo.Flags = flags;
|
||||
fileInfo.FileName = Path.GetFileName(path);
|
||||
fileInfo.TransferType = TransferType.Download;
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成上传请求必要信息
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="flags"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlFileInfo CreateUpload(string path, TransferFlags flags)
|
||||
{
|
||||
UrlFileInfo fileInfo = new UrlFileInfo();
|
||||
fileInfo.TransferType = TransferType.Upload;
|
||||
using (FileStream stream = File.OpenRead(path))
|
||||
{
|
||||
fileInfo.Flags = flags;
|
||||
fileInfo.FilePath = path;
|
||||
if (flags.HasFlag(TransferFlags.BreakpointResume) || flags.HasFlag(TransferFlags.QuickTransfer))
|
||||
{
|
||||
fileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
|
||||
}
|
||||
fileInfo.FileLength = stream.Length;
|
||||
fileInfo.FileName = Path.GetFileName(path);
|
||||
}
|
||||
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制
|
||||
/// </summary>
|
||||
/// <param name="urlFileInfo"></param>
|
||||
public void CopyFrom(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
this.FileHash = urlFileInfo.FileHash;
|
||||
this.FileLength = urlFileInfo.FileLength;
|
||||
this.FileName = urlFileInfo.FileName;
|
||||
this.FilePath = urlFileInfo.FilePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断参数是否相同
|
||||
/// </summary>
|
||||
/// <param name="urlFileInfo"></param>
|
||||
/// <returns></returns>
|
||||
public bool Equals(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
if (urlFileInfo.FileHash != this.FileHash)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (urlFileInfo.FileLength != this.FileLength)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (urlFileInfo.FileName != this.FileName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (urlFileInfo.FilePath != this.FilePath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
85
RRQMSocket.FileTransfer/Config/FileClientConfig.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Dependency;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件客户端配置
|
||||
/// </summary>
|
||||
public class FileClientConfig : TokenClientConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public FileClientConfig()
|
||||
{
|
||||
this.BufferLength = 64 * 1024;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认接收文件的存放目录
|
||||
/// </summary>
|
||||
public string ReceiveDirectory
|
||||
{
|
||||
get { return (string)GetValue(ReceiveDirectoryProperty); }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
value = string.Empty;
|
||||
}
|
||||
SetValue(ReceiveDirectoryProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认接收文件的存放目录, 所需类型<see cref="string"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ReceiveDirectoryProperty =
|
||||
DependencyProperty.Register("ReceiveDirectory", typeof(string), typeof(FileClientConfig), string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// 单次请求超时时间 min=5000,max=60*1000 ms
|
||||
/// </summary>
|
||||
public int Timeout
|
||||
{
|
||||
get { return (int)GetValue(TimeoutProperty); }
|
||||
set
|
||||
{
|
||||
SetValue(TimeoutProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单次请求超时时间 min=5000,max=60*1000 ms, 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TimeoutProperty =
|
||||
DependencyProperty.Register("Timeout", typeof(int), typeof(FileClientConfig), 10*1000);
|
||||
|
||||
/// <summary>
|
||||
/// 数据包尺寸
|
||||
/// </summary>
|
||||
public int PacketSize
|
||||
{
|
||||
get { return (int)GetValue(PacketSizeProperty); }
|
||||
set { SetValue(PacketSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据包尺寸, 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
[RRQMCore.Range]
|
||||
public static readonly DependencyProperty PacketSizeProperty =
|
||||
DependencyProperty.Register("PacketSize", typeof(int), typeof(FileClientConfig), 1024 * 1024);
|
||||
}
|
||||
}
|
||||
59
RRQMSocket.FileTransfer/Config/FileServiceConfig.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Dependency;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件服务器配置
|
||||
/// </summary>
|
||||
public class FileServiceConfig : TokenServiceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public FileServiceConfig()
|
||||
{
|
||||
this.BufferLength = 64 * 1024;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大下载速度
|
||||
/// </summary>
|
||||
public long MaxDownloadSpeed
|
||||
{
|
||||
get { return (long)GetValue(MaxDownloadSpeedProperty); }
|
||||
set { SetValue(MaxDownloadSpeedProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大下载速度, 所需类型<see cref="long"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxDownloadSpeedProperty =
|
||||
DependencyProperty.Register("MaxDownloadSpeed", typeof(long), typeof(FileServiceConfig), 1024 * 1024L);
|
||||
|
||||
/// <summary>
|
||||
/// 最大上传速度
|
||||
/// </summary>
|
||||
public long MaxUploadSpeed
|
||||
{
|
||||
get { return (long)GetValue(MaxUploadSpeedProperty); }
|
||||
set { SetValue(MaxUploadSpeedProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大上传速度, 所需类型<see cref="long"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxUploadSpeedProperty =
|
||||
DependencyProperty.Register("MaxUploadSpeed", typeof(long), typeof(FileServiceConfig), 1024 * 1024L);
|
||||
}
|
||||
}
|
||||
28
RRQMSocket.FileTransfer/Delegate/DelegateCollection.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输文件操作处理
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate void RRQMFileOperationEventHandler(object sender, FileOperationEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件消息
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public delegate void RRQMTransferFileMessageEventHandler(object sender, TransferFileMessageArgs e);
|
||||
}
|
||||
39
RRQMSocket.FileTransfer/Enum/FileHashType.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件Hash检验类型
|
||||
/// </summary>
|
||||
public enum FileHashType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// MD5
|
||||
/// </summary>
|
||||
MD5,
|
||||
|
||||
/// <summary>
|
||||
/// SHA1
|
||||
/// </summary>
|
||||
SHA1,
|
||||
|
||||
/// <summary>
|
||||
/// SHA256
|
||||
/// </summary>
|
||||
SHA256,
|
||||
|
||||
/// <summary>
|
||||
/// SHA512
|
||||
/// </summary>
|
||||
SHA512
|
||||
}
|
||||
}
|
||||
34
RRQMSocket.FileTransfer/Enum/RequestStatus.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求状态
|
||||
/// </summary>
|
||||
public enum RequestStatus : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 未开始
|
||||
/// </summary>
|
||||
Hovering,
|
||||
|
||||
/// <summary>
|
||||
/// 正在进行
|
||||
/// </summary>
|
||||
InProgress,
|
||||
|
||||
/// <summary>
|
||||
/// 完成
|
||||
/// </summary>
|
||||
Finished
|
||||
}
|
||||
}
|
||||
29
RRQMSocket.FileTransfer/Enum/StreamOperationType.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 流操作类型
|
||||
/// </summary>
|
||||
public enum StreamOperationType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 读
|
||||
/// </summary>
|
||||
Read,
|
||||
|
||||
/// <summary>
|
||||
/// 写
|
||||
/// </summary>
|
||||
Write
|
||||
}
|
||||
}
|
||||
37
RRQMSocket.FileTransfer/Enum/TransferFlags.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输标识
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum TransferFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// 无任何标识
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 断点续传
|
||||
/// </summary>
|
||||
BreakpointResume = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 快速传输
|
||||
/// </summary>
|
||||
QuickTransfer = 2
|
||||
}
|
||||
}
|
||||
44
RRQMSocket.FileTransfer/Enum/TransferStatus.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输类型
|
||||
/// </summary>
|
||||
public enum TransferStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 无下载
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// 上传
|
||||
/// </summary>
|
||||
Upload,
|
||||
|
||||
/// <summary>
|
||||
/// 下载
|
||||
/// </summary>
|
||||
Download,
|
||||
|
||||
/// <summary>
|
||||
/// 暂停下载状态
|
||||
/// </summary>
|
||||
PauseDownload,
|
||||
|
||||
/// <summary>
|
||||
/// 暂停上传状态
|
||||
/// </summary>
|
||||
PauseUpload
|
||||
}
|
||||
}
|
||||
30
RRQMSocket.FileTransfer/Enum/TransferType.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输类型
|
||||
/// </summary>
|
||||
public enum TransferType
|
||||
{
|
||||
/// <summary>
|
||||
/// 上传
|
||||
/// </summary>
|
||||
Upload,
|
||||
|
||||
/// <summary>
|
||||
/// 下载
|
||||
/// </summary>
|
||||
Download,
|
||||
}
|
||||
}
|
||||
26
RRQMSocket.FileTransfer/EventArgs/FileEventArgs.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Event;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件事件
|
||||
/// </summary>
|
||||
public class FileEventArgs : RRQMEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息
|
||||
/// </summary>
|
||||
public UrlFileInfo UrlFileInfo { get; internal set; }
|
||||
}
|
||||
}
|
||||
24
RRQMSocket.FileTransfer/EventArgs/FileOperationEventArgs.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作文件事件类
|
||||
/// </summary>
|
||||
public class FileOperationEventArgs : TransferFileMessageArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否允许操作
|
||||
/// </summary>
|
||||
public bool IsPermitOperation { get; set; }
|
||||
}
|
||||
}
|
||||
29
RRQMSocket.FileTransfer/EventArgs/TransferFileMessageArgs.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件传输消息
|
||||
/// </summary>
|
||||
public class TransferFileMessageArgs : FileEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
public string Message { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 传输类型
|
||||
/// </summary>
|
||||
public TransferType TransferType { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Exceptions;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输错误
|
||||
/// </summary>
|
||||
|
||||
public class RRQMTransferErrorException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RRQMTransferErrorException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RRQMTransferErrorException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RRQMTransferErrorException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RRQMTransferErrorException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Exceptions;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 没有传输任务异常
|
||||
/// </summary>
|
||||
|
||||
public class RRQMTransferingException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RRQMTransferingException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RRQMTransferingException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RRQMTransferingException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RRQMTransferingException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
40
RRQMSocket.FileTransfer/Interface/IFileClient.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件终端接口
|
||||
/// </summary>
|
||||
public interface IFileClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取当前传输文件信息
|
||||
/// </summary>
|
||||
UrlFileInfo TransferFileInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输进度
|
||||
/// </summary>
|
||||
float TransferProgress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输速度
|
||||
/// </summary>
|
||||
long TransferSpeed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输状态
|
||||
/// </summary>
|
||||
TransferStatus TransferStatus { get; }
|
||||
}
|
||||
}
|
||||
30
RRQMSocket.FileTransfer/Interface/IFileService.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器接口
|
||||
/// </summary>
|
||||
public interface IFileService
|
||||
{
|
||||
/// <summary>
|
||||
/// 最大下载速度
|
||||
/// </summary>
|
||||
long MaxDownloadSpeed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大上传速度
|
||||
/// </summary>
|
||||
long MaxUploadSpeed { get; set; }
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.FileTransfer/LICENSE
Normal file
@@ -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 procotol 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.
|
||||
BIN
RRQMSocket.FileTransfer/RRQM.ico
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMSocket.FileTransfer/RRQM.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
77
RRQMSocket.FileTransfer/RRQMSocket.FileTransfer.csproj
Normal file
@@ -0,0 +1,77 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
|
||||
<ApplicationIcon>RRQM.ico</ApplicationIcon>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
|
||||
<Version>5.5.0</Version>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
|
||||
<Description>介绍:RRQMSocket.FileTransfer是一个轻量级文件传输框架,您可以用它传输任意大小的文件,它可以完美支持断点续传、快速上传、传输限速等。在实时测试中,它的传输速率可达1000Mb/s。
|
||||
|
||||
更新说明:
|
||||
优化:传输逻辑。
|
||||
优化:临时文件存储逻辑。
|
||||
优化:断点续传逻辑。
|
||||
优化:文件验证支持MD5、SHA1、SHA256、SHA512。
|
||||
修改:UrlFileInfo属性特性,可以一键式设置文件上传,下载路径。
|
||||
修改:扩大客户端权限,传输的封包可以由配置PacketSize设置。
|
||||
修改:超时事件单位由“秒”调整为“毫秒”。
|
||||
|
||||
API:https://gitee.com/RRQM_OS/RRQM/wikis/pages
|
||||
Demo:https://gitee.com/RRQM_OS/RRQMBox</Description>
|
||||
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
|
||||
<PackageIconUrl></PackageIconUrl>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PackageIcon>RRQM.png</PackageIcon>
|
||||
<Authors>若汝棋茗</Authors>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageTags>FileTransfer,TCP,IOCP,BreakpointResume</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.FileTransfer.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.FileTransfer.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net45\RRQMSocket.FileTransfer.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\net45\RRQMSocket.FileTransfer.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.FileTransfer.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.FileTransfer.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="RRQM.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RRQMSocket.RPC" Version="5.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
1030
RRQMSocket.FileTransfer/Socket/FileClient.cs
Normal file
133
RRQMSocket.FileTransfer/Socket/FileService.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using RRQMSocket.RPC.RRQMRPC;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 通讯服务端主类
|
||||
/// </summary>
|
||||
public class FileService : TcpParser<FileSocketClient>, IFileService
|
||||
{
|
||||
#region 属性
|
||||
|
||||
private long maxDownloadSpeed;
|
||||
|
||||
private long maxUploadSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// 获取下载速度
|
||||
/// </summary>
|
||||
public long DownloadSpeed
|
||||
{
|
||||
get
|
||||
{
|
||||
this.downloadSpeed = Speed.downloadSpeed;
|
||||
Speed.downloadSpeed = 0;
|
||||
return this.downloadSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大下载速度
|
||||
/// </summary>
|
||||
public long MaxDownloadSpeed
|
||||
{
|
||||
get { return maxDownloadSpeed; }
|
||||
set { maxUploadSpeed = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大上传速度
|
||||
/// </summary>
|
||||
public long MaxUploadSpeed
|
||||
{
|
||||
get { return maxUploadSpeed; }
|
||||
set { maxUploadSpeed = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取上传速度
|
||||
/// </summary>
|
||||
public long UploadSpeed
|
||||
{
|
||||
get
|
||||
{
|
||||
this.uploadSpeed = Speed.uploadSpeed;
|
||||
Speed.uploadSpeed = 0;
|
||||
return this.uploadSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 属性
|
||||
|
||||
#region 字段
|
||||
|
||||
private long downloadSpeed;
|
||||
private long uploadSpeed;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
#region 事件
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件之前
|
||||
/// </summary>
|
||||
public event RRQMFileOperationEventHandler BeforeFileTransfer;
|
||||
|
||||
/// <summary>
|
||||
/// 当文件传输完成时
|
||||
/// </summary>
|
||||
public event RRQMTransferFileMessageEventHandler FinishedFileTransfer;
|
||||
|
||||
#endregion 事件
|
||||
|
||||
/// <summary>
|
||||
/// 载入配置
|
||||
/// </summary>
|
||||
/// <param name="serviceConfig"></param>
|
||||
protected override void LoadConfig(ServiceConfig serviceConfig)
|
||||
{
|
||||
base.LoadConfig(serviceConfig);
|
||||
this.maxDownloadSpeed = (long)serviceConfig.GetValue(FileServiceConfig.MaxDownloadSpeedProperty);
|
||||
this.maxUploadSpeed = (long)serviceConfig.GetValue(FileServiceConfig.MaxUploadSpeedProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建完成FileSocketClient
|
||||
/// </summary>
|
||||
/// <param name="socketClient"></param>
|
||||
/// <param name="creatOption"></param>
|
||||
protected override void OnCreateSocketCliect(FileSocketClient socketClient, CreateOption creatOption)
|
||||
{
|
||||
base.OnCreateSocketCliect(socketClient, creatOption);
|
||||
socketClient.MaxDownloadSpeed = this.MaxDownloadSpeed;
|
||||
socketClient.MaxUploadSpeed = this.MaxUploadSpeed;
|
||||
if (creatOption.NewCreate)
|
||||
{
|
||||
socketClient.BeforeFileTransfer = this.OnBeforeFileTransfer;
|
||||
socketClient.FinishedFileTransfer = this.OnFinishedFileTransfer;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBeforeFileTransfer(object sender, FileOperationEventArgs e)
|
||||
{
|
||||
this.BeforeFileTransfer?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void OnFinishedFileTransfer(object sender, TransferFileMessageArgs e)
|
||||
{
|
||||
this.FinishedFileTransfer?.Invoke(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
692
RRQMSocket.FileTransfer/Socket/FileSocketClient.cs
Normal file
@@ -0,0 +1,692 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Log;
|
||||
using RRQMCore.Serialization;
|
||||
using RRQMSocket.RPC.RRQMRPC;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 已接收的客户端
|
||||
/// </summary>
|
||||
public class FileSocketClient : RpcSocketClient, IFileService, IFileClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输文件之前
|
||||
/// </summary>
|
||||
internal RRQMFileOperationEventHandler BeforeFileTransfer;
|
||||
|
||||
/// <summary>
|
||||
/// 当文件传输完成时
|
||||
/// </summary>
|
||||
internal RRQMTransferFileMessageEventHandler FinishedFileTransfer;
|
||||
|
||||
private long dataTransferLength;
|
||||
|
||||
private long maxDownloadSpeed = 1024 * 1024;
|
||||
|
||||
private long maxUploadSpeed = 1024 * 1024;
|
||||
|
||||
private long position;
|
||||
|
||||
private float progress;
|
||||
|
||||
private string rrqmPath;
|
||||
|
||||
private long speed;
|
||||
|
||||
private Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
private long tempLength;
|
||||
|
||||
private long timeTick;
|
||||
|
||||
private TransferStatus transferStatus;
|
||||
|
||||
private UrlFileInfo transferUrlFileInfo;
|
||||
|
||||
static FileSocketClient()
|
||||
{
|
||||
AddUsedProtocol(110, "同步设置");
|
||||
AddUsedProtocol(111, "通用信道返回");
|
||||
AddUsedProtocol(112, "请求下载");
|
||||
AddUsedProtocol(113, "下载文件分块");
|
||||
AddUsedProtocol(114, "退出下载通道");
|
||||
AddUsedProtocol(115, "确认下载完成");
|
||||
AddUsedProtocol(116, "请求上传");
|
||||
AddUsedProtocol(117, "上传分块");
|
||||
AddUsedProtocol(118, "停止上传");
|
||||
AddUsedProtocol(119, "确认上传完成");
|
||||
AddUsedProtocol(120, "智能包调节");
|
||||
for (short i = 121; i < 200; i++)
|
||||
{
|
||||
AddUsedProtocol(i, "保留协议");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每秒最大下载速度(Byte),不可小于1024
|
||||
/// </summary>
|
||||
public long MaxDownloadSpeed
|
||||
{
|
||||
get { return maxDownloadSpeed; }
|
||||
set
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
value = 1024;
|
||||
}
|
||||
this.maxDownloadSpeed = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每秒最大上传速度(Byte),不可小于1024
|
||||
/// </summary>
|
||||
public long MaxUploadSpeed
|
||||
{
|
||||
get { return maxUploadSpeed; }
|
||||
set
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
value = 1024;
|
||||
}
|
||||
this.maxUploadSpeed = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输文件信息
|
||||
/// </summary>
|
||||
public UrlFileInfo TransferFileInfo { get => this.transferUrlFileInfo; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输进度
|
||||
/// </summary>
|
||||
public float TransferProgress
|
||||
{
|
||||
get
|
||||
{
|
||||
if (transferUrlFileInfo == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
this.progress = transferUrlFileInfo.FileLength > 0 ? (float)position / transferUrlFileInfo.FileLength : 0;//计算下载完成进度
|
||||
return progress <= 1 ? progress : 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输速度
|
||||
/// </summary>
|
||||
public long TransferSpeed
|
||||
{
|
||||
get
|
||||
{
|
||||
this.speed = tempLength;
|
||||
tempLength = 0;
|
||||
return speed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输状态
|
||||
/// </summary>
|
||||
public TransferStatus TransferStatus
|
||||
{
|
||||
get { return transferStatus; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
this.ResetVariable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置
|
||||
/// </summary>
|
||||
public override void Recreate()
|
||||
{
|
||||
base.Recreate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件辅助类处理其他协议
|
||||
/// </summary>
|
||||
/// <param name="procotol"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
protected virtual void FileSocketClientHandleDefaultData(short? procotol, ByteBlock byteBlock)
|
||||
{
|
||||
this.OnHandleDefaultData(procotol, byteBlock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 封装协议
|
||||
/// </summary>
|
||||
/// <param name="procotol"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
protected sealed override void RPCHandleDefaultData(short? procotol, ByteBlock byteBlock)
|
||||
{
|
||||
byte[] buffer = byteBlock.Buffer;
|
||||
|
||||
switch (procotol)
|
||||
{
|
||||
case 110:
|
||||
{
|
||||
try
|
||||
{
|
||||
//this.P110_SynchronizeTransferSetting();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 112:
|
||||
{
|
||||
try
|
||||
{
|
||||
UrlFileInfo fileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(buffer, 2);
|
||||
P112_RequestDownload(fileInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 113:
|
||||
{
|
||||
try
|
||||
{
|
||||
P113_DownloadBlockData(byteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 114:
|
||||
{
|
||||
try
|
||||
{
|
||||
P114_StopDownload();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 115:
|
||||
{
|
||||
try
|
||||
{
|
||||
P115_DownloadFinished();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 116:
|
||||
{
|
||||
try
|
||||
{
|
||||
UrlFileInfo urlFileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(buffer, 2);
|
||||
P116_RequestUpload(urlFileInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 117:
|
||||
{
|
||||
try
|
||||
{
|
||||
P117_UploadBlockData(buffer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 118:
|
||||
{
|
||||
try
|
||||
{
|
||||
P118_StopUpload();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 119:
|
||||
{
|
||||
try
|
||||
{
|
||||
P119_UploadFinished();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this.FileSocketClientHandleDefaultData(procotol, byteBlock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 继承
|
||||
/// </summary>
|
||||
protected override void WaitReceive()
|
||||
{
|
||||
if (this.GetNowTick() - timeTick > 0)
|
||||
{
|
||||
//时间过了一秒
|
||||
this.timeTick = GetNowTick();
|
||||
this.dataTransferLength = 0;
|
||||
this.dataTransferLength = 0;
|
||||
stopwatch.Restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
//在这一秒中
|
||||
switch (this.transferStatus)
|
||||
{
|
||||
case TransferStatus.Upload:
|
||||
if (this.dataTransferLength > this.maxUploadSpeed)
|
||||
{
|
||||
//上传饱和
|
||||
stopwatch.Stop();
|
||||
int sleepTime = 1000 - (int)stopwatch.ElapsedMilliseconds <= 0 ? 0 : 1000 - (int)stopwatch.ElapsedMilliseconds;
|
||||
Thread.Sleep(sleepTime);
|
||||
}
|
||||
break;
|
||||
|
||||
case TransferStatus.Download:
|
||||
if (this.dataTransferLength > this.maxDownloadSpeed)
|
||||
{
|
||||
//下载饱和
|
||||
stopwatch.Stop();
|
||||
int sleepTime = 1000 - (int)stopwatch.ElapsedMilliseconds <= 0 ? 0 : 1000 - (int)stopwatch.ElapsedMilliseconds;
|
||||
Thread.Sleep(sleepTime);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间帧
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private long GetNowTick()
|
||||
{
|
||||
return DateTime.Now.Ticks / 10000000;
|
||||
}
|
||||
|
||||
private FileOperationEventArgs OnBeforeFileTransfer(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
FileOperationEventArgs args = new FileOperationEventArgs();
|
||||
args.UrlFileInfo = urlFileInfo;
|
||||
args.TransferType = urlFileInfo.TransferType;
|
||||
args.IsPermitOperation = true;
|
||||
if (urlFileInfo.TransferType == TransferType.Download)
|
||||
{
|
||||
//下载
|
||||
urlFileInfo.FilePath = Path.GetFullPath(urlFileInfo.FilePath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.BeforeFileTransfer?.Invoke(this, args);//触发 接收文件事件
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, $"在事件{nameof(BeforeFileTransfer)}中发生异常", ex);
|
||||
}
|
||||
|
||||
if (urlFileInfo.TransferType == TransferType.Upload)
|
||||
{
|
||||
urlFileInfo.SaveFullPath = Path.GetFullPath(string.IsNullOrEmpty(urlFileInfo.SaveFullPath) ? urlFileInfo.FileName : urlFileInfo.SaveFullPath);
|
||||
this.rrqmPath = urlFileInfo.SaveFullPath + ".rrqm";
|
||||
}
|
||||
this.transferUrlFileInfo = urlFileInfo;
|
||||
return args;
|
||||
}
|
||||
|
||||
private void OnFinishedFileTransfer(TransferType transferType)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.transferUrlFileInfo.FileHash))
|
||||
{
|
||||
TransferFileHashDictionary.AddFile(this.transferUrlFileInfo);
|
||||
}
|
||||
TransferFileMessageArgs args = new TransferFileMessageArgs();
|
||||
args.UrlFileInfo = this.transferUrlFileInfo;
|
||||
args.TransferType = transferType;
|
||||
|
||||
if (transferType == TransferType.Download)
|
||||
{
|
||||
FileStreamPool.DisposeReadStream(this.transferUrlFileInfo.FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileStreamPool.DisposeWriteStream(this.rrqmPath, true);
|
||||
this.rrqmPath = null;
|
||||
}
|
||||
this.transferStatus = TransferStatus.None;
|
||||
this.transferUrlFileInfo = null;
|
||||
try
|
||||
{
|
||||
this.FinishedFileTransfer?.Invoke(this, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, $"在事件{nameof(FinishedFileTransfer)}中发生异常", ex);
|
||||
}
|
||||
this.ResetVariable();
|
||||
}
|
||||
|
||||
private void P112_RequestDownload(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
FileOperationEventArgs args = OnBeforeFileTransfer(urlFileInfo);
|
||||
FileWaitResult waitResult = new FileWaitResult();
|
||||
if (!args.IsPermitOperation)
|
||||
{
|
||||
waitResult.Message = string.IsNullOrEmpty(args.Message) ? "服务器拒绝下载" : args.Message;
|
||||
waitResult.Status = 2;
|
||||
this.transferStatus = TransferStatus.None;
|
||||
}
|
||||
else if (!File.Exists(urlFileInfo.FilePath))
|
||||
{
|
||||
waitResult.Message = $"路径{urlFileInfo.FilePath}文件不存在";
|
||||
waitResult.Status = 2;
|
||||
this.transferStatus = TransferStatus.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
UrlFileInfo fileInfo;
|
||||
|
||||
if (!TransferFileHashDictionary.GetFileInfo(urlFileInfo.FilePath, out fileInfo, urlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume)))
|
||||
{
|
||||
fileInfo = TransferFileHashDictionary.AddFile(urlFileInfo.FilePath, urlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume));
|
||||
}
|
||||
urlFileInfo.CopyFrom(fileInfo);
|
||||
if (FileStreamPool.LoadReadStream(ref urlFileInfo, out string mes))
|
||||
{
|
||||
this.transferStatus = TransferStatus.Download;
|
||||
waitResult.Message = null;
|
||||
waitResult.Status = 1;
|
||||
this.transferUrlFileInfo = urlFileInfo;
|
||||
waitResult.PBCollectionTemp = new PBCollectionTemp();
|
||||
waitResult.PBCollectionTemp.UrlFileInfo = urlFileInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
waitResult.Message = mes;
|
||||
waitResult.Status = 2;
|
||||
}
|
||||
}
|
||||
|
||||
this.SendDefaultObject(waitResult);
|
||||
}
|
||||
|
||||
private void P113_DownloadBlockData(ByteBlock receivedByteBlock)
|
||||
{
|
||||
receivedByteBlock.Pos = 2;
|
||||
|
||||
long position = receivedByteBlock.ReadInt64();
|
||||
int requestLength = receivedByteBlock.ReadInt32();
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(requestLength + 7);
|
||||
if (this.transferStatus != TransferStatus.Download)
|
||||
{
|
||||
byteBlock.Buffer[6] = 0;
|
||||
}
|
||||
|
||||
string mes;
|
||||
if (FileStreamPool.ReadFile(transferUrlFileInfo.FilePath, out mes, position, byteBlock, 7, requestLength))
|
||||
{
|
||||
Speed.downloadSpeed += requestLength;
|
||||
this.position = position + requestLength;
|
||||
this.tempLength += requestLength;
|
||||
this.dataTransferLength += requestLength;
|
||||
byteBlock.Buffer[6] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Position = 6;
|
||||
byteBlock.Write((byte)2);
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(string.IsNullOrEmpty(mes) ? "未知错误" : mes));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (this.Online)
|
||||
{
|
||||
this.InternalSend(111, byteBlock.Buffer, 0, byteBlock.Len, true);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void P114_StopDownload()
|
||||
{
|
||||
this.transferUrlFileInfo = null;
|
||||
this.transferStatus = TransferStatus.None;
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
}
|
||||
|
||||
private void P115_DownloadFinished()
|
||||
{
|
||||
if (this.transferStatus == TransferStatus.None)
|
||||
{
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
return;
|
||||
}
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
OnFinishedFileTransfer(TransferType.Download);
|
||||
}
|
||||
|
||||
private void P116_RequestUpload(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
FileOperationEventArgs args = OnBeforeFileTransfer(urlFileInfo);
|
||||
|
||||
FileWaitResult waitResult = new FileWaitResult();
|
||||
if (!args.IsPermitOperation)
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = string.IsNullOrEmpty(args.Message) ? "服务器拒绝上传" : args.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.transferStatus = TransferStatus.Upload;
|
||||
this.transferUrlFileInfo = urlFileInfo;
|
||||
if (urlFileInfo.Flags.HasFlag(TransferFlags.QuickTransfer) && TransferFileHashDictionary.GetFileInfoFromHash(urlFileInfo.FileHash, out UrlFileInfo oldUrlFileInfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (urlFileInfo.FilePath != oldUrlFileInfo.FilePath)
|
||||
{
|
||||
File.Copy(oldUrlFileInfo.FilePath, urlFileInfo.FilePath, true);
|
||||
}
|
||||
|
||||
waitResult.Status = 3;
|
||||
waitResult.Message = null;
|
||||
this.SendDefaultObject(waitResult);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = ex.Message;
|
||||
this.Logger.Debug(LogType.Error, this, "在处理快速上传时发生异常。", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ProgressBlockCollection blocks = ProgressBlockCollection.CreateProgressBlockCollection(urlFileInfo);
|
||||
|
||||
if (FileStreamPool.LoadWriteStream(ref blocks, false, out string mes))
|
||||
{
|
||||
waitResult.Status = 1;
|
||||
waitResult.Message = null;
|
||||
waitResult.PBCollectionTemp = PBCollectionTemp.GetFromProgressBlockCollection(blocks);
|
||||
}
|
||||
else
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = mes;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = ex.Message;
|
||||
waitResult.PBCollectionTemp = null;
|
||||
}
|
||||
}
|
||||
|
||||
this.SendDefaultObject(waitResult);
|
||||
}
|
||||
|
||||
private void P117_UploadBlockData(byte[] buffer)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
if (this.transferStatus != TransferStatus.Upload)
|
||||
{
|
||||
byteBlock.Write((byte)4);
|
||||
}
|
||||
byte status = buffer[2];
|
||||
int index = BitConverter.ToInt32(buffer, 3);
|
||||
long position = BitConverter.ToInt64(buffer, 7);
|
||||
int submitLength = BitConverter.ToInt32(buffer, 15);
|
||||
|
||||
string mes;
|
||||
if (FileStreamPool.WriteFile(this.rrqmPath, out mes, out RRQMStream stream, position, buffer, 19, submitLength))
|
||||
{
|
||||
this.position = position + submitLength;
|
||||
this.tempLength += submitLength;
|
||||
this.dataTransferLength += submitLength;
|
||||
Speed.uploadSpeed += submitLength;
|
||||
byteBlock.Write((byte)1);
|
||||
if (status == 1)
|
||||
{
|
||||
FileBlock fileProgress = stream.Blocks.FirstOrDefault(a => a.Index == index);
|
||||
fileProgress.RequestStatus = RequestStatus.Finished;
|
||||
stream.SaveProgressBlockCollection();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Write((byte)2);
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(mes));
|
||||
Logger.Debug(LogType.Error, this, $"上传文件写入错误,信息:{mes}");
|
||||
}
|
||||
this.InternalSend(111, byteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, "上传文件错误", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void P118_StopUpload()
|
||||
{
|
||||
try
|
||||
{
|
||||
FileStreamPool.SaveProgressBlockCollection(this.rrqmPath);
|
||||
FileStreamPool.DisposeWriteStream(this.rrqmPath, false);
|
||||
this.ResetVariable();
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, "客户端请求停止上传时发生异常", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void P119_UploadFinished()
|
||||
{
|
||||
if (this.transferStatus == TransferStatus.None)
|
||||
{
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
return;
|
||||
}
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
OnFinishedFileTransfer(TransferType.Upload);
|
||||
}
|
||||
|
||||
private void ResetVariable()
|
||||
{
|
||||
this.transferStatus = TransferStatus.None;
|
||||
this.transferUrlFileInfo = null;
|
||||
this.progress = 0;
|
||||
this.speed = 0;
|
||||
if (!string.IsNullOrEmpty(this.rrqmPath))
|
||||
{
|
||||
FileStreamPool.DisposeWriteStream(this.rrqmPath, false);
|
||||
this.rrqmPath = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendDefaultObject(object obj)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(obj, true));
|
||||
try
|
||||
{
|
||||
this.InternalSend(111, byteBlock);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
258
RRQMSocket.Http/Common/HttpBase.cs
Normal file
@@ -0,0 +1,258 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Http基础头部
|
||||
/// </summary>
|
||||
public abstract class HttpBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public HttpBase()
|
||||
{
|
||||
this.headers = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务器版本
|
||||
/// </summary>
|
||||
public static readonly string ServerVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
|
||||
private string requestLine;
|
||||
|
||||
/// <summary>
|
||||
/// 字符数据
|
||||
/// </summary>
|
||||
public string Body { get { return this.content == null ? null : this.encoding.GetString(this.content); } }
|
||||
|
||||
private byte[] content;
|
||||
|
||||
/// <summary>
|
||||
/// 内容器
|
||||
/// </summary>
|
||||
public byte[] Content
|
||||
{
|
||||
get { return content; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内容编码
|
||||
/// </summary>
|
||||
public string Content_Encoding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容长度
|
||||
/// </summary>
|
||||
public int Content_Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容类型
|
||||
/// </summary>
|
||||
public string Content_Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容语言
|
||||
/// </summary>
|
||||
public string ContentLanguage { get; set; }
|
||||
|
||||
private Encoding encoding = Encoding.UTF8;
|
||||
|
||||
/// <summary>
|
||||
/// 编码方式
|
||||
/// </summary>
|
||||
public Encoding Encoding
|
||||
{
|
||||
get { return encoding; }
|
||||
set { encoding = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 传递标识
|
||||
/// </summary>
|
||||
public object Flag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求头集合
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Headers { get { return this.headers; } }
|
||||
|
||||
private Dictionary<string, string> headers;
|
||||
|
||||
/// <summary>
|
||||
/// 协议名称
|
||||
/// </summary>
|
||||
public string Protocols { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP协议版本
|
||||
/// </summary>
|
||||
public string ProtocolVersion { get; set; } = "1.1";
|
||||
|
||||
/// <summary>
|
||||
/// 请求行
|
||||
/// </summary>
|
||||
public string RequestLine
|
||||
{
|
||||
get { return requestLine; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
public abstract void Build(ByteBlock byteBlock);
|
||||
|
||||
/// <summary>
|
||||
/// 获取头值
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
public string GetHeader(HttpHeaders header)
|
||||
{
|
||||
return GetHeaderByKey(header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取信息
|
||||
/// </summary>
|
||||
public abstract void ReadFromBase();
|
||||
|
||||
/// <summary>
|
||||
/// 从内存中读取
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
public void ReadHeaders(byte[] buffer, int offset, int length)
|
||||
{
|
||||
string data = Encoding.UTF8.GetString(buffer, offset, length);
|
||||
string[] rows = Regex.Split(data, Environment.NewLine);
|
||||
|
||||
//Request URL & Method & Version
|
||||
this.requestLine = rows[0];
|
||||
|
||||
//Request Headers
|
||||
GetRequestHeaders(rows);
|
||||
|
||||
string contentLength = this.GetHeader(HttpHeaders.ContentLength);
|
||||
int.TryParse(contentLength, out int content_Length);
|
||||
this.Content_Length = content_Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取头集合的值
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
protected string GetHeaderByKey(Enum header)
|
||||
{
|
||||
var fieldName = header.GetDescription();
|
||||
if (fieldName == null) return null;
|
||||
var hasKey = Headers.ContainsKey(fieldName);
|
||||
if (!hasKey) return null;
|
||||
return Headers[fieldName];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取头集合的值
|
||||
/// </summary>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
protected string GetHeaderByKey(string fieldName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fieldName)) return null;
|
||||
var hasKey = Headers.ContainsKey(fieldName);
|
||||
if (!hasKey) return null;
|
||||
return Headers[fieldName];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置头值
|
||||
/// </summary>
|
||||
protected void SetHeaderByKey(Enum header, string value)
|
||||
{
|
||||
var fieldName = header.GetDescription();
|
||||
if (fieldName == null) return;
|
||||
var hasKey = Headers.ContainsKey(fieldName);
|
||||
if (!hasKey) Headers.Add(fieldName, value);
|
||||
Headers[fieldName] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置头值
|
||||
/// </summary>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <param name="value"></param>
|
||||
protected void SetHeaderByKey(string fieldName, string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fieldName)) return;
|
||||
var hasKey = Headers.ContainsKey(fieldName);
|
||||
if (!hasKey) Headers.Add(fieldName, value);
|
||||
Headers[fieldName] = value;
|
||||
}
|
||||
|
||||
private void GetRequestHeaders(IEnumerable<string> rows)
|
||||
{
|
||||
this.headers.Clear();
|
||||
if (rows == null || rows.Count() <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in rows)
|
||||
{
|
||||
string[] kv = item.SplitFirst(':');
|
||||
if (kv.Length == 2)
|
||||
{
|
||||
if (!this.headers.ContainsKey(kv[0]))
|
||||
{
|
||||
this.headers.Add(kv[0], kv[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置内容
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
public void SetContent(byte[] content)
|
||||
{
|
||||
this.content = content;
|
||||
this.Content_Length = content.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置内容
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="encoding"></param>
|
||||
/// <returns></returns>
|
||||
public void SetContent(string content, Encoding encoding = null)
|
||||
{
|
||||
//初始化内容
|
||||
encoding = encoding != null ? encoding : Encoding.UTF8;
|
||||
SetContent(encoding.GetBytes(content));
|
||||
}
|
||||
}
|
||||
}
|
||||
222
RRQMSocket.Http/Common/HttpRequest.cs
Normal file
@@ -0,0 +1,222 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Exceptions;
|
||||
using RRQMCore.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP请求定义
|
||||
/// </summary>
|
||||
public class HttpRequest : HttpBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 表单参数
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Forms { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取时候保持连接
|
||||
/// </summary>
|
||||
public bool KeepAlive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP请求方式
|
||||
/// </summary>
|
||||
public string Method { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// URL参数
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Params { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// url参数
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Query { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 相对路径(不含参数)
|
||||
/// </summary>
|
||||
public string RelativeURL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP(S)地址
|
||||
/// </summary>
|
||||
public string URL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构建响应头部
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private void BuildHeader(ByteBlock byteBlock)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine($"{this.Method} / HTTP/{this.ProtocolVersion}");
|
||||
|
||||
this.SetHeader(HttpHeaders.UserAgent, "RRQMHTTP");
|
||||
|
||||
if (!string.IsNullOrEmpty(this.Content_Type))
|
||||
stringBuilder.AppendLine("Content-Type: " + this.Content_Type);
|
||||
stringBuilder.AppendLine("Content-Length: " + this.Content_Length);
|
||||
|
||||
foreach (var headerkey in this.Headers.Keys)
|
||||
{
|
||||
stringBuilder.Append($"{headerkey}: ");
|
||||
stringBuilder.AppendLine(this.Headers[headerkey]);
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine();
|
||||
byteBlock.Write(this.Encoding.GetBytes(stringBuilder.ToString()));
|
||||
}
|
||||
|
||||
private void BuildContent(ByteBlock byteBlock)
|
||||
{
|
||||
if (this.Content_Length > 0)
|
||||
{
|
||||
if (this.Content_Length != this.Content.Length)
|
||||
{
|
||||
throw new RRQMException("内容实际长度与设置长度不相等");
|
||||
}
|
||||
byteBlock.Write(this.Content);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建响应数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
public override void Build(ByteBlock byteBlock)
|
||||
{
|
||||
BuildHeader(byteBlock);
|
||||
BuildContent(byteBlock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取头值
|
||||
/// </summary>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
public string GetHeader(string fieldName)
|
||||
{
|
||||
return GetHeaderByKey(fieldName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从内存中读取
|
||||
/// </summary>
|
||||
public override void ReadFromBase()
|
||||
{
|
||||
var first = Regex.Split(this.RequestLine, @"(\s+)").Where(e => e.Trim() != string.Empty).ToArray();
|
||||
if (first.Length > 0) this.Method = first[0];
|
||||
if (first.Length > 1)
|
||||
{
|
||||
this.URL = Uri.UnescapeDataString(first[1]);
|
||||
this.RelativeURL = first[1].Split('?')[0];
|
||||
}
|
||||
if (first.Length > 2)
|
||||
{
|
||||
string[] ps = first[2].Split('/');
|
||||
if (ps.Length == 2)
|
||||
{
|
||||
this.Protocols = ps[0];
|
||||
this.ProtocolVersion = ps[1];
|
||||
}
|
||||
}
|
||||
|
||||
string contentLength = this.GetHeader(HttpHeaders.ContentLength);
|
||||
int.TryParse(contentLength, out int content_Length);
|
||||
this.Content_Length = content_Length;
|
||||
|
||||
if (this.Method == "GET")
|
||||
{
|
||||
var isUrlencoded = this.URL.Contains('?');
|
||||
if (isUrlencoded) this.Query = GetRequestParameters(URL.Split('?')[1]);
|
||||
}
|
||||
if (this.ProtocolVersion == "1.1")
|
||||
{
|
||||
if (this.GetHeader(HttpHeaders.Connection) == "keep-alive")
|
||||
{
|
||||
this.KeepAlive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.KeepAlive = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.KeepAlive = false;
|
||||
}
|
||||
|
||||
if (this.Method == "POST")
|
||||
{
|
||||
this.Content_Type = GetHeader(HttpHeaders.ContentType);
|
||||
if (this.Content_Type == @"application/x-www-form-urlencoded")
|
||||
{
|
||||
this.Params = GetRequestParameters(this.Body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置头值
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <param name="value"></param>
|
||||
public void SetHeader(HttpHeaders header, string value)
|
||||
{
|
||||
SetHeaderByKey(header, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置头值
|
||||
/// </summary>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <param name="value"></param>
|
||||
public void SetHeader(string fieldName, string value)
|
||||
{
|
||||
SetHeaderByKey(fieldName, value);
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetRequestParameters(string row)
|
||||
{
|
||||
if (string.IsNullOrEmpty(row))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string[] kvs = row.Split('&');
|
||||
if (kvs == null || kvs.Count() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<string, string> pairs = new Dictionary<string, string>();
|
||||
foreach (var item in kvs)
|
||||
{
|
||||
string[] kv = item.SplitFirst('=');
|
||||
if (kv.Length == 2)
|
||||
{
|
||||
pairs.Add(kv[0], kv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
}
|
||||
}
|
||||
123
RRQMSocket.Http/Common/HttpResponse.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Http响应
|
||||
/// </summary>
|
||||
public class HttpResponse : HttpBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态码
|
||||
/// </summary>
|
||||
public string StatusCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取头数据
|
||||
/// </summary>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
public string GetHeader(string fieldName)
|
||||
{
|
||||
return GetHeaderByKey(fieldName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置头数据
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <param name="value"></param>
|
||||
public void SetHeader(HttpHeaders header, string value)
|
||||
{
|
||||
SetHeaderByKey(header, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置头数据
|
||||
/// </summary>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <param name="value"></param>
|
||||
public void SetHeader(string fieldName, string value)
|
||||
{
|
||||
SetHeaderByKey(fieldName, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建响应头部
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private void BuildHeader(ByteBlock byteBlock)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
if (!string.IsNullOrEmpty(StatusCode))
|
||||
stringBuilder.AppendLine($"HTTP/{this.ProtocolVersion} {StatusCode}");
|
||||
if (!string.IsNullOrEmpty(this.Content_Type))
|
||||
stringBuilder.AppendLine("Content-Type: " + this.Content_Type);
|
||||
stringBuilder.AppendLine("Content-Length: " + this.Content_Length);
|
||||
foreach (var headerkey in this.Headers.Keys)
|
||||
{
|
||||
stringBuilder.Append($"{headerkey}: ");
|
||||
stringBuilder.AppendLine(this.Headers[headerkey]);
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine();
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString()));
|
||||
}
|
||||
|
||||
private void BuildContent(ByteBlock byteBlock)
|
||||
{
|
||||
if (this.Content_Length > 0)
|
||||
{
|
||||
byteBlock.Write(this.Content);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建响应数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
public override void Build(ByteBlock byteBlock)
|
||||
{
|
||||
BuildHeader(byteBlock);
|
||||
BuildContent(byteBlock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取数据
|
||||
/// </summary>
|
||||
public override void ReadFromBase()
|
||||
{
|
||||
var first = Regex.Split(this.RequestLine, @"(\s+)").Where(e => e.Trim() != string.Empty).ToArray();
|
||||
if (first.Length > 0)
|
||||
{
|
||||
string[] ps = first[0].Split('/');
|
||||
if (ps.Length == 2)
|
||||
{
|
||||
this.Protocols = ps[0];
|
||||
this.ProtocolVersion = ps[1];
|
||||
}
|
||||
}
|
||||
if (first.Length > 1)
|
||||
{
|
||||
this.StatusCode = first[1];
|
||||
}
|
||||
string contentLength = this.GetHeader(HttpHeaders.ContentLength);
|
||||
int.TryParse(contentLength, out int content_Length);
|
||||
this.Content_Length = content_Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
185
RRQMSocket.Http/DataAdapter/HttpDataHandlingAdapter.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Helper;
|
||||
using RRQMCore.Log;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Http数据处理适配器
|
||||
/// </summary>
|
||||
public class HttpDataHandlingAdapter : DataHandlingAdapter
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="maxSize"></param>
|
||||
/// <param name="httpType"></param>
|
||||
public HttpDataHandlingAdapter(int maxSize, HttpType httpType)
|
||||
{
|
||||
this.MaxSize = maxSize;
|
||||
this.terminatorCode = Encoding.UTF8.GetBytes("\r\n\r\n");
|
||||
this.httpType = httpType;
|
||||
}
|
||||
|
||||
private HttpType httpType;
|
||||
private byte[] terminatorCode;
|
||||
|
||||
/// <summary>
|
||||
/// 允许的最大长度
|
||||
/// </summary>
|
||||
public int MaxSize { get; private set; }
|
||||
|
||||
private ByteBlock tempByteBlock;
|
||||
private ByteBlock bodyByteBlock;
|
||||
|
||||
private HttpBase httpBase;
|
||||
|
||||
/// <summary>
|
||||
/// 预处理
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
protected override void PreviewReceived(ByteBlock byteBlock)
|
||||
{
|
||||
byte[] buffer = byteBlock.Buffer;
|
||||
int r = byteBlock.Len;
|
||||
if (this.tempByteBlock != null)
|
||||
{
|
||||
this.tempByteBlock.Write(buffer, 0, r);
|
||||
buffer = this.tempByteBlock.ToArray();
|
||||
r = this.tempByteBlock.Pos;
|
||||
this.tempByteBlock.Dispose();
|
||||
this.tempByteBlock = null;
|
||||
}
|
||||
if (this.httpBase == null)
|
||||
{
|
||||
this.Split(buffer, 0, r);
|
||||
}
|
||||
else
|
||||
{
|
||||
int surLen = this.httpBase.Content_Length - this.bodyByteBlock.Len;
|
||||
if (r == surLen)
|
||||
{
|
||||
this.bodyByteBlock.Write(buffer, 0, surLen);
|
||||
this.PreviewHandle(this.httpBase);
|
||||
}
|
||||
else if (r > surLen)
|
||||
{
|
||||
this.bodyByteBlock.Write(buffer, 0, surLen);
|
||||
this.PreviewHandle(this.httpBase);
|
||||
Split(buffer, surLen, r - surLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bodyByteBlock.Write(buffer, 0, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Split(byte[] buffer, int offset, int length)
|
||||
{
|
||||
int index = buffer.IndexOfFirst(offset, length, this.terminatorCode);
|
||||
if (index > 0)
|
||||
{
|
||||
switch (this.httpType)
|
||||
{
|
||||
case HttpType.Server:
|
||||
this.httpBase = new HttpRequest();
|
||||
break;
|
||||
|
||||
case HttpType.Client:
|
||||
this.httpBase = new HttpResponse();
|
||||
break;
|
||||
}
|
||||
|
||||
this.httpBase.ReadHeaders(buffer, 0, index);
|
||||
|
||||
if (this.httpBase.Content_Length > 0)
|
||||
{
|
||||
this.bodyByteBlock = this.BytePool.GetByteBlock(this.httpBase.Content_Length);
|
||||
int surLength = length - (index + 1 + this.httpBase.Content_Length);
|
||||
if (surLength == 0)
|
||||
{
|
||||
this.bodyByteBlock.Write(buffer, index + 1, this.httpBase.Content_Length);
|
||||
this.PreviewHandle(this.httpBase);
|
||||
}
|
||||
else if (surLength >0)
|
||||
{
|
||||
this.bodyByteBlock.Write(buffer, index + 1, this.httpBase.Content_Length);
|
||||
int indexBuffer = index + 1 + this.httpBase.Content_Length;
|
||||
this.PreviewHandle(this.httpBase);
|
||||
this.Split(buffer, indexBuffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bodyByteBlock.Write(buffer, index + 1, length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PreviewHandle(this.httpBase);
|
||||
}
|
||||
}
|
||||
else if (length > this.MaxSize)
|
||||
{
|
||||
if (this.tempByteBlock != null)
|
||||
{
|
||||
this.tempByteBlock.Dispose();
|
||||
this.tempByteBlock = null;
|
||||
}
|
||||
|
||||
Logger.Debug(LogType.Error, this, "在已接收数据大于设定值的情况下未找到终止符号,已放弃接收");
|
||||
return;
|
||||
}
|
||||
else if (this.tempByteBlock == null)
|
||||
{
|
||||
this.tempByteBlock = this.BytePool.GetByteBlock(length * 2);
|
||||
this.tempByteBlock.Write(buffer,offset, length-offset);
|
||||
}
|
||||
}
|
||||
|
||||
private void PreviewHandle(HttpBase httpBase)
|
||||
{
|
||||
this.httpBase = null;
|
||||
try
|
||||
{
|
||||
if (this.bodyByteBlock != null)
|
||||
{
|
||||
httpBase.SetContent(this.bodyByteBlock.ToArray());
|
||||
this.bodyByteBlock.Dispose();
|
||||
this.bodyByteBlock = null;
|
||||
}
|
||||
httpBase.ReadFromBase();
|
||||
this.GoReceived(null, httpBase);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, "处理数据错误", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预处理
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="isAsync"></param>
|
||||
protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync)
|
||||
{
|
||||
this.GoSend(buffer, offset, length, isAsync);
|
||||
}
|
||||
}
|
||||
}
|
||||
327
RRQMSocket.Http/Enum/HttpHeaders.cs
Normal file
@@ -0,0 +1,327 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求头枚举
|
||||
/// </summary>
|
||||
public enum HttpHeaders : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache-Control 标头,指定请求/响应链上所有缓存控制机制必须服从的指令。
|
||||
/// </summary>
|
||||
[Description("Cache-Control")]
|
||||
CacheControl = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Connection 标头,指定特定连接需要的选项。
|
||||
/// </summary>
|
||||
[Description("Connection")]
|
||||
Connection = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Date 标头,指定开始创建请求的日期和时间。
|
||||
/// </summary>
|
||||
[Description("Date")]
|
||||
Date = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Keep-Alive 标头,指定用以维护持久性连接的参数。
|
||||
/// </summary>
|
||||
[Description("Keep-Alive")]
|
||||
KeepAlive = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Pragma 标头,指定可应用于请求/响应链上的任何代理的特定于实现的指令。
|
||||
/// </summary>
|
||||
[Description("Pragma")]
|
||||
Pragma = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Trailer 标头,指定标头字段显示在以 chunked 传输编码方式编码的消息的尾部。
|
||||
/// </summary>
|
||||
[Description("Trailer")]
|
||||
Trailer = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Transfer-Encoding 标头,指定对消息正文应用的转换的类型(如果有)。
|
||||
/// </summary>
|
||||
[Description("Transfer-Encoding")]
|
||||
TransferEncoding = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Upgrade 标头,指定客户端支持的附加通信协议。
|
||||
/// </summary>
|
||||
[Description("Upgrade")]
|
||||
Upgrade = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Via 标头,指定网关和代理程序要使用的中间协议。
|
||||
/// </summary>
|
||||
[Description("Via")]
|
||||
Via = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Warning 标头,指定关于可能未在消息中反映的消息的状态或转换的附加信息。
|
||||
/// </summary>
|
||||
[Description("Warning")]
|
||||
Warning = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Allow 标头,指定支持的 HTTP 方法集。
|
||||
/// </summary>
|
||||
[Description("Allow")]
|
||||
Allow = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Content-Length 标头,指定伴随正文数据的长度(以字节为单位)。
|
||||
/// </summary>
|
||||
[Description("Content-Length")]
|
||||
ContentLength = 11,
|
||||
|
||||
/// <summary>
|
||||
/// Content-Type 标头,指定伴随正文数据的 MIME 类型。
|
||||
/// </summary>
|
||||
[Description("Content-Type")]
|
||||
ContentType = 12,
|
||||
|
||||
/// <summary>
|
||||
/// Content-Encoding 标头,指定已应用于伴随正文数据的编码。
|
||||
/// </summary>
|
||||
[Description("Content-Encoding")]
|
||||
ContentEncoding = 13,
|
||||
|
||||
/// <summary>
|
||||
/// Content-Langauge 标头,指定伴随正文数据的自然语言。
|
||||
/// </summary>
|
||||
[Description("Content-Langauge")]
|
||||
ContentLanguage = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Content-Location 标头,指定可从其中获得伴随正文的 URI。
|
||||
/// </summary>
|
||||
[Description("Content-Location")]
|
||||
ContentLocation = 15,
|
||||
|
||||
/// <summary>
|
||||
/// Content-MD5 标头,指定伴随正文数据的 MD5 摘要,用于提供端到端消息完整性检查。
|
||||
/// </summary>
|
||||
[Description("Content-MD5")]
|
||||
ContentMd5 = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Content-Range 标头,指定在完整正文中应用伴随部分正文数据的位置。
|
||||
/// </summary>
|
||||
[Description("Content-Range")]
|
||||
ContentRange = 17,
|
||||
|
||||
/// <summary>
|
||||
/// Expires 标头,指定日期和时间,在此之后伴随的正文数据应视为陈旧的。
|
||||
/// </summary>
|
||||
[Description("Expires")]
|
||||
Expires = 18,
|
||||
|
||||
/// <summary>
|
||||
/// Last-Modified 标头,指定上次修改伴随的正文数据的日期和时间。
|
||||
/// </summary>
|
||||
[Description("Last-Modified")]
|
||||
LastModified = 19,
|
||||
|
||||
/// <summary>
|
||||
/// Accept 标头,指定响应可接受的 MIME 类型。
|
||||
/// </summary>
|
||||
[Description("Accept")]
|
||||
Accept = 20,
|
||||
|
||||
/// <summary>
|
||||
/// Accept-Charset 标头,指定响应可接受的字符集。
|
||||
/// </summary>
|
||||
[Description("Accept-Charset")]
|
||||
AcceptCharset = 21,
|
||||
|
||||
/// <summary>
|
||||
/// Accept-Encoding 标头,指定响应可接受的内容编码。
|
||||
/// </summary>
|
||||
[Description("Accept-Encoding")]
|
||||
AcceptEncoding = 22,
|
||||
|
||||
/// <summary>
|
||||
/// Accept-Langauge 标头,指定响应首选的自然语言。
|
||||
/// </summary>
|
||||
[Description("Accept-Langauge")]
|
||||
AcceptLanguage = 23,
|
||||
|
||||
/// <summary>
|
||||
/// Authorization 标头,指定客户端为向服务器验证自身身份而出示的凭据。
|
||||
/// </summary>
|
||||
[Description("Authorization")]
|
||||
Authorization = 24,
|
||||
|
||||
/// <summary>
|
||||
/// Cookie 标头,指定向服务器提供的 Cookie 数据。
|
||||
/// </summary>
|
||||
[Description("Cookie")]
|
||||
Cookie = 25,
|
||||
|
||||
/// <summary>
|
||||
/// Expect 标头,指定客户端要求的特定服务器行为。
|
||||
/// </summary>
|
||||
[Description("Expect")]
|
||||
Expect = 26,
|
||||
|
||||
/// <summary>
|
||||
/// From 标头,指定控制请求用户代理的用户的 Internet 电子邮件地址。
|
||||
/// </summary>
|
||||
[Description("From")]
|
||||
From = 27,
|
||||
|
||||
/// <summary>
|
||||
/// Host 标头,指定所请求资源的主机名和端口号。
|
||||
/// </summary>
|
||||
[Description("Host")]
|
||||
Host = 28,
|
||||
|
||||
/// <summary>
|
||||
/// If-Match 标头,指定仅当客户端的指示资源的缓存副本是最新的时,才执行请求的操作。
|
||||
/// </summary>
|
||||
[Description("If-Match")]
|
||||
IfMatch = 29,
|
||||
|
||||
/// <summary>
|
||||
/// If-Modified-Since 标头,指定仅当自指示的数据和时间之后修改了请求的资源时,才执行请求的操作。
|
||||
/// </summary>
|
||||
[Description("If-Modified-Since")]
|
||||
IfModifiedSince = 30,
|
||||
|
||||
/// <summary>
|
||||
/// If-None-Match 标头,指定仅当客户端的指示资源的缓存副本都不是最新的时,才执行请求的操作。
|
||||
/// </summary>
|
||||
[Description("If-None-Match")]
|
||||
IfNoneMatch = 31,
|
||||
|
||||
/// <summary>
|
||||
/// If-Range 标头,指定如果客户端的缓存副本是最新的,仅发送指定范围的请求资源。
|
||||
/// </summary>
|
||||
[Description("If-Range")]
|
||||
IfRange = 32,
|
||||
|
||||
/// <summary>
|
||||
/// If-Unmodified-Since 标头,指定仅当自指示的日期和时间之后修改了请求的资源时,才执行请求的操作。
|
||||
/// </summary>
|
||||
[Description("If-Unmodified-Since")]
|
||||
IfUnmodifiedSince = 33,
|
||||
|
||||
/// <summary>
|
||||
/// Max-Forwards 标头,指定一个整数,表示此请求还可转发的次数。
|
||||
/// </summary>
|
||||
[Description("Max-Forwards")]
|
||||
MaxForwards = 34,
|
||||
|
||||
/// <summary>
|
||||
/// Proxy-Authorization 标头,指定客户端为向代理验证自身身份而出示的凭据。
|
||||
/// </summary>
|
||||
[Description("Proxy-Authorization")]
|
||||
ProxyAuthorization = 35,
|
||||
|
||||
/// <summary>
|
||||
/// Referer 标头,指定从中获得请求 URI 的资源的 URI。
|
||||
/// </summary>
|
||||
[Description("Referer")]
|
||||
Referer = 36,
|
||||
|
||||
/// <summary>
|
||||
/// Range 标头,指定代替整个响应返回的客户端请求的响应的子范围。
|
||||
/// </summary>
|
||||
[Description("Range")]
|
||||
Range = 37,
|
||||
|
||||
/// <summary>
|
||||
/// TE 标头,指定响应可接受的传输编码方式。
|
||||
/// </summary>
|
||||
[Description("TE")]
|
||||
Te = 38,
|
||||
|
||||
/// <summary>
|
||||
/// Translate 标头,与 WebDAV 功能一起使用的 HTTP 规范的 Microsoft 扩展。
|
||||
/// </summary>
|
||||
[Description("Translate")]
|
||||
Translate = 39,
|
||||
|
||||
/// <summary>
|
||||
/// User-Agent 标头,指定有关客户端代理的信息。
|
||||
/// </summary>
|
||||
[Description("User-Agent")]
|
||||
UserAgent = 40,
|
||||
|
||||
/// <summary>
|
||||
/// Accept-Ranges 标头,指定服务器接受的范围。
|
||||
/// </summary>
|
||||
[Description("Accept-Ranges")]
|
||||
AcceptRanges = 41,
|
||||
|
||||
/// <summary>
|
||||
/// Age 标头,指定自起始服务器生成响应以来的时间长度(以秒为单位)。
|
||||
/// </summary>
|
||||
[Description("Age")]
|
||||
Age = 42,
|
||||
|
||||
/// <summary>
|
||||
/// Etag 标头,指定请求的变量的当前值。
|
||||
/// </summary>
|
||||
[Description("Etag")]
|
||||
ETag = 43,
|
||||
|
||||
/// <summary>
|
||||
/// Location 标头,指定为获取请求的资源而将客户端重定向到的 URI。
|
||||
/// </summary>
|
||||
[Description("Location")]
|
||||
Location = 44,
|
||||
|
||||
/// <summary>
|
||||
/// Proxy-Authenticate 标头,指定客户端必须对代理验证其自身。
|
||||
/// </summary>
|
||||
[Description("Proxy-Authenticate")]
|
||||
ProxyAuthenticate = 45,
|
||||
|
||||
/// <summary>
|
||||
/// Retry-After 标头,指定某个时间(以秒为单位)或日期和时间,在此时间之后客户端可以重试其请求。
|
||||
/// </summary>
|
||||
[Description("Retry-After")]
|
||||
RetryAfter = 46,
|
||||
|
||||
/// <summary>
|
||||
/// Server 标头,指定关于起始服务器代理的信息。
|
||||
/// </summary>
|
||||
[Description("Server")]
|
||||
Server = 47,
|
||||
|
||||
/// <summary>
|
||||
/// Set-Cookie 标头,指定提供给客户端的 Cookie 数据。
|
||||
/// </summary>
|
||||
[Description("Set-Cookie")]
|
||||
SetCookie = 48,
|
||||
|
||||
/// <summary>
|
||||
/// Vary 标头,指定用于确定缓存的响应是否为新响应的请求标头。
|
||||
/// </summary>
|
||||
[Description("Vary")]
|
||||
Vary = 49,
|
||||
|
||||
/// <summary>
|
||||
/// WWW-Authenticate 标头,指定客户端必须对服务器验证其自身。
|
||||
/// </summary>
|
||||
[Description("WWW-Authenticate")]
|
||||
WwwAuthenticate = 50,
|
||||
}
|
||||
}
|
||||
30
RRQMSocket.Http/Enum/HttpType.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 解析类型
|
||||
/// </summary>
|
||||
public enum HttpType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器
|
||||
/// </summary>
|
||||
Server,
|
||||
|
||||
/// <summary>
|
||||
/// 客户端
|
||||
/// </summary>
|
||||
Client
|
||||
}
|
||||
}
|
||||
72
RRQMSocket.Http/Helper/EnumHelper.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 枚举扩展类
|
||||
/// </summary>
|
||||
public static class EnumHelper
|
||||
{
|
||||
private static ConcurrentDictionary<Enum, string> _cache = new ConcurrentDictionary<Enum, string>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取DescriptionAttribute
|
||||
/// </summary>
|
||||
/// <param name="enum"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDescription(this Enum @enum)
|
||||
{
|
||||
var result = string.Empty;
|
||||
|
||||
if (@enum == null) return result;
|
||||
|
||||
if (!_cache.TryGetValue(@enum, out result))
|
||||
{
|
||||
var typeInfo = @enum.GetType();
|
||||
|
||||
var enumValues = typeInfo.GetEnumValues();
|
||||
|
||||
foreach (var value in enumValues)
|
||||
{
|
||||
if (@enum.Equals(value))
|
||||
{
|
||||
MemberInfo memberInfo = typeInfo.GetMember(value.ToString()).First();
|
||||
|
||||
result = memberInfo.GetCustomAttribute<DescriptionAttribute>().Description;
|
||||
}
|
||||
}
|
||||
|
||||
_cache.TryAdd(@enum, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据字符串获取枚举
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetEnum<T>(string str, out T result) where T : struct
|
||||
{
|
||||
return Enum.TryParse<T>(str, out result);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
RRQMSocket.Http/Helper/RequestHelper.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求辅助类
|
||||
/// </summary>
|
||||
public static class RequestHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 从Xml格式
|
||||
/// </summary>
|
||||
/// <param name="httpRequest"></param>
|
||||
/// <param name="xmlText"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpRequest FromXML(this HttpRequest httpRequest, string xmlText)
|
||||
{
|
||||
httpRequest.SetContent(xmlText);
|
||||
httpRequest.Content_Type = "text/xml";
|
||||
return httpRequest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Json
|
||||
/// </summary>
|
||||
/// <param name="httpRequest"></param>
|
||||
/// <param name="jsonText"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpRequest FromJson(this HttpRequest httpRequest, string jsonText)
|
||||
{
|
||||
httpRequest.SetContent(jsonText);
|
||||
httpRequest.Content_Type = "text/json";
|
||||
return httpRequest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从文本
|
||||
/// </summary>
|
||||
/// <param name="httpRequest"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpRequest FromText(this HttpRequest httpRequest, string text)
|
||||
{
|
||||
httpRequest.SetContent(text);
|
||||
httpRequest.Content_Type = "text/plain";
|
||||
return httpRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
100
RRQMSocket.Http/Helper/ResponseHelper.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Helper;
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// 响应扩展
|
||||
/// </summary>
|
||||
public static class ResponseHelper
|
||||
{
|
||||
///// <summary>
|
||||
///// 从文件
|
||||
///// </summary>
|
||||
///// <param name="response"></param>
|
||||
///// <param name="fileName"></param>
|
||||
///// <returns></returns>
|
||||
//public static HttpResponse FromFile(this HttpResponse response, string fileName)
|
||||
//{
|
||||
// if (!File.Exists(fileName))
|
||||
// {
|
||||
// response.SetContent("<html><body><h1>404 -RRQM Not Found</h1></body></html>");
|
||||
// response.StatusCode = "404";
|
||||
// response.Content_Type = "text/html";
|
||||
// return response;
|
||||
// }
|
||||
|
||||
// var content = File.ReadAllBytes(fileName);
|
||||
// response.SetContent(content);
|
||||
// return response.FromSuccess();
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 从Xml格式
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="xmlText"></param>
|
||||
/// <param name="statusCode"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponse FromXML(this HttpResponse response, string xmlText, string statusCode = "200")
|
||||
{
|
||||
response.SetContent(xmlText);
|
||||
response.Content_Type = "text/xml";
|
||||
return response.FromSuccess(statusCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Json
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="jsonText"></param>
|
||||
/// <param name="statusCode"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponse FromJson(this HttpResponse response, string jsonText, string statusCode = "200")
|
||||
{
|
||||
response.SetContent(jsonText);
|
||||
response.Content_Type = "text/json";
|
||||
return response.FromSuccess(statusCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从文本
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="statusCode"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponse FromText(this HttpResponse response, string text, string statusCode = "200")
|
||||
{
|
||||
response.SetContent(text);
|
||||
response.Content_Type = "text/plain";
|
||||
|
||||
return response.FromSuccess(statusCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回成功
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="statusCode"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponse FromSuccess(this HttpResponse response, string statusCode = "200")
|
||||
{
|
||||
response.StatusCode = statusCode;
|
||||
response.SetHeader(HttpHeaders.Server, $"RRQMSocket.Http {HttpResponse.ServerVersion}");
|
||||
response.SetHeader(HttpHeaders.Date, DateTime.Now.ToGMTString("r"));
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.Http/LICENSE
Normal file
@@ -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 procotol 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.
|
||||
BIN
RRQMSocket.Http/RRQM.ico
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMSocket.Http/RRQM.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
70
RRQMSocket.Http/RRQMSocket.Http.csproj
Normal file
@@ -0,0 +1,70 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
|
||||
<ApplicationIcon>RRQM.ico</ApplicationIcon>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
|
||||
<Version>5.5.0</Version>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
|
||||
<Description>介绍:这是一个能够简单解析HTTP的扩展库,能够为RRQMSocket扩展解析HTTP的能力。
|
||||
|
||||
RRQMSocket is an extension library that can easily parse HTTP. The RRQMSocket extension has the ability to parse HTTP.
|
||||
|
||||
更新说明:
|
||||
优化:优化Http适配器
|
||||
|
||||
API:https://gitee.com/RRQM_OS/RRQM/wikis/pages</Description>
|
||||
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
|
||||
<PackageIconUrl></PackageIconUrl>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PackageIcon>RRQM.png</PackageIcon>
|
||||
<Authors>若汝棋茗</Authors>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageTags>HTTP;IOCP</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.Http.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.Http.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net45\RRQMSocket.Http.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\net45\RRQMSocket.Http.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.Http.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.Http.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="RRQM.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RRQMSocket" Version="5.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
43
RRQMSocket.RPC.JsonRpc/Attribute/JsonRpcAttribute.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// 适用于XmlRpc的标记
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class JsonRpcAttribute : RPCAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public JsonRpcAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="methodKey"></param>
|
||||
public JsonRpcAttribute(string methodKey)
|
||||
{
|
||||
this.MethodKey = methodKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务唯一标识
|
||||
/// </summary>
|
||||
public string MethodKey { get; private set; }
|
||||
}
|
||||
}
|
||||
70
RRQMSocket.RPC.JsonRpc/Common/ActionMap.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务映射图
|
||||
/// </summary>
|
||||
public class ActionMap : IEnumerable<KeyValuePair<string, MethodInstance>>
|
||||
{
|
||||
internal ActionMap()
|
||||
{
|
||||
this.actionMap = new Dictionary<string, MethodInstance>();
|
||||
}
|
||||
|
||||
private Dictionary<string, MethodInstance> actionMap;
|
||||
|
||||
internal void Add(string actionKey, MethodInstance methodInstance)
|
||||
{
|
||||
this.actionMap.Add(actionKey, methodInstance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务键集合
|
||||
/// </summary>
|
||||
public IEnumerable<string> ActionKeys { get { return this.actionMap.Keys; } }
|
||||
|
||||
/// <summary>
|
||||
/// 通过routeUrl获取函数实例
|
||||
/// </summary>
|
||||
/// <param name="actionKey"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGet(string actionKey, out MethodInstance methodInstance)
|
||||
{
|
||||
if (this.actionMap.ContainsKey(actionKey))
|
||||
{
|
||||
methodInstance = this.actionMap[actionKey];
|
||||
return true;
|
||||
}
|
||||
methodInstance = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回迭代器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<KeyValuePair<string, MethodInstance>> GetEnumerator()
|
||||
{
|
||||
return this.actionMap.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.actionMap.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
31
RRQMSocket.RPC.JsonRpc/Common/JsonRequestContext.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Linq;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpc调用器
|
||||
/// </summary>
|
||||
public class JsonRequestContext
|
||||
{
|
||||
#pragma warning disable
|
||||
public string jsonrpc;
|
||||
public string method;
|
||||
public object[] parameters;
|
||||
public JToken @params;
|
||||
public string id;
|
||||
public bool needResponse;
|
||||
#pragma warning restore
|
||||
}
|
||||
}
|
||||
40
RRQMSocket.RPC.JsonRpc/Common/JsonResponseContext.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
#pragma warning disable CS1591
|
||||
|
||||
/// <summary>
|
||||
/// JsonRpc响应器
|
||||
/// </summary>
|
||||
public class JsonResponseContext
|
||||
{
|
||||
public string jsonrpc;
|
||||
|
||||
public object result;
|
||||
|
||||
public error error;
|
||||
|
||||
public string id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 错误
|
||||
/// </summary>
|
||||
public class error
|
||||
{
|
||||
public int code;
|
||||
|
||||
public string message;
|
||||
}
|
||||
}
|
||||
22
RRQMSocket.RPC.JsonRpc/Common/JsonRpcWaitContext.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Run;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
internal class JsonRpcWaitContext : WaitResult
|
||||
{
|
||||
internal object Return;
|
||||
|
||||
internal error error;
|
||||
}
|
||||
}
|
||||
54
RRQMSocket.RPC.JsonRpc/Config/JsonRpcClientConfig.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Dependency;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcClient配置
|
||||
/// </summary>
|
||||
public class JsonRpcClientConfig : TcpClientConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 协议类型
|
||||
/// </summary>
|
||||
public JsonRpcProtocolType ProtocolType
|
||||
{
|
||||
get { return (JsonRpcProtocolType)GetValue(ProtocolTypeProperty); }
|
||||
set { SetValue(ProtocolTypeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 协议类型,
|
||||
/// 所需类型<see cref="JsonRpcProtocolType"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ProtocolTypeProperty =
|
||||
DependencyProperty.Register("ProtocolType", typeof(JsonRpcProtocolType), typeof(JsonRpcClientConfig), JsonRpcProtocolType.Tcp);
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return (int)GetValue(MaxPackageSizeProperty); }
|
||||
set { SetValue(MaxPackageSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度,所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPackageSizeProperty =
|
||||
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(JsonRpcClientConfig), 1024);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
55
RRQMSocket.RPC.JsonRpc/Config/JsonRpcParserConfig.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Dependency;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcParser配置
|
||||
/// </summary>
|
||||
public class JsonRpcParserConfig : TcpServiceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 协议类型
|
||||
/// </summary>
|
||||
public JsonRpcProtocolType ProtocolType
|
||||
{
|
||||
get { return (JsonRpcProtocolType)GetValue(ProtocolTypeProperty); }
|
||||
set { SetValue(ProtocolTypeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 协议类型,
|
||||
/// 所需类型<see cref="JsonRpcProtocolType"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ProtocolTypeProperty =
|
||||
DependencyProperty.Register("ProtocolType", typeof(JsonRpcProtocolType), typeof(JsonRpcParserConfig), JsonRpcProtocolType.Tcp);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return (int)GetValue(MaxPackageSizeProperty); }
|
||||
set { SetValue(MaxPackageSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度,所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPackageSizeProperty =
|
||||
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(JsonRpcParserConfig), 1024);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
29
RRQMSocket.RPC.JsonRpc/Enum/JsonRpcProtocolType.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpc协议类型
|
||||
/// </summary>
|
||||
public enum JsonRpcProtocolType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 普通TCP协议
|
||||
/// </summary>
|
||||
Tcp,
|
||||
|
||||
/// <summary>
|
||||
/// Http协议
|
||||
/// </summary>
|
||||
Http
|
||||
}
|
||||
}
|
||||
22
RRQMSocket.RPC.JsonRpc/Interface/IJsonRpcClient.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMSocket.RPC.RRQMRPC;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// Json客户端RPC接口
|
||||
/// </summary>
|
||||
public interface IJsonRpcClient : IRpcClient
|
||||
{
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.RPC.JsonRpc/LICENSE
Normal file
@@ -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.
|
||||
BIN
RRQMSocket.RPC.JsonRpc/RRQM.ico
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMSocket.RPC.JsonRpc/RRQM.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
71
RRQMSocket.RPC.JsonRpc/RRQMSocket.RPC.JsonRpc.csproj
Normal file
@@ -0,0 +1,71 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
|
||||
<ApplicationIcon>RRQM.ico</ApplicationIcon>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
|
||||
<Version>5.5.0</Version>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
|
||||
<Description>介绍:这是一个扩展于RRQMSocket.RPC的JsonRpc组件,可以通过该组件直接创建JsonRpc服务解析器,让Web端、移动端可以跨语言调用RPC函数。功能支持JsonRpc全功能。
|
||||
|
||||
更新说明:
|
||||
增加:配置中通过MaxPackageSize属性设定可处理数据的最大值。
|
||||
修复:内联调用。
|
||||
|
||||
Demo:https://gitee.com/RRQM_OS/RRQMBox
|
||||
API:https://gitee.com/RRQM_OS/RRQM/wikis/pages</Description>
|
||||
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
|
||||
<PackageIconUrl></PackageIconUrl>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PackageIcon>RRQM.png</PackageIcon>
|
||||
<Authors>若汝棋茗</Authors>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageTags>JsonRpc;Socket;IOCP</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.JsonRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.JsonRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net45\RRQMSocket.JsonRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\net45\RRQMSocket.JsonRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.JsonRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.JsonRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="RRQM.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RRQMSocket.Http" Version="5.5.0" />
|
||||
<PackageReference Include="RRQMSocket.RPC" Version="5.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
382
RRQMSocket.RPC.JsonRpc/Socket/JsonRpcClient.cs
Normal file
@@ -0,0 +1,382 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Exceptions;
|
||||
using RRQMCore.Helper;
|
||||
using RRQMCore.Run;
|
||||
using RRQMCore.XREF.Newtonsoft.Json;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Linq;
|
||||
using RRQMSocket.Http;
|
||||
using RRQMSocket.RPC.RRQMRPC;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpc客户端
|
||||
/// </summary>
|
||||
public class JsonRpcClient : TcpClient, IJsonRpcClient
|
||||
{
|
||||
private int maxPackageSize;
|
||||
|
||||
private JsonRpcProtocolType protocolType;
|
||||
|
||||
private RRQMWaitHandle<WaitResult> waitHandle;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public JsonRpcClient()
|
||||
{
|
||||
waitHandle = new RRQMWaitHandle<WaitResult>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return maxPackageSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 协议类型
|
||||
/// </summary>
|
||||
public JsonRpcProtocolType ProtocolType
|
||||
{
|
||||
get { return protocolType; }
|
||||
}
|
||||
/// <summary>
|
||||
/// RPC调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="invokeOption">调用配置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="types"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <returns></returns>
|
||||
public T Invoke<T>(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types)
|
||||
{
|
||||
JsonRpcWaitContext context = new JsonRpcWaitContext();
|
||||
WaitData<WaitResult> waitData = this.waitHandle.GetWaitData(context);
|
||||
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
if (invokeOption == null)
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
try
|
||||
{
|
||||
JObject jobject = new JObject();
|
||||
jobject.Add("jsonrpc", JToken.FromObject("2.0"));
|
||||
jobject.Add("method", JToken.FromObject(method));
|
||||
jobject.Add("params", JToken.FromObject(parameters));
|
||||
|
||||
if (invokeOption.FeedbackType == FeedbackType.WaitInvoke)
|
||||
{
|
||||
jobject.Add("id", JToken.FromObject(context.Sign.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
jobject.Add("id", null);
|
||||
}
|
||||
switch (this.protocolType)
|
||||
{
|
||||
case JsonRpcProtocolType.Tcp:
|
||||
{
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(jobject.ToString(Formatting.None)));
|
||||
break;
|
||||
}
|
||||
case JsonRpcProtocolType.Http:
|
||||
{
|
||||
HttpRequest httpRequest = new HttpRequest();
|
||||
httpRequest.Method = "POST";
|
||||
httpRequest.FromJson(jobject.ToString(Formatting.None));
|
||||
httpRequest.Build(byteBlock);
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.SendAsync(byteBlock);
|
||||
}
|
||||
break;
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.Send(byteBlock);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.waitHandle.Destroy(waitData);
|
||||
return default;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
waitData.Wait(invokeOption.Timeout);
|
||||
JsonRpcWaitContext resultContext = (JsonRpcWaitContext)waitData.WaitResult;
|
||||
this.waitHandle.Destroy(waitData);
|
||||
|
||||
if (resultContext.Status == 0)
|
||||
{
|
||||
throw new RRQMTimeoutException("等待结果超时");
|
||||
}
|
||||
if (resultContext.error != null)
|
||||
{
|
||||
throw new RRQMRPCException(resultContext.error.message);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (typeof(T).IsPrimitive || typeof(T) == typeof(string))
|
||||
{
|
||||
return (T)resultContext.Return.ToString().ParseToType(typeof(T));
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(resultContext.Return.ToString());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="invokeOption">调用配置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="types"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public void Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types)
|
||||
{
|
||||
JsonRpcWaitContext context = new JsonRpcWaitContext();
|
||||
WaitData<WaitResult> waitData = this.waitHandle.GetWaitData(context);
|
||||
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
if (invokeOption == null)
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
try
|
||||
{
|
||||
JObject jobject = new JObject();
|
||||
jobject.Add("jsonrpc", JToken.FromObject("2.0"));
|
||||
jobject.Add("method", JToken.FromObject(method));
|
||||
jobject.Add("params", JToken.FromObject(parameters));
|
||||
|
||||
if (invokeOption.FeedbackType == FeedbackType.WaitInvoke)
|
||||
{
|
||||
jobject.Add("id", JToken.FromObject(context.Sign.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
jobject.Add("id", null);
|
||||
}
|
||||
switch (this.protocolType)
|
||||
{
|
||||
case JsonRpcProtocolType.Tcp:
|
||||
{
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(jobject.ToString(Formatting.None)));
|
||||
break;
|
||||
}
|
||||
case JsonRpcProtocolType.Http:
|
||||
{
|
||||
HttpRequest httpRequest = new HttpRequest();
|
||||
httpRequest.Method = "POST";
|
||||
httpRequest.FromJson(jobject.ToString(Formatting.None));
|
||||
httpRequest.Build(byteBlock);
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.SendAsync(byteBlock);
|
||||
}
|
||||
break;
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.Send(byteBlock);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.waitHandle.Destroy(waitData);
|
||||
return;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
waitData.Wait(invokeOption.Timeout);
|
||||
JsonRpcWaitContext resultContext = (JsonRpcWaitContext)waitData.WaitResult;
|
||||
this.waitHandle.Destroy(waitData);
|
||||
|
||||
if (resultContext.Status == 0)
|
||||
{
|
||||
throw new RRQMTimeoutException("等待结果超时");
|
||||
}
|
||||
if (resultContext.error != null)
|
||||
{
|
||||
throw new RRQMRPCException(resultContext.error.message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="invokeOption">调用配置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public void Invoke(string method, InvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
this.Invoke(method, invokeOption, ref parameters, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="invokeOption">调用配置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <returns></returns>
|
||||
public T Invoke<T>(string method, InvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
return this.Invoke<T>(method, invokeOption, ref parameters, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <param name="obj"></param>
|
||||
protected override void HandleReceivedData(ByteBlock byteBlock, object obj)
|
||||
{
|
||||
switch (this.protocolType)
|
||||
{
|
||||
case JsonRpcProtocolType.Tcp:
|
||||
{
|
||||
string jsonString = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
JsonResponseContext responseContext = (JsonResponseContext)JsonConvert.DeserializeObject(jsonString, typeof(JsonResponseContext));
|
||||
if (responseContext != null)
|
||||
{
|
||||
JsonRpcWaitContext waitContext = new JsonRpcWaitContext();
|
||||
waitContext.Status = 1;
|
||||
waitContext.Sign = int.Parse(responseContext.id);
|
||||
waitContext.error = responseContext.error;
|
||||
waitContext.Return = responseContext.result;
|
||||
this.waitHandle.SetRun(waitContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JsonRpcProtocolType.Http:
|
||||
{
|
||||
HttpResponse httpResponse = (HttpResponse)obj;
|
||||
JsonResponseContext responseContext = (JsonResponseContext)JsonConvert.DeserializeObject(httpResponse.Body, typeof(JsonResponseContext));
|
||||
if (responseContext != null)
|
||||
{
|
||||
JsonRpcWaitContext waitContext = new JsonRpcWaitContext();
|
||||
waitContext.Status = 1;
|
||||
waitContext.Sign = int.Parse(responseContext.id);
|
||||
waitContext.error = responseContext.error;
|
||||
waitContext.Return = responseContext.result;
|
||||
this.waitHandle.SetRun(waitContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 载入配置
|
||||
/// </summary>
|
||||
/// <param name="clientConfig"></param>
|
||||
protected override void LoadConfig(TcpClientConfig clientConfig)
|
||||
{
|
||||
base.LoadConfig(clientConfig);
|
||||
this.maxPackageSize = (int)clientConfig.GetValue(JsonRpcClientConfig.MaxPackageSizeProperty);
|
||||
|
||||
this.protocolType = (JsonRpcProtocolType)clientConfig.GetValue(JsonRpcClientConfig.ProtocolTypeProperty);
|
||||
switch (this.protocolType)
|
||||
{
|
||||
case JsonRpcProtocolType.Tcp:
|
||||
base.SetDataHandlingAdapter(new TerminatorDataHandlingAdapter(this.maxPackageSize, "\r\n"));
|
||||
break;
|
||||
|
||||
case JsonRpcProtocolType.Http:
|
||||
base.SetDataHandlingAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Client));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
424
RRQMSocket.RPC.JsonRpc/Socket/JsonRpcParser.cs
Normal file
@@ -0,0 +1,424 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Log;
|
||||
using RRQMCore.XREF.Newtonsoft.Json;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Linq;
|
||||
using RRQMSocket.Http;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcParser解析器
|
||||
/// </summary>
|
||||
public class JsonRpcParser : TcpService<JsonRpcSocketClient>, IRPCParser
|
||||
{
|
||||
private ActionMap actionMap;
|
||||
|
||||
private MethodMap methodMap;
|
||||
|
||||
private JsonRpcProtocolType protocolType;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public JsonRpcParser()
|
||||
{
|
||||
this.actionMap = new ActionMap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数键映射图
|
||||
/// </summary>
|
||||
public ActionMap ActionMap { get { return this.actionMap; } }
|
||||
|
||||
private int maxPackageSize;
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return maxPackageSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数映射
|
||||
/// </summary>
|
||||
public MethodMap MethodMap
|
||||
{
|
||||
get { return methodMap; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 协议类型
|
||||
/// </summary>
|
||||
public JsonRpcProtocolType ProtocolType
|
||||
{
|
||||
get { return protocolType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所属服务器
|
||||
/// </summary>
|
||||
public RPCService RPCService { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行函数
|
||||
/// </summary>
|
||||
public Action<IRPCParser, MethodInvoker, MethodInstance> RRQMExecuteMethod { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结束调用
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
ISocketClient socketClient = (ISocketClient)methodInvoker.Caller;
|
||||
error error = new error();
|
||||
|
||||
switch (methodInvoker.Status)
|
||||
{
|
||||
case InvokeStatus.Success:
|
||||
{
|
||||
error = null;
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnFound:
|
||||
{
|
||||
error.code = -32601;
|
||||
error.message = "函数未找到";
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnEnable:
|
||||
{
|
||||
error.code = -32601;
|
||||
error.message = "函数已被禁用";
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Abort:
|
||||
{
|
||||
error.code = -32601;
|
||||
error.message = "函数已被中断执行";
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.InvocationException:
|
||||
{
|
||||
error.code = -32603;
|
||||
error.message = "函数内部异常";
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Exception:
|
||||
{
|
||||
error.code = -32602;
|
||||
error.message = methodInvoker.StatusMessage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
JsonRequestContext jsonRequestContext = (JsonRequestContext)methodInvoker.Flag;
|
||||
if (jsonRequestContext.needResponse)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
this.BuildResponseByteBlock(byteBlock, methodInvoker, jsonRequestContext.id, methodInvoker.ReturnParameter, error);
|
||||
if (socketClient.Online)
|
||||
{
|
||||
try
|
||||
{
|
||||
string s = Encoding.UTF8.GetString(byteBlock.ToArray());
|
||||
socketClient.Send(byteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="methodInstances"></param>
|
||||
public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
foreach (var att in methodInstance.RPCAttributes)
|
||||
{
|
||||
if (att is JsonRpcAttribute attribute)
|
||||
{
|
||||
if (methodInstance.IsByRef)
|
||||
{
|
||||
throw new RRQMRPCException($"JsonRpc服务中不允许有out及ref关键字,服务:{methodInstance.Method.Name}");
|
||||
}
|
||||
string actionKey = string.IsNullOrEmpty(attribute.MethodKey) ? methodInstance.Method.Name : attribute.MethodKey;
|
||||
|
||||
try
|
||||
{
|
||||
this.actionMap.Add(actionKey, methodInstance);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new RRQMRPCException($"函数键为{actionKey}的方法已注册。");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消注册服务
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="methodInstances"></param>
|
||||
public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置执行委托
|
||||
/// </summary>
|
||||
/// <param name="executeMethod"></param>
|
||||
public void SetExecuteMethod(Action<IRPCParser, MethodInvoker, MethodInstance> executeMethod)
|
||||
{
|
||||
this.RRQMExecuteMethod = executeMethod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置地图映射
|
||||
/// </summary>
|
||||
/// <param name="methodMap"></param>
|
||||
public void SetMethodMap(MethodMap methodMap)
|
||||
{
|
||||
this.methodMap = methodMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置服务
|
||||
/// </summary>
|
||||
/// <param name="service"></param>
|
||||
public void SetRPCService(RPCService service)
|
||||
{
|
||||
this.RPCService = service;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建请求内容
|
||||
/// </summary>
|
||||
/// <param name="jsonString">数据</param>
|
||||
/// <param name="methodInstance">调用服务实例</param>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual void BuildRequestContext(string jsonString, out MethodInstance methodInstance, out JsonRequestContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
context = JsonConvert.DeserializeObject<JsonRequestContext>(jsonString);
|
||||
if (context.id != null)
|
||||
{
|
||||
context.needResponse = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context = new JsonRequestContext();
|
||||
context.needResponse = true;
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (this.actionMap.TryGet(context.method, out methodInstance))
|
||||
{
|
||||
if (context.@params == null)
|
||||
{
|
||||
if (methodInstance.ParameterNames.Length != 0)
|
||||
{
|
||||
throw new RRQMRPCException("调用参数计数不匹配");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (context.@params.GetType() != typeof(JArray))
|
||||
{
|
||||
JObject obj = (JObject)context.@params;
|
||||
context.parameters = new object[methodInstance.ParameterNames.Length];
|
||||
//内联
|
||||
for (int i = 0; i < methodInstance.ParameterNames.Length; i++)
|
||||
{
|
||||
if (obj.TryGetValue(methodInstance.ParameterNames[i], out JToken jToken))
|
||||
{
|
||||
Type type = methodInstance.ParameterTypes[i];
|
||||
context.parameters[i] = jToken.ToObject(type);
|
||||
}
|
||||
else if (methodInstance.Parameters[i].HasDefaultValue)
|
||||
{
|
||||
context.parameters[i] = methodInstance.Parameters[i].DefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RRQMRPCException("调用参数计数不匹配");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JArray array = (JArray)context.@params;
|
||||
if (array.Count != methodInstance.ParameterNames.Length)
|
||||
{
|
||||
throw new RRQMRPCException("调用参数计数不匹配");
|
||||
}
|
||||
context.parameters = new object[methodInstance.ParameterNames.Length];
|
||||
|
||||
for (int i = 0; i < array.Count; i++)
|
||||
{
|
||||
context.parameters[i] = context.@params[i].ToObject(methodInstance.ParameterTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInstance = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建响应数据
|
||||
/// </summary>
|
||||
/// <param name="responseByteBlock"></param>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="error"></param>
|
||||
protected virtual void BuildResponseByteBlock(ByteBlock responseByteBlock, MethodInvoker methodInvoker, string id, object result, error error)
|
||||
{
|
||||
JObject jobject = new JObject();
|
||||
if (error == null)
|
||||
{
|
||||
//成功
|
||||
jobject.Add("jsonrpc", JToken.FromObject("2.0"));
|
||||
jobject.Add("result", result == null ? null : JToken.FromObject(result));
|
||||
jobject.Add("id", id == null ? null : JToken.FromObject(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
jobject.Add("jsonrpc", JToken.FromObject("2.0"));
|
||||
jobject.Add("error", JToken.FromObject(error));
|
||||
jobject.Add("id", id == null ? null : JToken.FromObject(id));
|
||||
}
|
||||
switch (this.protocolType)
|
||||
{
|
||||
case JsonRpcProtocolType.Tcp:
|
||||
{
|
||||
responseByteBlock.Write(Encoding.UTF8.GetBytes(jobject.ToString(Formatting.None)));
|
||||
break;
|
||||
}
|
||||
case JsonRpcProtocolType.Http:
|
||||
{
|
||||
HttpResponse httpResponse = new HttpResponse();
|
||||
httpResponse.FromJson(jobject.ToString(Formatting.None));
|
||||
httpResponse.Build(responseByteBlock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 载入配置
|
||||
/// </summary>
|
||||
/// <param name="serviceConfig"></param>
|
||||
protected override void LoadConfig(ServiceConfig serviceConfig)
|
||||
{
|
||||
base.LoadConfig(serviceConfig);
|
||||
this.protocolType = (JsonRpcProtocolType)serviceConfig.GetValue(JsonRpcParserConfig.ProtocolTypeProperty);
|
||||
this.maxPackageSize = (int)serviceConfig.GetValue(JsonRpcParserConfig.MaxPackageSizeProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建SocketCliect
|
||||
/// </summary>
|
||||
/// <param name="socketClient"></param>
|
||||
/// <param name="createOption"></param>
|
||||
protected override void OnCreateSocketCliect(JsonRpcSocketClient socketClient, CreateOption createOption)
|
||||
{
|
||||
if (createOption.NewCreate)
|
||||
{
|
||||
socketClient.OnReceived = this.OnReceived;
|
||||
}
|
||||
switch (this.protocolType)
|
||||
{
|
||||
case JsonRpcProtocolType.Tcp:
|
||||
socketClient.SetAdapter(new TerminatorDataHandlingAdapter(this.maxPackageSize, "\r\n"));
|
||||
break;
|
||||
|
||||
case JsonRpcProtocolType.Http:
|
||||
socketClient.SetAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Server));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReceived(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj)
|
||||
{
|
||||
MethodInvoker methodInvoker = new MethodInvoker();
|
||||
methodInvoker.Caller = socketClient;
|
||||
MethodInstance methodInstance = null;
|
||||
JsonRequestContext context = null;
|
||||
try
|
||||
{
|
||||
string jsonString = null;
|
||||
switch (this.protocolType)
|
||||
{
|
||||
case JsonRpcProtocolType.Tcp:
|
||||
{
|
||||
jsonString = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
break;
|
||||
}
|
||||
case JsonRpcProtocolType.Http:
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)obj;
|
||||
jsonString = httpRequest.Body;
|
||||
methodInvoker.Flag = httpRequest;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.BuildRequestContext(jsonString, out methodInstance, out context);
|
||||
|
||||
if (methodInstance == null)
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.UnFound;
|
||||
}
|
||||
else if (methodInstance.IsEnable)
|
||||
{
|
||||
methodInvoker.Parameters = context.parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.UnEnable;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.Exception;
|
||||
methodInvoker.StatusMessage = ex.Message;
|
||||
}
|
||||
|
||||
methodInvoker.Flag = context;
|
||||
|
||||
this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
RRQMSocket.RPC.JsonRpc/Socket/JsonRpcSocketClient.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using RRQMCore.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpc辅助类
|
||||
/// </summary>
|
||||
public class JsonRpcSocketClient : SimpleSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 禁用适配器赋值
|
||||
/// </summary>
|
||||
/// <param name="adapter"></param>
|
||||
public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter)
|
||||
{
|
||||
throw new RRQMException($"{nameof(JsonRpcSocketClient)}不允许设置适配器。");
|
||||
}
|
||||
|
||||
internal void SetAdapter(DataHandlingAdapter adapter)
|
||||
{
|
||||
base.SetDataHandlingAdapter(adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
RRQMSocket.RPC.WebApi/Attribute/RouteAttribute.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 适用于WebApi的路由标记
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class RouteAttribute : RPCAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RouteAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="template"></param>
|
||||
public RouteAttribute(string template)
|
||||
{
|
||||
this.Template = template;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 路由模板
|
||||
/// </summary>
|
||||
public string Template { get; private set; }
|
||||
}
|
||||
}
|
||||
30
RRQMSocket.RPC.WebApi/Common/ActionResult.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 结果状态
|
||||
/// </summary>
|
||||
public class ActionResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态类型
|
||||
/// </summary>
|
||||
public InvokeStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
||||
21
RRQMSocket.RPC.WebApi/Common/ControllerBase.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// ControllerBase
|
||||
/// </summary>
|
||||
public abstract class ControllerBase : ServerProvider
|
||||
{
|
||||
}
|
||||
}
|
||||
70
RRQMSocket.RPC.WebApi/Common/RouteMap.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 路由映射图
|
||||
/// </summary>
|
||||
public class RouteMap : IEnumerable<KeyValuePair<string, MethodInstance>>
|
||||
{
|
||||
internal RouteMap()
|
||||
{
|
||||
this.routeMap = new Dictionary<string, MethodInstance>();
|
||||
}
|
||||
|
||||
private Dictionary<string, MethodInstance> routeMap;
|
||||
|
||||
internal void Add(string routeUrl, MethodInstance methodInstance)
|
||||
{
|
||||
this.routeMap.Add(routeUrl, methodInstance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 路由路径集合
|
||||
/// </summary>
|
||||
public IEnumerable<string> Urls { get { return this.routeMap.Keys; } }
|
||||
|
||||
/// <summary>
|
||||
/// 通过routeUrl获取函数实例
|
||||
/// </summary>
|
||||
/// <param name="routeUrl"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGet(string routeUrl, out MethodInstance methodInstance)
|
||||
{
|
||||
if (this.routeMap.ContainsKey(routeUrl))
|
||||
{
|
||||
methodInstance = this.routeMap[routeUrl];
|
||||
return true;
|
||||
}
|
||||
methodInstance = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回迭代器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<KeyValuePair<string, MethodInstance>> GetEnumerator()
|
||||
{
|
||||
return this.routeMap.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.routeMap.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
53
RRQMSocket.RPC.WebApi/Config/WebApiParserConfig.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Dependency;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// WebApiParser配置
|
||||
/// </summary>
|
||||
public class WebApiParserConfig : TcpServiceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据转化器
|
||||
/// </summary>
|
||||
public ApiDataConverter ApiDataConverter
|
||||
{
|
||||
get { return (ApiDataConverter)GetValue(ApiDataConverterProperty); }
|
||||
set { SetValue(ApiDataConverterProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据转化器
|
||||
/// 所需类型<see cref="RRQMSocket.RPC.WebApi.ApiDataConverter"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ApiDataConverterProperty =
|
||||
DependencyProperty.Register("ApiDataConverter", typeof(ApiDataConverter), typeof(WebApiParserConfig), new JsonDataConverter());
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return (int)GetValue(MaxPackageSizeProperty); }
|
||||
set { SetValue(MaxPackageSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度,所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPackageSizeProperty =
|
||||
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(WebApiParserConfig), 1024);
|
||||
|
||||
}
|
||||
}
|
||||
37
RRQMSocket.RPC.WebApi/Converter/ApiDataConverter.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMSocket.Http;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Api结果转化器
|
||||
/// </summary>
|
||||
public abstract class ApiDataConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// 在调用完成时转换结果
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
/// <returns></returns>
|
||||
public abstract HttpResponse OnResult(MethodInvoker methodInvoker, MethodInstance methodInstance);
|
||||
|
||||
/// <summary>
|
||||
/// 在调用时
|
||||
/// </summary>
|
||||
/// <param name="httpRequest"></param>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
public abstract void OnPost(HttpRequest httpRequest, ref MethodInvoker methodInvoker, MethodInstance methodInstance);
|
||||
}
|
||||
}
|
||||
128
RRQMSocket.RPC.WebApi/Converter/JsonDataConverter.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Helper;
|
||||
using RRQMCore.XREF.Newtonsoft.Json;
|
||||
using RRQMSocket.Http;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Json数据转换器
|
||||
/// </summary>
|
||||
public class JsonDataConverter : ApiDataConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// OnPost
|
||||
/// </summary>
|
||||
/// <param name="httpRequest"></param>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
public override void OnPost(HttpRequest httpRequest, ref MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
switch (httpRequest.Content_Type)
|
||||
{
|
||||
case "application/x-www-form-urlencoded":
|
||||
{
|
||||
if (httpRequest.Params != null)
|
||||
{
|
||||
for (int i = 0; i < methodInstance.Parameters.Length; i++)
|
||||
{
|
||||
if (httpRequest.Params.TryGetValue(methodInstance.ParameterNames[i], out string value))
|
||||
{
|
||||
methodInvoker.Parameters[i] = value.ParseToType(methodInstance.ParameterTypes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "application/json":
|
||||
{
|
||||
if (methodInstance.Parameters.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < methodInstance.Parameters.Length; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
methodInvoker.Parameters[i] = JsonConvert.DeserializeObject(httpRequest.Body, methodInstance.ParameterTypes[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在调用完成时转换结果
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
/// <returns></returns>
|
||||
public override HttpResponse OnResult(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
|
||||
HttpResponse httpResponse = new HttpResponse();
|
||||
switch (methodInvoker.Status)
|
||||
{
|
||||
case InvokeStatus.Success:
|
||||
{
|
||||
if (methodInvoker.ReturnParameter != null)
|
||||
{
|
||||
httpResponse.FromJson(JsonConvert.SerializeObject(methodInvoker.ReturnParameter));
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
httpResponse.FromText(string.Empty);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnFound:
|
||||
{
|
||||
string jsonString = JsonConvert.SerializeObject(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
|
||||
httpResponse.FromJson(jsonString, "404");
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnEnable:
|
||||
{
|
||||
string jsonString = JsonConvert.SerializeObject(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
|
||||
httpResponse.FromJson(jsonString, "405");
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Abort:
|
||||
{
|
||||
string jsonString = JsonConvert.SerializeObject(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
|
||||
httpResponse.FromJson(jsonString, "403");
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.InvocationException:
|
||||
case InvokeStatus.Exception:
|
||||
{
|
||||
string jsonString = JsonConvert.SerializeObject(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
|
||||
httpResponse.FromJson(jsonString, "422");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return httpResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
129
RRQMSocket.RPC.WebApi/Converter/XmlDataConverter.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Helper;
|
||||
using RRQMCore.Serialization;
|
||||
using RRQMSocket.Http;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Xml结果转换器
|
||||
/// </summary>
|
||||
public class XmlDataConverter : ApiDataConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// OnPost
|
||||
/// </summary>
|
||||
/// <param name="httpRequest"></param>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
public override void OnPost(HttpRequest httpRequest, ref MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
switch (httpRequest.Content_Type)
|
||||
{
|
||||
case "application/x-www-form-urlencoded":
|
||||
{
|
||||
if (httpRequest.Params != null)
|
||||
{
|
||||
for (int i = 0; i < methodInstance.Parameters.Length; i++)
|
||||
{
|
||||
if (httpRequest.Params.TryGetValue(methodInstance.ParameterNames[i], out string value))
|
||||
{
|
||||
methodInvoker.Parameters[i] = value.ParseToType(methodInstance.ParameterTypes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "application/xml":
|
||||
{
|
||||
if (methodInstance.Parameters.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < methodInstance.Parameters.Length; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
methodInvoker.Parameters[i] = SerializeConvert.XmlDeserializeFromBytes(
|
||||
httpRequest.Encoding.GetBytes(httpRequest.Body), methodInstance.ParameterTypes[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在调用完成时转换结果
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
/// <returns></returns>
|
||||
public override HttpResponse OnResult(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
|
||||
HttpResponse httpResponse = new HttpResponse();
|
||||
switch (methodInvoker.Status)
|
||||
{
|
||||
case InvokeStatus.Success:
|
||||
{
|
||||
if (methodInvoker.ReturnParameter != null)
|
||||
{
|
||||
httpResponse.FromXML(SerializeConvert.XmlSerializeToString(methodInvoker.ReturnParameter));
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
httpResponse.FromText(string.Empty);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnFound:
|
||||
{
|
||||
string xmlString = SerializeConvert.XmlSerializeToString(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
|
||||
httpResponse.FromXML(xmlString, "404");
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnEnable:
|
||||
{
|
||||
string xmlString = SerializeConvert.XmlSerializeToString(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
|
||||
httpResponse.FromXML(xmlString, "405");
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Abort:
|
||||
{
|
||||
string xmlString = SerializeConvert.XmlSerializeToString(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
|
||||
httpResponse.FromXML(xmlString, "403");
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.InvocationException:
|
||||
case InvokeStatus.Exception:
|
||||
{
|
||||
string xmlString = SerializeConvert.XmlSerializeToString(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
|
||||
httpResponse.FromXML(xmlString, "422");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return httpResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.RPC.WebApi/LICENSE
Normal file
@@ -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.
|
||||
BIN
RRQMSocket.RPC.WebApi/RRQM.ico
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMSocket.RPC.WebApi/RRQM.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
70
RRQMSocket.RPC.WebApi/RRQMSocket.RPC.WebApi.csproj
Normal file
@@ -0,0 +1,70 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
|
||||
<ApplicationIcon>RRQM.ico</ApplicationIcon>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
|
||||
<Version>5.5.0</Version>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
|
||||
<Description>介绍:这是一个扩展于RRQMSocket.RPC的WebApi组件,可以通过该组件直接创建WebApi服务解析器,让Web端、移动端可以跨语言调用RPC函数。功能支持路由、Get传参、Post传参等。
|
||||
|
||||
更新说明:
|
||||
修改为稳定版。
|
||||
|
||||
Demo:https://gitee.com/RRQM_OS/RRQMBox
|
||||
API:https://gitee.com/RRQM_OS/RRQM/wikis/pages </Description>
|
||||
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
|
||||
<PackageIconUrl></PackageIconUrl>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PackageIcon>RRQM.png</PackageIcon>
|
||||
<Authors>若汝棋茗</Authors>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageTags>WebApi,RPC,IOCP</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net45\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\net45\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="RRQM.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RRQMSocket.Http" Version="5.5.0" />
|
||||
<PackageReference Include="RRQMSocket.RPC" Version="5.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
280
RRQMSocket.RPC.WebApi/Socket/WebApiParser.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Helper;
|
||||
using RRQMCore.Log;
|
||||
using RRQMSocket.Http;
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// WebApi解析器
|
||||
/// </summary>
|
||||
public class WebApiParser : TcpService<WebApiSocketClient>, IRPCParser
|
||||
{
|
||||
private RouteMap routeMap;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public WebApiParser()
|
||||
{
|
||||
this.routeMap = new RouteMap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据转化器
|
||||
/// </summary>
|
||||
public ApiDataConverter ApiDataConverter { get; private set; }
|
||||
|
||||
private int maxPackageSize;
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return maxPackageSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数映射
|
||||
/// </summary>
|
||||
public MethodMap MethodMap { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取路由映射图
|
||||
/// </summary>
|
||||
public RouteMap RouteMap { get { return this.routeMap; } }
|
||||
|
||||
/// <summary>
|
||||
/// 所属服务器
|
||||
/// </summary>
|
||||
public RPCService RPCService { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行函数
|
||||
/// </summary>
|
||||
public Action<IRPCParser, MethodInvoker, MethodInstance> RRQMExecuteMethod { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结束调用
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
|
||||
SimpleSocketClient socketClient = (SimpleSocketClient)methodInvoker.Caller;
|
||||
|
||||
HttpResponse httpResponse = this.ApiDataConverter.OnResult(methodInvoker, methodInstance);
|
||||
|
||||
httpResponse.ProtocolVersion = httpRequest.ProtocolVersion;
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
|
||||
try
|
||||
{
|
||||
httpResponse.Build(byteBlock);
|
||||
socketClient.Send(byteBlock);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
|
||||
if (!httpRequest.KeepAlive)
|
||||
{
|
||||
socketClient.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="methodInstances"></param>
|
||||
public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
if ((typeof(ControllerBase).IsAssignableFrom(methodInstance.Provider.GetType())))
|
||||
{
|
||||
string controllerName;
|
||||
RouteAttribute classAtt = methodInstance.Provider.GetType().GetCustomAttribute<RouteAttribute>(false);
|
||||
if (classAtt == null || string.IsNullOrEmpty(classAtt.Template))
|
||||
{
|
||||
controllerName = methodInstance.Provider.GetType().Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
controllerName = classAtt.Template.Replace("[controller]", methodInstance.Provider.GetType().Name);
|
||||
}
|
||||
|
||||
foreach (var att in methodInstance.RPCAttributes)
|
||||
{
|
||||
if (att is RouteAttribute attribute)
|
||||
{
|
||||
if (methodInstance.IsByRef)
|
||||
{
|
||||
throw new RRQMRPCException("WebApi服务中不允许有out及ref关键字");
|
||||
}
|
||||
string actionUrl;
|
||||
|
||||
if (controllerName.Contains("[action]"))
|
||||
{
|
||||
actionUrl = controllerName.Replace("[action]", methodInstance.Method.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(attribute.Template))
|
||||
{
|
||||
actionUrl = $"{controllerName}/{methodInstance.Method.Name}";
|
||||
}
|
||||
else
|
||||
{
|
||||
actionUrl = $"{controllerName}/{attribute.Template.Replace("[action]", methodInstance.Method.Name)}";
|
||||
}
|
||||
}
|
||||
|
||||
this.routeMap.Add(actionUrl, methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消注册服务
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="methodInstances"></param>
|
||||
public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置执行委托
|
||||
/// </summary>
|
||||
/// <param name="executeMethod"></param>
|
||||
public void SetExecuteMethod(Action<IRPCParser, MethodInvoker, MethodInstance> executeMethod)
|
||||
{
|
||||
this.RRQMExecuteMethod = executeMethod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置地图映射
|
||||
/// </summary>
|
||||
/// <param name="methodMap"></param>
|
||||
public void SetMethodMap(MethodMap methodMap)
|
||||
{
|
||||
this.MethodMap = methodMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置服务
|
||||
/// </summary>
|
||||
/// <param name="service"></param>
|
||||
public void SetRPCService(RPCService service)
|
||||
{
|
||||
this.RPCService = service;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 载入配置
|
||||
/// </summary>
|
||||
/// <param name="serviceConfig"></param>
|
||||
protected override void LoadConfig(ServiceConfig serviceConfig)
|
||||
{
|
||||
base.LoadConfig(serviceConfig);
|
||||
this.ApiDataConverter = (ApiDataConverter)serviceConfig.GetValue(WebApiParserConfig.ApiDataConverterProperty);
|
||||
this.maxPackageSize = (int)serviceConfig.GetValue(WebApiParserConfig.MaxPackageSizeProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在初次接收时
|
||||
/// </summary>
|
||||
/// <param name="socketClient"></param>
|
||||
/// <param name="createOption"></param>
|
||||
protected override void OnCreateSocketCliect(WebApiSocketClient socketClient, CreateOption createOption)
|
||||
{
|
||||
if (createOption.NewCreate)
|
||||
{
|
||||
socketClient.OnReceived = this.OnReceived;
|
||||
}
|
||||
socketClient.SetAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Server));
|
||||
}
|
||||
|
||||
private void OnReceived(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj)
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)obj;
|
||||
MethodInvoker methodInvoker = new MethodInvoker();
|
||||
methodInvoker.Caller = socketClient;
|
||||
methodInvoker.Flag = httpRequest;
|
||||
|
||||
if (this.routeMap.TryGet(httpRequest.RelativeURL, out MethodInstance methodInstance))
|
||||
{
|
||||
if (methodInstance.IsEnable)
|
||||
{
|
||||
try
|
||||
{
|
||||
methodInvoker.Parameters = new object[methodInstance.Parameters.Length];
|
||||
switch (httpRequest.Method)
|
||||
{
|
||||
case "GET":
|
||||
{
|
||||
if (httpRequest.Query != null)
|
||||
{
|
||||
for (int i = 0; i < methodInstance.Parameters.Length; i++)
|
||||
{
|
||||
if (httpRequest.Query.TryGetValue(methodInstance.ParameterNames[i], out string value))
|
||||
{
|
||||
methodInvoker.Parameters[i] = value.ParseToType(methodInstance.ParameterTypes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "POST":
|
||||
{
|
||||
this.ApiDataConverter.OnPost(httpRequest, ref methodInvoker, methodInstance);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.Exception;
|
||||
methodInvoker.StatusMessage = ex.Message;
|
||||
this.Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.UnEnable;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.UnFound;
|
||||
}
|
||||
|
||||
this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
RRQMSocket.RPC.WebApi/Socket/WebApiSocketClient.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using RRQMCore.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// WebApiSocket辅助类
|
||||
/// </summary>
|
||||
public class WebApiSocketClient : SimpleSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 禁用适配器赋值
|
||||
/// </summary>
|
||||
/// <param name="adapter"></param>
|
||||
public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter)
|
||||
{
|
||||
throw new RRQMException($"{nameof(WebApiSocketClient)}不允许设置适配器。");
|
||||
}
|
||||
|
||||
internal void SetAdapter(DataHandlingAdapter adapter)
|
||||
{
|
||||
base.SetDataHandlingAdapter(adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
RRQMSocket.RPC.XmlRpc/Attribute/XmlRpcAttribute.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.RPC.XmlRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// 适用于XmlRpc的标记
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class XmlRpcAttribute : RPCAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public XmlRpcAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="actionKey"></param>
|
||||
public XmlRpcAttribute(string actionKey)
|
||||
{
|
||||
this.ActionKey = actionKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务唯一标识
|
||||
/// </summary>
|
||||
public string ActionKey { get; private set; }
|
||||
}
|
||||
}
|
||||
70
RRQMSocket.RPC.XmlRpc/Common/ActionMap.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMSocket.RPC.XmlRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务映射图
|
||||
/// </summary>
|
||||
public class ActionMap : IEnumerable<KeyValuePair<string, MethodInstance>>
|
||||
{
|
||||
internal ActionMap()
|
||||
{
|
||||
this.actionMap = new Dictionary<string, MethodInstance>();
|
||||
}
|
||||
|
||||
private Dictionary<string, MethodInstance> actionMap;
|
||||
|
||||
internal void Add(string actionKey, MethodInstance methodInstance)
|
||||
{
|
||||
this.actionMap.Add(actionKey, methodInstance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务键集合
|
||||
/// </summary>
|
||||
public IEnumerable<string> ActionKeys { get { return this.actionMap.Keys; } }
|
||||
|
||||
/// <summary>
|
||||
/// 通过routeUrl获取函数实例
|
||||
/// </summary>
|
||||
/// <param name="actionKey"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGet(string actionKey, out MethodInstance methodInstance)
|
||||
{
|
||||
if (this.actionMap.ContainsKey(actionKey))
|
||||
{
|
||||
methodInstance = this.actionMap[actionKey];
|
||||
return true;
|
||||
}
|
||||
methodInstance = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回迭代器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<KeyValuePair<string, MethodInstance>> GetEnumerator()
|
||||
{
|
||||
return this.actionMap.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.actionMap.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
270
RRQMSocket.RPC.XmlRpc/Common/XmlDataTool.cs
Normal file
@@ -0,0 +1,270 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Helper;
|
||||
using RRQMSocket.Http;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace RRQMSocket.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 void CreateRequest(ByteBlock byteBlock, string host, 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ByteBlock xmlBlock = BytePool.Default.GetByteBlock(byteBlock.Capacity);
|
||||
xml.Save(xmlBlock);
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine("POST / HTTP/1.1");
|
||||
stringBuilder.AppendLine("Content-Type: text/xml");
|
||||
stringBuilder.AppendLine($"Host: {host}");
|
||||
stringBuilder.AppendLine("User-Agent: RRQMXmlRpc");
|
||||
stringBuilder.AppendLine($"Content-Length: {xmlBlock.Length}");
|
||||
//stringBuilder.AppendLine("Connection: Close");
|
||||
stringBuilder.AppendLine("Connection: keep-alive");
|
||||
stringBuilder.AppendLine();
|
||||
try
|
||||
{
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString()));
|
||||
byteBlock.Write(xmlBlock.Buffer, 0, xmlBlock.Len);
|
||||
}
|
||||
finally
|
||||
{
|
||||
xmlBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
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 = ((int)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 = BytePool.Default.GetByteBlock(1024 * 4);
|
||||
xml.Save(xmlBlock);
|
||||
|
||||
string xmlString = Encoding.UTF8.GetString(xmlBlock.Buffer, 0, xmlBlock.Len);
|
||||
|
||||
httpResponse.FromXML(xmlString);
|
||||
xmlBlock.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
RRQMSocket.RPC.XmlRpc/Config/XmlRpcClientConfig.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Dependency;
|
||||
|
||||
namespace RRQMSocket.RPC.XmlRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// XmlRpcClient配置
|
||||
/// </summary>
|
||||
public class XmlRpcClientConfig : TcpClientConfig
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return (int)GetValue(MaxPackageSizeProperty); }
|
||||
set { SetValue(MaxPackageSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度,所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPackageSizeProperty =
|
||||
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(XmlRpcClientConfig), 1024);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 等待超时时间(秒)
|
||||
/// </summary>
|
||||
public int Timeout
|
||||
{
|
||||
get { return (int)GetValue(TimeoutProperty); }
|
||||
set { SetValue(TimeoutProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待超时时间(秒),
|
||||
/// 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TimeoutProperty =
|
||||
DependencyProperty.Register("Timeout", typeof(int), typeof(XmlRpcClientConfig), 5);
|
||||
}
|
||||
}
|
||||
38
RRQMSocket.RPC.XmlRpc/Config/XmlRpcParserConfig.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using RRQMCore.Dependency;
|
||||
|
||||
namespace RRQMSocket.RPC.XmlRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// XmlRpcParser配置
|
||||
/// </summary>
|
||||
public class XmlRpcParserConfig : TcpServiceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return (int)GetValue(MaxPackageSizeProperty); }
|
||||
set { SetValue(MaxPackageSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度,所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPackageSizeProperty =
|
||||
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(XmlRpcParserConfig), 1024);
|
||||
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.RPC.XmlRpc/LICENSE
Normal file
@@ -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.
|
||||
BIN
RRQMSocket.RPC.XmlRpc/RRQM.ico
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMSocket.RPC.XmlRpc/RRQM.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
70
RRQMSocket.RPC.XmlRpc/RRQMSocket.RPC.XmlRpc.csproj
Normal file
@@ -0,0 +1,70 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
|
||||
<ApplicationIcon>RRQM.ico</ApplicationIcon>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
|
||||
<Version>5.5.0</Version>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
|
||||
<Description>介绍:这是一个扩展于RRQMSocket.RPC的XmlRpc组件,可以通过该组件直接创建XmlRpc服务解析器,让Web端、移动端可以跨语言调用RPC函数。功能支持XmlRpc全功能。
|
||||
|
||||
更新说明:
|
||||
同步更新。
|
||||
|
||||
Demo:https://gitee.com/RRQM_OS/RRQMBox
|
||||
API:https://gitee.com/RRQM_OS/RRQM/wikis/pages </Description>
|
||||
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
|
||||
<PackageIconUrl></PackageIconUrl>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PackageIcon>RRQM.png</PackageIcon>
|
||||
<Authors>若汝棋茗</Authors>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageTags>RPC;XmlRpc;Socket,IOCP</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net45\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\net45\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="RRQM.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RRQMSocket.Http" Version="5.5.0" />
|
||||
<PackageReference Include="RRQMSocket.RPC" Version="5.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
188
RRQMSocket.RPC.XmlRpc/Socket/XmlRpcClient.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Exceptions;
|
||||
using RRQMCore.Run;
|
||||
using RRQMSocket.Http;
|
||||
using RRQMSocket.RPC.RRQMRPC;
|
||||
using System;
|
||||
using System.Xml;
|
||||
|
||||
namespace RRQMSocket.RPC.XmlRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// XmlRpc客户端
|
||||
/// </summary>
|
||||
public class XmlRpcClient : TcpClient, IRpcClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public XmlRpcClient()
|
||||
{
|
||||
singleWaitHandle = new WaitData<HttpResponse>();
|
||||
}
|
||||
|
||||
private int maxPackageSize;
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return maxPackageSize; }
|
||||
}
|
||||
|
||||
private WaitData<HttpResponse> singleWaitHandle;
|
||||
|
||||
private int timeout;
|
||||
|
||||
/// <summary>
|
||||
/// 载入配置
|
||||
/// </summary>
|
||||
/// <param name="clientConfig"></param>
|
||||
protected override void LoadConfig(TcpClientConfig clientConfig)
|
||||
{
|
||||
base.LoadConfig(clientConfig);
|
||||
this.timeout = (int)clientConfig.GetValue(XmlRpcClientConfig.TimeoutProperty);
|
||||
this.maxPackageSize = (int)clientConfig.GetValue(XmlRpcClientConfig.MaxPackageSizeProperty);
|
||||
this.SetDataHandlingAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="invokeOption">调用配置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="types"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <returns></returns>
|
||||
public T Invoke<T>(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
HttpResponse response;
|
||||
try
|
||||
{
|
||||
XmlDataTool.CreateRequest(byteBlock, this.Name, method, parameters);
|
||||
response = this.WaitSend(byteBlock);
|
||||
if (response.StatusCode != "200")
|
||||
{
|
||||
throw new RRQMException("调用错误");
|
||||
}
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.LoadXml(response.Body);
|
||||
XmlNode paramNode = xml.SelectSingleNode("methodResponse/params/param");
|
||||
if (paramNode != null)
|
||||
{
|
||||
return (T)XmlDataTool.GetValue(paramNode.FirstChild.FirstChild, typeof(T));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="invokeOption">调用配置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="types"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public void Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
HttpResponse response;
|
||||
try
|
||||
{
|
||||
XmlDataTool.CreateRequest(byteBlock, this.Name, method, parameters);
|
||||
response = this.WaitSend(byteBlock);
|
||||
if (response.StatusCode != "200")
|
||||
{
|
||||
throw new RRQMException("调用错误");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="invokeOption">调用配置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public void Invoke(string method, InvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
this.Invoke(method, invokeOption, ref parameters, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="invokeOption">调用配置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <returns></returns>
|
||||
public T Invoke<T>(string method, InvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
return this.Invoke<T>(method, invokeOption, ref parameters, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <param name="obj"></param>
|
||||
protected override void HandleReceivedData(ByteBlock byteBlock, object obj)
|
||||
{
|
||||
this.singleWaitHandle.Set((HttpResponse)obj);
|
||||
}
|
||||
|
||||
private HttpResponse WaitSend(ByteBlock byteBlock)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
this.Send(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
if (this.singleWaitHandle.Wait(1000 * this.timeout))
|
||||
{
|
||||
return this.singleWaitHandle.WaitResult;
|
||||
}
|
||||
throw new RRQMTimeoutException("超时接收");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
234
RRQMSocket.RPC.XmlRpc/Socket/XmlRpcParser.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Log;
|
||||
using RRQMSocket.Http;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Xml;
|
||||
|
||||
namespace RRQMSocket.RPC.XmlRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// XmlRpc解析器
|
||||
/// </summary>
|
||||
public class XmlRpcParser : TcpService<XmlRpcSocketClient>, IRPCParser
|
||||
{
|
||||
private ActionMap actionMap;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public XmlRpcParser()
|
||||
{
|
||||
this.actionMap = new ActionMap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务键映射图
|
||||
/// </summary>
|
||||
public ActionMap ActionMap { get { return this.actionMap; } }
|
||||
|
||||
private int maxPackageSize;
|
||||
|
||||
/// <summary>
|
||||
/// 最大数据包长度
|
||||
/// </summary>
|
||||
public int MaxPackageSize
|
||||
{
|
||||
get { return maxPackageSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数映射
|
||||
/// </summary>
|
||||
public MethodMap MethodMap { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属服务器
|
||||
/// </summary>
|
||||
public RPCService RPCService { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行函数
|
||||
/// </summary>
|
||||
public Action<IRPCParser, MethodInvoker, MethodInstance> RRQMExecuteMethod { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结束调用
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
|
||||
SimpleSocketClient socketClient = (SimpleSocketClient)methodInvoker.Caller;
|
||||
|
||||
HttpResponse httpResponse = new HttpResponse();
|
||||
|
||||
httpResponse.ProtocolVersion = httpRequest.ProtocolVersion;
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
|
||||
XmlDataTool.CreatResponse(httpResponse, methodInvoker.ReturnParameter);
|
||||
try
|
||||
{
|
||||
httpResponse.Build(byteBlock);
|
||||
socketClient.Send(byteBlock);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
|
||||
if (!httpRequest.KeepAlive)
|
||||
{
|
||||
socketClient.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="methodInstances"></param>
|
||||
public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
foreach (var att in methodInstance.RPCAttributes)
|
||||
{
|
||||
if (att is XmlRpcAttribute attribute)
|
||||
{
|
||||
if (methodInstance.IsByRef)
|
||||
{
|
||||
throw new RRQMRPCException("XmlRpc服务中不允许有out及ref关键字");
|
||||
}
|
||||
string actionKey = string.IsNullOrEmpty(attribute.ActionKey) ? $"{methodInstance.Method.Name}" : attribute.ActionKey;
|
||||
|
||||
this.actionMap.Add(actionKey, methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消注册服务
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="methodInstances"></param>
|
||||
public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 载入配置
|
||||
/// </summary>
|
||||
/// <param name="serviceConfig"></param>
|
||||
protected override void LoadConfig(ServiceConfig serviceConfig)
|
||||
{
|
||||
base.LoadConfig(serviceConfig);
|
||||
this.maxPackageSize = (int)serviceConfig.GetValue(XmlRpcParserConfig.MaxPackageSizeProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置执行委托
|
||||
/// </summary>
|
||||
/// <param name="executeMethod"></param>
|
||||
public void SetExecuteMethod(Action<IRPCParser, MethodInvoker, MethodInstance> executeMethod)
|
||||
{
|
||||
this.RRQMExecuteMethod = executeMethod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置地图映射
|
||||
/// </summary>
|
||||
/// <param name="methodMap"></param>
|
||||
public void SetMethodMap(MethodMap methodMap)
|
||||
{
|
||||
this.MethodMap = methodMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置服务
|
||||
/// </summary>
|
||||
/// <param name="service"></param>
|
||||
public void SetRPCService(RPCService service)
|
||||
{
|
||||
this.RPCService = service;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="socketClient"></param>
|
||||
/// <param name="createOption"></param>
|
||||
protected override void OnCreateSocketCliect(XmlRpcSocketClient socketClient, CreateOption createOption)
|
||||
{
|
||||
if (createOption.NewCreate)
|
||||
{
|
||||
socketClient.OnReceived = this.OnReceived;
|
||||
}
|
||||
socketClient.SetAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Server));
|
||||
}
|
||||
|
||||
private void OnReceived(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj)
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)obj;
|
||||
MethodInvoker methodInvoker = new MethodInvoker();
|
||||
methodInvoker.Caller = socketClient;
|
||||
methodInvoker.Flag = httpRequest;
|
||||
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.LoadXml(httpRequest.Body);
|
||||
XmlNode methodName = xml.SelectSingleNode("methodCall/methodName");
|
||||
string actionKey = methodName.InnerText;
|
||||
|
||||
if (this.actionMap.TryGet(actionKey, out MethodInstance methodInstance))
|
||||
{
|
||||
if (methodInstance.IsEnable)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<object> ps = new List<object>();
|
||||
XmlNode paramsNode = xml.SelectSingleNode("methodCall/params");
|
||||
int index = 0;
|
||||
foreach (XmlNode paramNode in paramsNode.ChildNodes)
|
||||
{
|
||||
XmlNode valueNode = paramNode.FirstChild.FirstChild;
|
||||
ps.Add(XmlDataTool.GetValue(valueNode, methodInstance.ParameterTypes[index]));
|
||||
index++;
|
||||
}
|
||||
|
||||
methodInvoker.Parameters = ps.ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.Exception;
|
||||
methodInvoker.StatusMessage = ex.Message;
|
||||
this.Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.UnEnable;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.UnFound;
|
||||
}
|
||||
|
||||
this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
RRQMSocket.RPC.XmlRpc/Socket/XmlRpcSocketClient.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using RRQMCore.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC.XmlRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// XmlRpc辅助类
|
||||
/// </summary>
|
||||
public class XmlRpcSocketClient: SimpleSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 禁用适配器赋值
|
||||
/// </summary>
|
||||
/// <param name="adapter"></param>
|
||||
public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter)
|
||||
{
|
||||
throw new RRQMException($"{nameof(XmlRpcSocketClient)}不允许设置适配器。");
|
||||
}
|
||||
|
||||
internal void SetAdapter(DataHandlingAdapter adapter)
|
||||
{
|
||||
base.SetDataHandlingAdapter(adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
RRQMSocket.RPC/Delegete.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 收到字节数据
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="procotol"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
public delegate void RRQMReceivedProcotolEventHandler(object sender, short? procotol, ByteBlock byteBlock);
|
||||
}
|
||||
22
RRQMSocket.RPC/Global/Attribute/RPCAttribute.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC方法属性基类
|
||||
/// </summary>
|
||||
public abstract class RPCAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
55
RRQMSocket.RPC/Global/Commond/InvokeStatus.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 调用状态
|
||||
/// </summary>
|
||||
public enum InvokeStatus : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 就绪
|
||||
/// </summary>
|
||||
Ready,
|
||||
|
||||
/// <summary>
|
||||
/// 未找到服务
|
||||
/// </summary>
|
||||
UnFound,
|
||||
|
||||
/// <summary>
|
||||
/// 不可用
|
||||
/// </summary>
|
||||
UnEnable,
|
||||
|
||||
/// <summary>
|
||||
/// 成功调用
|
||||
/// </summary>
|
||||
Success,
|
||||
|
||||
/// <summary>
|
||||
/// 终止执行
|
||||
/// </summary>
|
||||
Abort,
|
||||
|
||||
/// <summary>
|
||||
/// 调用内部异常
|
||||
/// </summary>
|
||||
InvocationException,
|
||||
|
||||
/// <summary>
|
||||
/// 其他异常
|
||||
/// </summary>
|
||||
Exception
|
||||
}
|
||||
}
|
||||
77
RRQMSocket.RPC/Global/Commond/MethodInstance.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC函数实例
|
||||
/// </summary>
|
||||
public class MethodInstance
|
||||
{
|
||||
/// <summary>
|
||||
/// 执行此RPC的实例
|
||||
/// </summary>
|
||||
public IServerProvider Provider { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// RPC函数
|
||||
/// </summary>
|
||||
public MethodInfo Method { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// RPC属性集合
|
||||
/// </summary>
|
||||
public RPCAttribute[] RPCAttributes { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方法唯一令箭
|
||||
/// </summary>
|
||||
public int MethodToken { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 返回值类型,无返回值时为Null
|
||||
/// </summary>
|
||||
public Type ReturnType { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数类型集合,已处理out及ref,无参数时为空集合,
|
||||
/// </summary>
|
||||
public Type[] ParameterTypes { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数集合
|
||||
/// </summary>
|
||||
public ParameterInfo[] Parameters { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数名集合
|
||||
/// </summary>
|
||||
public string[] ParameterNames { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否异步执行
|
||||
/// </summary>
|
||||
public bool Async { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否有引用类型
|
||||
/// </summary>
|
||||
public bool IsByRef { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可用
|
||||
/// </summary>
|
||||
public bool IsEnable { get; internal set; }
|
||||
}
|
||||
}
|
||||
50
RRQMSocket.RPC/Global/Commond/MethodInvoker.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 函数调用信使
|
||||
/// </summary>
|
||||
public class MethodInvoker
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回值
|
||||
/// </summary>
|
||||
public object ReturnParameter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数值集合
|
||||
/// </summary>
|
||||
public object[] Parameters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取调用状态
|
||||
/// </summary>
|
||||
public InvokeStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态消息
|
||||
/// </summary>
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可以传递其他类型的数据容器
|
||||
/// </summary>
|
||||
public object Flag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 此函数执行者
|
||||
/// </summary>
|
||||
public object Caller { get; set; }
|
||||
}
|
||||
}
|
||||
81
RRQMSocket.RPC/Global/Commond/MethodMap.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore;
|
||||
using RRQMSocket.RPC.RRQMRPC;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 函数映射图
|
||||
/// </summary>
|
||||
public class MethodMap
|
||||
{
|
||||
internal MethodMap()
|
||||
{
|
||||
this.methodMap = new ConcurrentDictionary<int, MethodInstance>();
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<int, MethodInstance> methodMap;
|
||||
|
||||
internal void Add(MethodInstance methodInstance)
|
||||
{
|
||||
this.methodMap.TryAdd(methodInstance.MethodToken, methodInstance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过methodToken获取函数实例
|
||||
/// </summary>
|
||||
/// <param name="methodToken"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGet(int methodToken, out MethodInstance methodInstance)
|
||||
{
|
||||
return this.methodMap.TryGetValue(methodToken, out methodInstance);
|
||||
}
|
||||
|
||||
internal bool RemoveServer(Type type, out IServerProvider serverProvider, out MethodInstance[] methodInstances)
|
||||
{
|
||||
serverProvider = null;
|
||||
bool success = false;
|
||||
List<MethodInstance> keys = new List<MethodInstance>();
|
||||
foreach (var methodInstance in this.methodMap.Values)
|
||||
{
|
||||
if (methodInstance.Provider.GetType().FullName == type.FullName)
|
||||
{
|
||||
success = true;
|
||||
serverProvider = methodInstance.Provider;
|
||||
keys.Add(methodInstance);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in keys)
|
||||
{
|
||||
this.methodMap.TryRemove(item.MethodToken, out _);
|
||||
}
|
||||
methodInstances = keys.ToArray();
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有服务函数实例
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public MethodInstance[] GetAllMethodInstances()
|
||||
{
|
||||
return this.methodMap.Values.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||