From 59f562c38e60157b1361394f6cbfe1cc05a9e271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E6=B1=9D=E6=A3=8B=E8=8C=97?= <505554090@qq.com> Date: Fri, 13 Aug 2021 21:41:12 +0800 Subject: [PATCH] =?UTF-8?q?V5.5.0=E6=AD=A3=E5=BC=8F=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 341 +++++ LICENSE | 201 +++ README.md | 397 ++++++ RRQMSocket.FileTransfer/Common/FileBlock.cs | 40 + .../Common/FileHashGenerator.cs | 80 ++ .../Common/FileStreamPool.cs | 250 ++++ .../FileTransferErrorExceptionMapping.cs | 28 + .../Common/FileWaitResult.cs | 20 + .../Common/PBCollectionTemp.cs | 64 + .../Common/ProgressBlockCollection.cs | 106 ++ RRQMSocket.FileTransfer/Common/RRQMStream.cs | 157 +++ .../Common/ReadOnlyList.cs | 93 ++ RRQMSocket.FileTransfer/Common/Speed.cs | 22 + .../Common/TransferCollection.cs | 92 ++ .../Common/TransferFileHashDictionary.cs | 203 +++ RRQMSocket.FileTransfer/Common/UrlFileInfo.cs | 166 +++ .../Config/FileClientConfig.cs | 85 ++ .../Config/FileServiceConfig.cs | 59 + .../Delegate/DelegateCollection.cs | 28 + RRQMSocket.FileTransfer/Enum/FileHashType.cs | 39 + RRQMSocket.FileTransfer/Enum/RequestStatus.cs | 34 + .../Enum/StreamOperationType.cs | 29 + RRQMSocket.FileTransfer/Enum/TransferFlags.cs | 37 + .../Enum/TransferStatus.cs | 44 + RRQMSocket.FileTransfer/Enum/TransferType.cs | 30 + .../EventArgs/FileEventArgs.cs | 26 + .../EventArgs/FileOperationEventArgs.cs | 24 + .../EventArgs/TransferFileMessageArgs.cs | 29 + .../Exceptions/RRQMTransferErrorException.cs | 48 + .../Exceptions/RRQMTransferingException.cs | 52 + .../Interface/IFileClient.cs | 40 + .../Interface/IFileService.cs | 30 + RRQMSocket.FileTransfer/LICENSE | 201 +++ RRQMSocket.FileTransfer/RRQM.ico | Bin 0 -> 249918 bytes RRQMSocket.FileTransfer/RRQM.png | Bin 0 -> 87638 bytes .../RRQMSocket.FileTransfer.csproj | 77 ++ RRQMSocket.FileTransfer/Socket/FileClient.cs | 1030 ++++++++++++++ RRQMSocket.FileTransfer/Socket/FileService.cs | 133 ++ .../Socket/FileSocketClient.cs | 692 ++++++++++ RRQMSocket.Http/Common/HttpBase.cs | 258 ++++ RRQMSocket.Http/Common/HttpRequest.cs | 222 +++ RRQMSocket.Http/Common/HttpResponse.cs | 123 ++ .../DataAdapter/HttpDataHandlingAdapter.cs | 185 +++ RRQMSocket.Http/Enum/HttpHeaders.cs | 327 +++++ RRQMSocket.Http/Enum/HttpType.cs | 30 + RRQMSocket.Http/Helper/EnumHelper.cs | 72 + RRQMSocket.Http/Helper/RequestHelper.cs | 58 + RRQMSocket.Http/Helper/ResponseHelper.cs | 100 ++ RRQMSocket.Http/LICENSE | 201 +++ RRQMSocket.Http/RRQM.ico | Bin 0 -> 249918 bytes RRQMSocket.Http/RRQM.png | Bin 0 -> 87638 bytes RRQMSocket.Http/RRQMSocket.Http.csproj | 70 + .../Attribute/JsonRpcAttribute.cs | 43 + RRQMSocket.RPC.JsonRpc/Common/ActionMap.cs | 70 + .../Common/JsonRequestContext.cs | 31 + .../Common/JsonResponseContext.cs | 40 + .../Common/JsonRpcWaitContext.cs | 22 + .../Config/JsonRpcClientConfig.cs | 54 + .../Config/JsonRpcParserConfig.cs | 55 + .../Enum/JsonRpcProtocolType.cs | 29 + .../Interface/IJsonRpcClient.cs | 22 + RRQMSocket.RPC.JsonRpc/LICENSE | 201 +++ RRQMSocket.RPC.JsonRpc/RRQM.ico | Bin 0 -> 249918 bytes RRQMSocket.RPC.JsonRpc/RRQM.png | Bin 0 -> 87638 bytes .../RRQMSocket.RPC.JsonRpc.csproj | 71 + .../Socket/JsonRpcClient.cs | 382 ++++++ .../Socket/JsonRpcParser.cs | 424 ++++++ .../Socket/JsonRpcSocketClient.cs | 29 + .../Attribute/RouteAttribute.cs | 43 + RRQMSocket.RPC.WebApi/Common/ActionResult.cs | 30 + .../Common/ControllerBase.cs | 21 + RRQMSocket.RPC.WebApi/Common/RouteMap.cs | 70 + .../Config/WebApiParserConfig.cs | 53 + .../Converter/ApiDataConverter.cs | 37 + .../Converter/JsonDataConverter.cs | 128 ++ .../Converter/XmlDataConverter.cs | 129 ++ RRQMSocket.RPC.WebApi/LICENSE | 201 +++ RRQMSocket.RPC.WebApi/RRQM.ico | Bin 0 -> 249918 bytes RRQMSocket.RPC.WebApi/RRQM.png | Bin 0 -> 87638 bytes .../RRQMSocket.RPC.WebApi.csproj | 70 + RRQMSocket.RPC.WebApi/Socket/WebApiParser.cs | 280 ++++ .../Socket/WebApiSocketClient.cs | 29 + .../Attribute/XmlRpcAttribute.cs | 43 + RRQMSocket.RPC.XmlRpc/Common/ActionMap.cs | 70 + RRQMSocket.RPC.XmlRpc/Common/XmlDataTool.cs | 270 ++++ .../Config/XmlRpcClientConfig.cs | 54 + .../Config/XmlRpcParserConfig.cs | 38 + RRQMSocket.RPC.XmlRpc/LICENSE | 201 +++ RRQMSocket.RPC.XmlRpc/RRQM.ico | Bin 0 -> 249918 bytes RRQMSocket.RPC.XmlRpc/RRQM.png | Bin 0 -> 87638 bytes .../RRQMSocket.RPC.XmlRpc.csproj | 70 + RRQMSocket.RPC.XmlRpc/Socket/XmlRpcClient.cs | 188 +++ RRQMSocket.RPC.XmlRpc/Socket/XmlRpcParser.cs | 234 ++++ .../Socket/XmlRpcSocketClient.cs | 29 + RRQMSocket.RPC/Delegete.cs | 23 + .../Global/Attribute/RPCAttribute.cs | 22 + RRQMSocket.RPC/Global/Commond/InvokeStatus.cs | 55 + .../Global/Commond/MethodInstance.cs | 77 ++ .../Global/Commond/MethodInvoker.cs | 50 + RRQMSocket.RPC/Global/Commond/MethodMap.cs | 81 ++ .../Global/Commond/RPCParserCollection.cs | 79 ++ .../Global/Commond/ReadOnlyDictionary.cs | 85 ++ RRQMSocket.RPC/Global/Commond/ReadOnlyList.cs | 92 ++ .../Global/Commond/ServerProvider.cs | 62 + .../Commond/ServerProviderCollection.cs | 74 + .../Exceptions/RRQMAbandonRPCException.cs | 52 + .../Global/Exceptions/RRQMRPCException.cs | 52 + .../Exceptions/RRQMRPCInvokeException.cs | 48 + .../Global/Interface/IServerProvider.cs | 55 + RRQMSocket.RPC/Global/Parser/IRPCParser.cs | 75 + RRQMSocket.RPC/Global/Service/RPCService.cs | 336 +++++ RRQMSocket.RPC/LICENSE | 201 +++ RRQMSocket.RPC/RRQM.ico | Bin 0 -> 249918 bytes RRQMSocket.RPC/RRQM.png | Bin 0 -> 87638 bytes .../RRQMRPC/Attribute/RRQMRPCAttribute.cs | 42 + .../RRQMRPCCallBackMethodAttribute.cs | 36 + .../Attribute/RRQMRPCMemberAttribute.cs | 23 + RRQMSocket.RPC/RRQMRPC/Common/CellCode.cs | 36 + .../RRQMRPC/Common/CodeGenerator.cs | 502 +++++++ RRQMSocket.RPC/RRQMRPC/Common/CodeType.cs | 31 + RRQMSocket.RPC/RRQMRPC/Common/FeedbackType.cs | 35 + RRQMSocket.RPC/RRQMRPC/Common/InvokeOption.cs | 77 ++ RRQMSocket.RPC/RRQMRPC/Common/MethodItem.cs | 40 + RRQMSocket.RPC/RRQMRPC/Common/MethodStore.cs | 88 ++ .../RRQMRPC/Common/PropertyCodeGenerator.cs | 324 +++++ RRQMSocket.RPC/RRQMRPC/Common/RpcCompiler.cs | 103 ++ RRQMSocket.RPC/RRQMRPC/Common/RpcContext.cs | 74 + RRQMSocket.RPC/RRQMRPC/Common/RpcProxyInfo.cs | 42 + RRQMSocket.RPC/RRQMRPC/Common/Tools.cs | 240 ++++ .../RRQMRPC/Config/TcpRpcClientConfig.cs | 51 + .../RRQMRPC/Config/TcpRpcParserConfig.cs | 82 ++ .../RRQMRPC/Config/UdpRpcClientConfig.cs | 51 + .../RRQMRPC/Config/UdpRpcParserConfig.cs | 82 ++ .../RRQMRPC/Exceptions/RRQMRPCKeyException.cs | 47 + .../Exceptions/RRQMRPCNoRegisterException.cs | 47 + .../Exceptions/RRQMSerializationException.cs | 47 + .../RRQMRPC/Interface/IRRQMRpcClient.cs | 62 + .../RRQMRPC/Interface/IRRQMRpcParser.cs | 97 ++ .../RRQMRPC/Interface/IRpcClient.cs | 74 + .../Serialization/BinarySerializeConverter.cs | 44 + .../Serialization/JsonSerializeConverter.cs | 55 + .../Serialization/SerializeConverter.cs | 36 + .../Serialization/XmlSerializeConverter.cs | 44 + .../RRQMRPC/Socket/RpcSocketClient .cs | 474 +++++++ RRQMSocket.RPC/RRQMRPC/Socket/TcpParser.cs | 374 +++++ RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcClient.cs | 1201 +++++++++++++++++ RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcParser.cs | 21 + RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcClient.cs | 712 ++++++++++ RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcParser.cs | 382 ++++++ RRQMSocket.RPC/RRQMSocket.RPC.csproj | 72 + RRQMSocket.sln | 61 + RRQMSocket/BaseSocket.cs | 59 + RRQMSocket/ClassDiagram.cd | 516 +++++++ RRQMSocket/Common/AsyncByte.cs | 23 + RRQMSocket/Common/AsyncResult.cs | 29 + RRQMSocket/Common/AsyncSender.cs | 199 +++ RRQMSocket/Common/CreateOption.cs | 31 + RRQMSocket/Common/IPHost.cs | 96 ++ RRQMSocket/Common/ProcotolHelper.cs | 200 +++ RRQMSocket/Config/ClientConfig.cs | 20 + RRQMSocket/Config/ProtocolClientConfig.cs | 21 + RRQMSocket/Config/ProtocolServiceConfig.cs | 36 + RRQMSocket/Config/RRQMConfig.cs | 84 ++ RRQMSocket/Config/ServiceConfig.cs | 82 ++ RRQMSocket/Config/TcpClientConfig.cs | 130 ++ RRQMSocket/Config/TcpServiceConfig.cs | 83 ++ RRQMSocket/Config/TokenClientConfig.cs | 57 + RRQMSocket/Config/TokenServiceConfig.cs | 57 + RRQMSocket/Config/UdpSessionConfig.cs | 52 + RRQMSocket/DataAdapter/DataAdapterTester.cs | 201 +++ RRQMSocket/DataAdapter/DataHandlingAdapter.cs | 97 ++ .../FixedHeaderDataHandlingAdapter.cs | 279 ++++ .../FixedSizeDataHandlingAdapter.cs | 159 +++ .../JsonStringDataHandlingAdapter.cs | 135 ++ .../DataAdapter/NormalDataHandlingAdapter.cs | 42 + .../TerminatorDataHandlingAdapter.cs | 220 +++ RRQMSocket/DelegateCollection.cs | 49 + RRQMSocket/Enum/ClearType.cs | 32 + RRQMSocket/Enum/FixedHeaderType.cs | 35 + RRQMSocket/Enum/ServerState.cs | 39 + RRQMSocket/EventArgs/BytesEventArgs.cs | 35 + RRQMSocket/EventArgs/MesEventArgs.cs | 42 + RRQMSocket/EventArgs/ReturnBytesEventArgs.cs | 32 + .../Exceptions/RRQMNotConnectedException.cs | 52 + .../Exceptions/RRQMOverlengthException.cs | 47 + RRQMSocket/Exceptions/RRQMTimeoutException.cs | 48 + .../Exceptions/RRQMTokenVerifyException.cs | 47 + RRQMSocket/Interface/IClient.cs | 108 ++ RRQMSocket/Interface/IHandleBuffer.cs | 28 + RRQMSocket/Interface/IService.cs | 71 + RRQMSocket/Interface/ISocket.cs | 32 + RRQMSocket/Interface/ISocketClient.cs | 34 + RRQMSocket/Interface/ITcpClient.cs | 42 + RRQMSocket/Interface/ITcpService.cs | 134 ++ RRQMSocket/Interface/IUserClient.cs | 42 + RRQMSocket/Interface/IUserTcpClient.cs | 35 + RRQMSocket/Interface/_ITcpService.cs | 27 + RRQMSocket/InternalClass/BufferQueue.cs | 38 + RRQMSocket/InternalClass/BufferQueueGroup.cs | 41 + RRQMSocket/InternalClass/ClientBuffer.cs | 26 + .../InternalClass/SocketCliectCollection.cs | 113 ++ RRQMSocket/LICENSE | 201 +++ RRQMSocket/Logger/Log.cs | 45 + RRQMSocket/ParameterClass/VerifyOption.cs | 40 + RRQMSocket/Pool/Interface/IClientGroup.cs | 21 + RRQMSocket/Pool/Interface/IConnectionPool.cs | 91 ++ RRQMSocket/Pool/TcpConnectionPool.cs | 248 ++++ RRQMSocket/RRQM.ico | Bin 0 -> 249918 bytes RRQMSocket/RRQM.png | Bin 0 -> 87638 bytes RRQMSocket/RRQMSocket.csproj | 88 ++ RRQMSocket/TCP/Client/ProtocolClient.cs | 325 +++++ RRQMSocket/TCP/Client/SimpleProtocolClient.cs | 37 + RRQMSocket/TCP/Client/SimpleTcpClient.cs | 47 + RRQMSocket/TCP/Client/SimpleTokenClient.cs | 37 + RRQMSocket/TCP/Client/TcpClient.cs | 636 +++++++++ RRQMSocket/TCP/Client/TokenClient.cs | 163 +++ RRQMSocket/TCP/Service/ProtocolService.cs | 56 + .../TCP/Service/SimpleProtocolService.cs | 54 + RRQMSocket/TCP/Service/SimpleTcpService.cs | 57 + RRQMSocket/TCP/Service/SimpleTokenService.cs | 57 + RRQMSocket/TCP/Service/TcpService.cs | 655 +++++++++ RRQMSocket/TCP/Service/TokenService.cs | 173 +++ .../TCP/SocketClient/ProtocolSocketClient.cs | 270 ++++ .../SimpleProtocolSocketClient.cs | 37 + .../TCP/SocketClient/SimpleSocketClient.cs | 37 + RRQMSocket/TCP/SocketClient/SocketClient.cs | 545 ++++++++ RRQMSocket/UDP/SimpleUdpSession.cs | 37 + RRQMSocket/UDP/UdpSession.cs | 496 +++++++ 228 files changed, 26352 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 RRQMSocket.FileTransfer/Common/FileBlock.cs create mode 100644 RRQMSocket.FileTransfer/Common/FileHashGenerator.cs create mode 100644 RRQMSocket.FileTransfer/Common/FileStreamPool.cs create mode 100644 RRQMSocket.FileTransfer/Common/FileTransferErrorExceptionMapping.cs create mode 100644 RRQMSocket.FileTransfer/Common/FileWaitResult.cs create mode 100644 RRQMSocket.FileTransfer/Common/PBCollectionTemp.cs create mode 100644 RRQMSocket.FileTransfer/Common/ProgressBlockCollection.cs create mode 100644 RRQMSocket.FileTransfer/Common/RRQMStream.cs create mode 100644 RRQMSocket.FileTransfer/Common/ReadOnlyList.cs create mode 100644 RRQMSocket.FileTransfer/Common/Speed.cs create mode 100644 RRQMSocket.FileTransfer/Common/TransferCollection.cs create mode 100644 RRQMSocket.FileTransfer/Common/TransferFileHashDictionary.cs create mode 100644 RRQMSocket.FileTransfer/Common/UrlFileInfo.cs create mode 100644 RRQMSocket.FileTransfer/Config/FileClientConfig.cs create mode 100644 RRQMSocket.FileTransfer/Config/FileServiceConfig.cs create mode 100644 RRQMSocket.FileTransfer/Delegate/DelegateCollection.cs create mode 100644 RRQMSocket.FileTransfer/Enum/FileHashType.cs create mode 100644 RRQMSocket.FileTransfer/Enum/RequestStatus.cs create mode 100644 RRQMSocket.FileTransfer/Enum/StreamOperationType.cs create mode 100644 RRQMSocket.FileTransfer/Enum/TransferFlags.cs create mode 100644 RRQMSocket.FileTransfer/Enum/TransferStatus.cs create mode 100644 RRQMSocket.FileTransfer/Enum/TransferType.cs create mode 100644 RRQMSocket.FileTransfer/EventArgs/FileEventArgs.cs create mode 100644 RRQMSocket.FileTransfer/EventArgs/FileOperationEventArgs.cs create mode 100644 RRQMSocket.FileTransfer/EventArgs/TransferFileMessageArgs.cs create mode 100644 RRQMSocket.FileTransfer/Exceptions/RRQMTransferErrorException.cs create mode 100644 RRQMSocket.FileTransfer/Exceptions/RRQMTransferingException.cs create mode 100644 RRQMSocket.FileTransfer/Interface/IFileClient.cs create mode 100644 RRQMSocket.FileTransfer/Interface/IFileService.cs create mode 100644 RRQMSocket.FileTransfer/LICENSE create mode 100644 RRQMSocket.FileTransfer/RRQM.ico create mode 100644 RRQMSocket.FileTransfer/RRQM.png create mode 100644 RRQMSocket.FileTransfer/RRQMSocket.FileTransfer.csproj create mode 100644 RRQMSocket.FileTransfer/Socket/FileClient.cs create mode 100644 RRQMSocket.FileTransfer/Socket/FileService.cs create mode 100644 RRQMSocket.FileTransfer/Socket/FileSocketClient.cs create mode 100644 RRQMSocket.Http/Common/HttpBase.cs create mode 100644 RRQMSocket.Http/Common/HttpRequest.cs create mode 100644 RRQMSocket.Http/Common/HttpResponse.cs create mode 100644 RRQMSocket.Http/DataAdapter/HttpDataHandlingAdapter.cs create mode 100644 RRQMSocket.Http/Enum/HttpHeaders.cs create mode 100644 RRQMSocket.Http/Enum/HttpType.cs create mode 100644 RRQMSocket.Http/Helper/EnumHelper.cs create mode 100644 RRQMSocket.Http/Helper/RequestHelper.cs create mode 100644 RRQMSocket.Http/Helper/ResponseHelper.cs create mode 100644 RRQMSocket.Http/LICENSE create mode 100644 RRQMSocket.Http/RRQM.ico create mode 100644 RRQMSocket.Http/RRQM.png create mode 100644 RRQMSocket.Http/RRQMSocket.Http.csproj create mode 100644 RRQMSocket.RPC.JsonRpc/Attribute/JsonRpcAttribute.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Common/ActionMap.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Common/JsonRequestContext.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Common/JsonResponseContext.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Common/JsonRpcWaitContext.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Config/JsonRpcClientConfig.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Config/JsonRpcParserConfig.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Enum/JsonRpcProtocolType.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Interface/IJsonRpcClient.cs create mode 100644 RRQMSocket.RPC.JsonRpc/LICENSE create mode 100644 RRQMSocket.RPC.JsonRpc/RRQM.ico create mode 100644 RRQMSocket.RPC.JsonRpc/RRQM.png create mode 100644 RRQMSocket.RPC.JsonRpc/RRQMSocket.RPC.JsonRpc.csproj create mode 100644 RRQMSocket.RPC.JsonRpc/Socket/JsonRpcClient.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Socket/JsonRpcParser.cs create mode 100644 RRQMSocket.RPC.JsonRpc/Socket/JsonRpcSocketClient.cs create mode 100644 RRQMSocket.RPC.WebApi/Attribute/RouteAttribute.cs create mode 100644 RRQMSocket.RPC.WebApi/Common/ActionResult.cs create mode 100644 RRQMSocket.RPC.WebApi/Common/ControllerBase.cs create mode 100644 RRQMSocket.RPC.WebApi/Common/RouteMap.cs create mode 100644 RRQMSocket.RPC.WebApi/Config/WebApiParserConfig.cs create mode 100644 RRQMSocket.RPC.WebApi/Converter/ApiDataConverter.cs create mode 100644 RRQMSocket.RPC.WebApi/Converter/JsonDataConverter.cs create mode 100644 RRQMSocket.RPC.WebApi/Converter/XmlDataConverter.cs create mode 100644 RRQMSocket.RPC.WebApi/LICENSE create mode 100644 RRQMSocket.RPC.WebApi/RRQM.ico create mode 100644 RRQMSocket.RPC.WebApi/RRQM.png create mode 100644 RRQMSocket.RPC.WebApi/RRQMSocket.RPC.WebApi.csproj create mode 100644 RRQMSocket.RPC.WebApi/Socket/WebApiParser.cs create mode 100644 RRQMSocket.RPC.WebApi/Socket/WebApiSocketClient.cs create mode 100644 RRQMSocket.RPC.XmlRpc/Attribute/XmlRpcAttribute.cs create mode 100644 RRQMSocket.RPC.XmlRpc/Common/ActionMap.cs create mode 100644 RRQMSocket.RPC.XmlRpc/Common/XmlDataTool.cs create mode 100644 RRQMSocket.RPC.XmlRpc/Config/XmlRpcClientConfig.cs create mode 100644 RRQMSocket.RPC.XmlRpc/Config/XmlRpcParserConfig.cs create mode 100644 RRQMSocket.RPC.XmlRpc/LICENSE create mode 100644 RRQMSocket.RPC.XmlRpc/RRQM.ico create mode 100644 RRQMSocket.RPC.XmlRpc/RRQM.png create mode 100644 RRQMSocket.RPC.XmlRpc/RRQMSocket.RPC.XmlRpc.csproj create mode 100644 RRQMSocket.RPC.XmlRpc/Socket/XmlRpcClient.cs create mode 100644 RRQMSocket.RPC.XmlRpc/Socket/XmlRpcParser.cs create mode 100644 RRQMSocket.RPC.XmlRpc/Socket/XmlRpcSocketClient.cs create mode 100644 RRQMSocket.RPC/Delegete.cs create mode 100644 RRQMSocket.RPC/Global/Attribute/RPCAttribute.cs create mode 100644 RRQMSocket.RPC/Global/Commond/InvokeStatus.cs create mode 100644 RRQMSocket.RPC/Global/Commond/MethodInstance.cs create mode 100644 RRQMSocket.RPC/Global/Commond/MethodInvoker.cs create mode 100644 RRQMSocket.RPC/Global/Commond/MethodMap.cs create mode 100644 RRQMSocket.RPC/Global/Commond/RPCParserCollection.cs create mode 100644 RRQMSocket.RPC/Global/Commond/ReadOnlyDictionary.cs create mode 100644 RRQMSocket.RPC/Global/Commond/ReadOnlyList.cs create mode 100644 RRQMSocket.RPC/Global/Commond/ServerProvider.cs create mode 100644 RRQMSocket.RPC/Global/Commond/ServerProviderCollection.cs create mode 100644 RRQMSocket.RPC/Global/Exceptions/RRQMAbandonRPCException.cs create mode 100644 RRQMSocket.RPC/Global/Exceptions/RRQMRPCException.cs create mode 100644 RRQMSocket.RPC/Global/Exceptions/RRQMRPCInvokeException.cs create mode 100644 RRQMSocket.RPC/Global/Interface/IServerProvider.cs create mode 100644 RRQMSocket.RPC/Global/Parser/IRPCParser.cs create mode 100644 RRQMSocket.RPC/Global/Service/RPCService.cs create mode 100644 RRQMSocket.RPC/LICENSE create mode 100644 RRQMSocket.RPC/RRQM.ico create mode 100644 RRQMSocket.RPC/RRQM.png create mode 100644 RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCAttribute.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCCallBackMethodAttribute.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCMemberAttribute.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/CellCode.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/CodeGenerator.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/CodeType.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/FeedbackType.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/InvokeOption.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/MethodItem.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/MethodStore.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/PropertyCodeGenerator.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/RpcCompiler.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/RpcContext.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/RpcProxyInfo.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Common/Tools.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Config/TcpRpcClientConfig.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Config/TcpRpcParserConfig.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Config/UdpRpcClientConfig.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Config/UdpRpcParserConfig.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCKeyException.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCNoRegisterException.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMSerializationException.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Interface/IRRQMRpcClient.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Interface/IRRQMRpcParser.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Interface/IRpcClient.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Serialization/BinarySerializeConverter.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Serialization/JsonSerializeConverter.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Serialization/SerializeConverter.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Serialization/XmlSerializeConverter.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Socket/RpcSocketClient .cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Socket/TcpParser.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcClient.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcParser.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcClient.cs create mode 100644 RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcParser.cs create mode 100644 RRQMSocket.RPC/RRQMSocket.RPC.csproj create mode 100644 RRQMSocket.sln create mode 100644 RRQMSocket/BaseSocket.cs create mode 100644 RRQMSocket/ClassDiagram.cd create mode 100644 RRQMSocket/Common/AsyncByte.cs create mode 100644 RRQMSocket/Common/AsyncResult.cs create mode 100644 RRQMSocket/Common/AsyncSender.cs create mode 100644 RRQMSocket/Common/CreateOption.cs create mode 100644 RRQMSocket/Common/IPHost.cs create mode 100644 RRQMSocket/Common/ProcotolHelper.cs create mode 100644 RRQMSocket/Config/ClientConfig.cs create mode 100644 RRQMSocket/Config/ProtocolClientConfig.cs create mode 100644 RRQMSocket/Config/ProtocolServiceConfig.cs create mode 100644 RRQMSocket/Config/RRQMConfig.cs create mode 100644 RRQMSocket/Config/ServiceConfig.cs create mode 100644 RRQMSocket/Config/TcpClientConfig.cs create mode 100644 RRQMSocket/Config/TcpServiceConfig.cs create mode 100644 RRQMSocket/Config/TokenClientConfig.cs create mode 100644 RRQMSocket/Config/TokenServiceConfig.cs create mode 100644 RRQMSocket/Config/UdpSessionConfig.cs create mode 100644 RRQMSocket/DataAdapter/DataAdapterTester.cs create mode 100644 RRQMSocket/DataAdapter/DataHandlingAdapter.cs create mode 100644 RRQMSocket/DataAdapter/FixedHeaderDataHandlingAdapter.cs create mode 100644 RRQMSocket/DataAdapter/FixedSizeDataHandlingAdapter.cs create mode 100644 RRQMSocket/DataAdapter/JsonStringDataHandlingAdapter.cs create mode 100644 RRQMSocket/DataAdapter/NormalDataHandlingAdapter.cs create mode 100644 RRQMSocket/DataAdapter/TerminatorDataHandlingAdapter.cs create mode 100644 RRQMSocket/DelegateCollection.cs create mode 100644 RRQMSocket/Enum/ClearType.cs create mode 100644 RRQMSocket/Enum/FixedHeaderType.cs create mode 100644 RRQMSocket/Enum/ServerState.cs create mode 100644 RRQMSocket/EventArgs/BytesEventArgs.cs create mode 100644 RRQMSocket/EventArgs/MesEventArgs.cs create mode 100644 RRQMSocket/EventArgs/ReturnBytesEventArgs.cs create mode 100644 RRQMSocket/Exceptions/RRQMNotConnectedException.cs create mode 100644 RRQMSocket/Exceptions/RRQMOverlengthException.cs create mode 100644 RRQMSocket/Exceptions/RRQMTimeoutException.cs create mode 100644 RRQMSocket/Exceptions/RRQMTokenVerifyException.cs create mode 100644 RRQMSocket/Interface/IClient.cs create mode 100644 RRQMSocket/Interface/IHandleBuffer.cs create mode 100644 RRQMSocket/Interface/IService.cs create mode 100644 RRQMSocket/Interface/ISocket.cs create mode 100644 RRQMSocket/Interface/ISocketClient.cs create mode 100644 RRQMSocket/Interface/ITcpClient.cs create mode 100644 RRQMSocket/Interface/ITcpService.cs create mode 100644 RRQMSocket/Interface/IUserClient.cs create mode 100644 RRQMSocket/Interface/IUserTcpClient.cs create mode 100644 RRQMSocket/Interface/_ITcpService.cs create mode 100644 RRQMSocket/InternalClass/BufferQueue.cs create mode 100644 RRQMSocket/InternalClass/BufferQueueGroup.cs create mode 100644 RRQMSocket/InternalClass/ClientBuffer.cs create mode 100644 RRQMSocket/InternalClass/SocketCliectCollection.cs create mode 100644 RRQMSocket/LICENSE create mode 100644 RRQMSocket/Logger/Log.cs create mode 100644 RRQMSocket/ParameterClass/VerifyOption.cs create mode 100644 RRQMSocket/Pool/Interface/IClientGroup.cs create mode 100644 RRQMSocket/Pool/Interface/IConnectionPool.cs create mode 100644 RRQMSocket/Pool/TcpConnectionPool.cs create mode 100644 RRQMSocket/RRQM.ico create mode 100644 RRQMSocket/RRQM.png create mode 100644 RRQMSocket/RRQMSocket.csproj create mode 100644 RRQMSocket/TCP/Client/ProtocolClient.cs create mode 100644 RRQMSocket/TCP/Client/SimpleProtocolClient.cs create mode 100644 RRQMSocket/TCP/Client/SimpleTcpClient.cs create mode 100644 RRQMSocket/TCP/Client/SimpleTokenClient.cs create mode 100644 RRQMSocket/TCP/Client/TcpClient.cs create mode 100644 RRQMSocket/TCP/Client/TokenClient.cs create mode 100644 RRQMSocket/TCP/Service/ProtocolService.cs create mode 100644 RRQMSocket/TCP/Service/SimpleProtocolService.cs create mode 100644 RRQMSocket/TCP/Service/SimpleTcpService.cs create mode 100644 RRQMSocket/TCP/Service/SimpleTokenService.cs create mode 100644 RRQMSocket/TCP/Service/TcpService.cs create mode 100644 RRQMSocket/TCP/Service/TokenService.cs create mode 100644 RRQMSocket/TCP/SocketClient/ProtocolSocketClient.cs create mode 100644 RRQMSocket/TCP/SocketClient/SimpleProtocolSocketClient.cs create mode 100644 RRQMSocket/TCP/SocketClient/SimpleSocketClient.cs create mode 100644 RRQMSocket/TCP/SocketClient/SocketClient.cs create mode 100644 RRQMSocket/UDP/SimpleUdpSession.cs create mode 100644 RRQMSocket/UDP/UdpSession.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3e8a1553f --- /dev/null +++ b/.gitignore @@ -0,0 +1,341 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true +**/wwwroot/lib/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..b09cd7856 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 000000000..831734694 --- /dev/null +++ b/README.md @@ -0,0 +1,397 @@ +

+

+

+图片名称 +

+ +
+ +[![NuGet version (RRQMSocket)](https://img.shields.io/nuget/v/RRQMSocket.svg?style=flat-square)](https://www.nuget.org/packages/RRQMSocket/) +[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![Download](https://img.shields.io/nuget/dt/RRQMSocket)](https://www.nuget.org/packages/RRQMSocket/) +[![star](https://gitee.com/dotnetchina/RRQMSocket/badge/star.svg?theme=gvp)](https://gitee.com/dotnetchina/RRQMSocket/stargazers) +[![fork](https://gitee.com/dotnetchina/RRQMSocket/badge/fork.svg?theme=gvp)](https://gitee.com/dotnetchina/RRQMSocket/members) + +QQ + +
+ +
+ +合抱之木,生于毫末;九层之台,起于垒土。 + +
+
+图片名称 +
+ +## 💿描述 +| 名称 |描述| +|---|---| +|[![NuGet version (RRQMSocket)](https://img.shields.io/nuget/v/RRQMSocket.svg?label=RRQMSocket)](https://www.nuget.org/packages/RRQMSocket/)| **RRQMSocket**是一个整合性的、超轻量级的、可以免费商用使用的网络通信服务框架。
它具有 **高并发连接** 、 **高并发处理** 、 **事件订阅** 、 **插件式扩展** 、
**多线程处理** 、 **内存池** 、 **对象池** 等特点,
让使用者能够更加简单的、快速的搭建网络框架。| +|[![NuGet version](https://img.shields.io/nuget/v/RRQMSocketFramework.svg?label=RRQMSocketFramework)](https://www.nuget.org/packages/RRQMSocketFramework/)| **RRQMSocketFramework**是RRQMSocket系列的企业版,
两者在功能上几乎没有区别,但是RRQMSocketFramework无任何依赖,
且可以提供专属的定制功能。后续也会加入企业已定制的优秀功能,希望大家多多支持。| +| [![NuGet version (RRQMSocket.FileTransfer)](https://img.shields.io/nuget/v/RRQMSocket.FileTransfer.svg?label=RRQMSocket.FileTransfer)](https://www.nuget.org/packages/RRQMSocket.FileTransfer/) | RRQMSocket.FileTransfer是一个高性能的文件传输框架,
您可以用它传输**任意大小**的文件,它可以完美支持**上传下载混合式队列传输**、
**断点续传**、 **快速上传** 、**传输限速**、**获取文件信息**、**删除文件**等。
在实时测试中,它的传输速率可达500Mb/s。 | +|[![NuGet version (RRQMSocket.RPC)](https://img.shields.io/nuget/v/RRQMSocket.RPC.svg?label=RRQMSocket.RPC)](https://www.nuget.org/packages/RRQMSocket.RPC/) |RPC是一个超轻量、高性能、可扩展的微服务管理平台框架,
目前已完成开发**RRQMRPC**、**XmlRpc**、**JsonRpc**、**WebApi**部分。
**RRQMRPC**部分使用RRQM专属协议,支持客户端**异步调用**,
服务端**异步触发**、以及**out**和**ref**关键字,**函数回调**等。
在调用效率上也是非常强悍,在调用空载函数,且返回状态时,
**10w**次调用仅用时**3.8**秒,不返回状态用时**0.9**秒。
其他协议调用性能详看性能评测。| +|[![NuGet version (RRQMSocket.RPC.WebApi)](https://img.shields.io/nuget/v/RRQMSocket.RPC.WebApi.svg?label=RRQMSocket.RPC.WebApi)](https://www.nuget.org/packages/RRQMSocket.RPC.WebApi/)| WebApi是一个扩展于RRQMSocket.RPC的WebApi组件,
可以通过该组件创建WebApi服务解析器,让桌面端、Web端、移动端可以跨语言调用RPC函数。
功能支持路由、Get传参、Post传参等。| +|[![NuGet version (RRQMSocket.RPC.XmlRpc)](https://img.shields.io/nuget/v/RRQMSocket.RPC.XmlRpc.svg?label=RRQMSocket.RPC.XmlRpc)](https://www.nuget.org/packages/RRQMSocket.RPC.XmlRpc/)| XmlRpc是一个扩展于RRQMSocket.RPC的XmlRpc组件,
可以通过该组件创建XmlRpc服务解析器,完美支持XmlRpc数据类型,类型嵌套,
Array等,也能与CookComputing.XmlRpcV2完美对接。不限Web,Android等平台。| +| [![NuGet version (RRQMSocket.RPC.JsonRpc)](https://img.shields.io/nuget/v/RRQMSocket.RPC.JsonRpc.svg?label=RRQMSocket.RPC.JsonRpc)](https://www.nuget.org/packages/RRQMSocket.RPC.JsonRpc/)| JsonRpc是一个扩展于RRQMSocket.RPC的JsonRpc组件,
可以通过该组件创建JsonRpc服务解析器,支持JsonRpc全部功能,可与Web,Android等平台无缝对接。| +| [![NuGet version (RRQMSocket.Http)](https://img.shields.io/nuget/v/RRQMSocket.Http.svg?label=RRQMSocket.Http)](https://www.nuget.org/packages/RRQMSocket.Http/) | RRQMSocket.Http是一个能够简单解析Http的服务组件,
能够快速响应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) | [![NuGet version (RRQMCore)](https://img.shields.io/nuget/v/RRQMCore.svg?style=flat-square)](https://www.nuget.org/packages/RRQMCore/) | [![Download](https://img.shields.io/nuget/dt/RRQMCore)](https://www.nuget.org/packages/RRQMCore/) | RRQMCore是为RRQM系提供基础服务功能的库,其中包含:**内存池**、**对象池**、**等待逻辑池**、**AppMessenger**、**3DES加密**、**Xml快速存储**、**运行时间测量器**、**文件快捷操作**、**高性能序列化器**、**规范日志接口**等。 | +| [RRQMMVVM](https://gitee.com/RRQM_OS/RRQMMVVM) | [![NuGet version (RRQMMVVM)](https://img.shields.io/nuget/v/RRQMMVVM.svg?style=flat-square)](https://www.nuget.org/packages/RRQMMVVM/) | [![Download](https://img.shields.io/nuget/dt/RRQMMVVM)](https://www.nuget.org/packages/RRQMMVVM/) | RRQMMVVM是超轻简的MVVM框架,但是麻雀虽小,五脏俱全。| +| [RRQMSkin](https://gitee.com/RRQM_OS/RRQMSkin) | [![NuGet version (RRQMSkin)](https://img.shields.io/nuget/v/RRQMSkin.svg?style=flat-square)](https://www.nuget.org/packages/RRQMSkin/) | [![Download](https://img.shields.io/nuget/dt/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。 + +![输入图片说明](https://images.gitee.com/uploads/images/2021/0409/191343_e5827d04_8553710.png "屏幕截图.png") + +![输入图片说明](https://images.gitee.com/uploads/images/2021/0409/191501_abec9e45_8553710.png "屏幕截图.png") + +![输入图片说明](https://images.gitee.com/uploads/images/2021/0409/191531_d7f0a8d4_8553710.png "屏幕截图.png") + + + +#### 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基本上没有释放,性能非常强悍,图二是下载文件,性能依旧非常强悍。 + +![上传文件](https://images.gitee.com/uploads/images/2021/0409/190350_92a2ad36_8553710.png "上传文件") +![下载文件](https://images.gitee.com/uploads/images/2021/0409/190954_a212982d_8553710.png "下载文件") + + +## 致谢 + +谢谢大家对我的支持,如果还有其他问题,请加群QQ:234762506讨论。 + + +## 💕 支持本项目 +您的支持就是我不懈努力的动力。 + +#### 爱心赞助名单(以下排名只按照打赏时间顺序) + + 1. Bobo Joker(200¥) + 2. UnitySir(66¥) + 3. Coffee(100¥) + 4. Ninety(50¥) + 5. *琼(100¥) + 6. **安(5¥) + +#### 商业采购名单(以下排名只按照商业采购时间顺序) +1.凯斯得****有限公司 + +图片名称 + diff --git a/RRQMSocket.FileTransfer/Common/FileBlock.cs b/RRQMSocket.FileTransfer/Common/FileBlock.cs new file mode 100644 index 000000000..5d8216cf6 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/FileBlock.cs @@ -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 +{ + /// + /// 文件块 + /// + public class FileBlock + { + /// + /// 文件快索引 + /// + public int Index { get; internal set; } + + /// + /// 文件流位置 + /// + public long Position { get; internal set; } + + /// + /// 文件块长度 + /// + public long UnitLength { get; internal set; } + + /// + /// 请求状态 + /// + public RequestStatus RequestStatus { get; internal set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/FileHashGenerator.cs b/RRQMSocket.FileTransfer/Common/FileHashGenerator.cs new file mode 100644 index 000000000..e964c7c43 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/FileHashGenerator.cs @@ -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 +{ + /// + /// 文件Hash校验 + /// + public static class FileHashGenerator + { + private static FileHashType fileCheckType; + + /// + /// 文件 + /// + public static FileHashType FileCheckType + { + get { return fileCheckType; } + set { fileCheckType = value; } + } + + /// + /// 获取文件Hash + /// + /// + /// + public static string GetFileHash(string path) + { + using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + return GetFileHash(fileStream); + } + } + + /// + /// 获取文件Hash + /// + /// + /// + 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); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/FileStreamPool.cs b/RRQMSocket.FileTransfer/Common/FileStreamPool.cs new file mode 100644 index 000000000..08dd010b7 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/FileStreamPool.cs @@ -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 +{ + /// + /// 文件流池 + /// + public static class FileStreamPool + { + internal static ConcurrentDictionary pathStream = new ConcurrentDictionary(); + 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; + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/FileTransferErrorExceptionMapping.cs b/RRQMSocket.FileTransfer/Common/FileTransferErrorExceptionMapping.cs new file mode 100644 index 000000000..f1f92fbe1 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/FileTransferErrorExceptionMapping.cs @@ -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 +{ + /// + /// 文件传输错误码映射 + /// + public class FileTransferErrorExceptionMapping : ErrorExceptionMapping + { + private static FileTransferErrorExceptionMapping _instance = new FileTransferErrorExceptionMapping(); + + /// + /// 默认实例 + /// + public static FileTransferErrorExceptionMapping Default { get => _instance; } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/FileWaitResult.cs b/RRQMSocket.FileTransfer/Common/FileWaitResult.cs new file mode 100644 index 000000000..b52fa4483 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/FileWaitResult.cs @@ -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; } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/PBCollectionTemp.cs b/RRQMSocket.FileTransfer/Common/PBCollectionTemp.cs new file mode 100644 index 000000000..353a177c7 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/PBCollectionTemp.cs @@ -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 +{ + /// + /// 临时序列化 + /// + public class PBCollectionTemp + { + /// + /// 文件信息 + /// + public UrlFileInfo UrlFileInfo { get; internal set; } + + /// + /// 块集合 + /// + public List Blocks { get; internal set; } + + /// + /// 从文件块转换 + /// + /// + /// + public static PBCollectionTemp GetFromProgressBlockCollection(ProgressBlockCollection progressBlocks) + { + if (progressBlocks == null) + { + return null; + } + PBCollectionTemp collectionTemp = new PBCollectionTemp(); + collectionTemp.UrlFileInfo = progressBlocks.UrlFileInfo; + collectionTemp.Blocks = new List(); + collectionTemp.Blocks.AddRange(progressBlocks); + return collectionTemp; + } + + /// + /// 转换为ProgressBlockCollection + /// + /// + public ProgressBlockCollection ToPBCollection() + { + ProgressBlockCollection progressBlocks = new ProgressBlockCollection(); + progressBlocks.UrlFileInfo = this.UrlFileInfo; + if (this.Blocks != null) + { + progressBlocks.AddRange(this.Blocks); + } + return progressBlocks; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/ProgressBlockCollection.cs b/RRQMSocket.FileTransfer/Common/ProgressBlockCollection.cs new file mode 100644 index 000000000..3eb8e2f46 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/ProgressBlockCollection.cs @@ -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 +{ + /// + /// 文件进度块集合 + /// + public class ProgressBlockCollection : ReadOnlyList + { + /// + /// 文件信息 + /// + public UrlFileInfo UrlFileInfo { get; internal set; } + + private static int blockLength = 1024 * 1024 * 10; + + /// + /// 分块长度,min=1024*1024*5 + /// + public static int BlockLength + { + get { return blockLength; } + set + { + if (value < 1024 * 1024 * 5) + { + value = 1024 * 1024 * 5; + } + blockLength = value; + } + } + + /// + /// 保存 + /// + /// + 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); + } + } + + /// + /// 读取 + /// + /// + /// + 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(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; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/RRQMStream.cs b/RRQMSocket.FileTransfer/Common/RRQMStream.cs new file mode 100644 index 000000000..e03d7fc3b --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/RRQMStream.cs @@ -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(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(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/ReadOnlyList.cs b/RRQMSocket.FileTransfer/Common/ReadOnlyList.cs new file mode 100644 index 000000000..ca2da9cab --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/ReadOnlyList.cs @@ -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 +{ + /// + /// 只读 + /// + /// + + public class ReadOnlyList : IEnumerable + { + private List list = new List(); + + internal void Add(T block) + { + list.Add(block); + } + + internal void AddRange(IEnumerable collection) + { + list.AddRange(collection); + } + + internal void Remove(T block) + { + list.Remove(block); + } + + internal void RemoveAt(int index) + { + list.RemoveAt(index); + } + + internal void RemoveAll(Predicate 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 collection) + { + list.InsertRange(index, collection); + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator GetEnumerator() + { + return this.list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.list.GetEnumerator(); + } + + /// + /// 获取对象 + /// + /// + /// + public T this[int index] { get { return list[index]; } } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/Speed.cs b/RRQMSocket.FileTransfer/Common/Speed.cs new file mode 100644 index 000000000..19951c904 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/Speed.cs @@ -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 +{ + /// + /// + /// + internal class Speed + { + internal static long downloadSpeed; + internal static long uploadSpeed; + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/TransferCollection.cs b/RRQMSocket.FileTransfer/Common/TransferCollection.cs new file mode 100644 index 000000000..38d847c6f --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/TransferCollection.cs @@ -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 +{ + /// + /// 传输集合 + /// + public class TransferCollection : IEnumerable + { + internal TransferCollection() + { + list = new List(); + } + + internal event RRQMMessageEventHandler OnCollectionChanged; + + private List list; + + /// + /// 返回一个循环访问集合的枚举器 + /// + /// + public IEnumerator 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; + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/TransferFileHashDictionary.cs b/RRQMSocket.FileTransfer/Common/TransferFileHashDictionary.cs new file mode 100644 index 000000000..524f0d120 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/TransferFileHashDictionary.cs @@ -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 +{ + /// + /// 传输文件Hash暂存字典 + /// + public static class TransferFileHashDictionary + { + private static ConcurrentDictionary fileHashAndInfo = new ConcurrentDictionary(); + private static ConcurrentDictionary filePathAndInfo = new ConcurrentDictionary(); + + /// + /// 字典存储文件Hash的最大数量,默认为10000 + /// + public static int MaxCount { get; set; } = 10000; + + /// + /// 添加文件信息 + /// + /// + /// + /// + 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; + } + + /// + /// 添加文件信息 + /// + /// + 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; + } + } + } + } + + /// + /// 清除全部 + /// + public static void ClearDictionary() + { + if (filePathAndInfo == null) + { + return; + } + filePathAndInfo.Clear(); + } + + /// + /// 获取文件信息 + /// + /// + /// + /// + /// + 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; + } + + /// + /// 通过FileHash获取文件信息 + /// + /// + /// + /// + 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; + } + + /// + /// 移除 + /// + /// + /// + public static bool Remove(string filePath) + { + if (filePathAndInfo == null) + { + return false; + } + return filePathAndInfo.TryRemove(filePath, out _); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Common/UrlFileInfo.cs b/RRQMSocket.FileTransfer/Common/UrlFileInfo.cs new file mode 100644 index 000000000..9b63ab055 --- /dev/null +++ b/RRQMSocket.FileTransfer/Common/UrlFileInfo.cs @@ -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 +{ + /// + /// 文件信息类 + /// + public class UrlFileInfo + { + private string saveFullPath = string.Empty; + + private int timeout = 30 * 1000; + + /// + /// 文件哈希值 + /// + public string FileHash { get; internal set; } + + /// + /// 文件大小 + /// + public long FileLength { get; internal set; } + + /// + /// 文件名 + /// + public string FileName { get; internal set; } + + /// + /// 文件路径 + /// + public string FilePath { get; internal set; } + + /// + /// 传输标识 + /// + public TransferFlags Flags { get; set; } + + /// + /// 携带消息 + /// + public string Message { get; set; } + + /// + /// 存放目录 + /// + public string SaveFullPath + { + get { return saveFullPath; } + set + { + if (value == null) + { + value = string.Empty; + } + saveFullPath = value; + } + } + + /// + /// 超时时间,默认30*1000 ms + /// + public int Timeout + { + get { return timeout; } + set { timeout = value; } + } + + /// + /// 请求传输类型 + /// + public TransferType TransferType { get; internal set; } + + /// + /// 生成下载请求必要信息 + /// + /// + /// + /// + 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; + } + + /// + /// 生成上传请求必要信息 + /// + /// + /// + /// + 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; + } + + /// + /// 复制 + /// + /// + public void CopyFrom(UrlFileInfo urlFileInfo) + { + this.FileHash = urlFileInfo.FileHash; + this.FileLength = urlFileInfo.FileLength; + this.FileName = urlFileInfo.FileName; + this.FilePath = urlFileInfo.FilePath; + } + + /// + /// 判断参数是否相同 + /// + /// + /// + 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; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Config/FileClientConfig.cs b/RRQMSocket.FileTransfer/Config/FileClientConfig.cs new file mode 100644 index 000000000..18d2b0868 --- /dev/null +++ b/RRQMSocket.FileTransfer/Config/FileClientConfig.cs @@ -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 +{ + /// + /// 文件客户端配置 + /// + public class FileClientConfig : TokenClientConfig + { + /// + /// 构造函数 + /// + public FileClientConfig() + { + this.BufferLength = 64 * 1024; + } + + /// + /// 默认接收文件的存放目录 + /// + public string ReceiveDirectory + { + get { return (string)GetValue(ReceiveDirectoryProperty); } + set + { + if (value == null) + { + value = string.Empty; + } + SetValue(ReceiveDirectoryProperty, value); + } + } + + /// + /// 默认接收文件的存放目录, 所需类型 + /// + public static readonly DependencyProperty ReceiveDirectoryProperty = + DependencyProperty.Register("ReceiveDirectory", typeof(string), typeof(FileClientConfig), string.Empty); + + /// + /// 单次请求超时时间 min=5000,max=60*1000 ms + /// + public int Timeout + { + get { return (int)GetValue(TimeoutProperty); } + set + { + SetValue(TimeoutProperty, value); + } + } + + /// + /// 单次请求超时时间 min=5000,max=60*1000 ms, 所需类型 + /// + public static readonly DependencyProperty TimeoutProperty = + DependencyProperty.Register("Timeout", typeof(int), typeof(FileClientConfig), 10*1000); + + /// + /// 数据包尺寸 + /// + public int PacketSize + { + get { return (int)GetValue(PacketSizeProperty); } + set { SetValue(PacketSizeProperty, value); } + } + + /// + /// 数据包尺寸, 所需类型 + /// + [RRQMCore.Range] + public static readonly DependencyProperty PacketSizeProperty = + DependencyProperty.Register("PacketSize", typeof(int), typeof(FileClientConfig), 1024 * 1024); + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Config/FileServiceConfig.cs b/RRQMSocket.FileTransfer/Config/FileServiceConfig.cs new file mode 100644 index 000000000..40d0d60f0 --- /dev/null +++ b/RRQMSocket.FileTransfer/Config/FileServiceConfig.cs @@ -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 +{ + /// + /// 文件服务器配置 + /// + public class FileServiceConfig : TokenServiceConfig + { + /// + /// 构造函数 + /// + public FileServiceConfig() + { + this.BufferLength = 64 * 1024; + } + + /// + /// 最大下载速度 + /// + public long MaxDownloadSpeed + { + get { return (long)GetValue(MaxDownloadSpeedProperty); } + set { SetValue(MaxDownloadSpeedProperty, value); } + } + + /// + /// 最大下载速度, 所需类型 + /// + public static readonly DependencyProperty MaxDownloadSpeedProperty = + DependencyProperty.Register("MaxDownloadSpeed", typeof(long), typeof(FileServiceConfig), 1024 * 1024L); + + /// + /// 最大上传速度 + /// + public long MaxUploadSpeed + { + get { return (long)GetValue(MaxUploadSpeedProperty); } + set { SetValue(MaxUploadSpeedProperty, value); } + } + + /// + /// 最大上传速度, 所需类型 + /// + public static readonly DependencyProperty MaxUploadSpeedProperty = + DependencyProperty.Register("MaxUploadSpeed", typeof(long), typeof(FileServiceConfig), 1024 * 1024L); + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Delegate/DelegateCollection.cs b/RRQMSocket.FileTransfer/Delegate/DelegateCollection.cs new file mode 100644 index 000000000..a205109a9 --- /dev/null +++ b/RRQMSocket.FileTransfer/Delegate/DelegateCollection.cs @@ -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 +{ + /// + /// 传输文件操作处理 + /// + /// + /// + public delegate void RRQMFileOperationEventHandler(object sender, FileOperationEventArgs e); + + /// + /// 传输文件消息 + /// + /// + /// + public delegate void RRQMTransferFileMessageEventHandler(object sender, TransferFileMessageArgs e); +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Enum/FileHashType.cs b/RRQMSocket.FileTransfer/Enum/FileHashType.cs new file mode 100644 index 000000000..63e78a7ed --- /dev/null +++ b/RRQMSocket.FileTransfer/Enum/FileHashType.cs @@ -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 +{ + /// + /// 文件Hash检验类型 + /// + public enum FileHashType : byte + { + /// + /// MD5 + /// + MD5, + + /// + /// SHA1 + /// + SHA1, + + /// + /// SHA256 + /// + SHA256, + + /// + /// SHA512 + /// + SHA512 + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Enum/RequestStatus.cs b/RRQMSocket.FileTransfer/Enum/RequestStatus.cs new file mode 100644 index 000000000..9853e83d1 --- /dev/null +++ b/RRQMSocket.FileTransfer/Enum/RequestStatus.cs @@ -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 +{ + /// + /// 请求状态 + /// + public enum RequestStatus : byte + { + /// + /// 未开始 + /// + Hovering, + + /// + /// 正在进行 + /// + InProgress, + + /// + /// 完成 + /// + Finished + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Enum/StreamOperationType.cs b/RRQMSocket.FileTransfer/Enum/StreamOperationType.cs new file mode 100644 index 000000000..228181223 --- /dev/null +++ b/RRQMSocket.FileTransfer/Enum/StreamOperationType.cs @@ -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 +{ + /// + /// 流操作类型 + /// + public enum StreamOperationType : byte + { + /// + /// 读 + /// + Read, + + /// + /// 写 + /// + Write + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Enum/TransferFlags.cs b/RRQMSocket.FileTransfer/Enum/TransferFlags.cs new file mode 100644 index 000000000..4a6e1cd52 --- /dev/null +++ b/RRQMSocket.FileTransfer/Enum/TransferFlags.cs @@ -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 +{ + /// + /// 传输标识 + /// + [Flags] + public enum TransferFlags + { + /// + /// 无任何标识 + /// + None = 0, + + /// + /// 断点续传 + /// + BreakpointResume = 1, + + /// + /// 快速传输 + /// + QuickTransfer = 2 + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Enum/TransferStatus.cs b/RRQMSocket.FileTransfer/Enum/TransferStatus.cs new file mode 100644 index 000000000..2f9d84fa4 --- /dev/null +++ b/RRQMSocket.FileTransfer/Enum/TransferStatus.cs @@ -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 +{ + /// + /// 传输类型 + /// + public enum TransferStatus + { + /// + /// 无下载 + /// + None, + + /// + /// 上传 + /// + Upload, + + /// + /// 下载 + /// + Download, + + /// + /// 暂停下载状态 + /// + PauseDownload, + + /// + /// 暂停上传状态 + /// + PauseUpload + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Enum/TransferType.cs b/RRQMSocket.FileTransfer/Enum/TransferType.cs new file mode 100644 index 000000000..d8a1c0159 --- /dev/null +++ b/RRQMSocket.FileTransfer/Enum/TransferType.cs @@ -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 +{ + /// + /// 传输类型 + /// + public enum TransferType + { + /// + /// 上传 + /// + Upload, + + /// + /// 下载 + /// + Download, + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/EventArgs/FileEventArgs.cs b/RRQMSocket.FileTransfer/EventArgs/FileEventArgs.cs new file mode 100644 index 000000000..04083ea11 --- /dev/null +++ b/RRQMSocket.FileTransfer/EventArgs/FileEventArgs.cs @@ -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 +{ + /// + /// 文件事件 + /// + public class FileEventArgs : RRQMEventArgs + { + /// + /// 文件信息 + /// + public UrlFileInfo UrlFileInfo { get; internal set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/EventArgs/FileOperationEventArgs.cs b/RRQMSocket.FileTransfer/EventArgs/FileOperationEventArgs.cs new file mode 100644 index 000000000..aba8cbd17 --- /dev/null +++ b/RRQMSocket.FileTransfer/EventArgs/FileOperationEventArgs.cs @@ -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 +{ + /// + /// 操作文件事件类 + /// + public class FileOperationEventArgs : TransferFileMessageArgs + { + /// + /// 是否允许操作 + /// + public bool IsPermitOperation { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/EventArgs/TransferFileMessageArgs.cs b/RRQMSocket.FileTransfer/EventArgs/TransferFileMessageArgs.cs new file mode 100644 index 000000000..8e964b77d --- /dev/null +++ b/RRQMSocket.FileTransfer/EventArgs/TransferFileMessageArgs.cs @@ -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 +{ + /// + /// 文件传输消息 + /// + public class TransferFileMessageArgs : FileEventArgs + { + /// + /// 信息 + /// + public string Message { get; internal set; } + + /// + /// 传输类型 + /// + public TransferType TransferType { get; internal set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Exceptions/RRQMTransferErrorException.cs b/RRQMSocket.FileTransfer/Exceptions/RRQMTransferErrorException.cs new file mode 100644 index 000000000..688f354fd --- /dev/null +++ b/RRQMSocket.FileTransfer/Exceptions/RRQMTransferErrorException.cs @@ -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 +{ + /// + /// 传输错误 + /// + + public class RRQMTransferErrorException : RRQMException + { + /// + /// + /// + public RRQMTransferErrorException() : base() { } + + /// + /// + /// + /// + public RRQMTransferErrorException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMTransferErrorException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMTransferErrorException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Exceptions/RRQMTransferingException.cs b/RRQMSocket.FileTransfer/Exceptions/RRQMTransferingException.cs new file mode 100644 index 000000000..4483a684e --- /dev/null +++ b/RRQMSocket.FileTransfer/Exceptions/RRQMTransferingException.cs @@ -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 +{ + /* + 若汝棋茗 + */ + + /// + /// 没有传输任务异常 + /// + + public class RRQMTransferingException : RRQMException + { + /// + /// + /// + public RRQMTransferingException() : base() { } + + /// + /// + /// + /// + public RRQMTransferingException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMTransferingException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMTransferingException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Interface/IFileClient.cs b/RRQMSocket.FileTransfer/Interface/IFileClient.cs new file mode 100644 index 000000000..f39f32ce1 --- /dev/null +++ b/RRQMSocket.FileTransfer/Interface/IFileClient.cs @@ -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 +{ + /// + /// 文件终端接口 + /// + public interface IFileClient + { + /// + /// 获取当前传输文件信息 + /// + UrlFileInfo TransferFileInfo { get; } + + /// + /// 获取当前传输进度 + /// + float TransferProgress { get; } + + /// + /// 获取当前传输速度 + /// + long TransferSpeed { get; } + + /// + /// 获取当前传输状态 + /// + TransferStatus TransferStatus { get; } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Interface/IFileService.cs b/RRQMSocket.FileTransfer/Interface/IFileService.cs new file mode 100644 index 000000000..e09bb3db2 --- /dev/null +++ b/RRQMSocket.FileTransfer/Interface/IFileService.cs @@ -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 +{ + /// + /// 服务器接口 + /// + public interface IFileService + { + /// + /// 最大下载速度 + /// + long MaxDownloadSpeed { get; set; } + + /// + /// 最大上传速度 + /// + long MaxUploadSpeed { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/LICENSE b/RRQMSocket.FileTransfer/LICENSE new file mode 100644 index 000000000..5a9bb6217 --- /dev/null +++ b/RRQMSocket.FileTransfer/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license 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. diff --git a/RRQMSocket.FileTransfer/RRQM.ico b/RRQMSocket.FileTransfer/RRQM.ico new file mode 100644 index 0000000000000000000000000000000000000000..6465fb16e389ed1804d54b368018596580c6672e GIT binary patch literal 249918 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

&cP)Tdhs88a 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 + + net45;netcoreapp3.1;netstandard2.0 + RRQM.ico + true + RRQM.pfx + 5.5.0 + 若汝棋茗 + Copyright © 2021 若汝棋茗 + 介绍: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 + https://gitee.com/dotnetchina/RRQMSocket + + true + RRQM.png + 若汝棋茗 + true + LICENSE + FileTransfer,TCP,IOCP,BreakpointResume + + + + bin\Debug\netstandard2.0\RRQMSocket.FileTransfer.xml + + + + + bin\Release\netstandard2.0\RRQMSocket.FileTransfer.xml + + + + + bin\Debug\net45\RRQMSocket.FileTransfer.xml + + + + + bin\Release\net45\RRQMSocket.FileTransfer.xml + + + + + bin\Debug\netcoreapp3.1\RRQMSocket.FileTransfer.xml + + + + + bin\Release\netcoreapp3.1\RRQMSocket.FileTransfer.xml + + + + + + True + + + + True + + + + + + + + diff --git a/RRQMSocket.FileTransfer/Socket/FileClient.cs b/RRQMSocket.FileTransfer/Socket/FileClient.cs new file mode 100644 index 000000000..7abc66e67 --- /dev/null +++ b/RRQMSocket.FileTransfer/Socket/FileClient.cs @@ -0,0 +1,1030 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 RRQMCore.ByteManager; +using RRQMCore.Exceptions; +using RRQMCore.Log; +using RRQMCore.Run; +using RRQMCore.Serialization; +using RRQMSocket.RPC.RRQMRPC; +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace RRQMSocket.FileTransfer +{ + ///

+ /// 通讯客户端主类 + /// + public class FileClient : TcpRpcClient, IFileClient, IDisposable + { + private ProgressBlockCollection fileBlocks; + + private TransferCollection fileTransferCollection; + + private int packetSize; + + private long position; + + private float progress; + + private string receiveDirectory = string.Empty; + + private EventWaitHandle receiveWaitHandle; + + private string rrqmPath; + + private long speed; + + private bool stop; + + private long tempLength; + + private int timeout = 10 * 1000; + + private TransferStatus transferStatus; + + private UrlFileInfo transferUrlFileInfo; + + private EventWaitHandle transferWaitHandle; + + private WaitData waitDataSend; + + static FileClient() + { + 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, "保留协议"); + } + } + + /// + /// 无参数构造函数 + /// + public FileClient() + { + this.waitDataSend = new WaitData(); + this.transferWaitHandle = new AutoResetEvent(false); + this.receiveWaitHandle = new AutoResetEvent(false); + this.fileTransferCollection = new TransferCollection(); + this.transferStatus = TransferStatus.None; + this.FileTransferCollection.OnCollectionChanged += this.FileTransferCollection_OnCollectionChanged; + } + + /// + /// 传输文件之前 + /// + public event RRQMFileOperationEventHandler BeforeFileTransfer; + + /// + /// 当文件传输集合更改时 + /// + public event RRQMMessageEventHandler FileTransferCollectionChanged; + + /// + /// 当文件传输完成时 + /// + public event RRQMTransferFileMessageEventHandler FinishedFileTransfer; + + /// + /// 传输文件错误 + /// + public event RRQMTransferFileMessageEventHandler TransferFileError; + + /// + /// 获取当前传输文件包 + /// + public ProgressBlockCollection FileBlocks { get { return fileBlocks == null ? null : fileBlocks; } } + + /// + /// 文件传输队列集合 + /// + public TransferCollection FileTransferCollection + { + get { return fileTransferCollection; } + } + + /// + /// 默认接收文件的存放目录 + /// + public string ReceiveDirectory + { + get { return receiveDirectory; } + } + + /// + /// 单次请求超时时间 min=5000,max=60*1000 ms + /// + public int Timeout + { + get { return timeout; } + } + + /// + /// 获取当前传输文件信息 + /// + public UrlFileInfo TransferFileInfo { get { return this.transferUrlFileInfo; } } + + /// + /// 获取当前传输进度 + /// + public float TransferProgress + { + get + { + if (fileBlocks == null) + { + return 0; + } + if (fileBlocks.UrlFileInfo != null) + { + this.progress = fileBlocks.UrlFileInfo.FileLength > 0 ? (float)position / fileBlocks.UrlFileInfo.FileLength : 0;//计算下载完成进度 + } + else + { + this.progress = 0; + } + return progress <= 1 ? progress : 1; + } + } + + /// + /// 获取当前传输速度 + /// + public long TransferSpeed + { + get + { + this.speed = tempLength; + tempLength = 0; + return speed; + } + } + + /// + /// 获取当前传输状态 + /// + public TransferStatus TransferStatus + { + get { return transferStatus; } + } + + /// + /// 请求下载文件 + /// + /// + /// IP及端口 + /// 验证令箭 + /// 完成时回调 + /// + /// + public static FileClient RequestFile(UrlFileInfo urlFileInfo, string host, string verifyToken = null, + RRQMTransferFileMessageEventHandler finishedCallBack = null, + RRQMTransferFileMessageEventHandler errorCallBack = null) + { + FileClient fileClient = new FileClient(); + try + { + var config = new FileClientConfig(); + config.SetValue(TcpClientConfig.RemoteIPHostProperty, new IPHost(host)) + .SetValue(TokenClientConfig.VerifyTokenProperty, verifyToken); + + fileClient.Setup(config); + fileClient.Connect(); + + fileClient.FinishedFileTransfer += + (object sender, TransferFileMessageArgs e) => + { + fileClient.Dispose(); + finishedCallBack?.Invoke(sender, e); + }; + fileClient.TransferFileError += + (object sender, TransferFileMessageArgs e) => + { + fileClient.Dispose(); + errorCallBack?.Invoke(sender, e); + }; + fileClient.RequestTransfer(urlFileInfo); + return fileClient; + } + catch (Exception ex) + { + fileClient.Dispose(); + throw new RRQMException(ex.Message); + } + } + + /// + /// 取消指定传输任务 + /// + /// + /// + public bool CancelTransfer(UrlFileInfo fileInfo) + { + return this.FileTransferCollection.Remove(fileInfo); + } + + /// + /// 断开连接 + /// + public override void Disconnect() + { + base.Disconnect(); + this.ResetVariable(); + } + + /// + /// 释放资源 + /// + public override void Dispose() + { + base.Dispose(); + if (this.transferStatus == TransferStatus.Download) + { + this.StopDownload(); + } + else if (this.transferStatus == TransferStatus.Upload) + { + this.StopUpload(); + } + this.waitDataSend.Dispose(); + this.transferStatus = TransferStatus.None; + this.progress = 0; + this.speed = 0; + } + + /// + /// 暂停传输 + /// + public void PauseTransfer() + { + if (this.transferStatus == TransferStatus.Download) + { + this.transferStatus = TransferStatus.PauseDownload; + } + else if (this.transferStatus == TransferStatus.Upload) + { + this.transferStatus = TransferStatus.PauseUpload; + } + } + + /// + /// 请求传输文件 + /// + /// + public void RequestTransfer(UrlFileInfo fileInfo) + { + this.FileTransferCollection.Add(fileInfo); + BeginTransfer(); + } + + /// + /// 恢复传输 + /// + /// 是否有任务成功继续 + public bool ResumeTransfer() + { + if (this.transferStatus == TransferStatus.PauseDownload) + { + this.transferStatus = TransferStatus.Download; + } + else if (this.transferStatus == TransferStatus.PauseUpload) + { + this.transferStatus = TransferStatus.Upload; + } + else + { + return false; + } + + return this.transferWaitHandle.Set(); + } + + /// + /// 终止所有传输 + /// + public void StopAllTransfer() + { + this.stop = true; + this.FileTransferCollection.Clear(); + } + + /// + /// 终止当前传输 + /// + /// + public void StopThisTransfer() + { + this.stop = true; + this.BeginTransfer(); + } + + /// + /// 文件客户端处理其他协议 + /// + /// + /// + protected virtual void FileClientHandleDefaultData(short? procotol, ByteBlock byteBlock) + { + this.OnHandleDefaultData(procotol, byteBlock); + } + + /// + /// 加载配置 + /// + /// + protected override void LoadConfig(TcpClientConfig clientConfig) + { + base.LoadConfig(clientConfig); + this.receiveDirectory = (string)clientConfig.GetValue(FileClientConfig.ReceiveDirectoryProperty); + this.packetSize = (int)clientConfig.GetValue(FileClientConfig.PacketSizeProperty); + this.timeout = (int)clientConfig.GetValue(FileClientConfig.TimeoutProperty); + } + + /// + /// 密封方法 + /// + /// + /// + protected sealed override void RPCHandleDefaultData(short? procotol, ByteBlock byteBlock) + { + switch (procotol) + { + case 111: + { + this.waitDataSend.Set(byteBlock); + this.receiveWaitHandle.WaitOne(); + break; + } + default: + { + FileClientHandleDefaultData(procotol, byteBlock); + break; + } + } + } + + private void BeginTransfer() + { + Task.Run(() => + { + lock (locker) + { + if (this.transferStatus == TransferStatus.None) + { + this.receiveWaitHandle.Set(); + if (this.FileTransferCollection.GetFirst(out UrlFileInfo urlFileInfo)) + { + try + { + if (urlFileInfo.TransferType == TransferType.Download) + { + this.DownloadFile(urlFileInfo, true); + } + else + { + this.UploadFile(urlFileInfo, true); + } + } + catch (Exception ex) + { + this.OnTransferError(urlFileInfo.TransferType, ex.Message, urlFileInfo); + } + } + } + } + }); + } + + private void DownloadFile(UrlFileInfo urlFileInfo, bool triggerEvent) + { + if (!this.Online) + { + throw new RRQMException("未连接服务器"); + } + else if (this.transferStatus != TransferStatus.None) + { + throw new RRQMTransferingException("已有传输任务在进行中"); + } + + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + + try + { + SerializeConvert.RRQMBinarySerialize(byteBlock, urlFileInfo, true); + ByteBlock returnByteBlock = this.SingleSendWait(112, urlFileInfo.Timeout, byteBlock); + FileWaitResult waitResult = SerializeConvert.RRQMBinaryDeserialize(returnByteBlock.Buffer, 2); + if (waitResult.Status == 2) + { + throw new RRQMTransferErrorException(waitResult.Message); + } + urlFileInfo = waitResult.PBCollectionTemp.UrlFileInfo; + + ProgressBlockCollection blocks = ProgressBlockCollection.CreateProgressBlockCollection(urlFileInfo); + if (triggerEvent) + { + this.OnBeforeFileTransfer(blocks); + } + if (!FileStreamPool.LoadWriteStream(ref blocks, !triggerEvent, out string mes)) + { + this.OnTransferError(urlFileInfo.TransferType, mes, urlFileInfo); + return; + } + + this.transferStatus = TransferStatus.Download; + this.fileBlocks = blocks; + this.transferUrlFileInfo = blocks.UrlFileInfo; + this.rrqmPath = blocks.UrlFileInfo.SaveFullPath + ".rrqm"; + Thread thread_Transfer = new Thread(this.DownloadFileBlock); + thread_Transfer.IsBackground = true; + thread_Transfer.Name = "文件下载线程"; + thread_Transfer.Start(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + this.receiveWaitHandle.Set(); + byteBlock.Dispose(); + } + } + + private void DownloadFileBlock() + { + this.stop = false; + while (true) + { + if (FileStreamPool.GetFreeFileBlock(this.rrqmPath, out FileBlock fileBlock, out string errorMes)) + { + if (fileBlock == null) + { + break; + } + this.position = fileBlock.Position; + long surplusLength = fileBlock.UnitLength; + int reTryCount = 0; + while (surplusLength > 0) + { + if (!this.Online) + { + fileBlock.RequestStatus = RequestStatus.Hovering; + this.OnTransferError(TransferType.Download, "客户端已断开连接!!!"); + return; + } + if (disposable || stop) + { + fileBlock.RequestStatus = RequestStatus.Hovering; + StopDownload(); + return; + } + if (this.transferStatus == TransferStatus.PauseDownload) + { + transferWaitHandle.WaitOne(); + } + + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + byteBlock.Write(this.position); + int requestLength = surplusLength > this.packetSize ? this.packetSize : (int)surplusLength; + byteBlock.Write(requestLength); + + try + { + ByteBlock returnByteBlock = this.SingleSendWait(113, this.timeout, byteBlock); + if (returnByteBlock.Buffer[2] == 1) + { + if (this.transferStatus != TransferStatus.Download && this.transferStatus != TransferStatus.PauseDownload) + { + fileBlock.RequestStatus = RequestStatus.Hovering; + return; + } + if (FileStreamPool.WriteFile(this.rrqmPath, out string mes, out RRQMStream _, this.position, returnByteBlock.Buffer, 3, returnByteBlock.Len - 3)) + { + tempLength += requestLength; + this.position += requestLength; + surplusLength -= requestLength; + reTryCount = 0; + } + else + { + throw new RRQMException($"文件写入错误,信息:{mes}"); + } + } + else if (returnByteBlock.Buffer[2] == 2) + { + string mes = Encoding.UTF8.GetString(returnByteBlock.Buffer, 3, returnByteBlock.Len - 3); + throw new RRQMException($"文件请求错误,信息:{mes}"); + } + } + catch (Exception ex) + { + reTryCount++; + Logger.Debug(LogType.Message, this, $"下载文件错误,信息:{ex.Message},即将进行第{reTryCount}次重试"); + + if (reTryCount > 10) + { + fileBlock.RequestStatus = RequestStatus.Hovering; + this.OnTransferError(TransferType.Download, "重试次数达到最大,详细信息请查看日志"); + return; + } + } + finally + { + this.receiveWaitHandle.Set(); + byteBlock.Dispose(); + } + } + fileBlock.RequestStatus = RequestStatus.Finished; + if (this.transferUrlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume)) + { + try + { + FileStreamPool.SaveProgressBlockCollection(this.rrqmPath); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, "保存进度文件错误", ex); + } + } + } + else + { + this.Logger.Debug(LogType.Error, this, $"获取文件块错误,信息:{errorMes}"); + } + } + if (FileStreamPool.CheckAllFileBlockFinished(this.rrqmPath)) + { + this.DownloadFinished(); + } + } + + private void DownloadFinished() + { + for (int i = 0; i < 5; i++) + { + try + { + ByteBlock resultByteBlock = this.SingleSendWait(115, this.timeout); + + if (resultByteBlock.Buffer[2] == 1) + { + OnDownloadFileFinished(); + return; + } + else + { + this.Logger.Debug(LogType.Warning, this, $"确认下载完成返回状态错误,即将进行第{i + 1}次重试"); + } + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Warning, this, $"确认下载完成错误,信息:{ex.Message},即将进行第{i + 1}次重试"); + } + finally + { + this.receiveWaitHandle.Set(); + } + } + + this.OnTransferError(TransferType.Download, "确认下载完成状态重试次数已达到最大,具体信息请查看日志输出"); + } + + private void FileTransferCollection_OnCollectionChanged(object sender, MesEventArgs e) + { + this.FileTransferCollectionChanged?.Invoke(this, e); + } + + private void OnBeforeFileTransfer(ProgressBlockCollection blocks) + { + FileOperationEventArgs args = new FileOperationEventArgs(); + args.UrlFileInfo = blocks.UrlFileInfo; + if (blocks.UrlFileInfo.TransferType == TransferType.Download) + { + //下载 + if (string.IsNullOrEmpty(blocks.UrlFileInfo.SaveFullPath)) + { + blocks.UrlFileInfo.SaveFullPath = Path.Combine(this.receiveDirectory, blocks.UrlFileInfo.FileName); + } + } + + args.TransferType = blocks.UrlFileInfo.TransferType; + args.IsPermitOperation = true; + try + { + this.BeforeFileTransfer?.Invoke(this, args); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, $"在事件{nameof(BeforeFileTransfer)}中发生异常", ex); + } + if (blocks.UrlFileInfo.TransferType == TransferType.Download) + { + //下载 + blocks.UrlFileInfo.SaveFullPath = Path.GetFullPath(args.UrlFileInfo.SaveFullPath); + } + else + { + blocks.UrlFileInfo.FilePath = Path.GetFullPath(args.UrlFileInfo.FilePath); + } + } + + private void OnDownloadFileFinished() + { + try + { + FileStreamPool.DisposeWriteStream(this.rrqmPath, true); + TransferFileMessageArgs args = new TransferFileMessageArgs(); + args.UrlFileInfo = this.transferUrlFileInfo; + args.TransferType = TransferType.Download; + TransferFileHashDictionary.AddFile(this.transferUrlFileInfo); + + ResetVariable(); + try + { + this.FinishedFileTransfer?.Invoke(this, args); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, $"在事件{nameof(FinishedFileTransfer)}中发生异常", ex); + } + this.BeginTransfer(); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, $"在完成下载时中发生异常", ex); + } + } + + private void OnTransferError(TransferType transferType, string msg, UrlFileInfo urlFileInfo = null) + { + TransferFileMessageArgs args = new TransferFileMessageArgs(); + args.UrlFileInfo = urlFileInfo == null ? this.TransferFileInfo : urlFileInfo; + args.TransferType = transferType; + args.Message = msg; + switch (transferType) + { + case TransferType.Upload: + { + StopUpload(); + break; + } + case TransferType.Download: + { + StopDownload(); + break; + } + } + + try + { + this.TransferFileError?.Invoke(this, args); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, $"在事件{nameof(this.TransferFileError)}中发生异常。", ex); + } + + this.BeginTransfer(); + } + + private void OnUploadFileFinished() + { + TransferFileMessageArgs args = new TransferFileMessageArgs(); + args.UrlFileInfo = this.transferUrlFileInfo; + args.TransferType = TransferType.Upload; + + ResetVariable(); + try + { + this.FinishedFileTransfer?.Invoke(this, args); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, $"在事件{nameof(FinishedFileTransfer)}中发生异常", ex); + } + this.BeginTransfer(); + } + + private void ResetVariable() + { + this.fileBlocks = null; + 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 ByteBlock SingleSendWait(short procotol, int timeout, ByteBlock byteBlock = null, bool reserved = false) + { + lock (locker) + { + if (!this.Online) + { + throw new RRQMNotConnectedException("客户端未连接"); + } + if (byteBlock == null) + { + this.InternalSend(procotol, new byte[0], 0, 0); + } + else + { + this.InternalSend(procotol, byteBlock.Buffer, 0, byteBlock.Len, reserved); + } + if (!this.waitDataSend.Wait(timeout)) + { + this.receiveWaitHandle.Set(); + throw new RRQMTimeoutException("请求超时"); + } + return this.waitDataSend.WaitResult; + } + } + + private void StopDownload() + { + if (this.disposable) + { + return; + } + this.stop = true; + FileStreamPool.DisposeWriteStream(this.rrqmPath, false); + if (!this.Online) + { + ResetVariable(); + return; + } + try + { + this.SingleSendWait(114, this.timeout); + ResetVariable(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + this.receiveWaitHandle.Set(); + } + } + + private void StopUpload() + { + try + { + if (this.transferUrlFileInfo == null) + { + return; + } + FileStreamPool.DisposeReadStream(this.transferUrlFileInfo.FilePath); + if (!this.Online) + { + ResetVariable(); + return; + } + ByteBlock byteBlock = this.SingleSendWait(118, this.timeout); + ResetVariable(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + this.receiveWaitHandle.Set(); + } + } + + private void UploadFile(UrlFileInfo urlFileInfo, bool triggerEvent) + { + if (!this.Online) + { + throw new RRQMNotConnectedException("未连接到服务器"); + } + else if (this.transferStatus != TransferStatus.None) + { + throw new RRQMTransferingException("已有传输任务在进行中"); + } + byte[] datas = SerializeConvert.RRQMBinarySerialize(urlFileInfo, true); + ByteBlock byteBlock = this.BytePool.GetByteBlock(datas.Length); + byteBlock.Write(datas); + + try + { + ByteBlock resultByteBlock = this.SingleSendWait(116, this.timeout, byteBlock); + FileWaitResult waitResult = SerializeConvert.RRQMBinaryDeserialize(resultByteBlock.Buffer, 2); + if (waitResult.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (waitResult.Status == 2) + { + throw new RRQMTransferErrorException(waitResult.Message); + } + else if (waitResult.Status == 3) + { + this.transferStatus = TransferStatus.Upload; + this.transferUrlFileInfo = urlFileInfo; + this.fileBlocks = ProgressBlockCollection.CreateProgressBlockCollection(urlFileInfo); + if (triggerEvent) + { + this.OnBeforeFileTransfer(this.fileBlocks); + } + Task.Run(() => + { + UploadFinished(); + }); + + } + else + { + if (FileStreamPool.LoadReadStream(ref urlFileInfo, out string mes)) + { + this.transferStatus = TransferStatus.Upload; + ProgressBlockCollection blocks = waitResult.PBCollectionTemp.ToPBCollection(); + blocks.UrlFileInfo = urlFileInfo; + this.transferUrlFileInfo = urlFileInfo; + this.fileBlocks = blocks; + if (triggerEvent) + { + this.OnBeforeFileTransfer(blocks); + } + + Thread thread_Transfer = new Thread(this.UploadFileBlock); + thread_Transfer.IsBackground = true; + thread_Transfer.Name = "文件上传线程"; + thread_Transfer.Start(); + } + else + { + throw new RRQMException(mes); + } + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + this.receiveWaitHandle.Set(); + } + } + + private void UploadFileBlock() + { + this.stop = false; + + foreach (FileBlock fileBlock in this.fileBlocks) + { + if (fileBlock.RequestStatus == RequestStatus.Hovering) + { + this.position = fileBlock.Position; + long surplusLength = fileBlock.UnitLength; + int reTryCount = 0; + while (surplusLength > 0) + { + if (!this.Online) + { + fileBlock.RequestStatus = RequestStatus.Hovering; + this.OnTransferError(TransferType.Download, "客户端已断开连接!!!"); + return; + } + if (disposable || stop) + { + StopUpload(); + return; + } + if (this.transferStatus == TransferStatus.PauseUpload) + { + transferWaitHandle.WaitOne(); + } + + int submitLength = surplusLength > this.packetSize ? this.packetSize : (int)surplusLength; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.packetSize + 23); + byteBlock.Position = 6; + if (this.position + submitLength == fileBlock.Position + fileBlock.UnitLength) + { + byteBlock.Write((byte)1);//1 + } + else + { + byteBlock.Write((byte)1); + } + + byteBlock.Write(fileBlock.Index);//4 + byteBlock.Write(this.position);//8 + byteBlock.Write(submitLength);//4 + //17+2+4=23 + try + { + if (this.transferStatus != TransferStatus.Upload && this.transferStatus != TransferStatus.PauseUpload) + { + return; + } + if (FileStreamPool.ReadFile(this.transferUrlFileInfo.FilePath, out string mes, this.position, byteBlock, 23, submitLength)) + { + ByteBlock returnByteBlock = this.SingleSendWait(117, this.timeout, byteBlock, true); + + if (returnByteBlock.Buffer[2] == 1) + { + reTryCount = 0; + this.tempLength += submitLength; + this.position += submitLength; + surplusLength -= submitLength; + } + else if (returnByteBlock.Buffer[2] == 2) + { + throw new RRQMException(Encoding.UTF8.GetString(returnByteBlock.Buffer, 3, returnByteBlock.Len - 3)); + } + else + { + this.OnTransferError(TransferType.Upload, "服务器无此传输信息,已终止本次传输"); + return; + } + } + else + { + throw new RRQMException(mes); + } + } + catch (Exception ex) + { + reTryCount++; + Logger.Debug(LogType.Message, this, $"上传文件错误,正在尝试第{reTryCount}次重试", ex); + if (reTryCount > 10) + { + this.OnTransferError(TransferType.Upload, "重试次数达到最大,详细信息请查看日志"); + return; + } + } + finally + { + byteBlock.Dispose(); + this.receiveWaitHandle.Set(); + } + } + } + } + UploadFinished(); + } + + private void UploadFinished() + { + for (int i = 0; i < 5; i++) + { + try + { + ByteBlock byteBlock = this.SingleSendWait(119, this.timeout); + if (byteBlock.Length == 3 && byteBlock.Buffer[2] == 1) + { + this.OnUploadFileFinished(); + return; + } + else + { + this.Logger.Debug(LogType.Warning, this, $"确认上传完成返回状态错误,即将进行第{i + 1}次重试"); + } + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Warning, this, $"确认下载完成错误,信息:{ex.Message},即将进行第{i + 1}次重试"); + } + finally + { + this.receiveWaitHandle.Set(); + } + } + + this.OnTransferError(TransferType.Upload, "确认上传完成状态重试次数已达到最大,具体信息请查看日志输出"); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Socket/FileService.cs b/RRQMSocket.FileTransfer/Socket/FileService.cs new file mode 100644 index 000000000..ef4a3bc71 --- /dev/null +++ b/RRQMSocket.FileTransfer/Socket/FileService.cs @@ -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 +{ + /// + /// 通讯服务端主类 + /// + public class FileService : TcpParser, IFileService + { + #region 属性 + + private long maxDownloadSpeed; + + private long maxUploadSpeed; + + /// + /// 获取下载速度 + /// + public long DownloadSpeed + { + get + { + this.downloadSpeed = Speed.downloadSpeed; + Speed.downloadSpeed = 0; + return this.downloadSpeed; + } + } + + /// + /// 最大下载速度 + /// + public long MaxDownloadSpeed + { + get { return maxDownloadSpeed; } + set { maxUploadSpeed = value; } + } + + /// + /// 最大上传速度 + /// + public long MaxUploadSpeed + { + get { return maxUploadSpeed; } + set { maxUploadSpeed = value; } + } + + /// + /// 获取上传速度 + /// + public long UploadSpeed + { + get + { + this.uploadSpeed = Speed.uploadSpeed; + Speed.uploadSpeed = 0; + return this.uploadSpeed; + } + } + + #endregion 属性 + + #region 字段 + + private long downloadSpeed; + private long uploadSpeed; + + #endregion 字段 + + #region 事件 + + /// + /// 传输文件之前 + /// + public event RRQMFileOperationEventHandler BeforeFileTransfer; + + /// + /// 当文件传输完成时 + /// + public event RRQMTransferFileMessageEventHandler FinishedFileTransfer; + + #endregion 事件 + + /// + /// 载入配置 + /// + /// + protected override void LoadConfig(ServiceConfig serviceConfig) + { + base.LoadConfig(serviceConfig); + this.maxDownloadSpeed = (long)serviceConfig.GetValue(FileServiceConfig.MaxDownloadSpeedProperty); + this.maxUploadSpeed = (long)serviceConfig.GetValue(FileServiceConfig.MaxUploadSpeedProperty); + } + + /// + /// 创建完成FileSocketClient + /// + /// + /// + 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); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.FileTransfer/Socket/FileSocketClient.cs b/RRQMSocket.FileTransfer/Socket/FileSocketClient.cs new file mode 100644 index 000000000..5e27845ac --- /dev/null +++ b/RRQMSocket.FileTransfer/Socket/FileSocketClient.cs @@ -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 +{ + /// + /// 已接收的客户端 + /// + public class FileSocketClient : RpcSocketClient, IFileService, IFileClient + { + /// + /// 传输文件之前 + /// + internal RRQMFileOperationEventHandler BeforeFileTransfer; + + /// + /// 当文件传输完成时 + /// + 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, "保留协议"); + } + } + + /// + /// 每秒最大下载速度(Byte),不可小于1024 + /// + public long MaxDownloadSpeed + { + get { return maxDownloadSpeed; } + set + { + if (value < 1024) + { + value = 1024; + } + this.maxDownloadSpeed = value; + } + } + + /// + /// 每秒最大上传速度(Byte),不可小于1024 + /// + public long MaxUploadSpeed + { + get { return maxUploadSpeed; } + set + { + if (value < 1024) + { + value = 1024; + } + this.maxUploadSpeed = value; + } + } + + /// + /// 获取当前传输文件信息 + /// + public UrlFileInfo TransferFileInfo { get => this.transferUrlFileInfo; } + + /// + /// 获取当前传输进度 + /// + public float TransferProgress + { + get + { + if (transferUrlFileInfo == null) + { + return 0; + } + this.progress = transferUrlFileInfo.FileLength > 0 ? (float)position / transferUrlFileInfo.FileLength : 0;//计算下载完成进度 + return progress <= 1 ? progress : 1; + } + } + + /// + /// 获取当前传输速度 + /// + public long TransferSpeed + { + get + { + this.speed = tempLength; + tempLength = 0; + return speed; + } + } + + /// + /// 获取当前传输状态 + /// + public TransferStatus TransferStatus + { + get { return transferStatus; } + } + + /// + /// 释放资源 + /// + public override void Dispose() + { + base.Dispose(); + this.ResetVariable(); + } + + /// + /// 重置 + /// + public override void Recreate() + { + base.Recreate(); + } + + /// + /// 文件辅助类处理其他协议 + /// + /// + /// + protected virtual void FileSocketClientHandleDefaultData(short? procotol, ByteBlock byteBlock) + { + this.OnHandleDefaultData(procotol, byteBlock); + } + + /// + /// 封装协议 + /// + /// + /// + 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(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(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; + } + } + } + + /// + /// 继承 + /// + 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; + } + } + } + + /// + /// 获取当前时间帧 + /// + /// + 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(); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/Common/HttpBase.cs b/RRQMSocket.Http/Common/HttpBase.cs new file mode 100644 index 000000000..73bfd7f22 --- /dev/null +++ b/RRQMSocket.Http/Common/HttpBase.cs @@ -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 +{ + /// + /// Http基础头部 + /// + public abstract class HttpBase + { + /// + /// 构造函数 + /// + public HttpBase() + { + this.headers = new Dictionary(); + } + + /// + /// 服务器版本 + /// + public static readonly string ServerVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); + + private string requestLine; + + /// + /// 字符数据 + /// + public string Body { get { return this.content == null ? null : this.encoding.GetString(this.content); } } + + private byte[] content; + + /// + /// 内容器 + /// + public byte[] Content + { + get { return content; } + } + + /// + /// 内容编码 + /// + public string Content_Encoding { get; set; } + + /// + /// 内容长度 + /// + public int Content_Length { get; set; } + + /// + /// 内容类型 + /// + public string Content_Type { get; set; } + + /// + /// 内容语言 + /// + public string ContentLanguage { get; set; } + + private Encoding encoding = Encoding.UTF8; + + /// + /// 编码方式 + /// + public Encoding Encoding + { + get { return encoding; } + set { encoding = value; } + } + + /// + /// 传递标识 + /// + public object Flag { get; set; } + + /// + /// 请求头集合 + /// + public Dictionary Headers { get { return this.headers; } } + + private Dictionary headers; + + /// + /// 协议名称 + /// + public string Protocols { get; set; } + + /// + /// HTTP协议版本 + /// + public string ProtocolVersion { get; set; } = "1.1"; + + /// + /// 请求行 + /// + public string RequestLine + { + get { return requestLine; } + } + + /// + /// 构建数据 + /// + /// + public abstract void Build(ByteBlock byteBlock); + + /// + /// 获取头值 + /// + /// + /// + public string GetHeader(HttpHeaders header) + { + return GetHeaderByKey(header); + } + + /// + /// 读取信息 + /// + public abstract void ReadFromBase(); + + /// + /// 从内存中读取 + /// + /// + /// + /// + 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; + } + + /// + /// 获取头集合的值 + /// + /// + /// + 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]; + } + + /// + /// 获取头集合的值 + /// + /// + /// + protected string GetHeaderByKey(string fieldName) + { + if (string.IsNullOrEmpty(fieldName)) return null; + var hasKey = Headers.ContainsKey(fieldName); + if (!hasKey) return null; + return Headers[fieldName]; + } + + /// + /// 设置头值 + /// + 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; + } + + /// + /// 设置头值 + /// + /// + /// + 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 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]); + } + } + } + } + + /// + /// 设置内容 + /// + /// + /// + public void SetContent(byte[] content) + { + this.content = content; + this.Content_Length = content.Length; + } + + /// + /// 设置内容 + /// + /// + /// + /// + public void SetContent(string content, Encoding encoding = null) + { + //初始化内容 + encoding = encoding != null ? encoding : Encoding.UTF8; + SetContent(encoding.GetBytes(content)); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/Common/HttpRequest.cs b/RRQMSocket.Http/Common/HttpRequest.cs new file mode 100644 index 000000000..bba873ad4 --- /dev/null +++ b/RRQMSocket.Http/Common/HttpRequest.cs @@ -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 +{ + /// + /// HTTP请求定义 + /// + public class HttpRequest : HttpBase + { + /// + /// 表单参数 + /// + public Dictionary Forms { get; set; } + + /// + /// 获取时候保持连接 + /// + public bool KeepAlive { get; set; } + + /// + /// HTTP请求方式 + /// + public string Method { get; set; } + + /// + /// URL参数 + /// + public Dictionary Params { get; set; } + + /// + /// url参数 + /// + public Dictionary Query { get; set; } + + /// + /// 相对路径(不含参数) + /// + public string RelativeURL { get; set; } + + /// + /// HTTP(S)地址 + /// + public string URL { get; set; } + + /// + /// 构建响应头部 + /// + /// + 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); + } + } + + /// + /// 构建响应数据 + /// + /// + public override void Build(ByteBlock byteBlock) + { + BuildHeader(byteBlock); + BuildContent(byteBlock); + } + + /// + /// 获取头值 + /// + /// + /// + public string GetHeader(string fieldName) + { + return GetHeaderByKey(fieldName); + } + + /// + /// 从内存中读取 + /// + 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); + } + } + } + + /// + /// 设置头值 + /// + /// + /// + public void SetHeader(HttpHeaders header, string value) + { + SetHeaderByKey(header, value); + } + + /// + /// 设置头值 + /// + /// + /// + public void SetHeader(string fieldName, string value) + { + SetHeaderByKey(fieldName, value); + } + + private Dictionary GetRequestParameters(string row) + { + if (string.IsNullOrEmpty(row)) + { + return null; + } + string[] kvs = row.Split('&'); + if (kvs == null || kvs.Count() == 0) + { + return null; + } + + Dictionary pairs = new Dictionary(); + foreach (var item in kvs) + { + string[] kv = item.SplitFirst('='); + if (kv.Length == 2) + { + pairs.Add(kv[0], kv[1]); + } + } + + return pairs; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/Common/HttpResponse.cs b/RRQMSocket.Http/Common/HttpResponse.cs new file mode 100644 index 000000000..d6ab4c2a5 --- /dev/null +++ b/RRQMSocket.Http/Common/HttpResponse.cs @@ -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 +{ + /// + /// Http响应 + /// + public class HttpResponse : HttpBase + { + /// + /// 状态码 + /// + public string StatusCode { get; set; } + + /// + /// 获取头数据 + /// + /// + /// + public string GetHeader(string fieldName) + { + return GetHeaderByKey(fieldName); + } + + /// + /// 设置头数据 + /// + /// + /// + public void SetHeader(HttpHeaders header, string value) + { + SetHeaderByKey(header, value); + } + + /// + /// 设置头数据 + /// + /// + /// + public void SetHeader(string fieldName, string value) + { + SetHeaderByKey(fieldName, value); + } + + /// + /// 构建响应头部 + /// + /// + 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); + } + } + + /// + /// 构建响应数据 + /// + /// + public override void Build(ByteBlock byteBlock) + { + BuildHeader(byteBlock); + BuildContent(byteBlock); + } + + /// + /// 读取数据 + /// + 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; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/DataAdapter/HttpDataHandlingAdapter.cs b/RRQMSocket.Http/DataAdapter/HttpDataHandlingAdapter.cs new file mode 100644 index 000000000..5e966fdc5 --- /dev/null +++ b/RRQMSocket.Http/DataAdapter/HttpDataHandlingAdapter.cs @@ -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 +{ + /// + /// Http数据处理适配器 + /// + public class HttpDataHandlingAdapter : DataHandlingAdapter + { + /// + /// 构造函数 + /// + /// + /// + 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; + + /// + /// 允许的最大长度 + /// + public int MaxSize { get; private set; } + + private ByteBlock tempByteBlock; + private ByteBlock bodyByteBlock; + + private HttpBase httpBase; + + /// + /// 预处理 + /// + /// + 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); + } + } + + /// + /// 预处理 + /// + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync) + { + this.GoSend(buffer, offset, length, isAsync); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/Enum/HttpHeaders.cs b/RRQMSocket.Http/Enum/HttpHeaders.cs new file mode 100644 index 000000000..59086448c --- /dev/null +++ b/RRQMSocket.Http/Enum/HttpHeaders.cs @@ -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 +{ + /// + /// 请求头枚举 + /// + public enum HttpHeaders : byte + { + /// + /// Cache-Control 标头,指定请求/响应链上所有缓存控制机制必须服从的指令。 + /// + [Description("Cache-Control")] + CacheControl = 0, + + /// + /// Connection 标头,指定特定连接需要的选项。 + /// + [Description("Connection")] + Connection = 1, + + /// + /// Date 标头,指定开始创建请求的日期和时间。 + /// + [Description("Date")] + Date = 2, + + /// + /// Keep-Alive 标头,指定用以维护持久性连接的参数。 + /// + [Description("Keep-Alive")] + KeepAlive = 3, + + /// + /// Pragma 标头,指定可应用于请求/响应链上的任何代理的特定于实现的指令。 + /// + [Description("Pragma")] + Pragma = 4, + + /// + /// Trailer 标头,指定标头字段显示在以 chunked 传输编码方式编码的消息的尾部。 + /// + [Description("Trailer")] + Trailer = 5, + + /// + /// Transfer-Encoding 标头,指定对消息正文应用的转换的类型(如果有)。 + /// + [Description("Transfer-Encoding")] + TransferEncoding = 6, + + /// + /// Upgrade 标头,指定客户端支持的附加通信协议。 + /// + [Description("Upgrade")] + Upgrade = 7, + + /// + /// Via 标头,指定网关和代理程序要使用的中间协议。 + /// + [Description("Via")] + Via = 8, + + /// + /// Warning 标头,指定关于可能未在消息中反映的消息的状态或转换的附加信息。 + /// + [Description("Warning")] + Warning = 9, + + /// + /// Allow 标头,指定支持的 HTTP 方法集。 + /// + [Description("Allow")] + Allow = 10, + + /// + /// Content-Length 标头,指定伴随正文数据的长度(以字节为单位)。 + /// + [Description("Content-Length")] + ContentLength = 11, + + /// + /// Content-Type 标头,指定伴随正文数据的 MIME 类型。 + /// + [Description("Content-Type")] + ContentType = 12, + + /// + /// Content-Encoding 标头,指定已应用于伴随正文数据的编码。 + /// + [Description("Content-Encoding")] + ContentEncoding = 13, + + /// + /// Content-Langauge 标头,指定伴随正文数据的自然语言。 + /// + [Description("Content-Langauge")] + ContentLanguage = 14, + + /// + /// Content-Location 标头,指定可从其中获得伴随正文的 URI。 + /// + [Description("Content-Location")] + ContentLocation = 15, + + /// + /// Content-MD5 标头,指定伴随正文数据的 MD5 摘要,用于提供端到端消息完整性检查。 + /// + [Description("Content-MD5")] + ContentMd5 = 16, + + /// + /// Content-Range 标头,指定在完整正文中应用伴随部分正文数据的位置。 + /// + [Description("Content-Range")] + ContentRange = 17, + + /// + /// Expires 标头,指定日期和时间,在此之后伴随的正文数据应视为陈旧的。 + /// + [Description("Expires")] + Expires = 18, + + /// + /// Last-Modified 标头,指定上次修改伴随的正文数据的日期和时间。 + /// + [Description("Last-Modified")] + LastModified = 19, + + /// + /// Accept 标头,指定响应可接受的 MIME 类型。 + /// + [Description("Accept")] + Accept = 20, + + /// + /// Accept-Charset 标头,指定响应可接受的字符集。 + /// + [Description("Accept-Charset")] + AcceptCharset = 21, + + /// + /// Accept-Encoding 标头,指定响应可接受的内容编码。 + /// + [Description("Accept-Encoding")] + AcceptEncoding = 22, + + /// + /// Accept-Langauge 标头,指定响应首选的自然语言。 + /// + [Description("Accept-Langauge")] + AcceptLanguage = 23, + + /// + /// Authorization 标头,指定客户端为向服务器验证自身身份而出示的凭据。 + /// + [Description("Authorization")] + Authorization = 24, + + /// + /// Cookie 标头,指定向服务器提供的 Cookie 数据。 + /// + [Description("Cookie")] + Cookie = 25, + + /// + /// Expect 标头,指定客户端要求的特定服务器行为。 + /// + [Description("Expect")] + Expect = 26, + + /// + /// From 标头,指定控制请求用户代理的用户的 Internet 电子邮件地址。 + /// + [Description("From")] + From = 27, + + /// + /// Host 标头,指定所请求资源的主机名和端口号。 + /// + [Description("Host")] + Host = 28, + + /// + /// If-Match 标头,指定仅当客户端的指示资源的缓存副本是最新的时,才执行请求的操作。 + /// + [Description("If-Match")] + IfMatch = 29, + + /// + /// If-Modified-Since 标头,指定仅当自指示的数据和时间之后修改了请求的资源时,才执行请求的操作。 + /// + [Description("If-Modified-Since")] + IfModifiedSince = 30, + + /// + /// If-None-Match 标头,指定仅当客户端的指示资源的缓存副本都不是最新的时,才执行请求的操作。 + /// + [Description("If-None-Match")] + IfNoneMatch = 31, + + /// + /// If-Range 标头,指定如果客户端的缓存副本是最新的,仅发送指定范围的请求资源。 + /// + [Description("If-Range")] + IfRange = 32, + + /// + /// If-Unmodified-Since 标头,指定仅当自指示的日期和时间之后修改了请求的资源时,才执行请求的操作。 + /// + [Description("If-Unmodified-Since")] + IfUnmodifiedSince = 33, + + /// + /// Max-Forwards 标头,指定一个整数,表示此请求还可转发的次数。 + /// + [Description("Max-Forwards")] + MaxForwards = 34, + + /// + /// Proxy-Authorization 标头,指定客户端为向代理验证自身身份而出示的凭据。 + /// + [Description("Proxy-Authorization")] + ProxyAuthorization = 35, + + /// + /// Referer 标头,指定从中获得请求 URI 的资源的 URI。 + /// + [Description("Referer")] + Referer = 36, + + /// + /// Range 标头,指定代替整个响应返回的客户端请求的响应的子范围。 + /// + [Description("Range")] + Range = 37, + + /// + /// TE 标头,指定响应可接受的传输编码方式。 + /// + [Description("TE")] + Te = 38, + + /// + /// Translate 标头,与 WebDAV 功能一起使用的 HTTP 规范的 Microsoft 扩展。 + /// + [Description("Translate")] + Translate = 39, + + /// + /// User-Agent 标头,指定有关客户端代理的信息。 + /// + [Description("User-Agent")] + UserAgent = 40, + + /// + /// Accept-Ranges 标头,指定服务器接受的范围。 + /// + [Description("Accept-Ranges")] + AcceptRanges = 41, + + /// + /// Age 标头,指定自起始服务器生成响应以来的时间长度(以秒为单位)。 + /// + [Description("Age")] + Age = 42, + + /// + /// Etag 标头,指定请求的变量的当前值。 + /// + [Description("Etag")] + ETag = 43, + + /// + /// Location 标头,指定为获取请求的资源而将客户端重定向到的 URI。 + /// + [Description("Location")] + Location = 44, + + /// + /// Proxy-Authenticate 标头,指定客户端必须对代理验证其自身。 + /// + [Description("Proxy-Authenticate")] + ProxyAuthenticate = 45, + + /// + /// Retry-After 标头,指定某个时间(以秒为单位)或日期和时间,在此时间之后客户端可以重试其请求。 + /// + [Description("Retry-After")] + RetryAfter = 46, + + /// + /// Server 标头,指定关于起始服务器代理的信息。 + /// + [Description("Server")] + Server = 47, + + /// + /// Set-Cookie 标头,指定提供给客户端的 Cookie 数据。 + /// + [Description("Set-Cookie")] + SetCookie = 48, + + /// + /// Vary 标头,指定用于确定缓存的响应是否为新响应的请求标头。 + /// + [Description("Vary")] + Vary = 49, + + /// + /// WWW-Authenticate 标头,指定客户端必须对服务器验证其自身。 + /// + [Description("WWW-Authenticate")] + WwwAuthenticate = 50, + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/Enum/HttpType.cs b/RRQMSocket.Http/Enum/HttpType.cs new file mode 100644 index 000000000..46292013a --- /dev/null +++ b/RRQMSocket.Http/Enum/HttpType.cs @@ -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 +{ + /// + /// 解析类型 + /// + public enum HttpType : byte + { + /// + /// 服务器 + /// + Server, + + /// + /// 客户端 + /// + Client + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/Helper/EnumHelper.cs b/RRQMSocket.Http/Helper/EnumHelper.cs new file mode 100644 index 000000000..21bdd3797 --- /dev/null +++ b/RRQMSocket.Http/Helper/EnumHelper.cs @@ -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 +{ + /// + /// 枚举扩展类 + /// + public static class EnumHelper + { + private static ConcurrentDictionary _cache = new ConcurrentDictionary(); + + /// + /// 获取DescriptionAttribute + /// + /// + /// + 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().Description; + } + } + + _cache.TryAdd(@enum, result); + } + + return result; + } + + /// + /// 根据字符串获取枚举 + /// + /// + /// + /// + /// + public static bool GetEnum(string str, out T result) where T : struct + { + return Enum.TryParse(str, out result); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/Helper/RequestHelper.cs b/RRQMSocket.Http/Helper/RequestHelper.cs new file mode 100644 index 000000000..d379dc867 --- /dev/null +++ b/RRQMSocket.Http/Helper/RequestHelper.cs @@ -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 +{ + /// + /// 请求辅助类 + /// + public static class RequestHelper + { + /// + /// 从Xml格式 + /// + /// + /// + /// + public static HttpRequest FromXML(this HttpRequest httpRequest, string xmlText) + { + httpRequest.SetContent(xmlText); + httpRequest.Content_Type = "text/xml"; + return httpRequest; + } + + /// + /// 从Json + /// + /// + /// + /// + public static HttpRequest FromJson(this HttpRequest httpRequest, string jsonText) + { + httpRequest.SetContent(jsonText); + httpRequest.Content_Type = "text/json"; + return httpRequest; + } + + /// + /// 从文本 + /// + /// + /// + /// + public static HttpRequest FromText(this HttpRequest httpRequest, string text) + { + httpRequest.SetContent(text); + httpRequest.Content_Type = "text/plain"; + return httpRequest; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/Helper/ResponseHelper.cs b/RRQMSocket.Http/Helper/ResponseHelper.cs new file mode 100644 index 000000000..048340bda --- /dev/null +++ b/RRQMSocket.Http/Helper/ResponseHelper.cs @@ -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 +{ + /// + /// 响应扩展 + /// + public static class ResponseHelper + { + ///// + ///// 从文件 + ///// + ///// + ///// + ///// + //public static HttpResponse FromFile(this HttpResponse response, string fileName) + //{ + // if (!File.Exists(fileName)) + // { + // response.SetContent("

404 -RRQM Not Found

"); + // response.StatusCode = "404"; + // response.Content_Type = "text/html"; + // return response; + // } + + // var content = File.ReadAllBytes(fileName); + // response.SetContent(content); + // return response.FromSuccess(); + //} + + /// + /// 从Xml格式 + /// + /// + /// + /// + /// + public static HttpResponse FromXML(this HttpResponse response, string xmlText, string statusCode = "200") + { + response.SetContent(xmlText); + response.Content_Type = "text/xml"; + return response.FromSuccess(statusCode); + } + + /// + /// 从Json + /// + /// + /// + /// + /// + public static HttpResponse FromJson(this HttpResponse response, string jsonText, string statusCode = "200") + { + response.SetContent(jsonText); + response.Content_Type = "text/json"; + return response.FromSuccess(statusCode); + } + + /// + /// 从文本 + /// + /// + /// + /// + /// + public static HttpResponse FromText(this HttpResponse response, string text, string statusCode = "200") + { + response.SetContent(text); + response.Content_Type = "text/plain"; + + return response.FromSuccess(statusCode); + } + + /// + /// 返回成功 + /// + /// + /// + /// + 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; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.Http/LICENSE b/RRQMSocket.Http/LICENSE new file mode 100644 index 000000000..5a9bb6217 --- /dev/null +++ b/RRQMSocket.Http/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license 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. diff --git a/RRQMSocket.Http/RRQM.ico b/RRQMSocket.Http/RRQM.ico new file mode 100644 index 0000000000000000000000000000000000000000..6465fb16e389ed1804d54b368018596580c6672e GIT binary patch literal 249918 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

&cP)Tdhs88a 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 + + net45;netcoreapp3.1;netstandard2.0 + RRQM.ico + true + RRQM.pfx + 5.5.0 + 若汝棋茗 + Copyright © 2021 若汝棋茗 + 介绍:这是一个能够简单解析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 + https://gitee.com/dotnetchina/RRQMSocket + + true + RRQM.png + 若汝棋茗 + true + LICENSE + HTTP;IOCP + + + + bin\Debug\netstandard2.0\RRQMSocket.Http.xml + + + + + bin\Release\netstandard2.0\RRQMSocket.Http.xml + + + + + bin\Debug\net45\RRQMSocket.Http.xml + + + + + bin\Release\net45\RRQMSocket.Http.xml + + + + + bin\Debug\netcoreapp3.1\RRQMSocket.Http.xml + + + + + bin\Release\netcoreapp3.1\RRQMSocket.Http.xml + + + + + True + + + + True + + + + + + + diff --git a/RRQMSocket.RPC.JsonRpc/Attribute/JsonRpcAttribute.cs b/RRQMSocket.RPC.JsonRpc/Attribute/JsonRpcAttribute.cs new file mode 100644 index 000000000..f9724037a --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Attribute/JsonRpcAttribute.cs @@ -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 +{ + ///

+ /// 适用于XmlRpc的标记 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public sealed class JsonRpcAttribute : RPCAttribute + { + /// + /// 构造函数 + /// + public JsonRpcAttribute() + { + } + + /// + /// 构造函数 + /// + /// + public JsonRpcAttribute(string methodKey) + { + this.MethodKey = methodKey; + } + + /// + /// 服务唯一标识 + /// + public string MethodKey { get; private set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Common/ActionMap.cs b/RRQMSocket.RPC.JsonRpc/Common/ActionMap.cs new file mode 100644 index 000000000..a600a4f94 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Common/ActionMap.cs @@ -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 +{ + /// + /// 服务映射图 + /// + public class ActionMap : IEnumerable> + { + internal ActionMap() + { + this.actionMap = new Dictionary(); + } + + private Dictionary actionMap; + + internal void Add(string actionKey, MethodInstance methodInstance) + { + this.actionMap.Add(actionKey, methodInstance); + } + + /// + /// 服务键集合 + /// + public IEnumerable ActionKeys { get { return this.actionMap.Keys; } } + + /// + /// 通过routeUrl获取函数实例 + /// + /// + /// + /// + public bool TryGet(string actionKey, out MethodInstance methodInstance) + { + if (this.actionMap.ContainsKey(actionKey)) + { + methodInstance = this.actionMap[actionKey]; + return true; + } + methodInstance = null; + return false; + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator> GetEnumerator() + { + return this.actionMap.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.actionMap.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Common/JsonRequestContext.cs b/RRQMSocket.RPC.JsonRpc/Common/JsonRequestContext.cs new file mode 100644 index 000000000..0d299e8a1 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Common/JsonRequestContext.cs @@ -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 +{ + /// + /// JsonRpc调用器 + /// + 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 + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Common/JsonResponseContext.cs b/RRQMSocket.RPC.JsonRpc/Common/JsonResponseContext.cs new file mode 100644 index 000000000..e2960383e --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Common/JsonResponseContext.cs @@ -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 + + /// + /// JsonRpc响应器 + /// + public class JsonResponseContext + { + public string jsonrpc; + + public object result; + + public error error; + + public string id; + } + + /// + /// 错误 + /// + public class error + { + public int code; + + public string message; + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Common/JsonRpcWaitContext.cs b/RRQMSocket.RPC.JsonRpc/Common/JsonRpcWaitContext.cs new file mode 100644 index 000000000..23b44e143 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Common/JsonRpcWaitContext.cs @@ -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; + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Config/JsonRpcClientConfig.cs b/RRQMSocket.RPC.JsonRpc/Config/JsonRpcClientConfig.cs new file mode 100644 index 000000000..da6bf2588 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Config/JsonRpcClientConfig.cs @@ -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 +{ + /// + /// JsonRpcClient配置 + /// + public class JsonRpcClientConfig : TcpClientConfig + { + /// + /// 协议类型 + /// + public JsonRpcProtocolType ProtocolType + { + get { return (JsonRpcProtocolType)GetValue(ProtocolTypeProperty); } + set { SetValue(ProtocolTypeProperty, value); } + } + + /// + /// 协议类型, + /// 所需类型 + /// + public static readonly DependencyProperty ProtocolTypeProperty = + DependencyProperty.Register("ProtocolType", typeof(JsonRpcProtocolType), typeof(JsonRpcClientConfig), JsonRpcProtocolType.Tcp); + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return (int)GetValue(MaxPackageSizeProperty); } + set { SetValue(MaxPackageSizeProperty, value); } + } + + /// + /// 最大数据包长度,所需类型 + /// + public static readonly DependencyProperty MaxPackageSizeProperty = + DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(JsonRpcClientConfig), 1024); + + + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Config/JsonRpcParserConfig.cs b/RRQMSocket.RPC.JsonRpc/Config/JsonRpcParserConfig.cs new file mode 100644 index 000000000..d80f75b4d --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Config/JsonRpcParserConfig.cs @@ -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 +{ + /// + /// JsonRpcParser配置 + /// + public class JsonRpcParserConfig : TcpServiceConfig + { + /// + /// 协议类型 + /// + public JsonRpcProtocolType ProtocolType + { + get { return (JsonRpcProtocolType)GetValue(ProtocolTypeProperty); } + set { SetValue(ProtocolTypeProperty, value); } + } + + /// + /// 协议类型, + /// 所需类型 + /// + public static readonly DependencyProperty ProtocolTypeProperty = + DependencyProperty.Register("ProtocolType", typeof(JsonRpcProtocolType), typeof(JsonRpcParserConfig), JsonRpcProtocolType.Tcp); + + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return (int)GetValue(MaxPackageSizeProperty); } + set { SetValue(MaxPackageSizeProperty, value); } + } + + /// + /// 最大数据包长度,所需类型 + /// + public static readonly DependencyProperty MaxPackageSizeProperty = + DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(JsonRpcParserConfig), 1024); + + + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Enum/JsonRpcProtocolType.cs b/RRQMSocket.RPC.JsonRpc/Enum/JsonRpcProtocolType.cs new file mode 100644 index 000000000..ded7252d0 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Enum/JsonRpcProtocolType.cs @@ -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 +{ + /// + /// JsonRpc协议类型 + /// + public enum JsonRpcProtocolType : byte + { + /// + /// 普通TCP协议 + /// + Tcp, + + /// + /// Http协议 + /// + Http + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Interface/IJsonRpcClient.cs b/RRQMSocket.RPC.JsonRpc/Interface/IJsonRpcClient.cs new file mode 100644 index 000000000..e4f3473b1 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Interface/IJsonRpcClient.cs @@ -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 +{ + /// + /// Json客户端RPC接口 + /// + public interface IJsonRpcClient : IRpcClient + { + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/LICENSE b/RRQMSocket.RPC.JsonRpc/LICENSE new file mode 100644 index 000000000..b09cd7856 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/RRQMSocket.RPC.JsonRpc/RRQM.ico b/RRQMSocket.RPC.JsonRpc/RRQM.ico new file mode 100644 index 0000000000000000000000000000000000000000..6465fb16e389ed1804d54b368018596580c6672e GIT binary patch literal 249918 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

&cP)Tdhs88a z#ww*9&h??j$P05^!)oB)fhtd-j`BtdD4O)bC(5eV`%oXZ-Oi}pTKVW*f82eutyP1w z-d@=`u?xOf)=9Ik5Z@3n%xH^=1TeKpL8AGc)Ov<|Q?4`=0iA-LmBy7IdWJHLhh1^(>1f9agn*kiw$&+bAZ36W+ag$Y* zO*Jq7>%{RzrO&LZ)tm#{bv5$2^Y--!hM*PhMbEkD4aLVmoQ&ag64;}63l@pzh<85s9_K_k1O9} zIrGacA3BmTw{pU`rIpX!y(hLq?n~`wj+w5D?VCGie;I-G7D&S^>G==d-q$|ttovha zouwl(V3qU!@Cb-z?WOJ`^9&^e{f>+%yz-Iez^gY==(K>R ze6}(W-FV_x!=8G0=W0S4*5%?FsLYg7S_A-vO#qhP(BPJrmqRl&#|RLsxrJ9Iv`8_r ze25g;sZ3FAOKU+}V^boNO2^yUT1iL7flMj|sg4fla8lr;GT_OEcL^(>SEh|cEy$1M zLoz?F{;0jDz3^k^X#u50MRj#ayP|?Mx&wel=xm833Mq9PN=jBSIopppPVO_kI|A!1 zkeb8#(M|{5Qvdbh6N*!r1Zy%^7>>qsCaF}LS;a?`xow#D$`KH1@eyn;C)#-gOXLLs zIh?74z}jL_SYcDh6y&?{C;vWU=Z&`b4NA4vr768G&)t(-W%j&zcJIS<@vV6}6-}AtiRtNhR49w4XF9y)#fZ z6n&_y=Q;LcVml9@gHUL+0lJFwTz|&RckMZOyHk5^N%a1a`VwqeMp{EdL!n<@?sqO( zlJ4AK12^2T@7-_TE&cejm7A8|{r5B4TAMaZrBg+glPRn6{NxB0^y5>g{nutSEpx5t zqS;~$Ief}~SSo!&>5B1vIo^gF2Lq0L;-wYS3Kq1)5}uV;*p@7auOg>hG^1+7$Y(Is z7iW#F@7mhh0^7Fj^78UFtV-7Vv$}qtVZ8%VbGm13y2EV0p?Rxe4vjEVKF=3bnlMK` z=)=^TBPd1s9?6s3d>G-^qWj=+L_rc3dDmJ1R-9P~_JzNIoBVR7S}Y%GBLtkHe3#Dr z+g*EXxU~Y&z67Wr+BW^^TEf>lx@C-7cd~l{TOw%y=%m1laPuG| z1#oPeTDI*a^76Z4#f6LW&%NrhJvQ2I<`2zH?){!0fk6+XyeLO)Z5|mmtPY3ovDvf7 zmmG5XTV6Ufw9qG3wL_rTr7GJ!OE zN&%x-^@M^$2y|MMRkDY+!h~D;%7ZseshW6B&o7C-J7Q0QEt}^RD^?_`s;W|97WUA) zuWtXzg3tGu_~1i7cbZ#ASGsQTNHoLc6D-^1f+Alrhd!q2O28DouFN{I@&Sne8JJIG zwVH*ZbtBlV5t!t@a_uwc>%cgc+2ug?i{314prwAFCYMmt00gj z6uMYDZMJqO1=k|rSvF0@k}U=0m2Z`v`1{NDo4VVFJw3m<r~PtH1$M{CZ+id54Gw4(*94q$y8-g!>5MF=q?zM z^_ zOvR$?acEhYH}zzs8V>C>qxnr!u`7BaWX(SQ)N{i*|{^!w+cX=XtH_HZbx0a zJ;Nsuv%*c;n$U z*9_)G+?@tBT!o9>|67Ybp3r>G1%F-HP`@$l>KIn-Lvo}iOm_rDnL8l?2#qh}0cn`l zxDEpIg207r)?l^j*venZSgrP#@)C(=nL}lY%T*ErY{81f_f23l8yzC{@&|%kcKkKz zlxN=#xC8h(43|Ub-z}6ttp|P@tV~{Ber<6@)sx5k?Zw}k>kECV0FdQ(9?a`-P3~q>l=N_43JY%06>?`_-ghl?+B zmM`DA*!SYB4436mQbqs@jD(1wZ&QM30O;gdO)xd*MgCi;CG_J~ft=y5RKXt%KA9kg z_$`4nz#b*gArlpA24z;EA~oUbFw=+SQ(ge9UYp8o#jn+HZ^-*$%(N2-uG{tyz)<#9suMuU|cLH!^D!{85smjoLQA`+lf5YX@? zqSj4+M*7Op|7`*=&Y5~IyM_Xjt_eVt?9-fQWQj>A|G7CNi(SuY;HY3&xD*b7m^o zr#c?5c^lNeW&wHDHBxBvEoh{+NAe1m(1XwZ^O*-7byt8`Fcl0Z!lG+#?k6zagKs!q ztC{jqQEPf~xlbX_mHN={du*72rO;{8K*Cy2^$}f`Flen15Wt8*ps?#ePAGy{pv!>($AJ6DIKS|D8m7F- zECo`@_A;m#2!eLDBuXnivfNVmz?VTVyzMZXW<%-%KnGahP#-MIf(|R%T0iZqi!ML% zl$+PpIv5D&9q^2_J8*e<#Fk&=XPgbIS*DUJJw*Yq6o25;8yN)RTz89~50v?YN751A zEZsQ$mB3#eL(&wrd1Q3n0%(c?G{>WE{PDYQ`RQg`{ca#EqMp1)mRtUhdvCpP;+=P% zo=T%!;rkEf7_VOLhRyCjt*^~kB>iqIyA;*U= zO#;wLEm)cHeTXI6%F2e$nS9BkhfS%jR`ncY^ThR@p$>Q;4R7M-t2bL%k@m;3W^{R! z=|nM(E>R2b7)^OxNJhs`?d0c8L6p%b7MHrk zY{38$YAv*RtHwRR1a+jG2X}Z-$oP(wIt3V?N{m1TDa~>D1U3Up2vi7fraQru$np2h zdjclgZJ~Uza?u9>(=_wtqUQ`%R-gLpww> z@rvqaH#+zJ6LzhsVR-<#pMk6+?T(2)SGCEKGLMWNmZng`Xp72|4rPkq)EkcxZMbWu zs+pt6SepS@j87+|v%Y4w7{|@_^&AfC0RGOm&KAXkL1h8O` zP)nec)LsCcxkfN=-UL7yyi^hY5O`tor;fUtppDlW1ZWMi67(_nrPh*oK`~Mca3Par zzq#AP@YRMMCfJ#l`}H}q{r)U1ZHWQ2_!R1V;uAaB(Z0vY4;^{nzL!rdpSX-4fl^kX ziuq8PYDVd|2kRO(?`zO7(plA;ep`{IBg#FNGf#O>B|#Xlw7iy$NV20ATG*7=Tai1} zv;ABuF~Fn@5^hf{pm;mJ4t;b!%U`l$uERWQU#zWn&)$E028k4kn06Af=osj2*Mc0F)b4j z5DHo&;-M(eP3cq>lhnR+<#&}qrLd)f`Ai&)4Ml)Br#898n$cSpQ;3BtL%go)+$#5k z1YOf_uO0;2+A;%P!Jw4!zyS&l5a{#)GL!<#4D7Pvnaly_U3%^jCtkfi0Ot4I^Zv!+&ZTFjN&wu!ggN{7iOlMsm7Urw}d29cIA*Dz9#HuK-u52w# z7Ie0yJKJONSXTm)sTQ{>9k*hB#?ScRTb6D4mgAF%=Vg)|T^$LhE0d^iYRc>A=twj* zugb4$Y|Lw{t4;3x%rj#h*NM5V7xjHl_)V#ZYsU#8F&Qn75CVDJb)Z2wTc9u3fw^`} z2@?7h4Zp1!$O*D$?V}WKRgAXdIfAMI)Q#dw6xYTqAoRzIcLJGpAr>8w->Jj^^fSxr z3Ee-Q2N|^nc{xt<^KFzseFl6hSyDghl&dZ}Y=@tzC_nR`t}oI30SBZexI8oGnezDb zi#{#w@~T)*C0@M=KY$C}FmD2j5#t6rCM$ylp^lzt`lxQ9l6_!d31l!rU8Px((PK$c z1;czIz?kTA+k@6b)P48dqh|f;S10^>94Y&jU*iDESXx`KZ=emsZ77>yL%P68yJ?>~ zPKHt^4hg4|cKT&`Nw=e;gHp)z^YZ~ZIsn*jX1sQFcG+FP>Uri_Bnh?!gqfCh6i74! zUew8C;_aPIaTjEYS2Wbaf+Y)~?12Z4&8%t~>vpuq)9ExsJ;xqySyoAw&eQ~_?j!$# z)#9U8&%YVO4EkC_ayki$+9iR$SHXM({#HB>en*pI6+Ft0lNrG(USJ%cixOya0a{(+2ws?7M*Tz8l{(u2enc>1REV$AB zz>6v!@JY4rYciv__mVBs7MBHe3dBc{kKC$oc{2?m$c_1yIfp)E{=&I3OkQi-) zU;0h`${{T+Z40ZzZ z0A!VN)gaq5+zl8kQV(}@QSi@%14~k=zyeb2eKX6-@WBU}XQ=Rvp(asjs&bv8S+AL{ zPDc#}_Qb)5NP+A|I~s`hx){dc;zETeYofOcTXQvIi^;U1J;4S9jw07fdr(g z6Xr8>=9I^#AOBfdr#FnXM^5+@;s$Ujb6f?1x8pDGs{l-G_`M70i#iW!CY@);0(%~v~M2Qp7^c|!g4@1w5Q6)W%yzL zM==y}EM&X@E+xEXD$nT$0?iJkPG0fK@yB0t#^F2d``Egg@4h;3zXwvuM14X?3J2wd z;hQcic4#%LXkQ%Ytt4;9bkIu%fosuZ4U%T+1;yVq%^c*BhS{!M1yVK=(&Pn>&s76r zV~Bd90QC_cYNM9x73Q^8zcJ&K9ZSaltFIS2R5P+7Fyw0z9c zdU_wAqbleoFu*jxge4o6tQXg^`CSB1vlc2o9I!qs`(CR@pe_Tx6NzOiE2&!I#7*x zKG)I7U=dcd?`G48MI|fV8=HmuL?aYdMTnbD#yesU-f-^0TkLYDTv)x z0amWBthP3n3hv^O>ur=1KWEMgC{s8!5!-31T^O#DC) z$8aAh-)gAXh-re$U=%N8BVQM5R{QDs*`%fAtBAgNo)9?W4JwPvtSY5_v#71j7Vx9X z%Ve|CyhFB5x&8^de1LYBK)Y+XRy^6V(aASldFT#%-7pweS-%BRnK8i%T&OOIuZ`O3 z>%6W^%`nD9ec?$G95Seg4f?9gX;ThSvFO#^W5^wkrJ1NQm$;*|JAbGIZS<=e@)T2p zSWhS{iTi#_Jks9!e-~eQ`re2BWiT$N_2r%#XnNXPAHKJ7`wf?!*45BBEar6CQQspG z%K~CiU{S9;Lb*>>`xFsmgFZ;}p&wqmsu&4-!;%9RzvjP@XJj@f2@VO!UPAr6H+k9W5X6%P?+4tMn!IB04M5fsh- zIAY`DD@Js)JAtzCG*{+~$v^@!6w}Q>pf&=q$foWG7oBkX)hC^GE^}4%R*lZ}1L|<7 zZVrbMQ3F-h|7}iF>gAQzO+EXLllPu9^{I6+hrMymehZ}L&Azwsjvtf8md%HyJdv?v zgoXk@83MYXzfwnAHIU*Lf=p9CvqQ2M<6*8@gvvpcPkqIaIjW~E3T(I4#weX}!hX;E z;q(iBJ+4g1oN_;dYXlZHHjZ4?wQAqzUVUk7@gujNn3w7(8Dax*!G|be43!99D(?X$ zRxz&|fb3G4=`!GC1U$o8N^1QX5-LF=fi0l;_22*R=G`v* z`{|V~B}t!%=zKWFj(35-72p|FeGqX+h(ZH=f+7rl|VMN9m)nL&za4jXC!-NJfA$)rGLoLIuF8j#XQ{_TKE% z+i$=0mkn*rb__gw81<}TS!jft+ve^I08w`?01ZgW8j@A-&03~rN@{mtCjeOP3*0Bt z%@qhPDWw3q5R5eF|51cm9bc946BCU0%X&(sd;)C_%i)i?MWyA7_P*fZ>6=y8d^wPp zLcar2Gjr+oe?4^mgj27$YLrK;a;E$>&2~cwt)9+k@+fJOc+_K-iO#FWh`Z@!HT?m4 zkp~vLWDbGglzhUg;wBQ5S(LuR23``cAurxl^!V+^>^W)MT!elg@0K;V_HSFh9skkF zWqZ_Lef}T3l`E_Asl#Q-HUK0o%3V|e84`-24Vje!B1Hy-)gzdqF4lrwYx%=oE@#s} zYx?+2zp1jJ(AblX0ZfSvMD113HSGJ%4sfATv5{CJ^JWj~)T`{ukaEW!}r!fn*SY+5!B!j9`@6C=dZX zED@TOEy!$WiPCD_8*@Kc(5fR(uJR+(bB2QWc^e=Y!~GUBg*R@@b`N5NDvIg)h!V#) z=!xmqHGxzGf)R8D#li2lx&#^>%S-Nc;dOsF{FDncn9@9cihf>As^0)94&2oY98k7wR z0L61-h zKu6&IxE9tqkjl&@mV=v_-_S685}}m;ZHwu(vD+tnM?g~;rFL& zdh_c~4xay~Gp=)MmyOCJ9?w^{Er2|hF@-(Dl*z3@E*Kors+54Kje#BsbOA{fvQ;CU zl|!A$Yz?apfmZ2N%XU6(001BWNklMU%eJiyDT5 z!A{W(m)bQmsH7^Mi`!FAT2)U{95HB?;O9)46iPYp^U}>=`b6Q`YL6*3g?IxX61E58ceIsj1ib7df+qJX20%ID)&jqKWnm8Q7l_?Uj$I`834wc z(yW?P2EdIKEZge0_iVfW#O<+g^cr`d?d@4#=Rk@#c+YE3T~&3|#pf1fyhyb}phVUc zMTRK-+;Z^*!4)S#E98R0deNrVG+aVJ${DX&NLUs!k&8(bA;BYbb8Jc>Wf5p2ERP=O z3%@)1u@la`;P`>6iR#%1wB)5V`EeAWeHD4`${QvPtz?SZElEm|82du)6Xn}Af>2V8pnb5~x2l^! zYPn*kM`4v?gC9xM@A9jE?6UioQ|Bo{MQL7tbCLB6AboSeN7GvNJn^BS?dfEt1CZ~t z1!Dw&=sMJTv+GWvzG-(oVbNos3lA4Ded+MU{XKpzP zh;PSy-zu{y*kFi;px+eHBhd)E0`N0p%^O4l2}CF$rP(8PHr3=Lpk^_GPfDVN z$^x@`mfF{5#VN6qU0~8E0DVuKKI$E7 zMg7oG4zY&1+3k*1#L(1-W`Q6sC=GIfzTP+k{EiI-HhnfKdYN6AK>>3pLdh%L6M(uX zKy5tQ6@T#Nqo;4Z)1WUK)?XL&V7so@zL;~woXbwU)=PC(6wpkB1)~xyhaZLgxSUZW zZ-5_KaX~U6>4;*UvV^2E<+ZCoN9s`$W%@V;iD2i@8d0N$01s+OHGnMQqxG_;Tg}wN zO1GMHS+LJ{dIXx&1RNS`nRMtadmp*SzOxNx+HZnT>kLS7Fy7sM-!I*TOD9x0Knf{9 z+`~f1N`%pE74pD_!NrpmX;&OoL@O~F-;9bH2MYL11160u7GY#Sp`NdqiS8p7E7a^R z|MU6xoq6anCk?jEoV%aC9|1F6ayg~tk3Ie11s(TZacY#N5(e5Zj7C9?>R_Vb&X zP`18BFbTo3n`|lN&I+5}2*7eIOucA;!RmH8qHVTj(E3`$YdUBpU1w$uSE(*w^-VLB zKzoK&k&3i#bi^(D9RJh(-tGGt`QK;kb09SXFVB7W_U|J5pZ=FoDKElIdVGSan0n~y z0@^q<zijEem`kx7*S;V#Ih~0sK-kAaUH72Yzj({6szPF zqk>U$3=(zAT$L#vmMuxMQ0yY$npTW2;9d-+kY)vSm4r*~$pD)+B#3BrN@m)cCXk}B zw#modwf_;@@AihlOxL;3w9kPQZ~o(Di*{JL^WjfNTic7ry0%r$9zD9lxY{RXnwcnm zATF6d>ExT5h+oBd^u`wU2>Aere!d8PZew%Kb*)1oEAD;75di6O@v zVFW5&=}BienI^hcbZYQ4Q#H+KeIPqTc49O^RWn%=h=Wf}oVYXrXy>hzefs5%7v6j3 z&yPN#zf5ZGItKp;JU9QpM}2(Raewu?+DeKeex%s)Ax;1y(l4nyml|PMqtJLjhJ;3z zK~%ao!$a-HC7I9!LzwH|UzRUi#M;>N2K!WdQnGAxNpPR3Ye8$;f-c``n{w!_dmk>% zd`fweEAyGIlZ2N(15&fT=zo8D@T?VczuaS(Pa>tPz9{SdiL}!2a|WaEW^_`KdZTEA zu-DN69v0RIp1!h6lWE=yl4&^Fb<(JKe&a~V-z-YM)bf28QB^5^H+OgHsC+|74xo&xNVFV(@5fAbioMbW3?oECZuoUnjpaqJi7)bye+{7p- z8J4LFML(ycqKcgGEG#*C$b1bq1TQWW2%w>KN}fsH6U))h_y8TQ1sxf?WyjMV+I8CG z?XiVPgb>2oVD|Y>p8+ZQM&DoY)z4OKbLiuR=}dgML!j8xW;VK7y3H<<6Rdi}%gCOv z?gO>*v&xg{3Q$3@J(?Nf7+6{iCouT*MH7X00kr^D+CDVqC%P)0z3<4K$4;Kv=QEc( zVQvHffCZvnIdA`2E57+^a@@~E3v3Dro7F!RTU*GFFtaGQ*Z2nz6wS;j{<@?w{JV1X zn;B11YK6`8RJy7PB88&==rWM|OarXcaLcOy;+myuMloJ_q4IV1-A>m2Ic{@&i&w$|NQy*^Jr&FVrZOYM2XVTz5+x9){q(|#4ZD+_Hh3gSx(3t zg?mkWKopbK{#e{=!X(E&XM(~83$A1b#svSAY2l$LzHki#l^-TK=NdLX`qpcI$9rtcorxPiVmF`VlyqFwWFhL@y9&Gil*f}b?Xhh!w{+I4I zSkTX@wR944vofRfQx`u0z;fxA=f&LU%zIAWYtojvD18pg*69c^qOt^*#A;;S&bf7U zlkffKomUjUd+%OA9V;0nR*CIFUZk6f{L0U1_)tUf07WG5E{(1d;R;SjS`^?ZnUf|p zg4`IEq;eO?s6Ph842hJ|&=_tCJU7eD&v+K^R!ZU}i>~;~+;NHo(b`HvDr@^S|2?qxk^@RBoTTzK56NA|@8<<5~Cfz=&>R@yq@-iIDLxABQ<4gs$- zZ%AGwk`J!P)n_s!O5^`QD ztxg5D5=_z3L&0lwG!9k`2cC3KzoYN@~W}Voqge3`}gIH^%{_xQlQ5tZv9PhOV^0e4p?PUoS=Lu z%4E>MrF$z$P*WzqH0yQaP9^nF-{I|UgN12@&%hAbOQ00sYyh|#4P?Q}NPrbl0^cMe zPUhb0et*PI_Po9?CnAX*8|K_c0PdL-|Glhkajub`!Vitu6FCeWW z6C!vUj_S*x51yQt<1_YBC{TrrQkm`s^Of{TsRVc^%!tlo`x5hWLAjJ6>yoZL-1AzQ zAY@T3o#5?q^o*1C-)5J4WgSzdFXaghz4g;;K#CW9-p$usvG1SmyRh1|Nue)$FX=f{ z_a$7=m_ea|jCTqHD%;m$(>ha;fHe%TKw*Uq&{18{ zF?#mDCygQGo8Fp`+;MXw&=Vtoazo}ref^txzkU7UL(d~_XMVozMT%J!sR+*#l-5^> zk*eU61X^ygqa?{x(MT&%F-eg$qmQfiSiqeiqxaa~L}V<6EKEcu8qr;gtA<(?SNA38>l1F0FMe{}Y1TNVA{tanCtx^b3EA2t=tiwi%o zf|^qGt`-|hpyc3((u+X0k|EDP35Ja7t1^00wE?n7u4?LK0DZ~=XlFU~@d(X-`-wkH z9X9srbs?|#p^41BpBsVyH3A>4T=e^=&p+^7C)He76op7(ghJewK2y_NH)>d9F+#a7 zlye~D^E8W0vyXls!{xFp#Ylw^pU7kyeh>1vL0>NVXoISPfD6u03bbV`aP89Oqpx~n zlZm7p3q$u>PJV9ysj7JY!WKJyLRU0wGRCp2p_p%ggKxSnB^qi;g?zF}GeRtoUhnGsyz0IcV4}}zYm02Bxuez3(kN3vS0k(NwwuCBaE54kk6v| ze0w3&3}-HxzDzCf=lei@4`UUka9;qWSschHI*r9uq$P=Q4b}b`iA=zCV6bPEb)~CU zDH~R1P_;V*>f4E5RXy(0i!Xe03%PH5O{UlzK+4m!ZhqnMBSxNZ$$jN6jaEAV#WI(k zXF%{V)shRHnIudF{x|=SPD2YU*Z|m}`Jhb>!Dh8qEz7i*&J~q!j7-%yu4A#L+N?w# zKubYh*Eauo`DY`NLtgLi8z*;tYd-?h?j1)XBUT1eAp>wK>u|Odf%UgZuRs3kE4!`z zS^MS)AFfz<-iwzVenIQ1m4!nRB*HSG;>>5NTAJu`lY!u_ffS}MG>{b-Qo9KLgNDA@ zbWgWOSK@mEJXJ7Dj=4_z4w4~LBd)(A9t52ZKx@W=F4uPU{^f(`AF%CCH}vKR_c)N^ z#XeiJ8dJM_Fh5;C_z+!o35gyB~ih2PY$LAdo_bYcrIPU#C)1&N9J*`@zmzP zDl?RS2Lzrz%0=f2r{HVPa2H-%YwO|^yX1GQS1mhKEgFb$JVx$$QhcXd8AdvC^Ix-fd z++^!X7rgkB&4-QSX{5dJ(_=ttM(MA3;MViDJMXruM>^Chb3><4i!ubFQY@yyE?Y3K zGaEFrnv<&?-583`E;eFq?Eb23VlMT=}6&PVzFu;XRPu}uQ zkL|0qy|3{1O=dcK`GVg+f7vh2PqjDZ=SLt?8V5)+`JmacREgd(A}@9=+j7hgip-FY z6-zr+Y29W--(ZfIF3K%U5v@noD}XYTxyW1p37iN7zXI*iwNgMAwiXWq*JI3-KyxRh zBe%QikLMkF{1rVtrlDcznZuuZFPn#1(|t^Ftd@j6#(_U9i4s&9Vv>G>~Td*qpJ zS9@Vm)QuFzMQ*+=3o(nmDem9L{l&pfydKbhDsvm(!?DD|C5CLNn|&)JP&%Svx(Cpu zhni7Ah$O(Ws0zP6`4b3Ii9Oz)wxA^yPw#)?%suzocuQUox+jTIk3KnHS@7SDJ9jze z!?9_asB&~QdnIMUC5lgRQ-7vJ^4Y?9wHQ^zU;9?DPco}26A&1Skq)v?GsVsHyQ2LD z01Xie%VW0R5Vcw-KL6MuQ%6sDxi?IK{=C7~w`-gBv;A7*zxj8ec)XjNQN@DAY6@5~ z8eGvu#6FGDYI5l|*F5(2YZvs_u|#INn9`D^^FKXj)|J2bwGD25!geAhaSC~?Td4v| z35e1!Dx$?mLX5soh$ex!hS3sQZb=1@Mv)=iCI!b|uvOfq0Z=vBsgbQHK4WOj4M6R1 zY-nl+KUq+*`1&h8=K1)nun8fgxhLjmt%20^jlQ<^?(b#3S+>m>&$h}~Dk!fwBPhH` z`P7mm5%<(jAT%ae=Al8l+XwcMt#C<@M( zzdz-c%TN66Sv@hxxnuP25jgmX3Th>~Kmw zU@Hd^14iGkA4MP+kGf#cOB_)7UzI;KSk0}|v7kL;LuVS?F{3tm==`%@Il3o<$7?;& z=o@|JgSYoB-tXjRhIy7%;8BQUi9!T5e56b85=mg+} z#4Vt{1x{BHbbPfTWZoS5(9{39|A@Z2p8j&4L!K{UVmWm=%D6Oh(RF!aLv5nAaMrEx z2lQ=IGc#wt!ovjp^#_@0V`JmUr`~`2%+F_>bz(H?=O@6442e@nM)Ar+>7tU6V$ex= zI*p_o#RjF!(Wqgefmw`Suwh>i7c|HsU>ZJD6&o?6l!{pCU?4k&=Tn}G-;uV#b@Q8# zI`#R@wi!3>+n$=2wFXkWkasrSd1=v#`jOSFgggS7e3BW@E5p<_p6O!En)~W|(|4Wzk-v4*WNRLrnUlj-H7AQk194$rE0U}*HLs!4oB774}4GY!S*J0U}GV|pE5pAEf z09Tg31R)_Tj%p>jLaXXgHjef5i+)Y4$0Ja8SUHtXK(wmEk64KvoW4 zX%Sdx`%c|e=U@NZ!;brXe_!~kdwu(DcicxKPkVAQ`jWCAb_TOI0&%`?L*27`!_yBx zxW;Q`b+5I*e*Wk8jHS^k5!nwv@C9iIxtIVT^X^1=>aq_9)YvUf)$M)XxqHpJ zR_uGUoZ*_G-Tlp{!(fntNg;=nZ{Ul3P_fUw;p+-8&~PDVaqDQ+vMi>$l00Y3t55%8 zQu*+wdSY<<+cAE5*^abm%xCJdf?yDog#{mO6w>WwP=C)(x6hh=->LoWzWVBV4!n9x z8r%FUB?mH9B6Zrh(uV z-Xvj-^K58bMV-yI`O{IqJ@TYS)^?oNdV=5HWTzFyD;tJ!-Kg<{zDyy|)dfV&K{kCK z8q^pdYA`nQeZ^;VG1u@DNk0osp|F`*q1?CXnaOpd7J)k3r*p6Q{ljPf;+P`_b6e$O zuiKpF4PC0Mk*i+kK@FcF$<;Mmfk5r!2hgWx-XEOowOxe+4K zmK0f%Oh|43wqF0Wck5d3v%Vf87SW#h?!Pa3`_ALfFN|gqB?$r%#!UIW8l*&$8zeqv z`wa~kDnnFnD+PL!8YJ#8o=-+$T)6aaC`9>>wkV)Hw_~gQ>GU1-_Qln(F7m#sNW0K4) ziNLYtlMxLmKGf2*(gIjzq7&bC@N?f`_w=8+Gfe}@UJ958dZ7tIEDjIh8sniQ%#?44gdP{%WJiE`WhH|;(QE96Wh!SC7OsMhXWwu zHL)Ka-KT9pj#VqA8{YVjzyD>`>zD6S6t^RVF;D4B#r^6Xs7!UtY?60uM%@E}D12Y- zUG4tU!6KbT-W{{luZeNiz=_socHtwOCznO>9Sd5!Y+6<^_R%ZOe(SKc@s+Oj1e+l9 z>ejn{PQR<$XoN$oa%R#iQy$a0G-VHpnYBsHBY|o#P5-6zk#bW4107k84wh1 z6X}zZE2jC&E#Q$qy}sJ(XCREt_g&+G97w;Ak$c(b)))b#5y8MJ1?SGG&diyw42T?j zMLQ@hU{&S6Nww~O=}lLkUHZlSJ604Bs~{#)NJSS4?T75ntnU^?Wm>3G--M&>X5da< z4DR)C^d2QwSgy~EoM6OWIr_5BBhacnWkX9>yzPin{yl2fwFo$^_C{E_a%IJ^VZ-WP zn>%}2Y|oQs4oy?5Kvurj6uleAG!6<1=FvZC0;v-33uNU_7$)YIKr8B%YA{76ii4#m zM^$iEQF-*+hJ!6DBLK_t6VB*YA3JQT%CR#C@cNMr*#8QOMecppnhKfp_;FUo zPx?ocd!Rek8c4tqE`Y$E#$*7-zA(*ImE)5Z7iLs3UunvM`c~o$8?n({*Z%JH)7Eqx zS9@}?hx-Rx@9}l=o8>jbSmpbGj!rBfB{?#L&cT7!LC(P7t3Z_uAW5_ot^zYn&nWb) zz*SQEfZs;be6j9Dm&6nhXtycUS(K8|qrTbuwU=rJyGb8jB)`6EC?&QiT%09|3Vb*i zR8WaNK;XMufByP2v+o`-^*Gmbqpa28))MnMB$*iQ>d8(_BUALj~7EYmtGm$tt;Z z%3f1}E_^?X2Vs4=5ydww*LKH(=1$x1?26VNdD<%*?mK>b>zepV*JyG-u3t1^`ILh{ z8P(|~Duz7Wwg3Pi07*naR9TZ0DRn~mM>vRtkMO|jrd+{brP__G8HWQz?Ogy`>Kv zlzQ%!yOaI#9((ede*V|ZXmZ?=plOf#4_xHxAuks#E9K_I;9t`l*J!Wx{8jDa7a==JFqM;gtP{9(D@*&A*j?S%B`S8r2fdGk@B!>_k+Q{!sCX17(m{N9rz4Qzi5qohJtc3_GPBQ$t zM}D*OxXtcZ-GLhnpP#nRN!|trJuW2FhT;OHDgk+!+ytUcj5fE}_qtju;NIVSwMJ`c zAdTZe*9#y;8%O1c8-6;I5TKdw`8GUyK=Ys&pC{gb_2#$kIrfyi2#Ms!9mtEQ(GZr6 zAvx+cNMvZY&5R@AUJ6=4fdl|NuH4YN+FQ7YiBYFm=KqUzY!p%ICMk&fN}GIV^oULV ze%0Bp|9W-T<&U0R^dCO><_ps{IOOanCZt(Drt)6!^Xlk($gg2wW7tKis>w3%oS#pZ@e^aOV|wg6OKl2G6{Stn-+N~~b7S>(-|N+#n7;V@0h5nA zX3XhN-6tM^C_fYP@&D{yd7RGG_rITKncbKfW6LgN4@IPnl0?}e#FvVSqA%LN-@g6Y zzkMr_Hl-q4krbKmEE z-sjwNp^1z&!1suFAvH(YFj!P?^Y7`==IupJf_latG5H*$Hj0+rho+<4|}i6 zfzx_?HuKF%wVYbnzh!1td3)x>HwxE|?^rHQ6zT^h`@?gUNRLuGdNDZ>#bD_g)zvy~ z`$DFxa~szAPlz}~7SOhafv$!FW4so8T)l|-xhhqHa7cX$5=>Z%L$-OE z7H4+H8I|~p-0n*|GpY4$jB@ziH=iBe|MJc+|J}4v3Nj;KPm$6mEx@Nb6IMjvd=b__ zF0_4aH=dUE_8DEM-)ll$9$PUTlON#3frZj>q|7wvIPBfi97rjstjpNaZ^mOCCdGSm z{Rz>csfh+ULRj2-yVX=gSe(=o09xm5)N_QBGJs*2 zvp|TkK#|Z&9bUQizwdtR*5TuiMJqjOAQd-WzIk2!tSbhrsh$^zt`zh{&dif6CY%Ur zj(R2GI)bK=_nxnfTdJucdNzOoJ{|Ar>LWPY<=dRo5j0 zh!YzN64~p+wj7f^9m{z37EMvc?@bW9i zb-ANs@6V3bM*r0CX>H})Ms2pl>_1SgX3+7Z1Z+xewbvq(D%~NWAc(em`rhabpE2&)6)dFG~ z$wj@fr9rzv7L!z>ac&fQc}V)7+SBojx zQi|jO&oYUu0a1t9h6%cC40A3DEa2D{1jaCiYcldQSqe5RZ>w()Q7RlWtuV#x>4#?* z$2T9!^M!oAq#q~z=a**k=X#gdk!<%*4Ig$gy|H*s-#Yyso>sYtI|)I?#7;3viM7+g z#b=q44EJ>cL;u3CSG&a(yb#rxfPaQ(^-Mh&Xdwv3E{`N@#~g==(?O>U>9zWm2Oet$ zy6^EU?la{(_q?3SMF!Lqpx8T4(DTDTFi~J;N{oGod)W9PCDX*X$MDX)LaXI=F9*VQ z#MAGd+PPr-H_Z4W(P3>T!K#J=DS-dJD6F@rk3#!lv<^nvH3k+Yrj3`KI%W<2RB!G^gCUV^-fcVl z`)CHJ#8zb~x$wO&rE=)b1=^A32^u7*JY&Kogi-ML++pKxE16o!{?9ezWh!jdNsY)+ zjM(jxzTirhHofFR{Q>Wn<31M9y>=ClB1?v2Nn9YI!c@+tbUU*cDUgsg>6?1I|7?d@ zQJ%w|Xs_s7Y9D$@w{P0#&uehRb?*XBt?5|_XRIr=@1dd-q+8lfY_2_j+)?aN zxB+#ihYovKOl;Ma&))rgYrw$2#7N=G^XoLrseULBUs)F5+Y1VBKa=|tbO*tV(kzrqF}8jD$^snJn>L|VwtS=AI@(i`UM;fWiKUoS7MKG-^=CX zWEv)K8z6>Zm_*RVCw>9Don-i0azHxp#q)T4l4z)`77IidYHGDjX&~D(?`oblb7qND z4-A}@%srsCL6`~bMhm3|IE-zIv6<5S^e%sL8z9Z%k6$ol!lqB|ADj}$J#kVih5U(W z-fRP^y?MrD)k(8w5>Z;VNlKthk~Ff8sw{&LD@dkFY_gAsv2|L;4&^y4w=h2Y?MJpG zAI;+XQ${K-^2!(Q-dtSKZJ4~_W0hXxLN>SzY%@9>%XUs6D7080H^hNLi# zs|M-o8XDkQh8s93)Y$`OpSyh0B{tVJy4PXbqWyt7pU&-aVU^mY{tTTH2>``it82@lD;f-#)!J-U zQ1cabjutpOS{Dqh4YeHu#!nO-S|LzUcUYh7Hc-Txv?bxt^oJ5iT^n9M5H!F%tnl}$tmvb2X3Y8OlM+vioecYtYgBjCpSo<}|CY}fJTflY z@rlG!oKL2jEUYj!pWuWbIR$MuHGzZ@N_R#d>qa3mF^&tf|Jvz?X{|&;P^5t-z(`_S z-=iqVSfP|L%WoZj&-$8wHlD=-DGhs&bg**8U0s)cRpo3*uO^`Tbwl`hSIr^yz)*?; zIwWw;@I-+ETu3-FR#2G0Ub=hhQ90&6GfMaGyZ7zGt9JM_yh(=3jzHrTPrZM01NQDC zD^BS141Tw)uDPYUF}CW_ftOk2rrLzi1F`qs@v_2g68qFSfA0*Q*r zEAUQl*0pP=A8F%Gv4#fO`Z3er9DV7i=bx(%%}J=0 z>u}!eNFwZj6v7*JX%4S~mv@&<;Xqqb0d4c<+NBVY9fLGtz) zcQVoGyXn>&c=aZWF-p>>@?hA6$`hXNuB;VRZ^9V%XVqjA|6MYNymfAK%k*=H%ldNwO!*ojY?ZJ9gkE#RsfgI=EmznvF+A7F-iNFS7+(1!f-G(y77aQKVglj zwr6=1q+YDz9ReXgEBLeloBhVp6AJpr^RCD99if$q?of{7gckg~a`?xu^%#>B7xa~h zG2Q7^<$`%V*r=nrwvjqc>KGx!mr@jGAY){g6V1@mP+qG;R$Z&G z_3T`S)vfx>WB2sG<&lhxjLPN9m){*}oQ}ju6CKAnxVXv1o0BuLYgQsaYB#t*NVN9P zDt3SYn7lVV&qcCE8pk6$btk9vDWv3D5qoFqXv;1~;q0)(Sgwb$Z86b-=0AQ~t+rD! z{df%KO#IG}doSk|&iUEykw7hi%n9}S2&Ry+XN+z8;Y#-2n=?xc3`R^$;qrt^X)`+d zpz@NQAUgjCGOMwv_pCdnXS%*^_kq!u@0}E1e-rcj4>L!1iL@jS6xir7EsCKlGbDS@ z!7hQF$^XNGhZA-g3wj-v_i1A``_*N~^t`3bF7JJ?>27Z@vr=+wFk<%HlspljC2UlY zE{KS9=ub=C0AMLmBekN6nCYm1bnrJ!m}~+-sZeX#2-+rDmXq&cPN>|Tm+oI*`AAhh ze>!RNYc$QRRuGI6Wlx4#A|ckbqy|jQK)601!RRgaNkCN&w%m_vk_zUIhSj1+K~N^y zLM>`%dL6dQ!$Y6n+Uu>C?|*zqX*0Z2`8*?^tk2_Ob$Of)4cvmgWq=3<^ngM&=08vF zyCLg5}Fq&k!v_SD5xtpu9nfLzkr|Yt$ z#`$=!D|S3JavJ5#`|;}mOD6Z8Tt1;l!l6|tk05A={qFj3>5yCp;Nh|Eu4^cHiIOjp z;F2$6syrktTi>TU^z@t4eyE~kGS94*2|GT0ee^lxM+0Rci#t6+>9{`$Fz#(|VUo^~14@ z_wjyK0P56-du8}|R!p>yF|VvE#UdoLMoB4>v^@%(vJ1X@oJe>N52q_4&~CLIt4aa= zeOFbGf+UoiguJG%6GuDEeIqUT%E_~I?883$^J zzN1kHWzvlFfatI5K_DgihSs~8C@~!DU5Isz5$ecLgEFt+_F#DOC9HlDKJE50mL4CM z-(t?}bBbyfh3YzW4<4_PoN3?t&$H!q@&p)yF+QvQjyh0j^jeldP_uQef>0dWG{19T z{ui&Eumj(28(*8pM`!DkPjwAzgbBd|+4Sly4x6aP6dzaEN2d{_8P$D79QPm(yaw~4R zK|YI~qd>@Efq=t2PWkllBY&xM)Idrz+Fw^|5~!0OlC4{n*C31!A6^41SR|hMsh1)_ zcmjpG#Kv6+ZnOSJlxR588|3hhz?s6>4 z7PY+qxH*h%oY0}8uZ-`5@;$$fkBd1-w!@MnCPJ4fw}Xmhuz!o4MgUS89bvr#tQkzU zsNcwfa7>0MkO_JiJM?U;db3x4c0?(nv^(_82Y1zf<-hHJ@UiR|m2@hm&Rf5TIVwoE z*8@Y+tP&fJ(8Kg7leZ#K9p>wM;$C}VBliA#g9X zNIfcK;T$Xgw#!j|^D`cJ=Z&u2T3tH-Y}u2Uhhg_z$}5!r)g+pzVd~&h7QS1dk=ZK( z?$dH!F#Y=286o-$cDjB>r$HaDdVTU=0f4?EI`PU4SE@^dEh1b4#NitUU+DOlpFx)$ za!d^@9L%KKAt+oy-A}_R)ip_D^Ws8vng@_qA)8F7L?%9${l)q0{nwYA)@&5Ej*gi< zX+g%f_jgVZ2hiyCtnwa^Kq944$PP(;DUO0&^9d%V?9OP}s=*8+p8a|4s}>@N z8jv%K&-@ZtALfim17Ixb(%PMAE-Z6QP#HiN3}oyT8-`x8HK|)t|!(tLff+J8n zv$R1woaJPtvKhlRoz@^K=R`O7_$h1ab#Fg=+1wc4VNaA_Xr**~X!|_loM|*1vr48=>%GA;S9e%7pbEba&`ewHcEZ2PBq+0cqV?{@#Ul=q-FboXY z^&HS6B`8zFk|b>_ZlKF4D96U%fBZ)hcWymoQGY2zG?Wg4@mxz* zi(TMs5l6?7^L8M|!vgt9S&#Pr^xT>?YsNZ`W7U&JoV?{*)?a+^(q2oe2Dm3RM33P$ z*>K7TX*L}f5HVV{Ugu8l>R`4%aM#VB z3^=c5<0a*f21wUl+IhKev+7^b!!bE)v{qG1bb%Z=^uYSh|O??J?fNt z(Vsj#pgBI6m5ro~(|8|R>*X$oP}xjM|J}Q!C^OcJ)s?Spq`lLswhOj&^0TL^VPmCTr8BumhwLijCO}(*QUKC_r_VnoEZ)`I9 zrHb6kbVFQSLx>hh7Ls~5n^DMx2pCMC6)YMF0EBU-`^hz&YIEA@G`z=3l>vh0MMf*gn}5~#e+uv;C# zNU{*6A6i&X?OXgC+CSn>IRIiep)iqHZh`0q#X?E(RWqKr`|Imco%q#%3Z!4vXd0-O zU*t16Ognsz*vk*Disc^a>6Q4aw{5vJ3uG2Z!|lWtdMY9f7<#WH2NaiGA=ySBFi6l%kV96uMI86XT*}vg|wo_A|(e?og!Bt_Q z?#)?{`PftU96O+NzxI~kIqjBt5~BB+^t`^OWG=KUhS(w1=J8!z$4lV2xC*!7=eQdb z)O(8w=`1lYWY^YJkP7?_sNl zo|jZL-Vld7m&Sl)#B z6g`)?4tH3A;Z_FToZ5w?NSS~-<{gWNluNv$a}F=))V>!)!S&ce&W z3X)PaF;MDFs5FqJPYKN_6TfrNs_(0xZbo;!&)fUr;lT^8nCtO)0+<-Gb?0JALagwd zf-01uksT#e&Ouf|lLe-r9~KK_t;KtNH@ElR1heb;~A;Z+6{4R&?CKcwNsXnla`Z&9SRAkECI zlA4;jb8(AHGs~uDm8)2Uuc1YAqYW8u04PX|6M2Ktj;t33E>FUF1Byl$m9K;YtO40w z08N>&{!~}DD2+x-ZrgVpsgJ&K>+ZiTkP59dKOrG@-1C>LkM(DlO-c|WNZQ@uJP?NH%8$6C z3@QV_za_iXOjD6C>P&6?06bEqyvjbToDE$Q1ORqGiNEy4BxYs%xZkO zO?`Q_Cd*ljC(qV$Ns|j?D3DOlL|KG{_{RcuV>^%~2Cd$%bv0SuB9Djd`MDXJ@zQ4z z0k3P@8yD62$LH;&Tm?4;CZm56R?Mwd2Fu!CnN2wjyE&aG8waiQzKPG@pSS7Rr&E(* z=JZiE;zp!BBH9r;LZV*+sL}qT(q>KMi?-~t54w>86HUz7W|#eDB~PFFTx< znDgZ5RXuA(r+g2mi&7v>_-@CBKACO1O{h}jc*?<%BKkoAK4~?S0X_|yWZydtxAEV! z;|stzdJfY956u-p0cfmU2M7sNOlUcx2;X5_{N9}NKbn1WHDA&aamd|?GK$i4ogU3c zY;AMp{OW#hzA+@McF<3XAuy?Vi~u?a5D^$YurSN`0BlKP2<1?J9=EQz5%IK3_1?mv#Bwg zI%e?^8Do!YdKJ{}`h}_lEXI+;`x{GDpWXG{`E2HEU;b?wDVV~-A6B(|e_FTYDP@Dc zC_mSyjY1?rdb_zJ30DHownxJz?dVlofGcXUTKZ|5!%{!%=p0QOX)`9B+|0@GutSHU z10x1~d4I(!_1*-cW=-(g%R8_4{=T_>e9&Q0a1K5AV9>`9O?38G6PPe+Ocn=SBu4ju z`advxqNnP6NPwjJ30)d+Db=ce1kSjWqQxO(6JJpXJ6&MuaYI z{l4RPRFSg+D;H2$B_Vdg5R2&bHbpgeq=5&9_NGSDczT#Y5c!SK(nvuuVWY1Gn4cAK zKa2I`Md(pULvy0jViOcQbVt@qq9N3Sl`i1g0HT(k0zw6K*##BYwpquin4?4S zIBe{YeSdp43Ty9yXD|O`*Y4lir6zNKLM$F^gBuqxNo_SHf^5ASWrYFCM(Oruz!AVB zx-QW95xo;+9`!kxKNoSMy(RR&^AC$g&)!gla<#UO8}d!Bu>|E7ajSvqs zaM!nh$w&i6<&xB#f{E$t$?K3qt>89Pqab--Gr$yZ$pW%6|C(+5>SsLT*(d%vq|*&A zo+;o7?=iApSAK4#RjyMBw9g95d=fTkF*};IHlSvQ?k*i%cPvs_OxxIuY(q2lRL6#+ zVn|LD?14laCT!MB51FO0E@g+50h<}N7mNN3MoVe{4u;CIt?#uSG;h_kW9mfJd(gGK zX3JH2Ke)QKMKX{@*;}ZKd=7hY@afy6`9!WCk#zbYe}Fd zavju)19<94OWB=G5+d5B+TEig2~GS+iClQ)g?nxR+0@TNx}G#xloYsU#P2B(@uIi< zG3Sq_nN7Q`sh1a2%Y`gVB$y;TGGy3v1%mp~Fhc`2LUc5$Zz4m9)VEN7*Dz0*UagNf z9P9f8ux{`(Uh(7k-CI|wn|2}%;Z$GiKet}WDO4qb4w>)z4mYwbA z58Sb~L!;PAUl535?2A9vTpeoP|Ko-QAtLd+G&0L1Xaih#sS|Kb7rIl8iDp1i&jUl% zOo=WsTAwEef$U}0bYBeF##moby=5O=d|rHYYYW$@2EyaLf6qq4Mz+3e>6nD5eYSI> zB_i0=ngANeEC`OqvszAxB>POLWM}p1?jZce*B5V=2WqXvhpZB9L(I0{LT7ImZ%X9o{>*^nMz{rA#pjUKds^o>tvjjl7~ z|DLT^z~u|#LXiv2ge>xRctitq22u!*dKd`-VW3P{28%#FpdwW6vJwKo`daqqw5CDA ze0f@^*J1n0CZ;#|B&~hjGL?ThUhpa{-@EDJ5uuBlr#W6v5eaEc;s}k9Fh1pljc$jf zKNw9I?=43Wyfav)He%@2gIRS~I7>AtT2{2L@Eo>&$>oRUtr(klW0xVk`33W>Q$Nwg zTKW@}1@zqNNs#)uRv^`nG~m)2W6S9E0)rdr&+W>t%_cs%5<#tVtNznts}=T%O3rl( zvSV3bn`h9xRWl=o{Qd5{lGmuW)=HA8u{V3OQMZ%NqHcbms4RQ^?mx}~DOpfYO@8@? zEgK%2S)p7|pD_qkxwa%2Ddbi_X+&>u{8SgW#-j=Bhyw6CpSMC_i- z^|FiWy}sbK4n5?7k2uMTF7L1-_K%%as*%$|O-VB_9lF~E0FbaxxSIY^ary&2ArQhP zLG$Gc%WH%)TBAv69-}`87@z6kY^R5X*4}g1)1wCVeO2tzDlLF`tk2QC@m)V$)M{0; zlsNSYZZ9gqPxw1bC;>RqrVE6%!|}glNmHi>G7g48E@>xB4@6KkhIg#=-(;csg$nLDlXlJZG~4vj#p>KtIIKoDpJ3TZH2+z}?mwl(ldjTC=Ml3SXQ z5+Xt!B(PBveHnt6o9kt<(dT5oI(S`q3rIh2esOMc=Ki=!L1m)mwq$X->j!}~&@0he zQ5*a4|^F8mMMH|*k-wfSWa>VKUi;Z{Y!qTl^^t1Dk61!@=mVpcJL%bthEy$ z`mQd~wz$LTKrf@9U|r7|P?KCSdWc%&dpr)??)L^7ef&|+n*M|}<;s=Yek`8yRDSlx z^GD`4Yx-?W#n>&XtO@l`%bnq*W4KPT=?V;uZjAfJBK0Rg)@R!5MLM3rl4`Uq0O$(M zYU_de?58j5)%$Gy(H$W&bXZ4TJ9UleKS`Q>&^cEO8Q3D&lLq=?b`rrlFv%)ZU@_FD zi7d*p30%voZ{O9BO?u%g1i%~nbmMheEmIGG08A=dXvG9sbUU}zWmBG8aTZ8ji|gk9 zjNW`s^5mL02M}iy84ny`*zqF-IIV;@ofjZsv?(;q9Y)Kr1J1Fn*G~u-g#lCiB$`^r(BSBJhzS5PBdtvA_rPQKrRgy1_zA~ zm?5M5f_7gt_whtFZV;$m_xTl{6`#F(T_?#8R95-5wi_gz=t z${ST#!D9Reu%<|9K!g?2BZFaVEazh8$TW;`H5_q=N@2zOc1aYpCq$n~07N`l(DAZw zR(IvI78TDzi+ktmFCLzILAwv*;yigqJ9U>6h1L536V$>#)q&B_b=P!Pc^1_%r6swl z1(bameNJ3XFyWnh&tq@>Pj#-pp;Pao`d2OTLLn9kViD#89F6#U`ych$)N#ws0;$Uw zo_J&Y$61+=cl3!JPCmN(%tTz4&QJ7knsfwQu#!=lOsEYL%5GF1fUFbpZ(ANXa$7`< za^P4KS=YVxUl$}*e@agBoOR15)$TlaV0?%%$x|tG(UKLppp@RA9+4V20ILlIU`1-L ztF9oy44fI^FjgzS2taF?7A>Tu+TQP8hi6x=ysqmfi@KL(ECZSelr{hz*z)dBle(*& z^3gjP^9I%9xxA_J)HHmgPRNY2RoX%JCaaM%9#=JXR<{BcKn=?{NC@~f5bJhl^!W;S zG+Xppk7pLH9rKsk!u9KV3vbxu3l{AhR?ih?XEdpxpPkr*0W7pITrieHr{F08)A)F~ zz|fXSf>RrfI378d$FcmpBvv7Qm;SD1y2xzI8n9N5!`SxC4cL@%OV0u+S%jSP#0B4c zIVf#m{}&SCi#&1Bu)_%=VW@-v=cb2`Bt?yuZ|4TkDH82FjJ2W-DMPUHIE1nh@*!uK zCS?(z9oC`Qg134!X?v^u__&2Lmh`;!@k`;uD$Fxx;XVcg3?GZ|C5wX5iliUGwa8XQ zvasPn@d_mLq#`sdo=8%{dN1Qe^&6!1nKif6?PwZ&@d#eO+8S0NW;^qE1L0tXVL7Q@ z2xDF0RS|N`t*VA_paf8c2{I=S&<43=&SWVStqV0p&*FBQ4>e-XzyA3N1Bad+?h4jz zvBZ-cmBGB69*|}&{@q(DjD4lu+JyN0sQ5UM-KM3C;gt}S1lSUg zO*X8ZPDn;z&NRJ1+Xi<_n$K&%L<`U}r*=`Ad#RPEe%YY>Yafp2bYmC!zk6SQ_Jv;|w@)>Dyfuv*~)aTkPKx{@nn>&GNjTtOHQb&Ry zO`;@Rv@j=XsqNWcjlKE!*<=&7flS@5^Nz>QJLvcAFB31qU`r1VXN6&NL_bfQAp#ym z9Y8WD5bB44<9C4KAvi{e-jGsiTM>0z;weRGUfF_&mp^ms=(cj^S2SsTuxi%9GDfci zq290&VM>;P5)IVNdX5~b!nG-j)uF7sChb3|-r6u_0y26LK(mA2e2jZ0zB#IUOS^OR zu`J}{`E2jHLswkdrj2w(B!P%FZ|vCsHh?wl??Lbgl2q=QgJ=j# z?>Niec=OtKAAO;j{OFPfE%Iv}Ivk^wH5A{~BT%NKhgu^u>bb6DftCF-44QzV%frJ^ z;-Y|9%m$xu=4f>(c88t&c^NkT-p!|EyiNuv z9?w1CNTb)&-oIt#y1OQpPb$LERBNFaywOl(CyhuRfYd%4CrdkiQQ3=T>}_IaU!TCA z1W^<-QJ%}sDRW@*9ov)SB!5}&{K9kd0)CC%datVa5>4t*Xf=kTi80Bpp{I72C15H` zpUI@3)#wn^gQyTzdVDZPS{g%kSZ#{+=bpdhtE+3qm0Ny16MVei8Q%6zepxlKdxvDc z>3&}wDyj*h-H8lSrCJ_>qj+IB?NGn7G!SbX?6ET8F6f*H$LJHSI#6;w0Ce!3U|yh4 z3dgYXa4q)4gi~_{`(1an<2B2!w}2EKwk`uRhwz1m^E%j3A(@^NDi4Ss*^-Eze4;r6 zHL7acpd2TybKw}uiQ?>#H-?QFz2hv9Mp#^*ty$iDMq2mp$|u8CQ9FNP;FQjnX8pA9 zE@{uxH4aDQz6jN!ZESo7Uv$ zRzq4sKniIiExfR>3(yytE7APGsKLNpbz+(`86ePX3s#gURS}oC_sX{4OddOaXay%> z&GCZb@qX{U8|reeuTXy7IxRql0tU{=mRgzxgz+JXBOF&(=L76`g))H}Fbw12o>-Qq z85io(bc-o5Uj6bii;cz!6&mVuD>q-u-dZs6lmNp$qgwIGG5SzH>P)05QF{$9= zf8<-bs)8m;AqqAQk?P!d6<13`BlnnNV$8b0G;YK)DH2&)mao=C*50VXS)=wwJKyg5 zHZ}8-{(Bo1dT`5@G6X`gp%O(wg=w6tT>v$(aBa@sLn})TWDiI18v5x7ONe-s2sjl4 zAkFCXB6_NO=edvH_vpiQ%9Q!(&nECh|9)_byLqR&bM$2)+|*ne-jx&w3vVZn!O*WB zNk0wOH(}=n2`@;m0js5;`@C)(Yf|n*%cX!d!}CysA!S(emh}E+!P*zvoapg8n(O`h z{zklU7UZ-59nwdtYH*c-!R{8cd$&wLsw&XI>9ruoT~|6lj3J{d$6?|i z-Y4!&KP8UmXvXwZf9BRFY8{A+$w~B!dQvZGlw(C+VDAPD4R)BS71U4l+$ut#9H=EV zQW=s;JlfX+GO4mSlcY7crhlfRkgUD_qFEy|{Lbg!f738FG5;gfyOq5p06O%3LnX-pg-V;!zz`IZt%8^J+>0s?dvHa=LS5=^u@RR}L`K@ynGEXdZ`iexL?<;{7r_K6vjhVr^?CFq z^k5=$V4M}m1;g3e#~!_R;1!)_CnY6qKG_BV_nXx9LY^3vfjXYi3cd(fxhE>@ z1W=c^rhpoOMbf#kv{@QLStTT-E|csrM(xjGERV;r5wC7MW$fz7`_JVGoE%d^_Tgi~ z3FJ!A#?KqY{{8qir_=ejUEQq9vQJW+EOJb>tU*Dol%VvZOJmC>2mNJY$ zX;asV%$Gwz*>UsoWacyUuMRZ)m)9Oq4$ldL7xx5vq4;)*i-=@B{(Z zZX|5(LUcUX4den9W4Lyb4ncx|Z0jkHifHsaW9b){tXwnt-K3PDzf6oe2oa9Dfe1o{ z)J8tR<4Cllf@VA>ArANiRWQ(>16Zb($b`HGOvg>us7=7pJFeUftedP%Kd+VC=33{z zvCnj9H~#HU8U%0ywh7A-jRDMHDcYgGdx3^6SX!Du9>~yS`>Y)dw;($wZJZWB>x@5V zEZxi57LO-z?v&}BnlxK9K5(xvJz33+>L5-e70ss9Fhc`dC`D0kw>GN{8#`;(DPyG1-dl@D^8)3_ zg@IVdb8Arw9fZTS<=0{_j9V^$(zi>0eqqzk%`_4A2wEBdaKPhXYgSzmnz?X>m(J@` zk5)9&zGm%)$X>jz%-)~x?iLn#7n-=8y>p3X>owyA)O1H34rBW=e7sUZi@wg_M@C)S zbJ|A>6eHDuNyJ{N0m+w>KcERGvlGTmtL>s${UUM^nDuBpkhwSA7Ak*_3qO3%eY%IS z?LJ?id0JYpn&+ghNp_OAo@#^b*WjNyz3R`8cSJ*Gsv%Q=!w`^$?Ye#z=fMu?B@7Za zX|}ByP&B1fExXD<6BwR~aI@@0b#NK$xIh^rPG z@CE0bY}Ir#QaJ{sya`LAENr94Ijc$x>`MXblafiY)fhlq0BNG<+`-Nb_utv|mJhy| z)387>QUjLoZ-hs46a=8F4ymlN512*E*iF(!aUvB4=~llAYuxNtd{7Jg7=Du7Bk)w) zy^L*-iOFgI`Qkq1;*!^ubDUDqK5syyk-0tV&X1E|N^4h=$U%eT1?S;3FysE>(F%Cy-laB}e1mIbN9*2Fs=<02Amrt${>G}WnNJX_B zjMVn3#cGceRJDMeuluHT=-rRfPMHHLiMcqD*X(k4wK+)@3%gcI4yZy#jG`ixHDLt? z#gj;VAz-c8nyPVd`uhYd6()hN)G`kQ!Vx2L1=Ra8qIhgU)w`Vumt696)jgT_HwviB zn1iDT#U*>=!9b`188O&qm0FwEhKuz8)>cUX3A^bjNWHp2&&*E7$7ZXjDP3I&-5OPmnCQVk#ogi5bU*UKTtrH8NK=9vz^5V3UC1 z>@bgIF`j${oVskoj5pm#VE-FDdeHH(nLXtQdX7` zDupaLz>dlYyID$>Vr0aSEq_x~U`kiH>+~w{!czF1%6s?_3E# z>g*LTZY`+JUKo4iMA~!zsw4`p%=T$yM<%+`0h(2@^5gmo*tGXPI;CUxSI9s~f4A>L z4d!^u?CV+~IcVDMkUCz`7{vTBJN5*i;l>dw%ddcthVt6yD!@hiCS_0Leqr6_$ohic zsXT&Oivmc4c@_TSywIY>3w00W-QB3r(FOUyn6$b_TH3(_L1-@iwvZpURgng%dQlq{ z&m3N6{E0g>1z({d+S)2fWdP28^*a1O#foXSFI-wGfmFQXP4!3S_O3TS&MU#xF4>S{ zAT#w^fWZbBIuIdCkZMT4uy97es961Oken?*Dqleb?5R|8yfy*11Fdx28fRBWh6qKRtLC2m7SWE{%dlw5vzRElO z>R~*;O7*mx=YL*mfmFOr-}-m&ys^&5=lHyZc4v62C#IQT6A`#38^Rd`PKX*blb7S> zurGF9%U)aZiu~n(mZL(~)qP*Z3$6p&p!Uwvrid37Ki^zfm;HPCqEiY6&yA?Z%kW&Z zdT=V#-e{Sg+1#Kk8YLv+aDF@3ki9(Ni=%q47apvvo2S`q$Ap0k{w zi^cIFPqmtp?`-W_Atm5MszRZW5lS;qT>@9tp#UNdWY>w~Lo0x=f#{*`x?t)g&6aOv zCMK#>vXZDHJ&+#%U+2lj4PR|i7`nZ&%-ZX4iG4`#>dWwg||sMe0sE!Fv7i_vUQ!jI)fi zxcMIT{3UY^7H;TTAw@7!fpaJAQ>jxH=I zz%XUA<4rKqD4xA5`g!NcM)fB&39uoJVT&j!xR;AmuXvmG8jZlMMVRmt5W?<@X@Hrw z$kS*~69TTxG0p1Bv(EJ+{N`ocQ?FrK@9CwlGkzrF>0R%(fnCpCGbzcRVZv0(0Ex50 z=Ckgy481j$K&V9JAoH?0zjq5x`(cca-usd3y74CQKUmv#tr8wFxf*t@G9nGQA8qQv zrYs*95p;UA7@c$N`SapqSUxLqd~DELTaFr>juuS+cV{D>!n3WeO(w$&S0VP~Digy` zIE?N0mSHQux^%(()f11YwsYM5f{|(mq$>qwI1fjaMAZ5j`*}wb_V(n@PWYG{?bwy} z&)q$~{hZ9)pCu!W_c9^au8uM@N0Ogy|RZapNYw_5Uv zyFs){fdrY4z4u$!yqQ0ZiFYra2|Zi!RA0I^XL3&H@{UlO3G+5%?Tx>r{rIfh;Y0u2 ze)aAAvdRl}Mx3)E$Ik}7ed7CXP8eF9dzq+w(2IrWT6D2k(uLd(Xcm_^l6mc}R&3&X z9~>8`y?Cz%ISq~M2^=k@`j@wby-~f1I zt*K?8nj-5`gbiMYM>jq{t^1@|rxlQjw|}VZV18-RBGY>{<9@eSJsu^tR}#@3i_u)+4azEd%*E$!oVGm-2p;a$g*S{{t4vi3 z{rOHD8$9{96Al_L4Xwjt`C()sCaFUf9?8_oUEAa-b~zQ;?;D%4q|{87Sau(a_a9`@ zo@sI-#;UFrQ;KA=i6&GPE&#_QotQ}V3r5N$Uu(!8X&R(+J_e;9)$j=>=)mzcu5u15)uS0~_BP>{V@^$19RhRyQr$D^wrz z0x}DLgu_^2D2C14aLumw){l({qCFdpT-3k82kmenK-muT`of*Tk;9@O^RPbCO}Ktd zqY(o;H(NfbyeHkbalN@>XQ&Fhcj}2h$Nix}?RlMO(bS7B46q|tgBxidI^yA?Dnb1o zc5GRVtzF?b+P_B~XR^;*maSdZQUa;~QZRdKolsznAcOt5vk7~1%BLsXxs(*Jo$TvA z^!9agwx+L?jMNY}qTgFsWHfI8OKR8Z`$o$|%^dVl7rvR#)9vR5r_2#D5IvgeMA8bg?!H@h~uXKT+U^Qy}ulr?CW zE;$ZclF@;^^6{G|95k-KVEE1+7tA@w02o~?;jGkV@S1yD`{QYyvWc1~K*GO82dH&> zo3SR9)-XqOxsY!Mo!VUyge$ZcW3*;#b2jO09ci)n{O~*7=4{%v9D!8r9Mj`WBV#H> zMW_@4P^18><}mUe`>@;&5;TaU4IhO$H%VH9g@TbD*b)7P^Hie-?=&h3^;baZ(i+e( z$aX@|p4{w6hvcSc73xs+;s+SS(ADTy25^yZTl!rXRVQKR29LuNF1#@9x>rwMAO$NM zeEw+Ox$-A0)}zXN>+)favt!JAO0k*KtQ|v^=TXg*?TR5hlW;A-NVm8lrY) zhgcal=)Iqvel70_UVrXvkJkw*uot!@m>U2pV{G!;p09oM(+fjOg4Mh^qz3mfeNY-W zQY|Z}qiD1}S?{BTe92JFcq;jVI&ji7haLw5?AD#UilEig$_E@DvDbb}b2e$_*@FDy zY~qnAJ?3oKwXAD}asj!si5A*hyDUi*hK^FtkDHxJ(nU6<;M}0|H^fZE;VMr9zcz$} zbdZWru_0_qYNR`&-g2I7*kDTIAit?mk?BWjFJN10J~pMtoL_e>Q;bxPF94%*jka`SRh!U@%JZ|7 z`5D{L(CFGQ0gle(dC0bH&{8RIV-Cl)V@h{_%G}|9TLNjLVCbesYKNBAm+b7BFcNt* z1}-{V_(kA#WrEd!nD9q|Fnw8@0mBP|#$_Klq8|?iMK6@!9L|$kwmzeP6zrpagHicS zDs7Lc=-!Tfd^9$lu84!jRbO46ZKn#WhHtUV!Qt9hD?e_WJD~E!gBa3rcKUN`n2L%xgY2z1N)e+rL5}MfM1~ zmQFy?vOFLcig_acCs7B*9EDYSI>XDO0D3WM3Gd&a_Slonhx)$anpqh>p0y)-lE~Um zZ5#^rQ+w?-&Bg4QqKejjSE_-!s5Me!NSny(=uAD?Gi#jz4iW*mmSMdlWFwwQ4xLUS z2u7NG;hDuqPn03gz3x2jcj*3fb!Ds#)=3z(P1N?@#_5H3f-;7zSb(S>?elKQ9@G5t ztqpi$NHKINOCT89Z3r;}a<-EXv(@te}vYI+nJoZS~2x;mAHlwZIXxut^2}DrI zU9_CjB-7nw5fV|NvGcy|QSUfUG-)`saUj^QVUejawmh>wq)jE0%%ixQ1G_anWTP4Y z1*4UAio0fP)*D_33j^k=12eS+@_7W1CSGu6Xrw0!K*e?bdGRpbF=e4L3oJWxB@DHv zRS|%#A(|s$NYat&M1Ud=W6KX+%AQ*|wM1FhxLca?)X;vSozpFuX5`Q=t%QU-acPo9 zV9|<&n`LC{WI)B$axzkhiLT7nTe?r1v&G-F&YrnsPV$MI+cW7}k4*0|=eO<4x>hI; zZS>40Ab3w(nzE~Qls>MB6?EsaGWRsGTO?=PxRNDctj2$eUbM!L;E z1sSOVQm8IeH&=9+Xb+LPq(mwqA>UExsjopm&|R;n{E%IjiVlfn>=io(fta(6BH7fU zW!m*;K(gsXE|3p8HRf^NT++w^#w~Ioz7_gdYz_bxw$vdHli*vx{OrbADyv_Tf1V$7 z0k6zOJ3LZrs64a!8Q7Wpua+y|pJ2yRO=1^kBP- zRxKOLA;Z=W9ParN^A#cMC?UcQ#Q=Dn^1qLWg}S>|Je^vxA5i`pV-*A+T#Z zqM^;8E&P!t1${5{CL%|L_L)1PraDhFZ7{t_VW>|7p^>^Y2PkQR45#?L*&A+*7xzEI zAYge?F-Gk^go=htdO@gXA^Xa;p&K|*3u>d|@R+8}(t5rz^NdM0{ndprtknqKHFdsb znIP^&+CoVaCXtz^WfO$4fp`8Svm<-;tJg~$NdNnfHoQ99sX{NyUPymQ+L%{oZB25h zxTL9OnKE)RPM_MoA_FvuVP?qMAFkylYNL0&xU0m+=C9hzsr>$f?{t~7WzQ-Jq$s)2 zND0TDmQ8{K4Ubk~a}SkoWQip*QJa0bBQY2YcX^Z*aTCI~Ki$s{Y>%0Sp}iYOK_iP~ zh{mwgZ7t?XyQ&nMEsa#u2w{_E6D~cC8?9FCeWS+J9zRxMgZvNo=lL8cv_G{1Uc{XaW!_J^4a&jj+UG_t( zMe^E*y@W3Uqt$b0@5iUTeRVy%o?;6`Es029m_*!y zksjO@JI#5rNrNek0->84$Soim7?Cn-^wtkd^-be-wN_)D>*87=Sr) z5iLjrIG~KN4b0)52947CO*%cAmXx$%K5+36er4hp7>0y9AbZz{m3RTY$z_PpcLC>I zCj#F2qg(d->s~l1`rp5Lcj8T>epaTgGvdmYu-L^FYJ<@${IklX!koR{njFS-^$&_I zd!orDIIU7IP%gSmdDzewcbo;%BN+X?Z(coTd)Ar=p}k#>h7keTcCO~tl(~tciLhxb zf+(bk04&{6m`esCG9uWQT0@E^D{=w&Jq7*zfM&xS@# zz-EXvDFja1@+7XC*$dUhMCCJ?N&!6ENH=np&mN}Nf!Lvb_d9cV@Z9s#{xQAux6vzU z5bfFE_PRr=F5cjC0xD7?lD31>>H5Pbw4al4@Tab+GT8(~4)fYdN)#n!m```H{z#Fl#yT_a zMix+jtdYz0Zv;-AFu?r1wiR_fL-NG`_V112`?vewl|b4g5bEC`C}aeB1KXohHev)> z^%mGljD}Z~rc;#Hz-T~{7#}fw3et2DE8{ld=tl1Fyc)IAZkze(-(Dkq{_>u@S=0}z zzR5bNl_X=NO*yjO(V9~t%B%K`c7l-3LAH~`Zko5|q%y6$I`!w5CoeJ2>{={F-_(oI z`n@)OqP-aabTJa^0kcLoX@pi?s5U2;wjmzYcz?Z8HP~9l zNRv~zi-3f1nwct-wLO9e?XxRYNgF@bWVX@H6xx1MOR2^VE zX!Rb@ohGmZD&Y07m3uE>6Vm3$1^(8MYTT>KxeZU(p*=8vlF1iq@L*IF8#(Tevp{+T zqZstRR&x$}wn!jV(GuMXZ6}7rK&l;U#cbr!Bn$a0B?Gwmgc3x%q!S1yb+XpajOn25 z2p~PQD}K83?1e4fs*|5PNHS85z*LmgEZ3M2(Wi`VK~dlSH#}6t5GZ1q4f#H$?UtTu z!Z5)|_ok+%jb2bX55FrZU~yk}<`r#t1y4FTmB2M8R(Jv#`f$xh&6A6*qVr>H;eo5! zi_1!G2UBt5b<;(|f<0<}sEXep2s9i9DxOR|tR)LUQ!^6*S7(;;qDfSY3D2 z?6uQhfaiI8NHy*YDfh1yJm{(b-lWV=%Uk=Rq0}1-AT7vDobHTk zeZd>mb8>F2Uj+3Z+E8^E6p@+emo!ECuno&C4H$-?768qZkrD>FAka|7erYgQ{XJJP zzF?<+IE?Q}NLtt9lh3->U}ZBL$I%u!b0=BW>~!EkOwqDX~KaiG|ua z>rWSq!`N87WDWZ)YEoB2>vrC<@;d~f~((*RYRE^_wS5#Q@NRsPjZfQ~$ zhy?*;{Z82eNcWYU=Dd2vC9hS=$hfV3P@N(QK@(n37iQ6VIa6j}v?pt^>YG>z3fb6% z9y?+}EezDGFj9?_P2~-nkdgsoOca;wii*v-?ER0fig)66)hSnQ`{@UT$N$9L&%JHn zT~(G&@{9fOG*c<-=I9Qd@UagASeQ3Df7(;;cam7|g{ST$QE@KRutpzm2$w5teNqL7 z`VX)Sy67l)dQ=aI9li?e`=1-HW=p`}S4K3!?qdw{l9^~F2DbiYMvDbc&pZoGEO?4)=Z}&>M^j&wH7Ze9fx=I5gCXXzI z$arV1hsv>Vd3r_Jjdh!PF#Ve3xMdg&XpLsdR%r3984$78Ww*y4Xf|zro4N_fd&~XJ zfOJCJ>v%)&FE&$h?I5%CZtW_ejKk{Ag+Oc!R{Sf#d~D*j&fm;FLf_Mqv8?CxtN|y^ z;G#3k0&}c7k%sOW$A&V=9Dg+Xy`U!hZGE+8X0Ltgfg?SC&-43@?AdJTm`E~}>B&oF z5~b#Un|B@?KmF)VDLonESDNne$Nv2_3POcd{_}c^#c@dm{Hwm} z$~FLeilm{IO1d|p90~EdJO6_CMXEt)79TWP{VXE1k1eeJjx)9EH7~|(+I&}iQT~MC z5q%*2Zwm-*ok=~gUEik+9NOj3OuH$wf$Bcm9GJqi$}H1R)uz^BVTdE-c5rW?_RCY+ zp5LtH=5rh;vosk@Nj}T14MqiTNlnxFcT&?x3d14$PBm(3OjZ=48G&I2N{)Fey=&3* zwPXAx`7TFu?KwSb%Dfn6$)$O?HWUz61H?dvbso+Rd1Kl3P$l-$#yZ)vR=;`F^{@Rd z=@+=J_A(!6co6gZ?ZffhU!3}Ba#HRv_wG-DyH#O}LHJQMryb0CupoA0|EN9t*k%l}W@1y_gKd?i$g^uHhAN?)S?H<-)NhSUg|Q4@S$5coW?6x< zY}dZZZ129PQE6-6#N^Sj7|5{eyYb5szq1b0L$*U06E0YtM9qj!VDY?w#RLPmJ}E0U zNiTO}YPE3kqI_&ipd#D8qHM?a)_(Tsu{?8W|LiWlD|PXTwLRx78}Ld(68FT!s;1po zFY4-hOY5K27@GWxv3gQtYLP-C8JO^2nRGY_jJ&}^-q8YV^<}|GE5 zV-8z$+r8sE4jA&lg^rU~+KuQ$Jl~jB{dgPSDl1DZ$49d?%U~i^N6;;i#4u^7|7D;p zdvxiPQURjk-R5R+pN&_^UR|IZqfj^PLyhW{)gC@q^(15bgGHfO@Q!05*mh0w@OpkDT#C|*0| z!dILx1`m29d*zBpFtpbohQ=ZPPs3{ihDe~Lfl*l({vRHS;{-rC4r&h2S%nJ1t}Gb> zE*LT}6UL@?y79|b9(tmS^EUv}f#;1Z7@D#miaIuQKwwm)NLvciD6<0O> zzIAdS&&UW6KAK(C*tyIQ0asE47>%3;k_5zcptqRn`fT%#MtjZod)S)Ywb|>l7oQP; zI`X;4zdl^?`HKP6Fl!GHtNShW|AAwJCpo%ioq^!d}2ky^|Wij0rI5RKk|epqcabyM)Lmm{@z)^WBb z6G}Z2^%MZyau7V6rN<^_HkkTp(}v~C@BXWcr?h|ni&iaof^$&oH3T3vh`K=)x8dqq zT>J(&CfE1Gyd7pStmERJOU;7)@AVydQ@(+0dsRkH!)cneU6kLNjs5uDV}AbLEeE96 zs-97yYTO={5<1ADgGCW^IkR&HH;CxPC;5+lBD#z)5>wS57w@|# zHi7-T;+z>%S1syS+HLhn&v)yDTKoO+`;$?6jUWI3AOJ~3K~$h)Q*lm+mLy?S28o0r zF-wk}-olG@p%v>Mb6 z^o3Q}t~n~OPw*P(4Gg75)swJJG#lCv5Iqd&bdX5Utd}lu4Cjs1PxYqlQ85K=W`EtF zW>V7T)7iNG?Ac$tuorLPSwpt2sdf~+%E$-d> zG`lNjK(!C!J+QM4jT)^|MMOmM`PEZ{-8=iMKLyf$tp?`TuD&OxYSeC)9Liz-kjNfG z0A)a$zp0+FX*a8uCl{Z)tAo7O5ju#$@Y2Z+L1#gifTR}f9T#huAF2EBH;bTL<)9 zRfd2&Ys7s-vQ@Do9kCIHN}WZKhqL9|>+&~0T1+-<|5YnHIp6=5^SI~6RXUVZzQ7}r z*w|T4V}KoPQ2VxRfR2B-gCfofu8UDIh?jtEE{vnlM}d_dgvU5Lu*c8G-uzoTXIpmm zxj(dPyYburbg0&M(xD3R`NZQBv6i;n!$Hs*kiIDm@ohn#ioWE)D%hh>Gxh+$;Hg~R zeIxhqa^v2D&=p?=JgUb+4z$DmcfGQ4Xci-Ygx7?7RVIg&MeK zKkl-TT}~y|Yw6d2%IHdB6uLLQ>(ypecHYs{_bZDF9aaG5-eXM?0hBF*7AzS0q-`D6 zB$Wv?t5beEtKvy#WrI1)BTH!XYZY^HgMz(qKvZElBvwsj2{I;V)<^7DF=f*D!je<$ zNRQ4*q~u2=5D$78`)d8Ug_D zhW~5Sy}fQ8TT+vMs;=9=*3cD0la{xR^{9db01L}0k!COM6E;;wlkPXBAb~#J^jc($ zZE|X`0n1KqF?px@!>_)o=I@_0kzHoRsxWB)@lHA37|G+}0bDJ|t*b_8nTn{e6+K)? z$WKFZnrx#9ICLs>Aro7pl8HG+$BZKYzlj)Va+Gu?(ySBS5>Ip`Z2{GB=UC!xks0+p zhvmk2+0d7_oD!#Zyldj+k7r)<)%v?WO0H0-Tnl}A>=%24uwG*Uw)j@UqP;PNy~!D*$1NFWKM`IY#ql8nZ5N; zg*(Q$T-!$VyM*tc5uL5gLZO3cGzeO7O~v2vM!cK3!;7lbUe{yldtH-Q(!Mig&;2cR z{~5SFZjmp_lW%vvB6_Ghfl+Kz4{Zom`4C+R)dE*UNrlb=k^oHNKqv^Q-dgqkFFG$FGW7q22~`Gn6IN_l!mcQ4buGtbgZn z@ahO1@>yNZM>i~}P@9~>N*0+(xRM=sI@S!64al=fyBF&qZ1;_Jd=S>_nV@rx4AtRm z4L^rH|JJILHebgJprY(atj*z1|7Uc1!mH0Fm(!83rU>rtZkT{W5Yv&X+3Vv1VaUAG zL-gz&n<|%J$fC8Q)2KKRq7oIVD6CWS6Us>qyxV7Ul>E`+_7@*Y$=sKq$};S16^4$w z3JRf*hW_NjsBK`etKv{FK;~~U74pzAJDgH%0qnvZj_L1e?Nu1+Zth{(iAgzE&s*BL z42#)V-f>Rr?ES5EMig|2`y;BpI9>yqIe=CdRv1hi5_HVb<7tOLqSvMxQ@iJ=o+C1k zt5`EOV)^?gWntddY8daG_=%3F)HCk!rm*jF8?hIbOu}dA*?8!ybt-1xabE0Zc1|#Z zd3Y$Yy+*7~&^zsb(UU3^l{I#?ZNyC>dc24PVr)}am$+nyaIjPM3Qc?T|8Sv(6BZ2? zNJ2~vq%AqJ{|D8|QzzPkCO%-8XPsQ6w+Mn>iG<;(Bx_d>m0EIO-lnItV$SvGBJ zqG8p9h~oQrQCOJ*q9&({+o{N zcE|17Rmp_zWU5IkEAW6a+@Q6km`x*05j`mVETP(@TqIJcq&l7(uVD-khX)&)$O&Q& z+v|%Cw3)tOK&4RZmz642Qb$gnW`FLiGcwdKW|>pQb3i?LF`0NZ9`0I2q9H-{SWkG^ z7>ggcnmf}nlrMQ}_Q1-LJz`nBL(j%{ujp5KX=|}rat|xVemzi=?LEZn&0ar2cn~(Y z)g7UxDVv_dgfA_{oXE?nY-?g=I#XZ%}^KE6R!EEN?x*Q30v%BuPryA$fSl0`~SR? zm-y&SlS@C4a?a!Ce!sNG_EE?FUK>^qQGEXVZPA?0Mv*# zM`mP<9Bxhx5Ilhy2v?&M47ZdJB^ejIKQdhR&(!C#xx;pcSSWkwzsEn==jMOfLv?!m z@BN0?^ZL$jM)%X&Gt}kE@sNwl^*&T{BO0DEG7{24nF$$7{0w?><#lHTIJZV9lR^wD)u`*Mi@=?x9;n%^)ryGvu=@2mpfr?gJW5M5f8DKFBts5NyM zU$a<9qDNm)I$|m_;X*XKSaN+)Qj^`7a}L|KH`?lq|Iu|dBLjfl}AxiAA_rd9_+Nnr8C?@))c@#(}BJp!){(o8?XA@f5 ze*a_rhTQ9@P!`5Vxib<4xQ-$=zb(GJiOM208ddi&@sL`kit$W5d<}o?r|~DO(7R8= z5j$Iy+kH-B=XX{%q^Bl=28rNkHC2IU1SggIagaOe|keu54l+OZ4Zn z1Oc+4Lb+i;9J(j&DyK>-I03K2^8G%R?oD7D*C*$`y=-x@O{q(ho&T1ZS>^v`HQQb$ zDMvO*a+5U0_|+4;qfvDBRs;;6)sx|hM4+}BE^9@(+Ww`(vIvKO6e>Zgjj3n@oU!~I zA9M1`X3x20izID0;iF!CdhRu^zumQhRgb7Yf(*%$Vk0kjIyeZpIz%){G#Sv*Jj?p}^~GC7-rYsRQMj1DMA*!4dZPSvTt7ny+>m{I2W zzGa--x4XK+TkkpNJ*Uj%RN$nLc1-L9@2R;D1!~joEnPEkuTfJEYq`45zHAZX^FR@W z7jnK1X7LE&I_?}~cG68n&R9S5q=jxWSt7P?b0`PqIvwEql`SX!clJ0TrP|uh%cu8X z&5~8B_esC`vd6fape7iAfv+#FGl*`j4fy%sLyznF($^o0AY4=Z`DF1A$Bg-3zfYT$ zBviFIbm1Tc%x*Cen^Z zZt3%be&}QY=`)|deQWFMZoC7xW-D8R>=2qASrJC{S7Dl4{K=x}xSLYbM4C({wGY{> zW@45SbmQtbcWOX?t4kjp?yDOAbradfly8a zI@rWlq*z@7g784qk@F5M*u2kCY`UH2tr)##_QF2}@bAhKs$N+5@HVlWfqPvw_0$&g z`*ck&(}Y=BskRD%GH*5DbS|J)Z%dJIo$jRB0u{Tqq6f zHI!0$WjQ|cvVYyS`hG!3k(3B+DRvA*TUA>wB=C(+j1I8CTx{(|m%3Cl(gJT)DOAKFq% z;OwRjdwMJ|xG*{~AobLO2SfKCFpM3?rpRw-u(o}1;>>%8!N04HU-!bo(HV!p{n}zW ztNW7>H1%ks$Oe?;8w?)`?dQ{W3-J5vJ@ejkkq2jKpy0qb5^WCQ6rdtKK5 z!u+`t+Ol=Pb)VA$2f)m#)`=Wop(6?wI^9ysL_h>LJ0oesZ8ftvhy{j{pC~KF_}z{4 z#cbSq;ptf{7f59w0_AQVv`%jlL97XI5Zp6y`w|Pz+3TGC=X9MtAwP+V0t00t^T}~w zX|x1Jytea;yfjvjWsDUrsa(6qpPuYBGpD#FoR{w@1%zs`WqFbSAxR6TBuobmvSES% zT%~D8@KujN*O{@b&7|j_8DPhDY44~N&i94DEwe zW!mJNmB%Dwkiw*kA}jEB0)i|xiA+kVWJhFyAtS{XSNbyQmbN3YrhFW4ODS_<3Z^DPE;kY* zg7*98mAS|L?ydvNL#<#^S$FpIjAwO#?5w>9cYS^SOZDPY9D4A%HRrYbCdc(u4FF|@ ziN)svyu7wo)wmh2ZIdgcDb3OCY3r*~KDm7CSLcr|Y@Q4WAk{i)4D6W5DqZ8aCKS8S zB_uJ%qAd`NBUp3VZn0HiU+me+0@7}VEw};jHvD1y)PnM&&99xivXK5+Kk1zl{_sQY zx^+GB90$S}=2GS*^KP02(OKghPLaVys)J{9<+^-wtNE z860tj(>msQOO78l_TM+$a>@1#{Eq(a{LcHaASA`YG@fSaL&hrbQftSP8+1gONYwaP zeGxbqM*Q%iwNc)-?+7*sCTan+908N9fdz^A!yifhv9{#i*XKX=t0#fh$5>u-^qK6W zobOa1SOuOKgP(F+z~yhw*e>@$eYCH!-{b24yM64+$fFnJ7N*=tR9Y^$iK54bx)Kd* zG)7KFY(V++{c{8t5Cu-0x6<8&E;J*9!_O_30FhTwHGxyzYT19zTGBBqkUsP7Ys16; zxOq%l2i#)o3MGzLAgCWGn5xl*iog4&6EDah7lCpX(`YTx1NtLt;$;;$(?}c*JY+6X z2665e^8iZ2`N@;s`@T(k$JyA}Cm6Qx^G?UIcFr%lxt5thTp4onMAtVmQIm%FePC}m zXI`cR=e8ar*dR91k~~=qk_1j3NuJ<6@uMBJpLIZYEVJtiSdlh}q0X!sX^k(PBR-V} z1|PIDK!K|03kHyO9r!ua20pLo&Yt}C>3WlA)pm~DcH;5u$kal;k?{7sw5sQ{=V!m( zx3>5AJziJJO52Tk^q{4|yv?Ct1RxNQ%pS*COlh5=2$CqNbZ9CCrVe2>AC`Iw6+#&oM&=9o+Aw zrV_osv-3!HF8fq=kdA5EE)zZRgwGUrbi?EpJ00MpA17pGN4M`Yf(>M!6DEL;cQTPw zKR)FRfQRQjY~5$}{@nx~T7_ry6~1xS0O@0y{)vg-ry_i1Hk$}6h!T1;+-@+vwD}HU zpT7onx1D$bJ0c}B(EgX+5B~kh+q>B47CH>q-fQ1}cJV9I&waYESzI5oNjGt$(jl}HQ=B_ zzQ|yt7*!khhy6-hC*v(RkQ#Fwb6L$!A$Jf_?os|&>`}g=F3U&Lti*<*&ZeONs_#Ml zY{~?ryu%OPWS78vY2FX3x$mrP`=2fvJE?P1iQW(1eQ?*m2Y*-?auRYN)pm$y7f_iO z?wE83UhTAjC#u_Zdue5Mzu@hAU%>{k&rI|gEhg2c)Ft~II}YxjCxcY@GiSf}4L+;t&Yqg}#13blzXqn4^d6Y-n3H~P z#w*cZyYBb?8RE+2<9aVIi!EuN-z+V-ja{N%eFy58Kp_#qw4!4d^>9f76CT+iDb-R9ckL z$R@TY41)r%jQlGvh?2o%1dOZ>Fg{b=$++WS&N+g$cqZ+15^YoMDP;hgBKh%?#!u+k zp`h)mrV_pXSLcyzQ2H~YwfIo#TD3qxRN> zrcPO&BI+Iscm81K+RxdSoA&-q6V-seNl0A}WFi`0r;*lCUl{*XCV`hqZ(llN~aw17vT+prgZ1w{G#-@exs>>T!) z-heT89Q#a;mF)YsgGa#4bDp-Q>BRl|vXp7wiA+eJMLFJz1V; zVB+<sAIZ_PHZR{Cp-KRsPnA0FYuqr*4|RYq zD?22foBK$evyK|WSkX4Tbkc#WZLHiX%)_NwKSfJm%F0&j#?E}VP6-Z;?ftg3J)<7F zWBf|zp~1Puo|_YuNBfB%WTk2@qZKQGkX)2S#X;L*&qZSQYS$PAZt_j*`3l-q>;Z$G zI<8w zVxj=vj7+92Q+CaQ6ky9roN}RR5V7P6nBjuvz1l6%&!_q+;V`ITJbIs-I^wB!d-QDC zdEvHBgq`udOZOc9%Z+TtZV@MD9N#`xzR2we&&P|m=o9s~`=PxqW+$Y-$`JgczZrwrbqDXMxsPmD zF8|ILmtTA4t^H46$EM^oqyB8(PrSy&oZQ{un}yMCFU@b-`SNw?_u0#qb-d%fBNj#q zDuba26VZBOr6L<77O0wxB=yGl*lB>(+RTlBS<5tW@*zm8Mq8&8DEFo9N~A7Kw7LxN z$2R09-Z_7**!1z(lr014vAusNsx0e~=P=+xLhC_@;-orHwxd+FWQj&;tw0g2@`ApM z%(H7O->e1VzCtJJZLG!ZFj$syS>BBgU3=jlPkER+hwCyKcGk7S+Fv^LN@r1@R*o$8 zkK@3{|I_fHFnp0YhNCuZVEm-XBR9PvB}Mc%cs}9YEo_9dq-X~ z_QXS2$C?dlqftOXwA7W6Fuc35Q|hT{A6OdQ9ofbm@hk+HSHJw^%9rPy^GI>a6wP>7 ziRjc?mDZ4)=b1%ysI@6B%20nG&owE4M*FUdcV>JK?}dGmoh<`+X$MkqmsfoH>CFp% z?(FZwtc>(uFFZA*?W6aPYt7P9Pl`nVG>GD|Mlms|Ng`&i{rsnE%J-Zks@fT z=%cO4W-NLN%^2}_ny{f-Kx9##MY>1)f z*csR%nLZ2zUXx3YdGtmZK=ZOy@e70izi)#I`?2#B_;2tWSPS7~pT}Mwe)yjIZq<)i zm&wx9u6?H45O!2*CQcvQN9D5|esP{`ygw*-TR6L=l_@tN^Mj0ub96j$L!`2klQe_+Yv7lb?)1w7-TsaKunFA}6kgObZ&A;!tU+ry(``q%>!}rZB`{%WVC8&x{m}{+ z(iH{kKe%*dE1taMFC3pS(NItNpRRU?;}k%Oq4f=`cqA&6LBi5 z;=R0sG=S0FK7iL z-fg(PuCMu1oBN<|^t;mKz3&)*)JN%HMPZ(Z)^pR|FhLWQCm^awk+PC&ae9Xobxa=y~qOypm?=J_sz+2N^giSP-pHkwXk^_6Zu z^jzFw>nNP8u>c2PTK?|v=l3S<^fqtpowoKl_ll9Qiwc(h)e&7|Cav}k+=fT#;w6b>N;kVz2Vuyi_3%v&z#&i4#_UnR!LQ zFiAtOvm_{@$tW|Vq(4Fdvh^?iourVGUCQn>+M!BUN~+2DneqBGgNkTz{G?|lAKay& z;D@bEh~MJpuXR3~^-9h)8EWKQ8u7lQq*%mCLVeYf+2Ry^=@d8;`KLundlQSKC~ zjpR-%m%%&G8SejF>U5j(&w{Gb-v1ciXR;UB7>*XC^f;j((mGCNOF?GU0h&D`+$gJ8 zTeQeqm5UMGe}1-!8!cMFcvO+U+Niv*90G$O464@UCO^1f9f!fJKfgL?V^2Toe?DuBdRVdZMvA4Ko-GreiYse91;e(e{fTZ6@j zCE%8N4y;K9lI^d3@XtezJNdz;JW;o`?XPtn$a*K|8jYhrkSO*^Ic7;G1l^Z@-yn;6 zShtate{nv|qt$ltdkAZDKO^5D&WWV(A|5J@@@5r_|*cjqTc(Cx39`_-Pm2o!=rE$}3ER zIaHBPI6{^*p~48cGW{)PNX&EMdXkjRsD>z)6kwS3jC({Eax@9msH0Co)&50dC=ysU zw^;xB**~}1CLn$5va>H=@x!dq?Oh1*pc67nI&pEvdzcfh0h5qqvMhK+P47rL1IoOZ zXfy>~`d#bZs5L`Z0D`xARUep^c>wFuju&dyrgYH%y}2Jh_TcyCD}BAwKz49al5y-~ zIZgeVTn1?fK$oBAHVBZ8+5cR2bnH9ARM0IXi-zBxIC9u4OP;h87Grvy$quhkY+AHR zSx30l@?yJA0REjgblM9)j%_q0?M5DQiZ>)U-*A0go%-NHqF~|v(!!Q7{QaiqFGX{A z#flZp|N6m+^DC08OQJ<-Hsza9oCmpDviUPxe)%o>t7fK?X-+%U`Z%?i>kfI;)@jrC0*v(BBP#Kgq*9raA z(KOKkWRg<{yI({rSSbNc;*8ET<9)!a3qa$ULs@jF2-J=P2@jwe0Loc_wZCc1y{8{` z+|9o?U+Fs?&R{)L3p6`2w2tPz%YNp7*6HVY4FaT-_wLJDrZ-8?7g;!>J-jG&P7k0{Gf02?J1w!H*WTMH--yRPAJI04Jl;6%`Z#T96?iK2zhH0j8sHP zvr+}JdbDZn4j-8kID>51nC-L(6ON5kUzr2>5>-KnmjzOH9zUn;!Mp92A$y{RaMr=X z@>kEEc*u7J6&riD6~!lzKr048GnGW8YWuianbU0~HB?VZoyW2xebIPipY;3ccYlPQ zGA!9f{{dIB-TdzxJ%CtV^QtRe__jk+IvB4$R@8@kp2~Wp7LkGuXzG|TLaxXAvBUED z^$tpdx?ME%PBv|<84>A`vV2+&gN=a#$b}e0(kWA|Dod6e`ova+TflL%rq+9V>!aT% z9JxO$PShBQjwSa&OUeXO<`lMq%l|i}QNGKs^~Z|x@~(e-{gBx)XI(V65To>Jj-k1Y z>p5#?l6qxiqIk>@IU-(f{@No zuw>5}jO8BeIGm4V{A_Wskg7lQ;&Uf9d+g5lI=SHJe0$5`%gr(4K&PNaSt|bB_%w|_ zM3QVHh}FeXs9CQ+M{QZA49b#J@bBV5a#&>@05+ywSd(;;`~2<6t4=@ck4>s7)b=jw z345H%_DS(5GA>@6U1&kbF+gy-IdaJLFD)MT!1g|ue*f=1E@KzQ_yK&jz*@G6o&kl- z!EPI}SezRCQ(hS4e%5#0*m=)2%Az3eA9WyW8QYA;qz<-P#6tO}`QXGt0XSw--SxEf zIZoShulK+H;<_+Pt?-Z)>68tfziURmzGA?fr~ZerEhlt69 zts5){h)h_rQw&n7S*VYiChP|19XRl5-o7wu=JuTwx-Gy_+wXkQcOMo_C)MRNn-47l zQz{Xe(aWh0-b2$r*{M3%+PojGon@@7~j1Ouo62R3;w>+rYd?mPY9qyCaj7gn1|)YPt-wEGFHi}$k$_K_FJ zV2Hrr{+xc^!%H5m*TwvG*S@So_(%Qa70qI?&3w~H1Xwek45|WA=ryn5WLn!h#y1^y zG8>pczqDcDxM3I&P&>T}{(V{44*vAf=Z)UHM<9Lcn~7tdpE>BVNM6zjYTYPGh z$&vA97;>iNOvED5roM6msZBq_;#HWNO=vG3se{{E(rUT649GL!x%E{W9Iq(ScGjC0 z%ip-8xFhX={}!%p$(C!@QwOFi>gAh1)How%!nCO(1i0jwQ_qP0@isBpe#X8e3V5Iu*&dL5Z@P;$ilj%c%-n(MnH|Iu5hj00k&BnI}8C^?Ow{y zmKpKK&NI5R4QYT?2`Ab5ihJ)Eal$!wZmpw!3!hJJcRcHqS}rFOx@df?K=i1pG5b{X zXt-mEecZ_Q_QSl62e2rw6qRAZ`}BosBNf{ysc}n_K7I+cgk$Dq*PL!|JGb`z2mf#) zJEl^)N$3WYcBSGW$UJa7EG>wE47^yG_vjZ!M%x7=k z`s#PXZ!Kt%3`Gk)6+BcE3oT1>yu031@FCRtB(V~OY1(>0O9ZWb%{-}Q6fr>u6mmbpEmFH1Q6I{`U zjAG9IXg$&l!w9KAlm;0PK((n!c53@?+#P^UX`?8}@S_q<8I@&~F$Xqy;KhP@;8b5y_7(TQ(Hsf=TfSZ>*vDGus~4>*&BBKA`- z$eNT@Y5of~i%g3s3vg#MnnhkW6QG8JY1(D66K{C^)=NeWtm|TGYS(|;<`}jcTcpUSl%cJA(D2V8XYX&=`MkkWyA_JjjAwTM*}M_ms>>a{b@bRuS>){6Sf za}8_=d|F3nGu;edtN%K3CW{;h75&piOw8b!V2aYast(=gIZ*EArH;P)wQGBK+UHR* zFyxrkojp!6-k}4#!g0^;FzYS(O^dkce4+ zObvKN9R$zx0O z4>@VTFhV)u-poA|u3Y+Ty#gtJ?$SMaFqh%6yhgW*7LAzZ3Xl9|F<-2+qn+W*dGFVI zyXw-H{%bGlcIwb$T2zhgS*e0~;sQKD)dZ0!iLl-mv$RwY@L8{Y{L$||%h{ebHNn)ItrI+nHG<xc=e?uS+x@B+>ONN$YA zZ#eXgo&)wj?8n;9v04Ku=B1B2^N^L%veI@X0aAQKEliBA0!HFhe_)^3QYBJK53kb; z+;=Rq_T!md#TMn`;!~0bUw}#Oh8VFY3l#uT01#&mY)U&&9nP;l`Qf(*^laW)9+UYS z`-;f<&*E-ygqQ*vifJF|F7G{Y+%(?#X5PFFSD8IF4qA}itqq4 zbGyJ<^WUxYyxkc?c*#B|e>Ws&bEvNPT$eOj(>?k58-JXO_xz>`0I{L#*6 zdu^WiUFk2U{qxl$US@&vXrv$w!4QDUPX`sFLf16{n_=d{yr+f5wbg2hkJwC|1o2e- zUMe~C)+)JiHhog-35n7Bai6|( zRpRdJA8O%vPL9JMEa<%96gr~s%RG>QCUqTlI5GWk5U4q?{hEYb%JY5X;xeaJ()y+n zC~5Inn-SX@O8l&XIj}wf-rA$Cd~4LGKVQVpt*VWaxi+2LSg!fF&6(_gBnk8wcb+eb zE?fL*^dLBYxqY^MeZ0&0oi7@CSNxl?{8$iut`7R#)#xDtp&C#u9LIrwgnCaLw|HE? z`e;W(-h`NL1Y zI(A;-u9NbL({4_#r+u2#e5bBBVeadacl4xSQZXM{p^w#?zEiEy*r5uGsH00zMT7_H zIZDE(C6b1$S|I}bb20^xPPmY$2(UrTpB{SYNoS4ERtbMg{axz;qo6YS)Pq*KRh!zj zcEK&i(paQCo^hFr^U{w~>dJsns+kZ*Ms7$2S_JJ#}e&U9KJ9w;wyG z;ukg7E&quc2et95k6y{|0C!Gpyv3d0{ASYVao-Lc87W9Q!H_4bJNZBgsSIj>`Kt+a zsWoz>2olkEQcIIwui365N#+Q6L#m9DUHuIQiar4i= ziuv~|nN0pUuuYS4{ADLUwRZ83L)!;gs5$RNZJK2cxPjW>wJ67JaKX< z_K1-?B9{^`N}2E$g!}qBk|bbE5P1Wg+wCwYOF0nBZJs>&?)T2`+G_V#Rfpy}Td4X{ zmqoR+uYGLy%h)%s%3^9`@wiFB;8hw=_z>Xyckw zZhP|&uP1{WLn4ET6i`M+tsG~%vNE3NX$plxSaZD#SW=UY@x_Xwy!+x z!uq7+6}8)A-Kn>|b6AJs;-z)jnd&+KJM#ML+K=%5R>?DgNF7ks=d>NzR}-T>;hdE( zZqpp8&3pa3>&5Kc%4vFmWHJ!5cs?%JA1?XvKMmHF+O&6ju9?uQFKb`DQEl8tB&C7F zVNemufy2IQm{SS1we54+-25I+k4hdRxqI3WCHo9Vhomm97tVp>bX z-Vi4<&i;A}ax&6Qoj$`PeNxK>HzWQn#T2W$C}=r-UXp<=5PE!i+tBt?uZS z`mxRv6H`XVU2yc2n$;`%lmwU)bpV3oI8@v<%yG#ikU=Bsgat_eHuj~CWS+pvTo&{zy^53RK_k~k``EQ-)NL}9h!wx62{lu}wWD#k0A^%(v$b~!e zyLEeM{!5GMa_`1;?WOyi@c89{l_T=_siMTfGMhbvg#|6)jISG?f0Xy*_^&@2{mM7P zM!2DPFj|y`P>w!*O%0uaIUVm%dQm+NSk_Xraht@@fDs0i=y!!%&)WF?8I+hcPKp^> z>)yB-b-*j-h$>IjWdYVEzth(*oi(%Xwh*T}FA}8sUoD^0`HM>jeq8{`X02T27O9F% z2u#RK^*%)OVX~urFKgw^qlC#gUr;8c@YH6mL>G#Cy$ML!{#ga1GKw#5W}d~LmSzAk z22hrCAeGy!=J31zd*P97_j;`{Ez0d_%lzg?vzA_|-1k+PLg8lN!f?L1a3&!h;J{Q4 zq^la91#&RmKeki_V=yqI!xM0S{vX%_i=HCk%I)cao%h{Q`<)OUkzN)K@@o0$mcl9S z08DANJ6!tJr*&SF4gE%6u3R+m;SY`pM zH!o<;gh?-E4b}OoID?jVAv)?)FXZ|+sTX!E#Tp-6+twd_x%2`+6}Tvi)$jGR0GixO zw_W{>>qe{Ay2)0#drp3J=&Ws4gKXEJz5V6Ho2 zNiWB7DjUxx83uG&$mc7tR=T=yC6FYyWNYBt?P#m~;F7 z94%YBM{7a#k&T)RBh-6JmPvhZ#I#f|YfBtd2heD{8Z?yXQ1e~)mL5bDL#W-)dbW=d z>s^paGUWF*CHe6rIjOxzjK1@nBTl$oyhjsfrjNH9!Op3itaf!p&V9Zl{+=J@9t7vD zY8d&`)+X%Wy$5$~%0AJpz2B8Rj;}Z|QdO{ftPEm-08Gkj12;|kaGTfT)}B|}&lzK3 z$8kiR!?&h>dgs^~7u*yqtPVztR22lu7`17QcP9r>YOB(~u1#!A2wulAET5`Z{qr~g03ZNKL_t)&S*quYb*o4$?ThM-LCB4@S@y<-KX%*}-zeETYTL#3 zb?7U7`I8UMuKM@Yue5X1BE3NDI==FD)E{ajOUjHCtcd&P(3>h5r+#Tt*3I}`Wn08` z+IK=g5O+!IKs{wx5D68+x`~`-`co@B2i7GVFX`lLKKsG{U3E}Nr}5j?V~y)uKNTI$ znz6F1lMDOh_58kY*)LD+^u^t{dhYkpnmHSP9&+>8!yjScSV3O%lpD#DCcTMya1xEj z_{b?D*R1k{ihtCa)S(W$`jT43Dk(#LAKh?LP_K|rVFU&w<+E%TkO5U}p&2Iwpt>RA zLw@_pbrE(^>+#2*d+doH?GzxT)9JA@_A76Zs4k3v2Vo(a_Z1_-rRdjzQkF`5qLv?2 z?;^xcqF4ZCK$*X%>>xWkg36q9Zz;Ktc6OuB7Vk~YkFq8N&&5ykTzm&AQ;>=lm24jJ z;D>`d=Ct}yT-St|>2>WdPu^NKCCG)%mgEH20RwoYurFM(au<;P9-xyl(IwRz55M)L z!`~{aT3-~5dcmBc6htC^wn-x3Iy`BTWinhvzO|2iYTR@De*UPu3T6?1sQjL?)%|7h zjEi5j$i!2$Zdd&&m2!Y30+6mK*zo?472AFEb-l2SH)c#6vGSHnA8i@r(R-;YD}Z}T0M!gKKxX$LlY z4s48jsrca|KD_awk$-QO*X+BdzQCSoJDit|ms*`c{Q8rT)^sRTA(d zNf}mh24S>_qZT_RIOAug#^aCtS5hT@CR2Q4$h&0UmxrC#yZ?4uncEGdxRZ@J_u$oD z#fCP#m`TK85L8s3=Gco@P>x;+Xe93)7jcHTU-L+9hEiXL4W`5#KuMIAODLCt?pY#x zLff7WB&})c092cAa^ zeZ2=)K3T7a-~HBssHwdlwW`*#wXL82&pVG#DZTZSP&5?`=cgdd^`e$VNz7y7Iy3%H zRpt`UsiG<3x>$*_`~1F4u{N>bwXLk7IrHcPrS3lp@)~S)#VOfle*1J9Af0p|UKxT= zs`;w-hb(SaA7fS@Kw9EBPU(N9est;b+pl=6K%|X&kjG7YQqi9JPyEc$nB0b$;`PFB zqVHeQU8%3tw2Mft2wTMg;<@+GJdX40v|MiWSZIvFzJ3rrQmqYu2o3)uv4w zQ7!n9^A1@YFDvcXhMV|Guq%O35pfcgGslD|dUM8--@2<;|N9cG*PB)f@rJTg-B zt6FV9;8vnyYJzAmrEO=xGoLml0AgM!)&GvSMjzc_|Lbu8sGn(j24zQo_wx1^F21Ae zht3fu&tB)fQRC#oZkwlX_x#w=@3QN8wd(=De}Cf7^T*u(&M}t+a+1N^A`gOLRq@_R z14RM8e1_5cVz7y>LE@jJ0b>L^<(W7BdEZpasNI?ws4{?Q-WhQP?)}H zULWxCf+fq|9k#GD{~N`y+Vx)MRolH#c=VpPkBfIF%$Rce54T=LU0*@c`D01*&zPsC`VEqTzUfCg3L;MULb2gcCaP`hY~XG1Us z6)6{zfoQVtjW6CcpnGp2i)zY0BimnGbz9l&+z?9$&M_mh7yNOn1};`-qX;2>HxMPy3k7iaS{MIk&Y_Z-bI1uX{Tr=B#V`fC zM4}=W8Zt~{rAj_&iTPEBXwkjj5o*QsslL>K_+}Ss)`wCz_5I(F0s9^DU&e&~+hO^TEVcIF$0Un38dTnoTZi745L-Kj+NuzO}xp%jfk5q+El=t5JRW!`J&v{p-aO z^W1oGOGpb7Um5Sx&p}Lht>4s@V^qhI!?7}=>}pdK_oRAN{5#p5j4zhnH#3D5cTPPK z_&tyvYZG5h80Gg(GY8@fpn^-6Bl*d5@0oZ@m*Tef)ur=yUAwCXc4iMO*|_$~n_fTk z!K7OrisUm03MQ&DmwZfA3f&cXQOwf>n2Zz(aaVkX)}{hpBq0>?B#5e%PihUSEGS(6 zng>&G#XuJ6M7jJ;a0%g5J3Qgji0>Y__xKswYSBoR($;%ktSFRTMeI(1W)xUUl)cjt){A0u>tD4~s@u`x21c4?guxQ*srXoF zW0eac#T-a*W*TP@E^L`R>E`!t*soRl(e*u0yY9EE2kNT_=9jI!{H}M8eW)V7CK4@l z#98#BniHx2i*X7Kjd&74NIPx3dDg=Ac;^!sFGqZcrHW+Qok#0v`ChJ_mO zy#ef4c>vPodDXWc_jS)c?c3LTImUVi(nV}hVOOVX#YVew!fS-x3tlo6(pI_;HZ&h+r zI8vB~aE>`Q3oS>q5;Y*v>^CBRG65lUYT6_PS*CUi_`^mT2xX8-5F!QC7DW0{ijpxa z422;nLsjKD^)AFKf~-UF-fus3%H%U>)&JV|ooY6? zUO}Ms^0$Wmh-Wd?`_V!54y1HayfW?c;}+j_>3gk1$#8Qn>_q@W;8MqjuI?jiAZE7yf4asPea1MG)faa}vY$ ze&);zjy!pr%j9isWEvDm`NN;SxX(hTY<1UWJZF>~F<^`7DHHT*KP>=5U^Un1h&u^Z z$*NFf3)7M+;-kSyLSz^ysge;#;8TX|OLI%}!SfsesL5bKvfrrZ?>?q`?|*D< zAa;Ges|OmY2R{1o+gqRf>a1H+PDLo3my+ku2hHi9nR)Z3#;0V6Ht-p+RO?Bcs$d_> zE+g^O+B2Dk2-Y&7YcpGv_|Vt|USj5#ahe3mK;!%}3Bgvp{)fNaln29{M)bYoTuk1;a|Z zWFn5}9`GM~qJUlXkT!iVC5|v>^BF0@2Mnq_2R0`I;01G2{YSkz=E&~*Uxj_$l&eNH z)O^`>-}>nR|J?d~(d@e)nRMEXNvI4(3b;;G%9|vS!7`Lskc0~A740ElM`et9F8hI& zmbF9#6xR^tjznkT7gZJX6}F>vN`k6d_km}oZr;stO6zCI?7GXY9{BYhcw^ec2cQ3L$Viq`BQutQiir}fr8ojatQS1`98GOM z6SWy7LL6Fa5-9awb;B^aPC?k1-=+Wty7e@*qp~WWF4TT&40+LV3(3u4Z@1=M zKN)+{)B&PpbvUQKu5+uwfYjfR|99bmKL;x}?NJm22s<8x6aZzgJpo|SEI>iMhA%5` zo>Y=j2kFt2F&r$T44`HCP&;9Kn^s{4s&hj&iD^X`Eq3}jARRfwvuS8OGlQt((!0X7$8^W z;&TAgJDDoDj04Ck=i^R^%{D$!Ipor;C)HsT*y^2-L>0w7@Oi|KnyDo6^0KPY&iKf;o8%f*}vwAO%rJoJv92pS0q9AsZ3UwNpTKz*j6Vtbk8S=c$;6whD=P zFYca2PH2sg72wjVUV9-8oZ3tjF(eraKuwtgPBNOf`Plyr>bJ*%Z{tCJ4LK7U97tEN z70uf_vP9Lh*Bv{4{fcFSn+H;Eu}U4KEE3Ig`&7^D5k2Y0R_D{>u>}5%3^gd+p>45S zF&e}#ioKu`2W;1a1XWb1>FB)~M{;jpr7Jbr_;+|c(~3k8HpkPcW+m-5o`2hW7j@5R z^}#M?+K|)xw|{TSL>H$voqpR3M?Jm1{FkDf0w(=Q1()c#5u=rM;%W*!kD z`%#yxR0KyYBdz|F)JE00r-39K21~jmL7E=mETG=HMlMWAwa6K4I>01vtT?lHa=g-k z_=bqruB7v)V^90Kzgl0#j^mUyw1SWS}^hQ z{ET(vs-%^E8B*3`oAu7;E3L=>E=2m+^=cH*@vb9}_VKT#;uJYgN{tG-CX9(sh6^QH z4nW#-Am%ZsP6wep4yiz-sJ#DG@}t#h!6=|>O@p72C?MV{Fa`AL<6n{{`}E)8SJ74K1mQIZZ-eN8APA} zYJimgHC_>fNV3JoH_rK~h32!2)w^yqTibT%OnYzkSNkryXV}aFNQ84-20<)5g6z?k zj_KE`ArTa2HK}4RcTBZ&`ULm-)KQ!aRQIM`0mjs^{iT_cNt*QZxM`wA#R*H=q9>Qb zpep4+MLfX&O{Lv%)q$to|G=sJPao6Tan|mN=I_v{*rXr!3S;3xj+2kTzplVW|QN*od3e?xBNrSl;k{sbG!+@0nNDW|O zEgQZ_iIE=^>31>*My`6fq%h&stabjImvSH#cfqTScsCsI-s#8gd&s*xa)2A0k&<0O zREOeqOCNk|{N>dz-1=Bah`EL8ESL-}8v-2J{iNxS9f-%281sa8w}}$cqm{9+s|ha2 zAyGaX-3vs2O3r>Vfh%*mmTWIMA4-`uD4p|{2}I_~b*9{BTA6fUb1ImMCEV)v?e|=D z!C&6FsAITj+KwFjUC(OTJ+P>1(}DNCdE&TbtA5%u6ouSyeli%z^B@>x;BcKN{%9AM zU+|cvSTZ3S)*3$p$5c3>UBxO_$bcmaNb^ejo(m~Y{=F*hvWirwyyuB`-FM!}=e^X-aem$z6Jpmh z8+Q+EW^CUV-h1V&cYnP8+CX8vD4d^mT!){p1mN=Myg1^AW*Oms8+|oy<|a~~<%Ccz z+V^=)RS?OPxirs{bKO9nu+A`N-o`*_qARdPZ>na%nBJs^0v!Z?;AX(1^zjN8oMe9N z?|=OGv_G`ld#9W+w!?vR6GaP=GOlf1k;g%AcHXXnIglZf?VN; z!EQFub|Y~jzME{aCL)RQ3x362X$qV#$fYBd$~$Apv8eg4CW_@)w*qNI`hg&?-4qO} z5&_s0bG+)fn`qU#-NsW#ynOv3?K=Kfv~LHRD2*FNet)f_V?T4%q9G4|c=r9PH?AoP z=cdBB&C+f-m!GXwAY6!4I`b3$bSz%P8EhF(5QCC!#=sl^=lBQ;pu_EpO zji=;q1bQt`sO@2;QF{Qc7v-mcCMq3BRfdvh?Dp`VN1ZtMLA73*JC3tmhuPJ2rtNSb zRZ;vDXQjNce|h-+8={jRzb6t%hMI=}^0+Jt$6iMniI^T+j1h5ElM>;uHSiXQn%!AQ zqLlfA$C}_yjVu!R4`rl3uY+`KBC*L1`)#RUU8=mkga&z*T@P&%AmAF6D^7qs8 zjSv7cC4`n4pN$0Qdzz?|@l^U5tm^A5XyPXps9Yi*T*5o$ujVsaoY@}FWXy$FMF3Kp z-PD2A*FN?CuDkV01)^a92yX8gOm&?-I~+*$PD#!+`sdJ|lOb8rm+MQ5&`FMkMrcM6 zb}=!xEipZ^OU?BB0$_9Qy~RSafU_|BmAgPE4G@(8o?s|JR!%mi>YqwLHanU3F)R4VR@wpOQ|_@CB&PWa|@^0f=n~dpU0LiW`pp zxaTn)J2t3JbZeu(GlA4fkNoG5?(3R4H7$!nqLhMcw;yb>$d)WU8>XFVU_!s7928L% zifBb?)IB>3HD-})i(TA=|4mo^x8zs+xDyGaG7-Sm$;oUHqU$3;v@~OoNISqQ@AG3* zxbL(o6)o@D=dWYVIOWt2yB4&Zw6#Iq^?B3pfo0Vj4two`_Xm8o{FbYoysDyTUfSWc zAe@i`!H}wGuX6%1z=IPXQ$YRoDCl*jk1R0OfnD;sA`tReW3`qr|DEVTk<_3U&Puk? zM~u+o%g8^o!4QRe*={4>=cj=NA+af1b6ubJ`klB>FQInXnexG%2BiL}{^0*!?_Kl! z4U>z)UO3`12#FL@Y@RvV)c~w5RiXl4I)D<)H*F`mn~Zs?x+~m8pc|EKK-*>-~8e7;Ty}#-C)EE6g2nTa5OEY zLppjxYvdaDk@RJfb%P6r3g8uaG#PtzQ%4P_2NFSH!&9??rk{1% z?_nU-mnuBdpQtO$Ci6+e3Em8YEhTw@sVoere5O4MJUcxZ6svwuHd5@i7%eA4DK zvQw0E=t-e+>}fS8^!MoR5Ye&Xx>|5gfsmT_I#tc=;9^kyRilJiPbE@@N#nGktQu#P zl}w;S%m}#Rd&D)tt4PIoAqLI{0H7xBvYdi8tByT)%+39~_a5IECef}o)K3q5`u+5a z#(g{d?(+Dm)}h>#NMLsYo;ckz7!=1kk~+Ht=yW!aY6o>~iTPxwVj{7ia}?h|T7y`- z!X#!&nIAb6lDsm7Lppcuih3p}MW9#wlu=DFLob}Bh zMJ5_Nb7^ZMywicy-@yBZANW42*?2->$aBI0jN;3yjFwXlN=6PmVV{1m($V)V)iEV( z6=fOH6<{VOog`wMb>N8xlI(I~mj2XoEl{@uts+I9C*Rsy2>d9M@>tMId%<+e7A-1I zANuNT2es>@58G46VsqERE{3|b*}oG$_cKu5gzrj!9yRqVx#|5}N~%=e3;u#*l?Qcf#;(@sW)NNNI(ZdoJ2% zAxl&+yYf2*#L|_ag5tExcUjOd%N9v%FFK)m$ zXe$-lf9!GQGwk-MxA5siEv9OLD2)=>r-1VNaweKe@~TcQKy^;pW&4ajA2>p>%NV+$>QdmnFhGr15FI&#kL}b z7?C#siROwn(KXP@{g1i|a7#9tQF5NWioQ#bML_md1h;gp)OV_OemqLrCmlh?>es5G z!G%$OonJzf47?>t&w+TFiRx0Ep(eeESKQ%GW6wV2^cVJRx%9A(k$ZSSoRnk7qwugS z+|e<*##yVDjCkyefwz^Gu5X@z>LAZZisa(iNydcM5qZnXk~2msPW0?CL;&X>A)Fb$ z2+H!$001BWNkl(Q{c#t55)nu!{4Y3g-=R5NuYrMLtJrMe%pv z_j~}0qa%Hy0I8ZFRBv))$K>99-ajt5{4LeT`HclYvAvBENOMK!E5Z2{qwhYwaOz_( z=SG|yp7|8z7?DL^D$H$Ui#U8l!-;#btaFNi9bg`P-GI6aOxmBOwgxcJwtf{rh*dg?eKw33HRiAPJcSz-#fOF+#oFJ!(E+KR zPK;^6{y(lb=)OedhHDB!UN|o#HKsuYK5Gs`dAa3JjP9+Ck^pGNt1mG?3XZ1S=W&)CUPVS1%CZI|3xGq7$1{0;nkw3N;puq z+3~zoFkMhsklwr3?c)wT=%9xWYTI=l?(Y1T9*x9As{Pb$99Q}o=y#>ddrzPK^@vHU zZXR4-zBvHlR3N{ZC!+A$Z%#K|W3}tRsR19V2}KPlkuwo13XLLR-C)-cu(N1h?5EWH!C?izEW1Yz)he(>~D)z6;e`C5E z05ig4G*#4hUE>ec6VlH_i7yK8jnV&%YT&-_(&uW%Y31~zIzhP&)TTjGPh|j1?fCli zQ-G9UsNCP?f(IVdR6DH3%Pnistljs0j=6K((Y^P2zm3y49QKU^8tdMQrL1DFS+l-B z{+;jsGY_-LJFR&|CI$ii|4Ijnk~s~k)FjtdG!2$&*wGuU*|7alaN^S> z$jVcf&6nx@e6&(&MN!3Rtq}vyvV$~$`W2tV;?rFzUlKnt4hnrM?MO()0uU>6Aypkn z<~Rj!elUF5ISNE~N)CN(XG5a}Qo>9{***T>*I&@}-JD?R_^6Wz7KQ=B0Y^pi5k!f} zu5LgjOUN!UDk&!ln&9?MZop9P-1@lMY%(Xh!&8$?u|>a-pGN(+#3-qmX0ci|i?u|{ z54gz4DI3uyAA@RWBQ`x5Dwg2jSaPLn~+V9XgyssB6T2$DjOPBCG zfY>gkDkl=JM86L}4%dV`j#IIUv663Qezo7sIWv!%UH0JhNmiYcNGBmD>ICweF`0=( zRU*WlWC#F~0f&?hrNzq$wak*4WP-26f}-H1gR|<7z9W;h`+%$!Oq|mAp2c0Dfm9G? z;$HFrr-6A}~x=ad(y~DyzBG@bndUUUB1O{==4oXQrV zTrU7Y&*5jr3)ba&5Q=z$h0>slwmNVgqT`ePH}~Ijt+U$T1xV@QOIZ>2U6^HMyf?!H?->)!9cukL4XAd!VE%=Cw-Nbc?x=n zUx{WNA?wt@m_=vDKSOq?y+6J}D3s+QfKq9boWy3aP!Whfk}qaFO+r8e2u~C6=}-9^ zN;M)@=TXL#_J{cxJK0>SV=ip23V4a6ljg7P1|yX%n(hA8Aw91jeaJyaFX+^)nJ6^P zeS&M(uFVew0)di}lFf}Rdb+LP%+(B~rKJVwbUNL-b?a(;uchnO^_)I;Mu(3V-*ruC z`O02Nh;dd5p`3IeT9ne!cca!|su)-nO9$mdR0*QaHS%xd!W|@PG0RO@&KpG!RdJqd z?@BjzJ4wWt+*aU9yS{vPvwWW>x=#y3qPcFI1tzzi0^;6>7Sc}DM*B; zP8zxT$ZZ|Ro%Ow@1f-mq>eEQC8`fo7z>D|Fi$Jg_B6X%2vJW+3rC(Em7tO-3%zhnA zLhwQZ1SLlH`Ai0QjUErh{FH$jaL4xx_FamM^v3ki=zhksiy!5&t=TxF)ate!ThQg%}0zo_@Lf%x_9ZczIh~fO;yzW zrIRB8_P6r0pmcffg)3I{{N|hKy%wb(zA)icio-j21^PhHb9m+vH;H);JkLOq`cGv| z2%N+0BijlQn-DqJF=Kp5&=3I-|CA}bHxeYZZ7KvKfR_~rWtDs*ak5n_Vhm}8do`$- zimf(Mag84+sTuE|3-nr>oyrRLv9bUptKF2749%Q4a!nsXo_2Z;eQoD;lL6AK%=E%8 zU%Ra4prTwim>2Ryg?)bZ6ZJuwi6&=|zYZw^4Y~&;=$c5p{JvTo1ngAkiU{<#404)T zs#0R+8FtYX{f<6RH726(2y5-HMVA1P%!r$1JD`tjCW@)zLN#pLFd^J*VlfvgHoIOt z3F&|vfJjb3ytuH{lH#HkOHVxd&W{7Rh2OMqk-I7ZiFjLR8z_ZRw*+=RW93Y9!-fq- zyf<33Xi>8m7N@#8T}9=r*=yFcs*0`dGUMx6Ef%j_x$oNW`0L`yisE=G3863q@|t;W zG#58$HGdSnLQ@@68Z}6g4cQcG!nx-g6EkJRpcsq9K#wK|D1jmtm0sk&RcyJmXcQhN zp1QpbhAIojpD&MVXGwHJ4t6@*xiXb^(M5l=+(H6V~EB$Wo?G}Wd(2RIJEI=D&l+|ewiXM$5{lK9-P zRl$1oVpE_@YdDfNAv5r3Ub8QANuNcIjG8V!!a#M<%4#P@`_*#C4MH;wqfRhv#IRrO zM{^jYIAcvYBFCREIIdGoa3_E#-<^4pR3MPQFqA&!v5tFoUe$e{PHT#rbzXgJr%pSS zvHrAnZEG*z-F?lvHC1n40KD!IT+H%4DNP=44{{2I|PRpaB;%mXcL&ip4^6zPNhLL4+(dTA9<9 z0KCZoX*Om$@`8@Da-&XIR=~%Jk?|o0)FN27YElV!91GT zN@AoZnQ~dlV2%%f@LJ+d&_N#>O{EM&o8AmW;(&NQ_mz?AJ`@Zo=xTOJl?V#t$O8Af zGtj52Cp!UbKQq_;rnQB}|6CJuprSJ1#Zyk2-z%LC#8ZjT64wbX&5hDxutVM|W3<>Jd_lUa=l+hV|! zG97ch&3J5Cn0X%)FymM7j4G}M;J#J&ShY!sy~Ae8} z!0Erf$pWdLnLhl%2Zak>xpHbW>~_ly#DfJ95X@ApO~no+xTuMx|0PUSO=KDrzWRA-wd{;$$>t8a;XhqwDf6KYpJ&Cd7*|vGgJ%Es41@?g&+%M`v_7xgAN&?Ps>TQpvEdtFYMEB8bCD%(#duk z?T6-_;_qhj#VJMs0Oz@$C!(7SfMx>=%ltQyD~s`>-@f`Q@*6PZ^w=0Veo@ z=P!|*XC+U;sJxu0er15a;Ijc1wfI!^D*9at zNVeIppg{YBDF~U6f&pk$CHM=(*vu8#wX8m*f_i#v6yTAuGHi*|8K8ZS<4OLd?8x3& zY%|!dfk40uSEXv7seWWDHzX@H@oEZUde&)60ylBrIFVQ0viWZO?&!zQV3BJ6No?~~ zCbQHkq(YPhe`@|xbk$I7!<3no7`?}rATQ(lF87JXD+0iMqRDD!=HzQiX>`8H`9!mA zGCLd0>*e`WXL|MUuG1N-KCoHT4dw;Y5Ds$FQUz9MfB?ghs6VAGK_(@9lxoEgpv2u) zPJZLpvRJPM3sd$FnTnXNgmK6~1TGlEcBok=LC7wxW`Inw58N8bzdV>lHGlTA41iE( zf@y^rt^?d~$o;J&Vf03YMx9|xntl1&DBsKU2Yp9m>sr2sN1#yvBO3?*RRr%a3U2xN zbgaV)2W9f=S}^5ENrzpsX0&C5N>9Q2~ktlzhP+K8vTyXl|V+zu8O7nml@;c zZ;J*S!>D9Ca9KzeEVcq=D%1D37`#o!h<{$)OShdA7x!)478sNCc-8&lAH}KFrc0nr zkF}bsR(s6GOs#P_o+hCV--nvyrYFqP)ojReu9B%Qg;oJF(RhWE3PSFbPe-ggimutl zp0Ttw0L9OLGeAlPho1>9LLOHQ@A6r|jUAC6VZq!GXQnO$_(udBwd6_ngjzg`Y2qZ7 z!3baQiZV*=@3Vt85=@o1$`1tUJ6@K<$@BoC`O8@rO+BSYL;C>DfFrsKsM$tO39ti6 z8qCyt>a(k8l-}>xq|8SHw0uzw{0gLXyVN2_CaR5ND@#l+T+4MJf>4U@SSB&yK-d>z zut+K-EdowVa(YIQRiaRBMA~;v$KJns2!k|0=XV1bcrxreQ?&0NcbnnTAQ-7+Ps;4+ z4O;gPfkit1$UB&A*p@NbfGXz_1q}QiEt-cTA*(n6B&xYdA56OOoC%+e`sI|`0#j4F z?zae}7BjtJ)ZQP(lbesu&v8Npp%mou9B5>iMC2^ZUBez^9N6biA||B8ppb=TV|s*z znuV>nl&CLC=$Qf>``#*)prXneSSa{XAXTiF4 z+h}bL2E4R8L;;eO?PW1T+0O_-SR4j7I7+PeSy#BR$$t$$%zR(r^H=`ts9cjSKP3A*iWf$^209+yA>{=|Jo%dU9}61I#V8_csTm zWUzF_m_OZk!1zSXra^hZR5&lpfS*pvqxmLMtCp)?FoX$_9?A&Dh@c1hKjjql2VW2f z3;-gqDW5G_L>7QjP$fccIai6FThv`h(4WiT-`kfV6qLo5`Sj-@C6N1QuVQUqKe2|!L*^UV}iycqe z^%Z=^elfg(s7xtTP_M9g9&s?Ji_Lb&^Bd9$7vfb8q$)#+!f=c6Z(X?HQt@u2UdC?) zKz+maTYD{8T;o-M)F4%Y@0P#x`d7{74Oa()$!K9%M)Na3Pc0~V95aHC#p2MnWJT$H zW}1(wQ4qHMjhX&e1XRI_MLP*S2#hjKC)At?}zZUI{H$7hD3e^)aV#kTkcVNQ}H z@0PK#kRTZWf9=jdwoBNg?n~-(Rn~wGgi)qWe6DiI+Gl5J9w#Z5${^Bz6~AczpT*G3 zsj}*;0#FQlGz>dqh2UJ#vNa8<+Mlce$CtTg1Go)blJy%Oy%xS(l*jh7$~j`6F@|mw zlcs8(WBWo8EVqmS^3le$_ivhpp#mgp9B#^UooKuu(&EXtF8uLo1){t@7B7j}sH-?_ zD-!-@8L6JEjOlu&ciejD#T!ajJ&+qo7v@D6gaR@*AE$_zU|MiZqv+~xbV2*w0JJBm zDd_8A^c&KMt6{6=`5X?U@03Kpg=#&M6&WULQV^~CBfw>ABZ3U^ed^=^0=inNB$yPM z)U>h|W!Q=#S|WG+oB$l&%L>RLgUd|6q>Nenxrqux+*tvo97`Ka_2+0ZD*?N4J1EG| zz$bg(-UO*%nT~~t+-SY4YLD5Z&|$uXF%;JuQ(JEsRB0lLqR2UGr(>%5s-}nqma0$W zlr`U@0Ep;KrwAnvTLu`}USy&?I-jlxRkv!^?v9rR&c0WHs9uBH3RI2#d%p)DQKWraNC3x20_A@8LC+B2e>$gJf_ zI1b7Qh-dm)DN34{`|HLL0w({nQxQ^ib@kZihO=`|lkJ-I} zGzi8^V%yB{DDa17ILf5_2FU(ue>I6D_|B@5~C{My@HMSRl8hoYpR>7DW(*g6Gpvt2s}7k&PZfNsF;Cg7YTod8GbB0L5}y|{Y-nQ-$XZd^F-BM5$iu`Nj* zJP=Z*$=Nh`Mwv< zwZ;(Q=j+c4hLQ3F+Csm^7%Pq1%zwM|qeovb`RH#h9%*)lZ4fFj5jh1gjw%yih56bX zAPMu$dBI@-#9nT7k$!E!%O0~X08Y%WM&G7qyZpjOEQW(;k|r9tBmiW2wP>A946NwS zXyUW;A<%dVfH5l%6A~Es!wN{E=<$Bw$TbmUeeu|XUz;%o*_OC6(BCL-k4VD{t`k}8 zk-~wSyEXF%~L%%DpD#q4`+bG-c7 zbdLjBvU*rEVcPb%6%wgoC)h|j86X*%WuAdC-!T>0V#KW!-fsx`|i8% zB>(=6iHY&szIw`CX)?QiZZcE1<=5)A>{_&_1CvtCQe~jQ}0nCt{>EcIV z@v&CVG{LkcK#3#Eyd;&K@^dxl#n%YS;5R{hhM`|i7K*TEVlUJ$1q6DQyK&5{QP#t* z3f}@`lOB{55(7CJp}n^l;GZyArnbPTN|-;hOBtCM=x}AAUYMSWi373$F>CuhpsDOS zgcoPxi+GD~fF?S-V_;lp6AWOE+RBlATXO*Q(s57;S!UFt-~eTtsbqbj{hn`VKHF-) z@t`#)pL*n9d}FRPwGaTbWS?9}-FBv(JM3(He0+){`gR1~bK#-?F+IKI_-4a27Y*g6 zmG;HlMV1tsY7XEEX0rMGK!k`9Gb_BFIz~k=;8v{n+ z9Z;h|M+yM}1#%Y@f<;B(WMGK_G8i)soS^wDeWrGZlm}V%9Bzx~jV3PzjTKbwqJd>b zucm%6mDi6Jg^+@c5a36~Bhs(p{FMN#-x}#Y?z?kTt`}XbJ~Q03&@hL&08<=bnY$|n zKW;|FR8Pf(o{h?HNli9W%Z7$VH(dUT@4w`*#rv&wW0dEuNi(@*PdHj;ccIvVWu)dxoV+~k{Q|Q%Ot)l!DsC#zC9ji>Ql&^!%Ygon!yZB;-WR6Oj_kke$2VOc#Q|}qERcpUuq+8L=6nV zCg|G)lp1xcaQ>HrPMJ28#sL)L#v@D|xFp4u{ALzzIO0NyBJ#!fyuMlGe$rrTa1ZKC z*UjvvBpb*_H=q5ye?4o};YVL9cPUvjPZeQ zeW$6*h*A?-QYo2PPQxXIOnMrXph*_!I zRfu6RbK|j=K%YmS0BEr!9R;*x?no3Nra9bKz}|I3!JXMTz@m;b6{+?c0L^J2fdV&A zWW@`wl=sJffeQc0)-{*d-ea0KomPv+NnHgv@ z+loQXznW@>lfeYU#TT|9GdZdmD%W8?Ikzz|Wkb*vAYdjG1TSDQvPKmEMI2_)-%xU7 zFJpNV8-O0*AhX7yL8Ks{%>|PJgjEqR__lN6fWNz_5NLepQSSDE%*kF#X}$^zG}w_# zKmvI<=g|fs+YBeEGZ6E(1zaWXGl}fW+o`+92O6W z{Fm-{02R9n!$X$=n4i)<2Li<+AVo8oBOAohiKPh>17ERYe+;e?0jF+Lc9d==G&ys) zR2YC=HGEFPMRvyMD*-$d!|RL{CY#(4XeZ<5$D~rLSE2Sad})HYh7FU)T!D=HPDMrl zWRYF+&$QR7IsquHYikUyC16_=)Z>@*XX^{?w-eKww#R`qI?G1)x%0d~|Jq5h4!wg>N1v+# zj5dlB10+8_&b4P*6tFnpH-VDCfi<$CC}5`TSB}HAH|3sD+acMKjyJ}(tB5;hk)j}Q z0M6`QIZ~j#WxxqcSnxuFSzO#C_~N)?5`t=24pD)Te!@&7rh-wnQVdUStZfl$K}i2R z5B`XP{>oTW%X1aHp3!O*RYs62AC_N6b_zI5xAmV|)4#nvF*B3(tdWmA^7?)L;q22_ zz546GLJRSOg$$ZyeXoG@Nxl&mUU}4&n>VdLXRwtGWX4yKYBs$8)W4lkzI`AqqD3v{ zHvt^Z2AAl=Gm1(8*gZ$gK#&HZiOJ+8_H#zSB$0LwZ1D4d5te~*z`R_oRPQsDzz?=t zfFBhL%>hD>ofh&UK7fLM8HO{=QjY9-IGiz8Y5)K zg+vRf-b6qu$3BB^mg#52(p~?9V{tUkNWq&SmA#{({9d;bec5ehQny_*d1n10ndxq; z_m&Mm>uYOH`td1Ga!D-c%PJs!g40jF)211a z*iv?-8A8enyxvqF>KP&w(3Pk^eFrKlh1YrjK(o?E=ppE1ZxNkMB}_-Yi@_^)t7-O= zuqfUfz+6TXT>C_B1O#DO@f;k(1y6sY`v!qKhi<+)m%W9$9H>&2a}mHsLSX1Y%`?_m zvc?!H-w{CtGehBF9!lLas88&{p#M6+q`s*?nK}-@jBK6{<@31d`xP9Z7n|$_7RocC zAMhn}F(tH6_`5C|Kb2h!0OukIG5#F>cmV8nPX^ONg) z>LOwWgg{yZXo$LtS?N0*n35$Cc?KHyWt2M6wH%9KGOR8G2!av#`c`X&sX%;=DuzP3 zBiAKRO{+i}oAW{Xr<%x2@PdATJSa4!A-W%BSt)>rVxq#h$Oh)e3#C&G$OxkR+DY1P zDPY3;5=fiSkx=3*g=yz4oX=3Q)tYK1F*8$n-k%0SEdrCFfro z?hBcqjD?sQ&MpLem=Aie(Ns(E*CLz5@!__48YRBH(n7}UHjp;(l4gk&Fn2)}1uKoP zW16W)bvENgBf6twkpq?&B^nUn^sR~Xwe%;M8~DBaZ_KXsfdQbi*)Gq5yOg+7*mEJ9 zWy!l5vQeH1oOpk=jmFPzYnaaVT2|}Vy8G<4-z}?8`tgY?sX7zYpja@~nx5pcpYyT` zNO$sx{@4At{pk(YzWsCC9-lmXXfSIIwKCI4$#;roJuDn&NK4^oEHg*cA_Ao_a|hf8 zF(3t6RXv_VsuNM<9~Ywpyb9V%@Psl8B)3E7@U=emq8<~J;pcz$K7XX=96~$u6Iu6w8KtkmQ#D4-72HYISN;BrdT1~}J zy}xe^sH{fFddBqHiRsLwW_C-`8EGxK`;0^X`E92hdF zK~%;R3V~3;YmY>l`WmL$f=$h1Da;fCiiDlS)3xW|%Fzrn>MV~(V77w`VF#;|Kh~s9 zg;^fM&U9jCC)2EzF24V`(JRh6=hY{>%JueN{Lb#ArLZ7xQvvBNp7zh*c-^UY-u14} zr1j2XyFlypnrSrbe?c}SfEckLFr~F1N>SG-d<5#8dh?fAkoo{UXlQ^(z@1MRrSag% zyRt(BQH`>MRhrP>%g=_RO)z7~Jva)C;RaFwEp0dYg>m{&O2+aka##}hGtx(en8oF& zysk`&#)Ee5?W?=^RbSAzuYhzXPya-o4?WMAAi8fK@qugp@uCOr|NHaue0Is=(L5O( z=!>RML9Z-W0)QAZ)soau5&pB2k%B{kiA;D=ED{~EA<-!o(pf_=xBWx&UL)A-5B31& zrA!)pb88>oKoQkrXq_3IYyjlp1wS*^X$`@S!8bgc9nV7weV8S|Il?F%KS5pIazKTF zDhjzGJmN($PZbyN4yv0+T?fRsgT|@Nz!!V=-kwg)%%&tu@_|i9*57-@rDvRbrFo`}pcdAO6^-jYem{`bBF=W*SXnQY+pj2CBS; z{GU|u-T{_S7Cpm9Kr8?yVuWn^3kYLsX*nQbphqM2Z2FU?vc%1xY!{A%W-b^h1BCk# zn6h4!d90Ky1O_b}4A`m^TaGpv9V`Em%Na?+_86By3=ifxkUZT400jO0)ju78Iiq=r zyFx$>i>7cIYFy|9-XG=4e%oSYYt~Cl*BrcH+%(-~Pb+D}>o*3{=bA&?x&f{kTG%2NdF zAOfudbrzh5L8&-E&{xgQpdkYkWTiYk||Nd-bh9sjJblpX>n25I8M_XH66fH?vi zcNB|yYc(G3fZ3y}0-e{B`aYuj1UCgJ?E#=13jLMg7Q|4ZrT{N#RGD8vGip*e=1u=fG>6$;7y+jeby(IKngYG0>-Y z5zjG|yT27x3uFY=-2SbX-g4_ZKQq(Yd_Y?7CpOA&nPQUUrrGp*RAxLFn9yJjNqHQ- z1*sCRZ3)t_c9lROHfQY(ZOv6qU83tl|1J9$^}oI&v5O!U+N*Fqa51=N5Q8Nk!aAMk z!U+1yj8QU*pymMUHlh8VO?#nisNLk&^O&fa?zR+Wt}X!}x|ZQQP#%yKfO`#VNh5O} z!c^`~?v&1UV)`x<$(|jbo4i-=4W(nhc=^cXfBn{1oKopP_aNM;80l`F4C_PPxN+mq z^5x5IUbFa7Z~NKL4!Z7pZ~DUIV-FwE?)97XR$gDSsPFWs4yvSzI-G{-fRnvyC3)uV zqfo=D!6YJufuEK*E4d3isG$##O=2JDBWm~(tT0#ad`O!t71GAj*( zJ1A!gyt&HgWuEDkk7^j;YoP3#HXAn#pg)xw2jRA&3ItFVAc&${g9o0QBO~j_#_B(( zT`qjB->j$8%NOr`%jrja^$n}wDDgbcM>lTV*jm1Pxvl@Opib@F&C9m%_zFn(v>A!o zbMv}&W8c61J15+~{$m$qX7e8p4)zmU$k_hRR+~!5mnsm)hvzW^MJ5^fCsAwap~8Q` z%A%x@Mr3{l3=*VC-Vdt4!l1(bQEpBae}{Gie_zn2LOP|-`chC2hA8l>5~GZsA*~96 zP*L!XK^)o>gtMZ8*fH>eV?=8c1Pu)XiTaU8T4tbJjj6pg={I^yf4cAT{nvc%`2Q9O z(;oi1F4*Q(K)Q!ceOa{sTR*x_t5oP0qGt(F*|D3XTN^ksT1ojzI?W~dA}s> z*K2jZz-`puWlp7-y^hg!@D^_#K&~ zfHV3XOKPhIzD5dcl~sQdRvAj9kR|({iRHR-dzdf~dn_>{%A;hM-K4ITFu?$LCq1v< zOPudBw`U^R7T9y*`)Rw?U-Zip20n7unJ1t2gB{I%_4%GR0u_+%d2>?QqPcvjYuBzF zz2V+F&iUyBA9}~s<6D-bY1UZ0BufTbv{EBB%DMCcX)JGI{F8tRG=u)eqIRihFO}WN zFN<#z3ib&AJre{I9RgXx3Ry-}5ZD*}plBYKrF4R$!TXehfEvZsrJyJU+A)g@`p2GU zh2Jop*LNMkU#q@&SFdNtwhrj_O-a`8B(qCK#~wbm^}$Qdea#!bh?8FVKA$FwvbaQ^ zehsf$TpWShA6|RdEw|ow;x8Wl@VVXY)@7#APwMtesT!Sr+9Z9d%d0ODv|BU~W`;n4 zIq`(J=pT*1*QLA6Z%w^|#&n>{q^g-W`uza@OYQt;>_NKQcJlO9ltCz|W~C znnJFQ6WU8&lLVoBb`ok!(eH@C8$HTH{gE1M!5XM4X)0m0Sj;6Z>;h(fa4IW-Hxopj zUTz0p7XHpvoY)Uc4hpwAC;-P!3s^DIgqS_ojA?I6%*^A>e%47J8yjAT&!_orOHSsguabppAAcdNtFTwPzmrUbs^@J4tSmq}OURHxD)U`pK(S zeEJ=)J^V$#S|G33g6?Jor1Nz8txt7wa&l3Be7wKhm~EJAea}7jJmZda_Z@rZBOiJ1 z*7nr?vz^XRJf>jL4R*zWv(= zZ@B+g`#qDbiGBB(eR;s}aO=}lu;>Zxmf7Car?2Z*v z8th?zs=5+lxl!n=1sNz*c#4gF)N=Z2P@Z?9WUI5iZni&G&rHA3tJmw@TCMf)e!qL& zmCt;}-gmEj(Sg5Mb?_?5K3kjTqb+07?VC0YE?sKOQnPeR#W;8T?#;(6`c6e)PJvzh1fiw-3E=WGX8-`NC}Ai#G#Y}81fKY}c+?X`6y>4Q9otm+X(*Co)%wD&aTc(*< zG_9F_lGJ-?TAyt;np+Qe^sMhZYsG#y?X_&_t*0INvfu8ap{#B@&qkmE(s?$ayQ@1l z-gx8a#`^Ys@0$G7@zb5j7tD4$f7HolM@-UP+!)@zXkfVCFuAdCn&cM4a#PC^Uzf>b zc`b8tERtVA;bJ~Ninwl6ZQfpCRR}d3*Rt4XJ*1Y#=6Pl^lbBv_rrzmo8QhX*&BvO} zbh?=gKQuHjcIy${xButar=3;-DpNAszFRbS@M2vk5if9A64Ni_o12<)a2_& + + net45;netcoreapp3.1;netstandard2.0 + RRQM.ico + true + RRQM.pfx + 5.5.0 + 若汝棋茗 + Copyright © 2021 若汝棋茗 + 介绍:这是一个扩展于RRQMSocket.RPC的JsonRpc组件,可以通过该组件直接创建JsonRpc服务解析器,让Web端、移动端可以跨语言调用RPC函数。功能支持JsonRpc全功能。 + +更新说明: +增加:配置中通过MaxPackageSize属性设定可处理数据的最大值。 +修复:内联调用。 + +Demo:https://gitee.com/RRQM_OS/RRQMBox +API:https://gitee.com/RRQM_OS/RRQM/wikis/pages + https://gitee.com/dotnetchina/RRQMSocket + + true + RRQM.png + 若汝棋茗 + true + LICENSE + JsonRpc;Socket;IOCP + + + + bin\Debug\netstandard2.0\RRQMSocket.JsonRpc.xml + + + + + bin\Release\netstandard2.0\RRQMSocket.JsonRpc.xml + + + + + bin\Debug\net45\RRQMSocket.JsonRpc.xml + + + + + bin\Release\net45\RRQMSocket.JsonRpc.xml + + + + + bin\Debug\netcoreapp3.1\RRQMSocket.JsonRpc.xml + + + + + bin\Release\netcoreapp3.1\RRQMSocket.JsonRpc.xml + + + + + True + + + + True + + + + + + + + diff --git a/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcClient.cs b/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcClient.cs new file mode 100644 index 000000000..f06032b6c --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcClient.cs @@ -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 +{ + ///

+ /// JsonRpc客户端 + /// + public class JsonRpcClient : TcpClient, IJsonRpcClient + { + private int maxPackageSize; + + private JsonRpcProtocolType protocolType; + + private RRQMWaitHandle waitHandle; + + /// + /// 构造函数 + /// + public JsonRpcClient() + { + waitHandle = new RRQMWaitHandle(); + } + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return maxPackageSize; } + } + + /// + /// 协议类型 + /// + public JsonRpcProtocolType ProtocolType + { + get { return protocolType; } + } + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types) + { + JsonRpcWaitContext context = new JsonRpcWaitContext(); + WaitData 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(resultContext.Return.ToString()); + } + catch (Exception ex) + { + throw ex; + } + } + default: + return default; + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types) + { + JsonRpcWaitContext context = new JsonRpcWaitContext(); + WaitData 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; + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + public void Invoke(string method, InvokeOption invokeOption, params object[] parameters) + { + this.Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public T Invoke(string method, InvokeOption invokeOption, params object[] parameters) + { + return this.Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// 处理数据 + /// + /// + /// + 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; + } + } + } + + /// + /// 载入配置 + /// + /// + 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; + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcParser.cs b/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcParser.cs new file mode 100644 index 000000000..406d3aae0 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcParser.cs @@ -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 +{ + /// + /// JsonRpcParser解析器 + /// + public class JsonRpcParser : TcpService, IRPCParser + { + private ActionMap actionMap; + + private MethodMap methodMap; + + private JsonRpcProtocolType protocolType; + + /// + /// 构造函数 + /// + public JsonRpcParser() + { + this.actionMap = new ActionMap(); + } + + /// + /// 函数键映射图 + /// + public ActionMap ActionMap { get { return this.actionMap; } } + + private int maxPackageSize; + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return maxPackageSize; } + } + + /// + /// 函数映射 + /// + public MethodMap MethodMap + { + get { return methodMap; } + } + + /// + /// 协议类型 + /// + public JsonRpcProtocolType ProtocolType + { + get { return protocolType; } + } + + /// + /// 所属服务器 + /// + public RPCService RPCService { get; private set; } + + /// + /// 执行函数 + /// + public Action RRQMExecuteMethod { get; private set; } + + /// + /// 结束调用 + /// + /// + /// + 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(); + } + } + } + } + + /// + /// 初始化 + /// + /// + /// + 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}的方法已注册。"); + } + } + } + } + } + + /// + /// 取消注册服务 + /// + /// + /// + public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances) + { + } + + /// + /// 设置执行委托 + /// + /// + public void SetExecuteMethod(Action executeMethod) + { + this.RRQMExecuteMethod = executeMethod; + } + + /// + /// 设置地图映射 + /// + /// + public void SetMethodMap(MethodMap methodMap) + { + this.methodMap = methodMap; + } + + /// + /// 设置服务 + /// + /// + public void SetRPCService(RPCService service) + { + this.RPCService = service; + } + + /// + /// 构建请求内容 + /// + /// 数据 + /// 调用服务实例 + /// + /// + protected virtual void BuildRequestContext(string jsonString, out MethodInstance methodInstance, out JsonRequestContext context) + { + try + { + context = JsonConvert.DeserializeObject(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; + } + } + + /// + /// 构建响应数据 + /// + /// + /// + /// + /// + /// + 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; + } + } + } + + /// + /// 载入配置 + /// + /// + protected override void LoadConfig(ServiceConfig serviceConfig) + { + base.LoadConfig(serviceConfig); + this.protocolType = (JsonRpcProtocolType)serviceConfig.GetValue(JsonRpcParserConfig.ProtocolTypeProperty); + this.maxPackageSize = (int)serviceConfig.GetValue(JsonRpcParserConfig.MaxPackageSizeProperty); + } + + /// + /// 创建SocketCliect + /// + /// + /// + 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); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcSocketClient.cs b/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcSocketClient.cs new file mode 100644 index 000000000..e293c95b6 --- /dev/null +++ b/RRQMSocket.RPC.JsonRpc/Socket/JsonRpcSocketClient.cs @@ -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 +{ + /// + /// JsonRpc辅助类 + /// + public class JsonRpcSocketClient : SimpleSocketClient + { + /// + /// 禁用适配器赋值 + /// + /// + public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + throw new RRQMException($"{nameof(JsonRpcSocketClient)}不允许设置适配器。"); + } + + internal void SetAdapter(DataHandlingAdapter adapter) + { + base.SetDataHandlingAdapter(adapter); + } + } +} diff --git a/RRQMSocket.RPC.WebApi/Attribute/RouteAttribute.cs b/RRQMSocket.RPC.WebApi/Attribute/RouteAttribute.cs new file mode 100644 index 000000000..d8bd55ebc --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Attribute/RouteAttribute.cs @@ -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 +{ + /// + /// 适用于WebApi的路由标记 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public sealed class RouteAttribute : RPCAttribute + { + /// + /// 构造函数 + /// + public RouteAttribute() + { + } + + /// + /// 构造函数 + /// + /// + public RouteAttribute(string template) + { + this.Template = template; + } + + /// + /// 路由模板 + /// + public string Template { get; private set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/Common/ActionResult.cs b/RRQMSocket.RPC.WebApi/Common/ActionResult.cs new file mode 100644 index 000000000..d34666b80 --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Common/ActionResult.cs @@ -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 +{ + /// + /// 结果状态 + /// + public class ActionResult + { + /// + /// 状态类型 + /// + public InvokeStatus Status { get; set; } + + /// + /// 消息 + /// + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/Common/ControllerBase.cs b/RRQMSocket.RPC.WebApi/Common/ControllerBase.cs new file mode 100644 index 000000000..c5242b240 --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Common/ControllerBase.cs @@ -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 +{ + /// + /// ControllerBase + /// + public abstract class ControllerBase : ServerProvider + { + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/Common/RouteMap.cs b/RRQMSocket.RPC.WebApi/Common/RouteMap.cs new file mode 100644 index 000000000..1a51b3d3c --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Common/RouteMap.cs @@ -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 +{ + /// + /// 路由映射图 + /// + public class RouteMap : IEnumerable> + { + internal RouteMap() + { + this.routeMap = new Dictionary(); + } + + private Dictionary routeMap; + + internal void Add(string routeUrl, MethodInstance methodInstance) + { + this.routeMap.Add(routeUrl, methodInstance); + } + + /// + /// 路由路径集合 + /// + public IEnumerable Urls { get { return this.routeMap.Keys; } } + + /// + /// 通过routeUrl获取函数实例 + /// + /// + /// + /// + public bool TryGet(string routeUrl, out MethodInstance methodInstance) + { + if (this.routeMap.ContainsKey(routeUrl)) + { + methodInstance = this.routeMap[routeUrl]; + return true; + } + methodInstance = null; + return false; + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator> GetEnumerator() + { + return this.routeMap.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.routeMap.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/Config/WebApiParserConfig.cs b/RRQMSocket.RPC.WebApi/Config/WebApiParserConfig.cs new file mode 100644 index 000000000..edb739626 --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Config/WebApiParserConfig.cs @@ -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 +{ + /// + /// WebApiParser配置 + /// + public class WebApiParserConfig : TcpServiceConfig + { + /// + /// 数据转化器 + /// + public ApiDataConverter ApiDataConverter + { + get { return (ApiDataConverter)GetValue(ApiDataConverterProperty); } + set { SetValue(ApiDataConverterProperty, value); } + } + + /// + /// 数据转化器 + /// 所需类型 + /// + public static readonly DependencyProperty ApiDataConverterProperty = + DependencyProperty.Register("ApiDataConverter", typeof(ApiDataConverter), typeof(WebApiParserConfig), new JsonDataConverter()); + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return (int)GetValue(MaxPackageSizeProperty); } + set { SetValue(MaxPackageSizeProperty, value); } + } + + /// + /// 最大数据包长度,所需类型 + /// + public static readonly DependencyProperty MaxPackageSizeProperty = + DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(WebApiParserConfig), 1024); + + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/Converter/ApiDataConverter.cs b/RRQMSocket.RPC.WebApi/Converter/ApiDataConverter.cs new file mode 100644 index 000000000..b4fcda805 --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Converter/ApiDataConverter.cs @@ -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 +{ + /// + /// Api结果转化器 + /// + public abstract class ApiDataConverter + { + /// + /// 在调用完成时转换结果 + /// + /// + /// + /// + public abstract HttpResponse OnResult(MethodInvoker methodInvoker, MethodInstance methodInstance); + + /// + /// 在调用时 + /// + /// + /// + /// + public abstract void OnPost(HttpRequest httpRequest, ref MethodInvoker methodInvoker, MethodInstance methodInstance); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/Converter/JsonDataConverter.cs b/RRQMSocket.RPC.WebApi/Converter/JsonDataConverter.cs new file mode 100644 index 000000000..16bbd2bd6 --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Converter/JsonDataConverter.cs @@ -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 +{ + /// + /// Json数据转换器 + /// + public class JsonDataConverter : ApiDataConverter + { + /// + /// OnPost + /// + /// + /// + /// + 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; + } + } + } + + /// + /// 在调用完成时转换结果 + /// + /// + /// + /// + 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; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/Converter/XmlDataConverter.cs b/RRQMSocket.RPC.WebApi/Converter/XmlDataConverter.cs new file mode 100644 index 000000000..de6638c86 --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Converter/XmlDataConverter.cs @@ -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 +{ + /// + /// Xml结果转换器 + /// + public class XmlDataConverter : ApiDataConverter + { + /// + /// OnPost + /// + /// + /// + /// + 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; + } + } + } + + /// + /// 在调用完成时转换结果 + /// + /// + /// + /// + 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; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/LICENSE b/RRQMSocket.RPC.WebApi/LICENSE new file mode 100644 index 000000000..b09cd7856 --- /dev/null +++ b/RRQMSocket.RPC.WebApi/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/RRQMSocket.RPC.WebApi/RRQM.ico b/RRQMSocket.RPC.WebApi/RRQM.ico new file mode 100644 index 0000000000000000000000000000000000000000..6465fb16e389ed1804d54b368018596580c6672e GIT binary patch literal 249918 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

&cP)Tdhs88a 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 + + net45;netcoreapp3.1;netstandard2.0 + RRQM.ico + true + RRQM.pfx + 5.5.0 + 若汝棋茗 + Copyright © 2021 若汝棋茗 + 介绍:这是一个扩展于RRQMSocket.RPC的WebApi组件,可以通过该组件直接创建WebApi服务解析器,让Web端、移动端可以跨语言调用RPC函数。功能支持路由、Get传参、Post传参等。 + +更新说明: +修改为稳定版。 + +Demo:https://gitee.com/RRQM_OS/RRQMBox +API:https://gitee.com/RRQM_OS/RRQM/wikis/pages + https://gitee.com/dotnetchina/RRQMSocket + + true + RRQM.png + 若汝棋茗 + true + LICENSE + WebApi,RPC,IOCP + + + + bin\Debug\netstandard2.0\RRQMSocket.RPC.WebApi.xml + + + + + bin\Release\netstandard2.0\RRQMSocket.RPC.WebApi.xml + + + + + bin\Debug\net45\RRQMSocket.RPC.WebApi.xml + + + + + bin\Release\net45\RRQMSocket.RPC.WebApi.xml + + + + + bin\Debug\netcoreapp3.1\RRQMSocket.RPC.WebApi.xml + + + + + bin\Release\netcoreapp3.1\RRQMSocket.RPC.WebApi.xml + + + + + True + + + + True + + + + + + + + diff --git a/RRQMSocket.RPC.WebApi/Socket/WebApiParser.cs b/RRQMSocket.RPC.WebApi/Socket/WebApiParser.cs new file mode 100644 index 000000000..0ae6aa559 --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Socket/WebApiParser.cs @@ -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 +{ + ///

+ /// WebApi解析器 + /// + public class WebApiParser : TcpService, IRPCParser + { + private RouteMap routeMap; + + /// + /// 构造函数 + /// + public WebApiParser() + { + this.routeMap = new RouteMap(); + } + + /// + /// 数据转化器 + /// + public ApiDataConverter ApiDataConverter { get; private set; } + + private int maxPackageSize; + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return maxPackageSize; } + } + + /// + /// 函数映射 + /// + public MethodMap MethodMap { get; private set; } + + /// + /// 获取路由映射图 + /// + public RouteMap RouteMap { get { return this.routeMap; } } + + /// + /// 所属服务器 + /// + public RPCService RPCService { get; private set; } + + /// + /// 执行函数 + /// + public Action RRQMExecuteMethod { get; private set; } + + /// + /// 结束调用 + /// + /// + /// + 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); + } + } + + /// + /// 初始化 + /// + /// + /// + 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(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); + } + } + } + } + } + + /// + /// 取消注册服务 + /// + /// + /// + public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances) + { + } + + /// + /// 设置执行委托 + /// + /// + public void SetExecuteMethod(Action executeMethod) + { + this.RRQMExecuteMethod = executeMethod; + } + + /// + /// 设置地图映射 + /// + /// + public void SetMethodMap(MethodMap methodMap) + { + this.MethodMap = methodMap; + } + + /// + /// 设置服务 + /// + /// + public void SetRPCService(RPCService service) + { + this.RPCService = service; + } + + /// + /// 载入配置 + /// + /// + protected override void LoadConfig(ServiceConfig serviceConfig) + { + base.LoadConfig(serviceConfig); + this.ApiDataConverter = (ApiDataConverter)serviceConfig.GetValue(WebApiParserConfig.ApiDataConverterProperty); + this.maxPackageSize = (int)serviceConfig.GetValue(WebApiParserConfig.MaxPackageSizeProperty); + } + + /// + /// 在初次接收时 + /// + /// + /// + 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); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.WebApi/Socket/WebApiSocketClient.cs b/RRQMSocket.RPC.WebApi/Socket/WebApiSocketClient.cs new file mode 100644 index 000000000..71cfa3d0f --- /dev/null +++ b/RRQMSocket.RPC.WebApi/Socket/WebApiSocketClient.cs @@ -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 +{ + /// + /// WebApiSocket辅助类 + /// + public class WebApiSocketClient : SimpleSocketClient + { + /// + /// 禁用适配器赋值 + /// + /// + public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + throw new RRQMException($"{nameof(WebApiSocketClient)}不允许设置适配器。"); + } + + internal void SetAdapter(DataHandlingAdapter adapter) + { + base.SetDataHandlingAdapter(adapter); + } + } +} diff --git a/RRQMSocket.RPC.XmlRpc/Attribute/XmlRpcAttribute.cs b/RRQMSocket.RPC.XmlRpc/Attribute/XmlRpcAttribute.cs new file mode 100644 index 000000000..2629a50db --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/Attribute/XmlRpcAttribute.cs @@ -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 +{ + /// + /// 适用于XmlRpc的标记 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public sealed class XmlRpcAttribute : RPCAttribute + { + /// + /// 构造函数 + /// + public XmlRpcAttribute() + { + } + + /// + /// 构造函数 + /// + /// + public XmlRpcAttribute(string actionKey) + { + this.ActionKey = actionKey; + } + + /// + /// 服务唯一标识 + /// + public string ActionKey { get; private set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.XmlRpc/Common/ActionMap.cs b/RRQMSocket.RPC.XmlRpc/Common/ActionMap.cs new file mode 100644 index 000000000..7cc41dc5e --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/Common/ActionMap.cs @@ -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 +{ + /// + /// 服务映射图 + /// + public class ActionMap : IEnumerable> + { + internal ActionMap() + { + this.actionMap = new Dictionary(); + } + + private Dictionary actionMap; + + internal void Add(string actionKey, MethodInstance methodInstance) + { + this.actionMap.Add(actionKey, methodInstance); + } + + /// + /// 服务键集合 + /// + public IEnumerable ActionKeys { get { return this.actionMap.Keys; } } + + /// + /// 通过routeUrl获取函数实例 + /// + /// + /// + /// + public bool TryGet(string actionKey, out MethodInstance methodInstance) + { + if (this.actionMap.ContainsKey(actionKey)) + { + methodInstance = this.actionMap[actionKey]; + return true; + } + methodInstance = null; + return false; + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator> GetEnumerator() + { + return this.actionMap.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.actionMap.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.XmlRpc/Common/XmlDataTool.cs b/RRQMSocket.RPC.XmlRpc/Common/XmlDataTool.cs new file mode 100644 index 000000000..7771e86b4 --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/Common/XmlDataTool.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.XmlRpc/Config/XmlRpcClientConfig.cs b/RRQMSocket.RPC.XmlRpc/Config/XmlRpcClientConfig.cs new file mode 100644 index 000000000..f8411356d --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/Config/XmlRpcClientConfig.cs @@ -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 +{ + /// + /// XmlRpcClient配置 + /// + public class XmlRpcClientConfig : TcpClientConfig + { + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return (int)GetValue(MaxPackageSizeProperty); } + set { SetValue(MaxPackageSizeProperty, value); } + } + + /// + /// 最大数据包长度,所需类型 + /// + public static readonly DependencyProperty MaxPackageSizeProperty = + DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(XmlRpcClientConfig), 1024); + + + /// + /// 等待超时时间(秒) + /// + public int Timeout + { + get { return (int)GetValue(TimeoutProperty); } + set { SetValue(TimeoutProperty, value); } + } + + /// + /// 等待超时时间(秒), + /// 所需类型 + /// + public static readonly DependencyProperty TimeoutProperty = + DependencyProperty.Register("Timeout", typeof(int), typeof(XmlRpcClientConfig), 5); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.XmlRpc/Config/XmlRpcParserConfig.cs b/RRQMSocket.RPC.XmlRpc/Config/XmlRpcParserConfig.cs new file mode 100644 index 000000000..ae4ba6bea --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/Config/XmlRpcParserConfig.cs @@ -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 +{ + /// + /// XmlRpcParser配置 + /// + public class XmlRpcParserConfig : TcpServiceConfig + { + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return (int)GetValue(MaxPackageSizeProperty); } + set { SetValue(MaxPackageSizeProperty, value); } + } + + /// + /// 最大数据包长度,所需类型 + /// + public static readonly DependencyProperty MaxPackageSizeProperty = + DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(XmlRpcParserConfig), 1024); + + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.XmlRpc/LICENSE b/RRQMSocket.RPC.XmlRpc/LICENSE new file mode 100644 index 000000000..b09cd7856 --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/RRQMSocket.RPC.XmlRpc/RRQM.ico b/RRQMSocket.RPC.XmlRpc/RRQM.ico new file mode 100644 index 0000000000000000000000000000000000000000..6465fb16e389ed1804d54b368018596580c6672e GIT binary patch literal 249918 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

&cP)Tdhs88a z#ww*9&h??j$P05^!)oB)fhtd-j`BtdD4O)bC(5eV`%oXZ-Oi}pTKVW*f82eutyP1w z-d@=`u?xOf)=9Ik5Z@3n%xH^=1TeKpL8AGc)Ov<|Q?4`=0iA-LmBy7IdWJHLhh1^(>1f9agn*kiw$&+bAZ36W+ag$Y* zO*Jq7>%{RzrO&LZ)tm#{bv5$2^Y--!hM*PhMbEkD4aLVmoQ&ag64;}63l@pzh<85s9_K_k1O9} zIrGacA3BmTw{pU`rIpX!y(hLq?n~`wj+w5D?VCGie;I-G7D&S^>G==d-q$|ttovha zouwl(V3qU!@Cb-z?WOJ`^9&^e{f>+%yz-Iez^gY==(K>R ze6}(W-FV_x!=8G0=W0S4*5%?FsLYg7S_A-vO#qhP(BPJrmqRl&#|RLsxrJ9Iv`8_r ze25g;sZ3FAOKU+}V^boNO2^yUT1iL7flMj|sg4fla8lr;GT_OEcL^(>SEh|cEy$1M zLoz?F{;0jDz3^k^X#u50MRj#ayP|?Mx&wel=xm833Mq9PN=jBSIopppPVO_kI|A!1 zkeb8#(M|{5Qvdbh6N*!r1Zy%^7>>qsCaF}LS;a?`xow#D$`KH1@eyn;C)#-gOXLLs zIh?74z}jL_SYcDh6y&?{C;vWU=Z&`b4NA4vr768G&)t(-W%j&zcJIS<@vV6}6-}AtiRtNhR49w4XF9y)#fZ z6n&_y=Q;LcVml9@gHUL+0lJFwTz|&RckMZOyHk5^N%a1a`VwqeMp{EdL!n<@?sqO( zlJ4AK12^2T@7-_TE&cejm7A8|{r5B4TAMaZrBg+glPRn6{NxB0^y5>g{nutSEpx5t zqS;~$Ief}~SSo!&>5B1vIo^gF2Lq0L;-wYS3Kq1)5}uV;*p@7auOg>hG^1+7$Y(Is z7iW#F@7mhh0^7Fj^78UFtV-7Vv$}qtVZ8%VbGm13y2EV0p?Rxe4vjEVKF=3bnlMK` z=)=^TBPd1s9?6s3d>G-^qWj=+L_rc3dDmJ1R-9P~_JzNIoBVR7S}Y%GBLtkHe3#Dr z+g*EXxU~Y&z67Wr+BW^^TEf>lx@C-7cd~l{TOw%y=%m1laPuG| z1#oPeTDI*a^76Z4#f6LW&%NrhJvQ2I<`2zH?){!0fk6+XyeLO)Z5|mmtPY3ovDvf7 zmmG5XTV6Ufw9qG3wL_rTr7GJ!OE zN&%x-^@M^$2y|MMRkDY+!h~D;%7ZseshW6B&o7C-J7Q0QEt}^RD^?_`s;W|97WUA) zuWtXzg3tGu_~1i7cbZ#ASGsQTNHoLc6D-^1f+Alrhd!q2O28DouFN{I@&Sne8JJIG zwVH*ZbtBlV5t!t@a_uwc>%cgc+2ug?i{314prwAFCYMmt00gj z6uMYDZMJqO1=k|rSvF0@k}U=0m2Z`v`1{NDo4VVFJw3m<r~PtH1$M{CZ+id54Gw4(*94q$y8-g!>5MF=q?zM z^_ zOvR$?acEhYH}zzs8V>C>qxnr!u`7BaWX(SQ)N{i*|{^!w+cX=XtH_HZbx0a zJ;Nsuv%*c;n$U z*9_)G+?@tBT!o9>|67Ybp3r>G1%F-HP`@$l>KIn-Lvo}iOm_rDnL8l?2#qh}0cn`l zxDEpIg207r)?l^j*venZSgrP#@)C(=nL}lY%T*ErY{81f_f23l8yzC{@&|%kcKkKz zlxN=#xC8h(43|Ub-z}6ttp|P@tV~{Ber<6@)sx5k?Zw}k>kECV0FdQ(9?a`-P3~q>l=N_43JY%06>?`_-ghl?+B zmM`DA*!SYB4436mQbqs@jD(1wZ&QM30O;gdO)xd*MgCi;CG_J~ft=y5RKXt%KA9kg z_$`4nz#b*gArlpA24z;EA~oUbFw=+SQ(ge9UYp8o#jn+HZ^-*$%(N2-uG{tyz)<#9suMuU|cLH!^D!{85smjoLQA`+lf5YX@? zqSj4+M*7Op|7`*=&Y5~IyM_Xjt_eVt?9-fQWQj>A|G7CNi(SuY;HY3&xD*b7m^o zr#c?5c^lNeW&wHDHBxBvEoh{+NAe1m(1XwZ^O*-7byt8`Fcl0Z!lG+#?k6zagKs!q ztC{jqQEPf~xlbX_mHN={du*72rO;{8K*Cy2^$}f`Flen15Wt8*ps?#ePAGy{pv!>($AJ6DIKS|D8m7F- zECo`@_A;m#2!eLDBuXnivfNVmz?VTVyzMZXW<%-%KnGahP#-MIf(|R%T0iZqi!ML% zl$+PpIv5D&9q^2_J8*e<#Fk&=XPgbIS*DUJJw*Yq6o25;8yN)RTz89~50v?YN751A zEZsQ$mB3#eL(&wrd1Q3n0%(c?G{>WE{PDYQ`RQg`{ca#EqMp1)mRtUhdvCpP;+=P% zo=T%!;rkEf7_VOLhRyCjt*^~kB>iqIyA;*U= zO#;wLEm)cHeTXI6%F2e$nS9BkhfS%jR`ncY^ThR@p$>Q;4R7M-t2bL%k@m;3W^{R! z=|nM(E>R2b7)^OxNJhs`?d0c8L6p%b7MHrk zY{38$YAv*RtHwRR1a+jG2X}Z-$oP(wIt3V?N{m1TDa~>D1U3Up2vi7fraQru$np2h zdjclgZJ~Uza?u9>(=_wtqUQ`%R-gLpww> z@rvqaH#+zJ6LzhsVR-<#pMk6+?T(2)SGCEKGLMWNmZng`Xp72|4rPkq)EkcxZMbWu zs+pt6SepS@j87+|v%Y4w7{|@_^&AfC0RGOm&KAXkL1h8O` zP)nec)LsCcxkfN=-UL7yyi^hY5O`tor;fUtppDlW1ZWMi67(_nrPh*oK`~Mca3Par zzq#AP@YRMMCfJ#l`}H}q{r)U1ZHWQ2_!R1V;uAaB(Z0vY4;^{nzL!rdpSX-4fl^kX ziuq8PYDVd|2kRO(?`zO7(plA;ep`{IBg#FNGf#O>B|#Xlw7iy$NV20ATG*7=Tai1} zv;ABuF~Fn@5^hf{pm;mJ4t;b!%U`l$uERWQU#zWn&)$E028k4kn06Af=osj2*Mc0F)b4j z5DHo&;-M(eP3cq>lhnR+<#&}qrLd)f`Ai&)4Ml)Br#898n$cSpQ;3BtL%go)+$#5k z1YOf_uO0;2+A;%P!Jw4!zyS&l5a{#)GL!<#4D7Pvnaly_U3%^jCtkfi0Ot4I^Zv!+&ZTFjN&wu!ggN{7iOlMsm7Urw}d29cIA*Dz9#HuK-u52w# z7Ie0yJKJONSXTm)sTQ{>9k*hB#?ScRTb6D4mgAF%=Vg)|T^$LhE0d^iYRc>A=twj* zugb4$Y|Lw{t4;3x%rj#h*NM5V7xjHl_)V#ZYsU#8F&Qn75CVDJb)Z2wTc9u3fw^`} z2@?7h4Zp1!$O*D$?V}WKRgAXdIfAMI)Q#dw6xYTqAoRzIcLJGpAr>8w->Jj^^fSxr z3Ee-Q2N|^nc{xt<^KFzseFl6hSyDghl&dZ}Y=@tzC_nR`t}oI30SBZexI8oGnezDb zi#{#w@~T)*C0@M=KY$C}FmD2j5#t6rCM$ylp^lzt`lxQ9l6_!d31l!rU8Px((PK$c z1;czIz?kTA+k@6b)P48dqh|f;S10^>94Y&jU*iDESXx`KZ=emsZ77>yL%P68yJ?>~ zPKHt^4hg4|cKT&`Nw=e;gHp)z^YZ~ZIsn*jX1sQFcG+FP>Uri_Bnh?!gqfCh6i74! zUew8C;_aPIaTjEYS2Wbaf+Y)~?12Z4&8%t~>vpuq)9ExsJ;xqySyoAw&eQ~_?j!$# z)#9U8&%YVO4EkC_ayki$+9iR$SHXM({#HB>en*pI6+Ft0lNrG(USJ%cixOya0a{(+2ws?7M*Tz8l{(u2enc>1REV$AB zz>6v!@JY4rYciv__mVBs7MBHe3dBc{kKC$oc{2?m$c_1yIfp)E{=&I3OkQi-) zU;0h`${{T+Z40ZzZ z0A!VN)gaq5+zl8kQV(}@QSi@%14~k=zyeb2eKX6-@WBU}XQ=Rvp(asjs&bv8S+AL{ zPDc#}_Qb)5NP+A|I~s`hx){dc;zETeYofOcTXQvIi^;U1J;4S9jw07fdr(g z6Xr8>=9I^#AOBfdr#FnXM^5+@;s$Ujb6f?1x8pDGs{l-G_`M70i#iW!CY@);0(%~v~M2Qp7^c|!g4@1w5Q6)W%yzL zM==y}EM&X@E+xEXD$nT$0?iJkPG0fK@yB0t#^F2d``Egg@4h;3zXwvuM14X?3J2wd z;hQcic4#%LXkQ%Ytt4;9bkIu%fosuZ4U%T+1;yVq%^c*BhS{!M1yVK=(&Pn>&s76r zV~Bd90QC_cYNM9x73Q^8zcJ&K9ZSaltFIS2R5P+7Fyw0z9c zdU_wAqbleoFu*jxge4o6tQXg^`CSB1vlc2o9I!qs`(CR@pe_Tx6NzOiE2&!I#7*x zKG)I7U=dcd?`G48MI|fV8=HmuL?aYdMTnbD#yesU-f-^0TkLYDTv)x z0amWBthP3n3hv^O>ur=1KWEMgC{s8!5!-31T^O#DC) z$8aAh-)gAXh-re$U=%N8BVQM5R{QDs*`%fAtBAgNo)9?W4JwPvtSY5_v#71j7Vx9X z%Ve|CyhFB5x&8^de1LYBK)Y+XRy^6V(aASldFT#%-7pweS-%BRnK8i%T&OOIuZ`O3 z>%6W^%`nD9ec?$G95Seg4f?9gX;ThSvFO#^W5^wkrJ1NQm$;*|JAbGIZS<=e@)T2p zSWhS{iTi#_Jks9!e-~eQ`re2BWiT$N_2r%#XnNXPAHKJ7`wf?!*45BBEar6CQQspG z%K~CiU{S9;Lb*>>`xFsmgFZ;}p&wqmsu&4-!;%9RzvjP@XJj@f2@VO!UPAr6H+k9W5X6%P?+4tMn!IB04M5fsh- zIAY`DD@Js)JAtzCG*{+~$v^@!6w}Q>pf&=q$foWG7oBkX)hC^GE^}4%R*lZ}1L|<7 zZVrbMQ3F-h|7}iF>gAQzO+EXLllPu9^{I6+hrMymehZ}L&Azwsjvtf8md%HyJdv?v zgoXk@83MYXzfwnAHIU*Lf=p9CvqQ2M<6*8@gvvpcPkqIaIjW~E3T(I4#weX}!hX;E z;q(iBJ+4g1oN_;dYXlZHHjZ4?wQAqzUVUk7@gujNn3w7(8Dax*!G|be43!99D(?X$ zRxz&|fb3G4=`!GC1U$o8N^1QX5-LF=fi0l;_22*R=G`v* z`{|V~B}t!%=zKWFj(35-72p|FeGqX+h(ZH=f+7rl|VMN9m)nL&za4jXC!-NJfA$)rGLoLIuF8j#XQ{_TKE% z+i$=0mkn*rb__gw81<}TS!jft+ve^I08w`?01ZgW8j@A-&03~rN@{mtCjeOP3*0Bt z%@qhPDWw3q5R5eF|51cm9bc946BCU0%X&(sd;)C_%i)i?MWyA7_P*fZ>6=y8d^wPp zLcar2Gjr+oe?4^mgj27$YLrK;a;E$>&2~cwt)9+k@+fJOc+_K-iO#FWh`Z@!HT?m4 zkp~vLWDbGglzhUg;wBQ5S(LuR23``cAurxl^!V+^>^W)MT!elg@0K;V_HSFh9skkF zWqZ_Lef}T3l`E_Asl#Q-HUK0o%3V|e84`-24Vje!B1Hy-)gzdqF4lrwYx%=oE@#s} zYx?+2zp1jJ(AblX0ZfSvMD113HSGJ%4sfATv5{CJ^JWj~)T`{ukaEW!}r!fn*SY+5!B!j9`@6C=dZX zED@TOEy!$WiPCD_8*@Kc(5fR(uJR+(bB2QWc^e=Y!~GUBg*R@@b`N5NDvIg)h!V#) z=!xmqHGxzGf)R8D#li2lx&#^>%S-Nc;dOsF{FDncn9@9cihf>As^0)94&2oY98k7wR z0L61-h zKu6&IxE9tqkjl&@mV=v_-_S685}}m;ZHwu(vD+tnM?g~;rFL& zdh_c~4xay~Gp=)MmyOCJ9?w^{Er2|hF@-(Dl*z3@E*Kors+54Kje#BsbOA{fvQ;CU zl|!A$Yz?apfmZ2N%XU6(001BWNklMU%eJiyDT5 z!A{W(m)bQmsH7^Mi`!FAT2)U{95HB?;O9)46iPYp^U}>=`b6Q`YL6*3g?IxX61E58ceIsj1ib7df+qJX20%ID)&jqKWnm8Q7l_?Uj$I`834wc z(yW?P2EdIKEZge0_iVfW#O<+g^cr`d?d@4#=Rk@#c+YE3T~&3|#pf1fyhyb}phVUc zMTRK-+;Z^*!4)S#E98R0deNrVG+aVJ${DX&NLUs!k&8(bA;BYbb8Jc>Wf5p2ERP=O z3%@)1u@la`;P`>6iR#%1wB)5V`EeAWeHD4`${QvPtz?SZElEm|82du)6Xn}Af>2V8pnb5~x2l^! zYPn*kM`4v?gC9xM@A9jE?6UioQ|Bo{MQL7tbCLB6AboSeN7GvNJn^BS?dfEt1CZ~t z1!Dw&=sMJTv+GWvzG-(oVbNos3lA4Ded+MU{XKpzP zh;PSy-zu{y*kFi;px+eHBhd)E0`N0p%^O4l2}CF$rP(8PHr3=Lpk^_GPfDVN z$^x@`mfF{5#VN6qU0~8E0DVuKKI$E7 zMg7oG4zY&1+3k*1#L(1-W`Q6sC=GIfzTP+k{EiI-HhnfKdYN6AK>>3pLdh%L6M(uX zKy5tQ6@T#Nqo;4Z)1WUK)?XL&V7so@zL;~woXbwU)=PC(6wpkB1)~xyhaZLgxSUZW zZ-5_KaX~U6>4;*UvV^2E<+ZCoN9s`$W%@V;iD2i@8d0N$01s+OHGnMQqxG_;Tg}wN zO1GMHS+LJ{dIXx&1RNS`nRMtadmp*SzOxNx+HZnT>kLS7Fy7sM-!I*TOD9x0Knf{9 z+`~f1N`%pE74pD_!NrpmX;&OoL@O~F-;9bH2MYL11160u7GY#Sp`NdqiS8p7E7a^R z|MU6xoq6anCk?jEoV%aC9|1F6ayg~tk3Ie11s(TZacY#N5(e5Zj7C9?>R_Vb&X zP`18BFbTo3n`|lN&I+5}2*7eIOucA;!RmH8qHVTj(E3`$YdUBpU1w$uSE(*w^-VLB zKzoK&k&3i#bi^(D9RJh(-tGGt`QK;kb09SXFVB7W_U|J5pZ=FoDKElIdVGSan0n~y z0@^q<zijEem`kx7*S;V#Ih~0sK-kAaUH72Yzj({6szPF zqk>U$3=(zAT$L#vmMuxMQ0yY$npTW2;9d-+kY)vSm4r*~$pD)+B#3BrN@m)cCXk}B zw#modwf_;@@AihlOxL;3w9kPQZ~o(Di*{JL^WjfNTic7ry0%r$9zD9lxY{RXnwcnm zATF6d>ExT5h+oBd^u`wU2>Aere!d8PZew%Kb*)1oEAD;75di6O@v zVFW5&=}BienI^hcbZYQ4Q#H+KeIPqTc49O^RWn%=h=Wf}oVYXrXy>hzefs5%7v6j3 z&yPN#zf5ZGItKp;JU9QpM}2(Raewu?+DeKeex%s)Ax;1y(l4nyml|PMqtJLjhJ;3z zK~%ao!$a-HC7I9!LzwH|UzRUi#M;>N2K!WdQnGAxNpPR3Ye8$;f-c``n{w!_dmk>% zd`fweEAyGIlZ2N(15&fT=zo8D@T?VczuaS(Pa>tPz9{SdiL}!2a|WaEW^_`KdZTEA zu-DN69v0RIp1!h6lWE=yl4&^Fb<(JKe&a~V-z-YM)bf28QB^5^H+OgHsC+|74xo&xNVFV(@5fAbioMbW3?oECZuoUnjpaqJi7)bye+{7p- z8J4LFML(ycqKcgGEG#*C$b1bq1TQWW2%w>KN}fsH6U))h_y8TQ1sxf?WyjMV+I8CG z?XiVPgb>2oVD|Y>p8+ZQM&DoY)z4OKbLiuR=}dgML!j8xW;VK7y3H<<6Rdi}%gCOv z?gO>*v&xg{3Q$3@J(?Nf7+6{iCouT*MH7X00kr^D+CDVqC%P)0z3<4K$4;Kv=QEc( zVQvHffCZvnIdA`2E57+^a@@~E3v3Dro7F!RTU*GFFtaGQ*Z2nz6wS;j{<@?w{JV1X zn;B11YK6`8RJy7PB88&==rWM|OarXcaLcOy;+myuMloJ_q4IV1-A>m2Ic{@&i&w$|NQy*^Jr&FVrZOYM2XVTz5+x9){q(|#4ZD+_Hh3gSx(3t zg?mkWKopbK{#e{=!X(E&XM(~83$A1b#svSAY2l$LzHki#l^-TK=NdLX`qpcI$9rtcorxPiVmF`VlyqFwWFhL@y9&Gil*f}b?Xhh!w{+I4I zSkTX@wR944vofRfQx`u0z;fxA=f&LU%zIAWYtojvD18pg*69c^qOt^*#A;;S&bf7U zlkffKomUjUd+%OA9V;0nR*CIFUZk6f{L0U1_)tUf07WG5E{(1d;R;SjS`^?ZnUf|p zg4`IEq;eO?s6Ph842hJ|&=_tCJU7eD&v+K^R!ZU}i>~;~+;NHo(b`HvDr@^S|2?qxk^@RBoTTzK56NA|@8<<5~Cfz=&>R@yq@-iIDLxABQ<4gs$- zZ%AGwk`J!P)n_s!O5^`QD ztxg5D5=_z3L&0lwG!9k`2cC3KzoYN@~W}Voqge3`}gIH^%{_xQlQ5tZv9PhOV^0e4p?PUoS=Lu z%4E>MrF$z$P*WzqH0yQaP9^nF-{I|UgN12@&%hAbOQ00sYyh|#4P?Q}NPrbl0^cMe zPUhb0et*PI_Po9?CnAX*8|K_c0PdL-|Glhkajub`!Vitu6FCeWW z6C!vUj_S*x51yQt<1_YBC{TrrQkm`s^Of{TsRVc^%!tlo`x5hWLAjJ6>yoZL-1AzQ zAY@T3o#5?q^o*1C-)5J4WgSzdFXaghz4g;;K#CW9-p$usvG1SmyRh1|Nue)$FX=f{ z_a$7=m_ea|jCTqHD%;m$(>ha;fHe%TKw*Uq&{18{ zF?#mDCygQGo8Fp`+;MXw&=Vtoazo}ref^txzkU7UL(d~_XMVozMT%J!sR+*#l-5^> zk*eU61X^ygqa?{x(MT&%F-eg$qmQfiSiqeiqxaa~L}V<6EKEcu8qr;gtA<(?SNA38>l1F0FMe{}Y1TNVA{tanCtx^b3EA2t=tiwi%o zf|^qGt`-|hpyc3((u+X0k|EDP35Ja7t1^00wE?n7u4?LK0DZ~=XlFU~@d(X-`-wkH z9X9srbs?|#p^41BpBsVyH3A>4T=e^=&p+^7C)He76op7(ghJewK2y_NH)>d9F+#a7 zlye~D^E8W0vyXls!{xFp#Ylw^pU7kyeh>1vL0>NVXoISPfD6u03bbV`aP89Oqpx~n zlZm7p3q$u>PJV9ysj7JY!WKJyLRU0wGRCp2p_p%ggKxSnB^qi;g?zF}GeRtoUhnGsyz0IcV4}}zYm02Bxuez3(kN3vS0k(NwwuCBaE54kk6v| ze0w3&3}-HxzDzCf=lei@4`UUka9;qWSschHI*r9uq$P=Q4b}b`iA=zCV6bPEb)~CU zDH~R1P_;V*>f4E5RXy(0i!Xe03%PH5O{UlzK+4m!ZhqnMBSxNZ$$jN6jaEAV#WI(k zXF%{V)shRHnIudF{x|=SPD2YU*Z|m}`Jhb>!Dh8qEz7i*&J~q!j7-%yu4A#L+N?w# zKubYh*Eauo`DY`NLtgLi8z*;tYd-?h?j1)XBUT1eAp>wK>u|Odf%UgZuRs3kE4!`z zS^MS)AFfz<-iwzVenIQ1m4!nRB*HSG;>>5NTAJu`lY!u_ffS}MG>{b-Qo9KLgNDA@ zbWgWOSK@mEJXJ7Dj=4_z4w4~LBd)(A9t52ZKx@W=F4uPU{^f(`AF%CCH}vKR_c)N^ z#XeiJ8dJM_Fh5;C_z+!o35gyB~ih2PY$LAdo_bYcrIPU#C)1&N9J*`@zmzP zDl?RS2Lzrz%0=f2r{HVPa2H-%YwO|^yX1GQS1mhKEgFb$JVx$$QhcXd8AdvC^Ix-fd z++^!X7rgkB&4-QSX{5dJ(_=ttM(MA3;MViDJMXruM>^Chb3><4i!ubFQY@yyE?Y3K zGaEFrnv<&?-583`E;eFq?Eb23VlMT=}6&PVzFu;XRPu}uQ zkL|0qy|3{1O=dcK`GVg+f7vh2PqjDZ=SLt?8V5)+`JmacREgd(A}@9=+j7hgip-FY z6-zr+Y29W--(ZfIF3K%U5v@noD}XYTxyW1p37iN7zXI*iwNgMAwiXWq*JI3-KyxRh zBe%QikLMkF{1rVtrlDcznZuuZFPn#1(|t^Ftd@j6#(_U9i4s&9Vv>G>~Td*qpJ zS9@Vm)QuFzMQ*+=3o(nmDem9L{l&pfydKbhDsvm(!?DD|C5CLNn|&)JP&%Svx(Cpu zhni7Ah$O(Ws0zP6`4b3Ii9Oz)wxA^yPw#)?%suzocuQUox+jTIk3KnHS@7SDJ9jze z!?9_asB&~QdnIMUC5lgRQ-7vJ^4Y?9wHQ^zU;9?DPco}26A&1Skq)v?GsVsHyQ2LD z01Xie%VW0R5Vcw-KL6MuQ%6sDxi?IK{=C7~w`-gBv;A7*zxj8ec)XjNQN@DAY6@5~ z8eGvu#6FGDYI5l|*F5(2YZvs_u|#INn9`D^^FKXj)|J2bwGD25!geAhaSC~?Td4v| z35e1!Dx$?mLX5soh$ex!hS3sQZb=1@Mv)=iCI!b|uvOfq0Z=vBsgbQHK4WOj4M6R1 zY-nl+KUq+*`1&h8=K1)nun8fgxhLjmt%20^jlQ<^?(b#3S+>m>&$h}~Dk!fwBPhH` z`P7mm5%<(jAT%ae=Al8l+XwcMt#C<@M( zzdz-c%TN66Sv@hxxnuP25jgmX3Th>~Kmw zU@Hd^14iGkA4MP+kGf#cOB_)7UzI;KSk0}|v7kL;LuVS?F{3tm==`%@Il3o<$7?;& z=o@|JgSYoB-tXjRhIy7%;8BQUi9!T5e56b85=mg+} z#4Vt{1x{BHbbPfTWZoS5(9{39|A@Z2p8j&4L!K{UVmWm=%D6Oh(RF!aLv5nAaMrEx z2lQ=IGc#wt!ovjp^#_@0V`JmUr`~`2%+F_>bz(H?=O@6442e@nM)Ar+>7tU6V$ex= zI*p_o#RjF!(Wqgefmw`Suwh>i7c|HsU>ZJD6&o?6l!{pCU?4k&=Tn}G-;uV#b@Q8# zI`#R@wi!3>+n$=2wFXkWkasrSd1=v#`jOSFgggS7e3BW@E5p<_p6O!En)~W|(|4Wzk-v4*WNRLrnUlj-H7AQk194$rE0U}*HLs!4oB774}4GY!S*J0U}GV|pE5pAEf z09Tg31R)_Tj%p>jLaXXgHjef5i+)Y4$0Ja8SUHtXK(wmEk64KvoW4 zX%Sdx`%c|e=U@NZ!;brXe_!~kdwu(DcicxKPkVAQ`jWCAb_TOI0&%`?L*27`!_yBx zxW;Q`b+5I*e*Wk8jHS^k5!nwv@C9iIxtIVT^X^1=>aq_9)YvUf)$M)XxqHpJ zR_uGUoZ*_G-Tlp{!(fntNg;=nZ{Ul3P_fUw;p+-8&~PDVaqDQ+vMi>$l00Y3t55%8 zQu*+wdSY<<+cAE5*^abm%xCJdf?yDog#{mO6w>WwP=C)(x6hh=->LoWzWVBV4!n9x z8r%FUB?mH9B6Zrh(uV z-Xvj-^K58bMV-yI`O{IqJ@TYS)^?oNdV=5HWTzFyD;tJ!-Kg<{zDyy|)dfV&K{kCK z8q^pdYA`nQeZ^;VG1u@DNk0osp|F`*q1?CXnaOpd7J)k3r*p6Q{ljPf;+P`_b6e$O zuiKpF4PC0Mk*i+kK@FcF$<;Mmfk5r!2hgWx-XEOowOxe+4K zmK0f%Oh|43wqF0Wck5d3v%Vf87SW#h?!Pa3`_ALfFN|gqB?$r%#!UIW8l*&$8zeqv z`wa~kDnnFnD+PL!8YJ#8o=-+$T)6aaC`9>>wkV)Hw_~gQ>GU1-_Qln(F7m#sNW0K4) ziNLYtlMxLmKGf2*(gIjzq7&bC@N?f`_w=8+Gfe}@UJ958dZ7tIEDjIh8sniQ%#?44gdP{%WJiE`WhH|;(QE96Wh!SC7OsMhXWwu zHL)Ka-KT9pj#VqA8{YVjzyD>`>zD6S6t^RVF;D4B#r^6Xs7!UtY?60uM%@E}D12Y- zUG4tU!6KbT-W{{luZeNiz=_socHtwOCznO>9Sd5!Y+6<^_R%ZOe(SKc@s+Oj1e+l9 z>ejn{PQR<$XoN$oa%R#iQy$a0G-VHpnYBsHBY|o#P5-6zk#bW4107k84wh1 z6X}zZE2jC&E#Q$qy}sJ(XCREt_g&+G97w;Ak$c(b)))b#5y8MJ1?SGG&diyw42T?j zMLQ@hU{&S6Nww~O=}lLkUHZlSJ604Bs~{#)NJSS4?T75ntnU^?Wm>3G--M&>X5da< z4DR)C^d2QwSgy~EoM6OWIr_5BBhacnWkX9>yzPin{yl2fwFo$^_C{E_a%IJ^VZ-WP zn>%}2Y|oQs4oy?5Kvurj6uleAG!6<1=FvZC0;v-33uNU_7$)YIKr8B%YA{76ii4#m zM^$iEQF-*+hJ!6DBLK_t6VB*YA3JQT%CR#C@cNMr*#8QOMecppnhKfp_;FUo zPx?ocd!Rek8c4tqE`Y$E#$*7-zA(*ImE)5Z7iLs3UunvM`c~o$8?n({*Z%JH)7Eqx zS9@}?hx-Rx@9}l=o8>jbSmpbGj!rBfB{?#L&cT7!LC(P7t3Z_uAW5_ot^zYn&nWb) zz*SQEfZs;be6j9Dm&6nhXtycUS(K8|qrTbuwU=rJyGb8jB)`6EC?&QiT%09|3Vb*i zR8WaNK;XMufByP2v+o`-^*Gmbqpa28))MnMB$*iQ>d8(_BUALj~7EYmtGm$tt;Z z%3f1}E_^?X2Vs4=5ydww*LKH(=1$x1?26VNdD<%*?mK>b>zepV*JyG-u3t1^`ILh{ z8P(|~Duz7Wwg3Pi07*naR9TZ0DRn~mM>vRtkMO|jrd+{brP__G8HWQz?Ogy`>Kv zlzQ%!yOaI#9((ede*V|ZXmZ?=plOf#4_xHxAuks#E9K_I;9t`l*J!Wx{8jDa7a==JFqM;gtP{9(D@*&A*j?S%B`S8r2fdGk@B!>_k+Q{!sCX17(m{N9rz4Qzi5qohJtc3_GPBQ$t zM}D*OxXtcZ-GLhnpP#nRN!|trJuW2FhT;OHDgk+!+ytUcj5fE}_qtju;NIVSwMJ`c zAdTZe*9#y;8%O1c8-6;I5TKdw`8GUyK=Ys&pC{gb_2#$kIrfyi2#Ms!9mtEQ(GZr6 zAvx+cNMvZY&5R@AUJ6=4fdl|NuH4YN+FQ7YiBYFm=KqUzY!p%ICMk&fN}GIV^oULV ze%0Bp|9W-T<&U0R^dCO><_ps{IOOanCZt(Drt)6!^Xlk($gg2wW7tKis>w3%oS#pZ@e^aOV|wg6OKl2G6{Stn-+N~~b7S>(-|N+#n7;V@0h5nA zX3XhN-6tM^C_fYP@&D{yd7RGG_rITKncbKfW6LgN4@IPnl0?}e#FvVSqA%LN-@g6Y zzkMr_Hl-q4krbKmEE z-sjwNp^1z&!1suFAvH(YFj!P?^Y7`==IupJf_latG5H*$Hj0+rho+<4|}i6 zfzx_?HuKF%wVYbnzh!1td3)x>HwxE|?^rHQ6zT^h`@?gUNRLuGdNDZ>#bD_g)zvy~ z`$DFxa~szAPlz}~7SOhafv$!FW4so8T)l|-xhhqHa7cX$5=>Z%L$-OE z7H4+H8I|~p-0n*|GpY4$jB@ziH=iBe|MJc+|J}4v3Nj;KPm$6mEx@Nb6IMjvd=b__ zF0_4aH=dUE_8DEM-)ll$9$PUTlON#3frZj>q|7wvIPBfi97rjstjpNaZ^mOCCdGSm z{Rz>csfh+ULRj2-yVX=gSe(=o09xm5)N_QBGJs*2 zvp|TkK#|Z&9bUQizwdtR*5TuiMJqjOAQd-WzIk2!tSbhrsh$^zt`zh{&dif6CY%Ur zj(R2GI)bK=_nxnfTdJucdNzOoJ{|Ar>LWPY<=dRo5j0 zh!YzN64~p+wj7f^9m{z37EMvc?@bW9i zb-ANs@6V3bM*r0CX>H})Ms2pl>_1SgX3+7Z1Z+xewbvq(D%~NWAc(em`rhabpE2&)6)dFG~ z$wj@fr9rzv7L!z>ac&fQc}V)7+SBojx zQi|jO&oYUu0a1t9h6%cC40A3DEa2D{1jaCiYcldQSqe5RZ>w()Q7RlWtuV#x>4#?* z$2T9!^M!oAq#q~z=a**k=X#gdk!<%*4Ig$gy|H*s-#Yyso>sYtI|)I?#7;3viM7+g z#b=q44EJ>cL;u3CSG&a(yb#rxfPaQ(^-Mh&Xdwv3E{`N@#~g==(?O>U>9zWm2Oet$ zy6^EU?la{(_q?3SMF!Lqpx8T4(DTDTFi~J;N{oGod)W9PCDX*X$MDX)LaXI=F9*VQ z#MAGd+PPr-H_Z4W(P3>T!K#J=DS-dJD6F@rk3#!lv<^nvH3k+Yrj3`KI%W<2RB!G^gCUV^-fcVl z`)CHJ#8zb~x$wO&rE=)b1=^A32^u7*JY&Kogi-ML++pKxE16o!{?9ezWh!jdNsY)+ zjM(jxzTirhHofFR{Q>Wn<31M9y>=ClB1?v2Nn9YI!c@+tbUU*cDUgsg>6?1I|7?d@ zQJ%w|Xs_s7Y9D$@w{P0#&uehRb?*XBt?5|_XRIr=@1dd-q+8lfY_2_j+)?aN zxB+#ihYovKOl;Ma&))rgYrw$2#7N=G^XoLrseULBUs)F5+Y1VBKa=|tbO*tV(kzrqF}8jD$^snJn>L|VwtS=AI@(i`UM;fWiKUoS7MKG-^=CX zWEv)K8z6>Zm_*RVCw>9Don-i0azHxp#q)T4l4z)`77IidYHGDjX&~D(?`oblb7qND z4-A}@%srsCL6`~bMhm3|IE-zIv6<5S^e%sL8z9Z%k6$ol!lqB|ADj}$J#kVih5U(W z-fRP^y?MrD)k(8w5>Z;VNlKthk~Ff8sw{&LD@dkFY_gAsv2|L;4&^y4w=h2Y?MJpG zAI;+XQ${K-^2!(Q-dtSKZJ4~_W0hXxLN>SzY%@9>%XUs6D7080H^hNLi# zs|M-o8XDkQh8s93)Y$`OpSyh0B{tVJy4PXbqWyt7pU&-aVU^mY{tTTH2>``it82@lD;f-#)!J-U zQ1cabjutpOS{Dqh4YeHu#!nO-S|LzUcUYh7Hc-Txv?bxt^oJ5iT^n9M5H!F%tnl}$tmvb2X3Y8OlM+vioecYtYgBjCpSo<}|CY}fJTflY z@rlG!oKL2jEUYj!pWuWbIR$MuHGzZ@N_R#d>qa3mF^&tf|Jvz?X{|&;P^5t-z(`_S z-=iqVSfP|L%WoZj&-$8wHlD=-DGhs&bg**8U0s)cRpo3*uO^`Tbwl`hSIr^yz)*?; zIwWw;@I-+ETu3-FR#2G0Ub=hhQ90&6GfMaGyZ7zGt9JM_yh(=3jzHrTPrZM01NQDC zD^BS141Tw)uDPYUF}CW_ftOk2rrLzi1F`qs@v_2g68qFSfA0*Q*r zEAUQl*0pP=A8F%Gv4#fO`Z3er9DV7i=bx(%%}J=0 z>u}!eNFwZj6v7*JX%4S~mv@&<;Xqqb0d4c<+NBVY9fLGtz) zcQVoGyXn>&c=aZWF-p>>@?hA6$`hXNuB;VRZ^9V%XVqjA|6MYNymfAK%k*=H%ldNwO!*ojY?ZJ9gkE#RsfgI=EmznvF+A7F-iNFS7+(1!f-G(y77aQKVglj zwr6=1q+YDz9ReXgEBLeloBhVp6AJpr^RCD99if$q?of{7gckg~a`?xu^%#>B7xa~h zG2Q7^<$`%V*r=nrwvjqc>KGx!mr@jGAY){g6V1@mP+qG;R$Z&G z_3T`S)vfx>WB2sG<&lhxjLPN9m){*}oQ}ju6CKAnxVXv1o0BuLYgQsaYB#t*NVN9P zDt3SYn7lVV&qcCE8pk6$btk9vDWv3D5qoFqXv;1~;q0)(Sgwb$Z86b-=0AQ~t+rD! z{df%KO#IG}doSk|&iUEykw7hi%n9}S2&Ry+XN+z8;Y#-2n=?xc3`R^$;qrt^X)`+d zpz@NQAUgjCGOMwv_pCdnXS%*^_kq!u@0}E1e-rcj4>L!1iL@jS6xir7EsCKlGbDS@ z!7hQF$^XNGhZA-g3wj-v_i1A``_*N~^t`3bF7JJ?>27Z@vr=+wFk<%HlspljC2UlY zE{KS9=ub=C0AMLmBekN6nCYm1bnrJ!m}~+-sZeX#2-+rDmXq&cPN>|Tm+oI*`AAhh ze>!RNYc$QRRuGI6Wlx4#A|ckbqy|jQK)601!RRgaNkCN&w%m_vk_zUIhSj1+K~N^y zLM>`%dL6dQ!$Y6n+Uu>C?|*zqX*0Z2`8*?^tk2_Ob$Of)4cvmgWq=3<^ngM&=08vF zyCLg5}Fq&k!v_SD5xtpu9nfLzkr|Yt$ z#`$=!D|S3JavJ5#`|;}mOD6Z8Tt1;l!l6|tk05A={qFj3>5yCp;Nh|Eu4^cHiIOjp z;F2$6syrktTi>TU^z@t4eyE~kGS94*2|GT0ee^lxM+0Rci#t6+>9{`$Fz#(|VUo^~14@ z_wjyK0P56-du8}|R!p>yF|VvE#UdoLMoB4>v^@%(vJ1X@oJe>N52q_4&~CLIt4aa= zeOFbGf+UoiguJG%6GuDEeIqUT%E_~I?883$^J zzN1kHWzvlFfatI5K_DgihSs~8C@~!DU5Isz5$ecLgEFt+_F#DOC9HlDKJE50mL4CM z-(t?}bBbyfh3YzW4<4_PoN3?t&$H!q@&p)yF+QvQjyh0j^jeldP_uQef>0dWG{19T z{ui&Eumj(28(*8pM`!DkPjwAzgbBd|+4Sly4x6aP6dzaEN2d{_8P$D79QPm(yaw~4R zK|YI~qd>@Efq=t2PWkllBY&xM)Idrz+Fw^|5~!0OlC4{n*C31!A6^41SR|hMsh1)_ zcmjpG#Kv6+ZnOSJlxR588|3hhz?s6>4 z7PY+qxH*h%oY0}8uZ-`5@;$$fkBd1-w!@MnCPJ4fw}Xmhuz!o4MgUS89bvr#tQkzU zsNcwfa7>0MkO_JiJM?U;db3x4c0?(nv^(_82Y1zf<-hHJ@UiR|m2@hm&Rf5TIVwoE z*8@Y+tP&fJ(8Kg7leZ#K9p>wM;$C}VBliA#g9X zNIfcK;T$Xgw#!j|^D`cJ=Z&u2T3tH-Y}u2Uhhg_z$}5!r)g+pzVd~&h7QS1dk=ZK( z?$dH!F#Y=286o-$cDjB>r$HaDdVTU=0f4?EI`PU4SE@^dEh1b4#NitUU+DOlpFx)$ za!d^@9L%KKAt+oy-A}_R)ip_D^Ws8vng@_qA)8F7L?%9${l)q0{nwYA)@&5Ej*gi< zX+g%f_jgVZ2hiyCtnwa^Kq944$PP(;DUO0&^9d%V?9OP}s=*8+p8a|4s}>@N z8jv%K&-@ZtALfim17Ixb(%PMAE-Z6QP#HiN3}oyT8-`x8HK|)t|!(tLff+J8n zv$R1woaJPtvKhlRoz@^K=R`O7_$h1ab#Fg=+1wc4VNaA_Xr**~X!|_loM|*1vr48=>%GA;S9e%7pbEba&`ewHcEZ2PBq+0cqV?{@#Ul=q-FboXY z^&HS6B`8zFk|b>_ZlKF4D96U%fBZ)hcWymoQGY2zG?Wg4@mxz* zi(TMs5l6?7^L8M|!vgt9S&#Pr^xT>?YsNZ`W7U&JoV?{*)?a+^(q2oe2Dm3RM33P$ z*>K7TX*L}f5HVV{Ugu8l>R`4%aM#VB z3^=c5<0a*f21wUl+IhKev+7^b!!bE)v{qG1bb%Z=^uYSh|O??J?fNt z(Vsj#pgBI6m5ro~(|8|R>*X$oP}xjM|J}Q!C^OcJ)s?Spq`lLswhOj&^0TL^VPmCTr8BumhwLijCO}(*QUKC_r_VnoEZ)`I9 zrHb6kbVFQSLx>hh7Ls~5n^DMx2pCMC6)YMF0EBU-`^hz&YIEA@G`z=3l>vh0MMf*gn}5~#e+uv;C# zNU{*6A6i&X?OXgC+CSn>IRIiep)iqHZh`0q#X?E(RWqKr`|Imco%q#%3Z!4vXd0-O zU*t16Ognsz*vk*Disc^a>6Q4aw{5vJ3uG2Z!|lWtdMY9f7<#WH2NaiGA=ySBFi6l%kV96uMI86XT*}vg|wo_A|(e?og!Bt_Q z?#)?{`PftU96O+NzxI~kIqjBt5~BB+^t`^OWG=KUhS(w1=J8!z$4lV2xC*!7=eQdb z)O(8w=`1lYWY^YJkP7?_sNl zo|jZL-Vld7m&Sl)#B z6g`)?4tH3A;Z_FToZ5w?NSS~-<{gWNluNv$a}F=))V>!)!S&ce&W z3X)PaF;MDFs5FqJPYKN_6TfrNs_(0xZbo;!&)fUr;lT^8nCtO)0+<-Gb?0JALagwd zf-01uksT#e&Ouf|lLe-r9~KK_t;KtNH@ElR1heb;~A;Z+6{4R&?CKcwNsXnla`Z&9SRAkECI zlA4;jb8(AHGs~uDm8)2Uuc1YAqYW8u04PX|6M2Ktj;t33E>FUF1Byl$m9K;YtO40w z08N>&{!~}DD2+x-ZrgVpsgJ&K>+ZiTkP59dKOrG@-1C>LkM(DlO-c|WNZQ@uJP?NH%8$6C z3@QV_za_iXOjD6C>P&6?06bEqyvjbToDE$Q1ORqGiNEy4BxYs%xZkO zO?`Q_Cd*ljC(qV$Ns|j?D3DOlL|KG{_{RcuV>^%~2Cd$%bv0SuB9Djd`MDXJ@zQ4z z0k3P@8yD62$LH;&Tm?4;CZm56R?Mwd2Fu!CnN2wjyE&aG8waiQzKPG@pSS7Rr&E(* z=JZiE;zp!BBH9r;LZV*+sL}qT(q>KMi?-~t54w>86HUz7W|#eDB~PFFTx< znDgZ5RXuA(r+g2mi&7v>_-@CBKACO1O{h}jc*?<%BKkoAK4~?S0X_|yWZydtxAEV! z;|stzdJfY956u-p0cfmU2M7sNOlUcx2;X5_{N9}NKbn1WHDA&aamd|?GK$i4ogU3c zY;AMp{OW#hzA+@McF<3XAuy?Vi~u?a5D^$YurSN`0BlKP2<1?J9=EQz5%IK3_1?mv#Bwg zI%e?^8Do!YdKJ{}`h}_lEXI+;`x{GDpWXG{`E2HEU;b?wDVV~-A6B(|e_FTYDP@Dc zC_mSyjY1?rdb_zJ30DHownxJz?dVlofGcXUTKZ|5!%{!%=p0QOX)`9B+|0@GutSHU z10x1~d4I(!_1*-cW=-(g%R8_4{=T_>e9&Q0a1K5AV9>`9O?38G6PPe+Ocn=SBu4ju z`advxqNnP6NPwjJ30)d+Db=ce1kSjWqQxO(6JJpXJ6&MuaYI z{l4RPRFSg+D;H2$B_Vdg5R2&bHbpgeq=5&9_NGSDczT#Y5c!SK(nvuuVWY1Gn4cAK zKa2I`Md(pULvy0jViOcQbVt@qq9N3Sl`i1g0HT(k0zw6K*##BYwpquin4?4S zIBe{YeSdp43Ty9yXD|O`*Y4lir6zNKLM$F^gBuqxNo_SHf^5ASWrYFCM(Oruz!AVB zx-QW95xo;+9`!kxKNoSMy(RR&^AC$g&)!gla<#UO8}d!Bu>|E7ajSvqs zaM!nh$w&i6<&xB#f{E$t$?K3qt>89Pqab--Gr$yZ$pW%6|C(+5>SsLT*(d%vq|*&A zo+;o7?=iApSAK4#RjyMBw9g95d=fTkF*};IHlSvQ?k*i%cPvs_OxxIuY(q2lRL6#+ zVn|LD?14laCT!MB51FO0E@g+50h<}N7mNN3MoVe{4u;CIt?#uSG;h_kW9mfJd(gGK zX3JH2Ke)QKMKX{@*;}ZKd=7hY@afy6`9!WCk#zbYe}Fd zavju)19<94OWB=G5+d5B+TEig2~GS+iClQ)g?nxR+0@TNx}G#xloYsU#P2B(@uIi< zG3Sq_nN7Q`sh1a2%Y`gVB$y;TGGy3v1%mp~Fhc`2LUc5$Zz4m9)VEN7*Dz0*UagNf z9P9f8ux{`(Uh(7k-CI|wn|2}%;Z$GiKet}WDO4qb4w>)z4mYwbA z58Sb~L!;PAUl535?2A9vTpeoP|Ko-QAtLd+G&0L1Xaih#sS|Kb7rIl8iDp1i&jUl% zOo=WsTAwEef$U}0bYBeF##moby=5O=d|rHYYYW$@2EyaLf6qq4Mz+3e>6nD5eYSI> zB_i0=ngANeEC`OqvszAxB>POLWM}p1?jZce*B5V=2WqXvhpZB9L(I0{LT7ImZ%X9o{>*^nMz{rA#pjUKds^o>tvjjl7~ z|DLT^z~u|#LXiv2ge>xRctitq22u!*dKd`-VW3P{28%#FpdwW6vJwKo`daqqw5CDA ze0f@^*J1n0CZ;#|B&~hjGL?ThUhpa{-@EDJ5uuBlr#W6v5eaEc;s}k9Fh1pljc$jf zKNw9I?=43Wyfav)He%@2gIRS~I7>AtT2{2L@Eo>&$>oRUtr(klW0xVk`33W>Q$Nwg zTKW@}1@zqNNs#)uRv^`nG~m)2W6S9E0)rdr&+W>t%_cs%5<#tVtNznts}=T%O3rl( zvSV3bn`h9xRWl=o{Qd5{lGmuW)=HA8u{V3OQMZ%NqHcbms4RQ^?mx}~DOpfYO@8@? zEgK%2S)p7|pD_qkxwa%2Ddbi_X+&>u{8SgW#-j=Bhyw6CpSMC_i- z^|FiWy}sbK4n5?7k2uMTF7L1-_K%%as*%$|O-VB_9lF~E0FbaxxSIY^ary&2ArQhP zLG$Gc%WH%)TBAv69-}`87@z6kY^R5X*4}g1)1wCVeO2tzDlLF`tk2QC@m)V$)M{0; zlsNSYZZ9gqPxw1bC;>RqrVE6%!|}glNmHi>G7g48E@>xB4@6KkhIg#=-(;csg$nLDlXlJZG~4vj#p>KtIIKoDpJ3TZH2+z}?mwl(ldjTC=Ml3SXQ z5+Xt!B(PBveHnt6o9kt<(dT5oI(S`q3rIh2esOMc=Ki=!L1m)mwq$X->j!}~&@0he zQ5*a4|^F8mMMH|*k-wfSWa>VKUi;Z{Y!qTl^^t1Dk61!@=mVpcJL%bthEy$ z`mQd~wz$LTKrf@9U|r7|P?KCSdWc%&dpr)??)L^7ef&|+n*M|}<;s=Yek`8yRDSlx z^GD`4Yx-?W#n>&XtO@l`%bnq*W4KPT=?V;uZjAfJBK0Rg)@R!5MLM3rl4`Uq0O$(M zYU_de?58j5)%$Gy(H$W&bXZ4TJ9UleKS`Q>&^cEO8Q3D&lLq=?b`rrlFv%)ZU@_FD zi7d*p30%voZ{O9BO?u%g1i%~nbmMheEmIGG08A=dXvG9sbUU}zWmBG8aTZ8ji|gk9 zjNW`s^5mL02M}iy84ny`*zqF-IIV;@ofjZsv?(;q9Y)Kr1J1Fn*G~u-g#lCiB$`^r(BSBJhzS5PBdtvA_rPQKrRgy1_zA~ zm?5M5f_7gt_whtFZV;$m_xTl{6`#F(T_?#8R95-5wi_gz=t z${ST#!D9Reu%<|9K!g?2BZFaVEazh8$TW;`H5_q=N@2zOc1aYpCq$n~07N`l(DAZw zR(IvI78TDzi+ktmFCLzILAwv*;yigqJ9U>6h1L536V$>#)q&B_b=P!Pc^1_%r6swl z1(bameNJ3XFyWnh&tq@>Pj#-pp;Pao`d2OTLLn9kViD#89F6#U`ych$)N#ws0;$Uw zo_J&Y$61+=cl3!JPCmN(%tTz4&QJ7knsfwQu#!=lOsEYL%5GF1fUFbpZ(ANXa$7`< za^P4KS=YVxUl$}*e@agBoOR15)$TlaV0?%%$x|tG(UKLppp@RA9+4V20ILlIU`1-L ztF9oy44fI^FjgzS2taF?7A>Tu+TQP8hi6x=ysqmfi@KL(ECZSelr{hz*z)dBle(*& z^3gjP^9I%9xxA_J)HHmgPRNY2RoX%JCaaM%9#=JXR<{BcKn=?{NC@~f5bJhl^!W;S zG+Xppk7pLH9rKsk!u9KV3vbxu3l{AhR?ih?XEdpxpPkr*0W7pITrieHr{F08)A)F~ zz|fXSf>RrfI378d$FcmpBvv7Qm;SD1y2xzI8n9N5!`SxC4cL@%OV0u+S%jSP#0B4c zIVf#m{}&SCi#&1Bu)_%=VW@-v=cb2`Bt?yuZ|4TkDH82FjJ2W-DMPUHIE1nh@*!uK zCS?(z9oC`Qg134!X?v^u__&2Lmh`;!@k`;uD$Fxx;XVcg3?GZ|C5wX5iliUGwa8XQ zvasPn@d_mLq#`sdo=8%{dN1Qe^&6!1nKif6?PwZ&@d#eO+8S0NW;^qE1L0tXVL7Q@ z2xDF0RS|N`t*VA_paf8c2{I=S&<43=&SWVStqV0p&*FBQ4>e-XzyA3N1Bad+?h4jz zvBZ-cmBGB69*|}&{@q(DjD4lu+JyN0sQ5UM-KM3C;gt}S1lSUg zO*X8ZPDn;z&NRJ1+Xi<_n$K&%L<`U}r*=`Ad#RPEe%YY>Yafp2bYmC!zk6SQ_Jv;|w@)>Dyfuv*~)aTkPKx{@nn>&GNjTtOHQb&Ry zO`;@Rv@j=XsqNWcjlKE!*<=&7flS@5^Nz>QJLvcAFB31qU`r1VXN6&NL_bfQAp#ym z9Y8WD5bB44<9C4KAvi{e-jGsiTM>0z;weRGUfF_&mp^ms=(cj^S2SsTuxi%9GDfci zq290&VM>;P5)IVNdX5~b!nG-j)uF7sChb3|-r6u_0y26LK(mA2e2jZ0zB#IUOS^OR zu`J}{`E2jHLswkdrj2w(B!P%FZ|vCsHh?wl??Lbgl2q=QgJ=j# z?>Niec=OtKAAO;j{OFPfE%Iv}Ivk^wH5A{~BT%NKhgu^u>bb6DftCF-44QzV%frJ^ z;-Y|9%m$xu=4f>(c88t&c^NkT-p!|EyiNuv z9?w1CNTb)&-oIt#y1OQpPb$LERBNFaywOl(CyhuRfYd%4CrdkiQQ3=T>}_IaU!TCA z1W^<-QJ%}sDRW@*9ov)SB!5}&{K9kd0)CC%datVa5>4t*Xf=kTi80Bpp{I72C15H` zpUI@3)#wn^gQyTzdVDZPS{g%kSZ#{+=bpdhtE+3qm0Ny16MVei8Q%6zepxlKdxvDc z>3&}wDyj*h-H8lSrCJ_>qj+IB?NGn7G!SbX?6ET8F6f*H$LJHSI#6;w0Ce!3U|yh4 z3dgYXa4q)4gi~_{`(1an<2B2!w}2EKwk`uRhwz1m^E%j3A(@^NDi4Ss*^-Eze4;r6 zHL7acpd2TybKw}uiQ?>#H-?QFz2hv9Mp#^*ty$iDMq2mp$|u8CQ9FNP;FQjnX8pA9 zE@{uxH4aDQz6jN!ZESo7Uv$ zRzq4sKniIiExfR>3(yytE7APGsKLNpbz+(`86ePX3s#gURS}oC_sX{4OddOaXay%> z&GCZb@qX{U8|reeuTXy7IxRql0tU{=mRgzxgz+JXBOF&(=L76`g))H}Fbw12o>-Qq z85io(bc-o5Uj6bii;cz!6&mVuD>q-u-dZs6lmNp$qgwIGG5SzH>P)05QF{$9= zf8<-bs)8m;AqqAQk?P!d6<13`BlnnNV$8b0G;YK)DH2&)mao=C*50VXS)=wwJKyg5 zHZ}8-{(Bo1dT`5@G6X`gp%O(wg=w6tT>v$(aBa@sLn})TWDiI18v5x7ONe-s2sjl4 zAkFCXB6_NO=edvH_vpiQ%9Q!(&nECh|9)_byLqR&bM$2)+|*ne-jx&w3vVZn!O*WB zNk0wOH(}=n2`@;m0js5;`@C)(Yf|n*%cX!d!}CysA!S(emh}E+!P*zvoapg8n(O`h z{zklU7UZ-59nwdtYH*c-!R{8cd$&wLsw&XI>9ruoT~|6lj3J{d$6?|i z-Y4!&KP8UmXvXwZf9BRFY8{A+$w~B!dQvZGlw(C+VDAPD4R)BS71U4l+$ut#9H=EV zQW=s;JlfX+GO4mSlcY7crhlfRkgUD_qFEy|{Lbg!f738FG5;gfyOq5p06O%3LnX-pg-V;!zz`IZt%8^J+>0s?dvHa=LS5=^u@RR}L`K@ynGEXdZ`iexL?<;{7r_K6vjhVr^?CFq z^k5=$V4M}m1;g3e#~!_R;1!)_CnY6qKG_BV_nXx9LY^3vfjXYi3cd(fxhE>@ z1W=c^rhpoOMbf#kv{@QLStTT-E|csrM(xjGERV;r5wC7MW$fz7`_JVGoE%d^_Tgi~ z3FJ!A#?KqY{{8qir_=ejUEQq9vQJW+EOJb>tU*Dol%VvZOJmC>2mNJY$ zX;asV%$Gwz*>UsoWacyUuMRZ)m)9Oq4$ldL7xx5vq4;)*i-=@B{(Z zZX|5(LUcUX4den9W4Lyb4ncx|Z0jkHifHsaW9b){tXwnt-K3PDzf6oe2oa9Dfe1o{ z)J8tR<4Cllf@VA>ArANiRWQ(>16Zb($b`HGOvg>us7=7pJFeUftedP%Kd+VC=33{z zvCnj9H~#HU8U%0ywh7A-jRDMHDcYgGdx3^6SX!Du9>~yS`>Y)dw;($wZJZWB>x@5V zEZxi57LO-z?v&}BnlxK9K5(xvJz33+>L5-e70ss9Fhc`dC`D0kw>GN{8#`;(DPyG1-dl@D^8)3_ zg@IVdb8Arw9fZTS<=0{_j9V^$(zi>0eqqzk%`_4A2wEBdaKPhXYgSzmnz?X>m(J@` zk5)9&zGm%)$X>jz%-)~x?iLn#7n-=8y>p3X>owyA)O1H34rBW=e7sUZi@wg_M@C)S zbJ|A>6eHDuNyJ{N0m+w>KcERGvlGTmtL>s${UUM^nDuBpkhwSA7Ak*_3qO3%eY%IS z?LJ?id0JYpn&+ghNp_OAo@#^b*WjNyz3R`8cSJ*Gsv%Q=!w`^$?Ye#z=fMu?B@7Za zX|}ByP&B1fExXD<6BwR~aI@@0b#NK$xIh^rPG z@CE0bY}Ir#QaJ{sya`LAENr94Ijc$x>`MXblafiY)fhlq0BNG<+`-Nb_utv|mJhy| z)387>QUjLoZ-hs46a=8F4ymlN512*E*iF(!aUvB4=~llAYuxNtd{7Jg7=Du7Bk)w) zy^L*-iOFgI`Qkq1;*!^ubDUDqK5syyk-0tV&X1E|N^4h=$U%eT1?S;3FysE>(F%Cy-laB}e1mIbN9*2Fs=<02Amrt${>G}WnNJX_B zjMVn3#cGceRJDMeuluHT=-rRfPMHHLiMcqD*X(k4wK+)@3%gcI4yZy#jG`ixHDLt? z#gj;VAz-c8nyPVd`uhYd6()hN)G`kQ!Vx2L1=Ra8qIhgU)w`Vumt696)jgT_HwviB zn1iDT#U*>=!9b`188O&qm0FwEhKuz8)>cUX3A^bjNWHp2&&*E7$7ZXjDP3I&-5OPmnCQVk#ogi5bU*UKTtrH8NK=9vz^5V3UC1 z>@bgIF`j${oVskoj5pm#VE-FDdeHH(nLXtQdX7` zDupaLz>dlYyID$>Vr0aSEq_x~U`kiH>+~w{!czF1%6s?_3E# z>g*LTZY`+JUKo4iMA~!zsw4`p%=T$yM<%+`0h(2@^5gmo*tGXPI;CUxSI9s~f4A>L z4d!^u?CV+~IcVDMkUCz`7{vTBJN5*i;l>dw%ddcthVt6yD!@hiCS_0Leqr6_$ohic zsXT&Oivmc4c@_TSywIY>3w00W-QB3r(FOUyn6$b_TH3(_L1-@iwvZpURgng%dQlq{ z&m3N6{E0g>1z({d+S)2fWdP28^*a1O#foXSFI-wGfmFQXP4!3S_O3TS&MU#xF4>S{ zAT#w^fWZbBIuIdCkZMT4uy97es961Oken?*Dqleb?5R|8yfy*11Fdx28fRBWh6qKRtLC2m7SWE{%dlw5vzRElO z>R~*;O7*mx=YL*mfmFOr-}-m&ys^&5=lHyZc4v62C#IQT6A`#38^Rd`PKX*blb7S> zurGF9%U)aZiu~n(mZL(~)qP*Z3$6p&p!Uwvrid37Ki^zfm;HPCqEiY6&yA?Z%kW&Z zdT=V#-e{Sg+1#Kk8YLv+aDF@3ki9(Ni=%q47apvvo2S`q$Ap0k{w zi^cIFPqmtp?`-W_Atm5MszRZW5lS;qT>@9tp#UNdWY>w~Lo0x=f#{*`x?t)g&6aOv zCMK#>vXZDHJ&+#%U+2lj4PR|i7`nZ&%-ZX4iG4`#>dWwg||sMe0sE!Fv7i_vUQ!jI)fi zxcMIT{3UY^7H;TTAw@7!fpaJAQ>jxH=I zz%XUA<4rKqD4xA5`g!NcM)fB&39uoJVT&j!xR;AmuXvmG8jZlMMVRmt5W?<@X@Hrw z$kS*~69TTxG0p1Bv(EJ+{N`ocQ?FrK@9CwlGkzrF>0R%(fnCpCGbzcRVZv0(0Ex50 z=Ckgy481j$K&V9JAoH?0zjq5x`(cca-usd3y74CQKUmv#tr8wFxf*t@G9nGQA8qQv zrYs*95p;UA7@c$N`SapqSUxLqd~DELTaFr>juuS+cV{D>!n3WeO(w$&S0VP~Digy` zIE?N0mSHQux^%(()f11YwsYM5f{|(mq$>qwI1fjaMAZ5j`*}wb_V(n@PWYG{?bwy} z&)q$~{hZ9)pCu!W_c9^au8uM@N0Ogy|RZapNYw_5Uv zyFs){fdrY4z4u$!yqQ0ZiFYra2|Zi!RA0I^XL3&H@{UlO3G+5%?Tx>r{rIfh;Y0u2 ze)aAAvdRl}Mx3)E$Ik}7ed7CXP8eF9dzq+w(2IrWT6D2k(uLd(Xcm_^l6mc}R&3&X z9~>8`y?Cz%ISq~M2^=k@`j@wby-~f1I zt*K?8nj-5`gbiMYM>jq{t^1@|rxlQjw|}VZV18-RBGY>{<9@eSJsu^tR}#@3i_u)+4azEd%*E$!oVGm-2p;a$g*S{{t4vi3 z{rOHD8$9{96Al_L4Xwjt`C()sCaFUf9?8_oUEAa-b~zQ;?;D%4q|{87Sau(a_a9`@ zo@sI-#;UFrQ;KA=i6&GPE&#_QotQ}V3r5N$Uu(!8X&R(+J_e;9)$j=>=)mzcu5u15)uS0~_BP>{V@^$19RhRyQr$D^wrz z0x}DLgu_^2D2C14aLumw){l({qCFdpT-3k82kmenK-muT`of*Tk;9@O^RPbCO}Ktd zqY(o;H(NfbyeHkbalN@>XQ&Fhcj}2h$Nix}?RlMO(bS7B46q|tgBxidI^yA?Dnb1o zc5GRVtzF?b+P_B~XR^;*maSdZQUa;~QZRdKolsznAcOt5vk7~1%BLsXxs(*Jo$TvA z^!9agwx+L?jMNY}qTgFsWHfI8OKR8Z`$o$|%^dVl7rvR#)9vR5r_2#D5IvgeMA8bg?!H@h~uXKT+U^Qy}ulr?CW zE;$ZclF@;^^6{G|95k-KVEE1+7tA@w02o~?;jGkV@S1yD`{QYyvWc1~K*GO82dH&> zo3SR9)-XqOxsY!Mo!VUyge$ZcW3*;#b2jO09ci)n{O~*7=4{%v9D!8r9Mj`WBV#H> zMW_@4P^18><}mUe`>@;&5;TaU4IhO$H%VH9g@TbD*b)7P^Hie-?=&h3^;baZ(i+e( z$aX@|p4{w6hvcSc73xs+;s+SS(ADTy25^yZTl!rXRVQKR29LuNF1#@9x>rwMAO$NM zeEw+Ox$-A0)}zXN>+)favt!JAO0k*KtQ|v^=TXg*?TR5hlW;A-NVm8lrY) zhgcal=)Iqvel70_UVrXvkJkw*uot!@m>U2pV{G!;p09oM(+fjOg4Mh^qz3mfeNY-W zQY|Z}qiD1}S?{BTe92JFcq;jVI&ji7haLw5?AD#UilEig$_E@DvDbb}b2e$_*@FDy zY~qnAJ?3oKwXAD}asj!si5A*hyDUi*hK^FtkDHxJ(nU6<;M}0|H^fZE;VMr9zcz$} zbdZWru_0_qYNR`&-g2I7*kDTIAit?mk?BWjFJN10J~pMtoL_e>Q;bxPF94%*jka`SRh!U@%JZ|7 z`5D{L(CFGQ0gle(dC0bH&{8RIV-Cl)V@h{_%G}|9TLNjLVCbesYKNBAm+b7BFcNt* z1}-{V_(kA#WrEd!nD9q|Fnw8@0mBP|#$_Klq8|?iMK6@!9L|$kwmzeP6zrpagHicS zDs7Lc=-!Tfd^9$lu84!jRbO46ZKn#WhHtUV!Qt9hD?e_WJD~E!gBa3rcKUN`n2L%xgY2z1N)e+rL5}MfM1~ zmQFy?vOFLcig_acCs7B*9EDYSI>XDO0D3WM3Gd&a_Slonhx)$anpqh>p0y)-lE~Um zZ5#^rQ+w?-&Bg4QqKejjSE_-!s5Me!NSny(=uAD?Gi#jz4iW*mmSMdlWFwwQ4xLUS z2u7NG;hDuqPn03gz3x2jcj*3fb!Ds#)=3z(P1N?@#_5H3f-;7zSb(S>?elKQ9@G5t ztqpi$NHKINOCT89Z3r;}a<-EXv(@te}vYI+nJoZS~2x;mAHlwZIXxut^2}DrI zU9_CjB-7nw5fV|NvGcy|QSUfUG-)`saUj^QVUejawmh>wq)jE0%%ixQ1G_anWTP4Y z1*4UAio0fP)*D_33j^k=12eS+@_7W1CSGu6Xrw0!K*e?bdGRpbF=e4L3oJWxB@DHv zRS|%#A(|s$NYat&M1Ud=W6KX+%AQ*|wM1FhxLca?)X;vSozpFuX5`Q=t%QU-acPo9 zV9|<&n`LC{WI)B$axzkhiLT7nTe?r1v&G-F&YrnsPV$MI+cW7}k4*0|=eO<4x>hI; zZS>40Ab3w(nzE~Qls>MB6?EsaGWRsGTO?=PxRNDctj2$eUbM!L;E z1sSOVQm8IeH&=9+Xb+LPq(mwqA>UExsjopm&|R;n{E%IjiVlfn>=io(fta(6BH7fU zW!m*;K(gsXE|3p8HRf^NT++w^#w~Ioz7_gdYz_bxw$vdHli*vx{OrbADyv_Tf1V$7 z0k6zOJ3LZrs64a!8Q7Wpua+y|pJ2yRO=1^kBP- zRxKOLA;Z=W9ParN^A#cMC?UcQ#Q=Dn^1qLWg}S>|Je^vxA5i`pV-*A+T#Z zqM^;8E&P!t1${5{CL%|L_L)1PraDhFZ7{t_VW>|7p^>^Y2PkQR45#?L*&A+*7xzEI zAYge?F-Gk^go=htdO@gXA^Xa;p&K|*3u>d|@R+8}(t5rz^NdM0{ndprtknqKHFdsb znIP^&+CoVaCXtz^WfO$4fp`8Svm<-;tJg~$NdNnfHoQ99sX{NyUPymQ+L%{oZB25h zxTL9OnKE)RPM_MoA_FvuVP?qMAFkylYNL0&xU0m+=C9hzsr>$f?{t~7WzQ-Jq$s)2 zND0TDmQ8{K4Ubk~a}SkoWQip*QJa0bBQY2YcX^Z*aTCI~Ki$s{Y>%0Sp}iYOK_iP~ zh{mwgZ7t?XyQ&nMEsa#u2w{_E6D~cC8?9FCeWS+J9zRxMgZvNo=lL8cv_G{1Uc{XaW!_J^4a&jj+UG_t( zMe^E*y@W3Uqt$b0@5iUTeRVy%o?;6`Es029m_*!y zksjO@JI#5rNrNek0->84$Soim7?Cn-^wtkd^-be-wN_)D>*87=Sr) z5iLjrIG~KN4b0)52947CO*%cAmXx$%K5+36er4hp7>0y9AbZz{m3RTY$z_PpcLC>I zCj#F2qg(d->s~l1`rp5Lcj8T>epaTgGvdmYu-L^FYJ<@${IklX!koR{njFS-^$&_I zd!orDIIU7IP%gSmdDzewcbo;%BN+X?Z(coTd)Ar=p}k#>h7keTcCO~tl(~tciLhxb zf+(bk04&{6m`esCG9uWQT0@E^D{=w&Jq7*zfM&xS@# zz-EXvDFja1@+7XC*$dUhMCCJ?N&!6ENH=np&mN}Nf!Lvb_d9cV@Z9s#{xQAux6vzU z5bfFE_PRr=F5cjC0xD7?lD31>>H5Pbw4al4@Tab+GT8(~4)fYdN)#n!m```H{z#Fl#yT_a zMix+jtdYz0Zv;-AFu?r1wiR_fL-NG`_V112`?vewl|b4g5bEC`C}aeB1KXohHev)> z^%mGljD}Z~rc;#Hz-T~{7#}fw3et2DE8{ld=tl1Fyc)IAZkze(-(Dkq{_>u@S=0}z zzR5bNl_X=NO*yjO(V9~t%B%K`c7l-3LAH~`Zko5|q%y6$I`!w5CoeJ2>{={F-_(oI z`n@)OqP-aabTJa^0kcLoX@pi?s5U2;wjmzYcz?Z8HP~9l zNRv~zi-3f1nwct-wLO9e?XxRYNgF@bWVX@H6xx1MOR2^VE zX!Rb@ohGmZD&Y07m3uE>6Vm3$1^(8MYTT>KxeZU(p*=8vlF1iq@L*IF8#(Tevp{+T zqZstRR&x$}wn!jV(GuMXZ6}7rK&l;U#cbr!Bn$a0B?Gwmgc3x%q!S1yb+XpajOn25 z2p~PQD}K83?1e4fs*|5PNHS85z*LmgEZ3M2(Wi`VK~dlSH#}6t5GZ1q4f#H$?UtTu z!Z5)|_ok+%jb2bX55FrZU~yk}<`r#t1y4FTmB2M8R(Jv#`f$xh&6A6*qVr>H;eo5! zi_1!G2UBt5b<;(|f<0<}sEXep2s9i9DxOR|tR)LUQ!^6*S7(;;qDfSY3D2 z?6uQhfaiI8NHy*YDfh1yJm{(b-lWV=%Uk=Rq0}1-AT7vDobHTk zeZd>mb8>F2Uj+3Z+E8^E6p@+emo!ECuno&C4H$-?768qZkrD>FAka|7erYgQ{XJJP zzF?<+IE?Q}NLtt9lh3->U}ZBL$I%u!b0=BW>~!EkOwqDX~KaiG|ua z>rWSq!`N87WDWZ)YEoB2>vrC<@;d~f~((*RYRE^_wS5#Q@NRsPjZfQ~$ zhy?*;{Z82eNcWYU=Dd2vC9hS=$hfV3P@N(QK@(n37iQ6VIa6j}v?pt^>YG>z3fb6% z9y?+}EezDGFj9?_P2~-nkdgsoOca;wii*v-?ER0fig)66)hSnQ`{@UT$N$9L&%JHn zT~(G&@{9fOG*c<-=I9Qd@UagASeQ3Df7(;;cam7|g{ST$QE@KRutpzm2$w5teNqL7 z`VX)Sy67l)dQ=aI9li?e`=1-HW=p`}S4K3!?qdw{l9^~F2DbiYMvDbc&pZoGEO?4)=Z}&>M^j&wH7Ze9fx=I5gCXXzI z$arV1hsv>Vd3r_Jjdh!PF#Ve3xMdg&XpLsdR%r3984$78Ww*y4Xf|zro4N_fd&~XJ zfOJCJ>v%)&FE&$h?I5%CZtW_ejKk{Ag+Oc!R{Sf#d~D*j&fm;FLf_Mqv8?CxtN|y^ z;G#3k0&}c7k%sOW$A&V=9Dg+Xy`U!hZGE+8X0Ltgfg?SC&-43@?AdJTm`E~}>B&oF z5~b#Un|B@?KmF)VDLonESDNne$Nv2_3POcd{_}c^#c@dm{Hwm} z$~FLeilm{IO1d|p90~EdJO6_CMXEt)79TWP{VXE1k1eeJjx)9EH7~|(+I&}iQT~MC z5q%*2Zwm-*ok=~gUEik+9NOj3OuH$wf$Bcm9GJqi$}H1R)uz^BVTdE-c5rW?_RCY+ zp5LtH=5rh;vosk@Nj}T14MqiTNlnxFcT&?x3d14$PBm(3OjZ=48G&I2N{)Fey=&3* zwPXAx`7TFu?KwSb%Dfn6$)$O?HWUz61H?dvbso+Rd1Kl3P$l-$#yZ)vR=;`F^{@Rd z=@+=J_A(!6co6gZ?ZffhU!3}Ba#HRv_wG-DyH#O}LHJQMryb0CupoA0|EN9t*k%l}W@1y_gKd?i$g^uHhAN?)S?H<-)NhSUg|Q4@S$5coW?6x< zY}dZZZ129PQE6-6#N^Sj7|5{eyYb5szq1b0L$*U06E0YtM9qj!VDY?w#RLPmJ}E0U zNiTO}YPE3kqI_&ipd#D8qHM?a)_(Tsu{?8W|LiWlD|PXTwLRx78}Ld(68FT!s;1po zFY4-hOY5K27@GWxv3gQtYLP-C8JO^2nRGY_jJ&}^-q8YV^<}|GE5 zV-8z$+r8sE4jA&lg^rU~+KuQ$Jl~jB{dgPSDl1DZ$49d?%U~i^N6;;i#4u^7|7D;p zdvxiPQURjk-R5R+pN&_^UR|IZqfj^PLyhW{)gC@q^(15bgGHfO@Q!05*mh0w@OpkDT#C|*0| z!dILx1`m29d*zBpFtpbohQ=ZPPs3{ihDe~Lfl*l({vRHS;{-rC4r&h2S%nJ1t}Gb> zE*LT}6UL@?y79|b9(tmS^EUv}f#;1Z7@D#miaIuQKwwm)NLvciD6<0O> zzIAdS&&UW6KAK(C*tyIQ0asE47>%3;k_5zcptqRn`fT%#MtjZod)S)Ywb|>l7oQP; zI`X;4zdl^?`HKP6Fl!GHtNShW|AAwJCpo%ioq^!d}2ky^|Wij0rI5RKk|epqcabyM)Lmm{@z)^WBb z6G}Z2^%MZyau7V6rN<^_HkkTp(}v~C@BXWcr?h|ni&iaof^$&oH3T3vh`K=)x8dqq zT>J(&CfE1Gyd7pStmERJOU;7)@AVydQ@(+0dsRkH!)cneU6kLNjs5uDV}AbLEeE96 zs-97yYTO={5<1ADgGCW^IkR&HH;CxPC;5+lBD#z)5>wS57w@|# zHi7-T;+z>%S1syS+HLhn&v)yDTKoO+`;$?6jUWI3AOJ~3K~$h)Q*lm+mLy?S28o0r zF-wk}-olG@p%v>Mb6 z^o3Q}t~n~OPw*P(4Gg75)swJJG#lCv5Iqd&bdX5Utd}lu4Cjs1PxYqlQ85K=W`EtF zW>V7T)7iNG?Ac$tuorLPSwpt2sdf~+%E$-d> zG`lNjK(!C!J+QM4jT)^|MMOmM`PEZ{-8=iMKLyf$tp?`TuD&OxYSeC)9Liz-kjNfG z0A)a$zp0+FX*a8uCl{Z)tAo7O5ju#$@Y2Z+L1#gifTR}f9T#huAF2EBH;bTL<)9 zRfd2&Ys7s-vQ@Do9kCIHN}WZKhqL9|>+&~0T1+-<|5YnHIp6=5^SI~6RXUVZzQ7}r z*w|T4V}KoPQ2VxRfR2B-gCfofu8UDIh?jtEE{vnlM}d_dgvU5Lu*c8G-uzoTXIpmm zxj(dPyYburbg0&M(xD3R`NZQBv6i;n!$Hs*kiIDm@ohn#ioWE)D%hh>Gxh+$;Hg~R zeIxhqa^v2D&=p?=JgUb+4z$DmcfGQ4Xci-Ygx7?7RVIg&MeK zKkl-TT}~y|Yw6d2%IHdB6uLLQ>(ypecHYs{_bZDF9aaG5-eXM?0hBF*7AzS0q-`D6 zB$Wv?t5beEtKvy#WrI1)BTH!XYZY^HgMz(qKvZElBvwsj2{I;V)<^7DF=f*D!je<$ zNRQ4*q~u2=5D$78`)d8Ug_D zhW~5Sy}fQ8TT+vMs;=9=*3cD0la{xR^{9db01L}0k!COM6E;;wlkPXBAb~#J^jc($ zZE|X`0n1KqF?px@!>_)o=I@_0kzHoRsxWB)@lHA37|G+}0bDJ|t*b_8nTn{e6+K)? z$WKFZnrx#9ICLs>Aro7pl8HG+$BZKYzlj)Va+Gu?(ySBS5>Ip`Z2{GB=UC!xks0+p zhvmk2+0d7_oD!#Zyldj+k7r)<)%v?WO0H0-Tnl}A>=%24uwG*Uw)j@UqP;PNy~!D*$1NFWKM`IY#ql8nZ5N; zg*(Q$T-!$VyM*tc5uL5gLZO3cGzeO7O~v2vM!cK3!;7lbUe{yldtH-Q(!Mig&;2cR z{~5SFZjmp_lW%vvB6_Ghfl+Kz4{Zom`4C+R)dE*UNrlb=k^oHNKqv^Q-dgqkFFG$FGW7q22~`Gn6IN_l!mcQ4buGtbgZn z@ahO1@>yNZM>i~}P@9~>N*0+(xRM=sI@S!64al=fyBF&qZ1;_Jd=S>_nV@rx4AtRm z4L^rH|JJILHebgJprY(atj*z1|7Uc1!mH0Fm(!83rU>rtZkT{W5Yv&X+3Vv1VaUAG zL-gz&n<|%J$fC8Q)2KKRq7oIVD6CWS6Us>qyxV7Ul>E`+_7@*Y$=sKq$};S16^4$w z3JRf*hW_NjsBK`etKv{FK;~~U74pzAJDgH%0qnvZj_L1e?Nu1+Zth{(iAgzE&s*BL z42#)V-f>Rr?ES5EMig|2`y;BpI9>yqIe=CdRv1hi5_HVb<7tOLqSvMxQ@iJ=o+C1k zt5`EOV)^?gWntddY8daG_=%3F)HCk!rm*jF8?hIbOu}dA*?8!ybt-1xabE0Zc1|#Z zd3Y$Yy+*7~&^zsb(UU3^l{I#?ZNyC>dc24PVr)}am$+nyaIjPM3Qc?T|8Sv(6BZ2? zNJ2~vq%AqJ{|D8|QzzPkCO%-8XPsQ6w+Mn>iG<;(Bx_d>m0EIO-lnItV$SvGBJ zqG8p9h~oQrQCOJ*q9&({+o{N zcE|17Rmp_zWU5IkEAW6a+@Q6km`x*05j`mVETP(@TqIJcq&l7(uVD-khX)&)$O&Q& z+v|%Cw3)tOK&4RZmz642Qb$gnW`FLiGcwdKW|>pQb3i?LF`0NZ9`0I2q9H-{SWkG^ z7>ggcnmf}nlrMQ}_Q1-LJz`nBL(j%{ujp5KX=|}rat|xVemzi=?LEZn&0ar2cn~(Y z)g7UxDVv_dgfA_{oXE?nY-?g=I#XZ%}^KE6R!EEN?x*Q30v%BuPryA$fSl0`~SR? zm-y&SlS@C4a?a!Ce!sNG_EE?FUK>^qQGEXVZPA?0Mv*# zM`mP<9Bxhx5Ilhy2v?&M47ZdJB^ejIKQdhR&(!C#xx;pcSSWkwzsEn==jMOfLv?!m z@BN0?^ZL$jM)%X&Gt}kE@sNwl^*&T{BO0DEG7{24nF$$7{0w?><#lHTIJZV9lR^wD)u`*Mi@=?x9;n%^)ryGvu=@2mpfr?gJW5M5f8DKFBts5NyM zU$a<9qDNm)I$|m_;X*XKSaN+)Qj^`7a}L|KH`?lq|Iu|dBLjfl}AxiAA_rd9_+Nnr8C?@))c@#(}BJp!){(o8?XA@f5 ze*a_rhTQ9@P!`5Vxib<4xQ-$=zb(GJiOM208ddi&@sL`kit$W5d<}o?r|~DO(7R8= z5j$Iy+kH-B=XX{%q^Bl=28rNkHC2IU1SggIagaOe|keu54l+OZ4Zn z1Oc+4Lb+i;9J(j&DyK>-I03K2^8G%R?oD7D*C*$`y=-x@O{q(ho&T1ZS>^v`HQQb$ zDMvO*a+5U0_|+4;qfvDBRs;;6)sx|hM4+}BE^9@(+Ww`(vIvKO6e>Zgjj3n@oU!~I zA9M1`X3x20izID0;iF!CdhRu^zumQhRgb7Yf(*%$Vk0kjIyeZpIz%){G#Sv*Jj?p}^~GC7-rYsRQMj1DMA*!4dZPSvTt7ny+>m{I2W zzGa--x4XK+TkkpNJ*Uj%RN$nLc1-L9@2R;D1!~joEnPEkuTfJEYq`45zHAZX^FR@W z7jnK1X7LE&I_?}~cG68n&R9S5q=jxWSt7P?b0`PqIvwEql`SX!clJ0TrP|uh%cu8X z&5~8B_esC`vd6fape7iAfv+#FGl*`j4fy%sLyznF($^o0AY4=Z`DF1A$Bg-3zfYT$ zBviFIbm1Tc%x*Cen^Z zZt3%be&}QY=`)|deQWFMZoC7xW-D8R>=2qASrJC{S7Dl4{K=x}xSLYbM4C({wGY{> zW@45SbmQtbcWOX?t4kjp?yDOAbradfly8a zI@rWlq*z@7g784qk@F5M*u2kCY`UH2tr)##_QF2}@bAhKs$N+5@HVlWfqPvw_0$&g z`*ck&(}Y=BskRD%GH*5DbS|J)Z%dJIo$jRB0u{Tqq6f zHI!0$WjQ|cvVYyS`hG!3k(3B+DRvA*TUA>wB=C(+j1I8CTx{(|m%3Cl(gJT)DOAKFq% z;OwRjdwMJ|xG*{~AobLO2SfKCFpM3?rpRw-u(o}1;>>%8!N04HU-!bo(HV!p{n}zW ztNW7>H1%ks$Oe?;8w?)`?dQ{W3-J5vJ@ejkkq2jKpy0qb5^WCQ6rdtKK5 z!u+`t+Ol=Pb)VA$2f)m#)`=Wop(6?wI^9ysL_h>LJ0oesZ8ftvhy{j{pC~KF_}z{4 z#cbSq;ptf{7f59w0_AQVv`%jlL97XI5Zp6y`w|Pz+3TGC=X9MtAwP+V0t00t^T}~w zX|x1Jytea;yfjvjWsDUrsa(6qpPuYBGpD#FoR{w@1%zs`WqFbSAxR6TBuobmvSES% zT%~D8@KujN*O{@b&7|j_8DPhDY44~N&i94DEwe zW!mJNmB%Dwkiw*kA}jEB0)i|xiA+kVWJhFyAtS{XSNbyQmbN3YrhFW4ODS_<3Z^DPE;kY* zg7*98mAS|L?ydvNL#<#^S$FpIjAwO#?5w>9cYS^SOZDPY9D4A%HRrYbCdc(u4FF|@ ziN)svyu7wo)wmh2ZIdgcDb3OCY3r*~KDm7CSLcr|Y@Q4WAk{i)4D6W5DqZ8aCKS8S zB_uJ%qAd`NBUp3VZn0HiU+me+0@7}VEw};jHvD1y)PnM&&99xivXK5+Kk1zl{_sQY zx^+GB90$S}=2GS*^KP02(OKghPLaVys)J{9<+^-wtNE z860tj(>msQOO78l_TM+$a>@1#{Eq(a{LcHaASA`YG@fSaL&hrbQftSP8+1gONYwaP zeGxbqM*Q%iwNc)-?+7*sCTan+908N9fdz^A!yifhv9{#i*XKX=t0#fh$5>u-^qK6W zobOa1SOuOKgP(F+z~yhw*e>@$eYCH!-{b24yM64+$fFnJ7N*=tR9Y^$iK54bx)Kd* zG)7KFY(V++{c{8t5Cu-0x6<8&E;J*9!_O_30FhTwHGxyzYT19zTGBBqkUsP7Ys16; zxOq%l2i#)o3MGzLAgCWGn5xl*iog4&6EDah7lCpX(`YTx1NtLt;$;;$(?}c*JY+6X z2665e^8iZ2`N@;s`@T(k$JyA}Cm6Qx^G?UIcFr%lxt5thTp4onMAtVmQIm%FePC}m zXI`cR=e8ar*dR91k~~=qk_1j3NuJ<6@uMBJpLIZYEVJtiSdlh}q0X!sX^k(PBR-V} z1|PIDK!K|03kHyO9r!ua20pLo&Yt}C>3WlA)pm~DcH;5u$kal;k?{7sw5sQ{=V!m( zx3>5AJziJJO52Tk^q{4|yv?Ct1RxNQ%pS*COlh5=2$CqNbZ9CCrVe2>AC`Iw6+#&oM&=9o+Aw zrV_osv-3!HF8fq=kdA5EE)zZRgwGUrbi?EpJ00MpA17pGN4M`Yf(>M!6DEL;cQTPw zKR)FRfQRQjY~5$}{@nx~T7_ry6~1xS0O@0y{)vg-ry_i1Hk$}6h!T1;+-@+vwD}HU zpT7onx1D$bJ0c}B(EgX+5B~kh+q>B47CH>q-fQ1}cJV9I&waYESzI5oNjGt$(jl}HQ=B_ zzQ|yt7*!khhy6-hC*v(RkQ#Fwb6L$!A$Jf_?os|&>`}g=F3U&Lti*<*&ZeONs_#Ml zY{~?ryu%OPWS78vY2FX3x$mrP`=2fvJE?P1iQW(1eQ?*m2Y*-?auRYN)pm$y7f_iO z?wE83UhTAjC#u_Zdue5Mzu@hAU%>{k&rI|gEhg2c)Ft~II}YxjCxcY@GiSf}4L+;t&Yqg}#13blzXqn4^d6Y-n3H~P z#w*cZyYBb?8RE+2<9aVIi!EuN-z+V-ja{N%eFy58Kp_#qw4!4d^>9f76CT+iDb-R9ckL z$R@TY41)r%jQlGvh?2o%1dOZ>Fg{b=$++WS&N+g$cqZ+15^YoMDP;hgBKh%?#!u+k zp`h)mrV_pXSLcyzQ2H~YwfIo#TD3qxRN> zrcPO&BI+Iscm81K+RxdSoA&-q6V-seNl0A}WFi`0r;*lCUl{*XCV`hqZ(llN~aw17vT+prgZ1w{G#-@exs>>T!) z-heT89Q#a;mF)YsgGa#4bDp-Q>BRl|vXp7wiA+eJMLFJz1V; zVB+<sAIZ_PHZR{Cp-KRsPnA0FYuqr*4|RYq zD?22foBK$evyK|WSkX4Tbkc#WZLHiX%)_NwKSfJm%F0&j#?E}VP6-Z;?ftg3J)<7F zWBf|zp~1Puo|_YuNBfB%WTk2@qZKQGkX)2S#X;L*&qZSQYS$PAZt_j*`3l-q>;Z$G zI<8w zVxj=vj7+92Q+CaQ6ky9roN}RR5V7P6nBjuvz1l6%&!_q+;V`ITJbIs-I^wB!d-QDC zdEvHBgq`udOZOc9%Z+TtZV@MD9N#`xzR2we&&P|m=o9s~`=PxqW+$Y-$`JgczZrwrbqDXMxsPmD zF8|ILmtTA4t^H46$EM^oqyB8(PrSy&oZQ{un}yMCFU@b-`SNw?_u0#qb-d%fBNj#q zDuba26VZBOr6L<77O0wxB=yGl*lB>(+RTlBS<5tW@*zm8Mq8&8DEFo9N~A7Kw7LxN z$2R09-Z_7**!1z(lr014vAusNsx0e~=P=+xLhC_@;-orHwxd+FWQj&;tw0g2@`ApM z%(H7O->e1VzCtJJZLG!ZFj$syS>BBgU3=jlPkER+hwCyKcGk7S+Fv^LN@r1@R*o$8 zkK@3{|I_fHFnp0YhNCuZVEm-XBR9PvB}Mc%cs}9YEo_9dq-X~ z_QXS2$C?dlqftOXwA7W6Fuc35Q|hT{A6OdQ9ofbm@hk+HSHJw^%9rPy^GI>a6wP>7 ziRjc?mDZ4)=b1%ysI@6B%20nG&owE4M*FUdcV>JK?}dGmoh<`+X$MkqmsfoH>CFp% z?(FZwtc>(uFFZA*?W6aPYt7P9Pl`nVG>GD|Mlms|Ng`&i{rsnE%J-Zks@fT z=%cO4W-NLN%^2}_ny{f-Kx9##MY>1)f z*csR%nLZ2zUXx3YdGtmZK=ZOy@e70izi)#I`?2#B_;2tWSPS7~pT}Mwe)yjIZq<)i zm&wx9u6?H45O!2*CQcvQN9D5|esP{`ygw*-TR6L=l_@tN^Mj0ub96j$L!`2klQe_+Yv7lb?)1w7-TsaKunFA}6kgObZ&A;!tU+ry(``q%>!}rZB`{%WVC8&x{m}{+ z(iH{kKe%*dE1taMFC3pS(NItNpRRU?;}k%Oq4f=`cqA&6LBi5 z;=R0sG=S0FK7iL z-fg(PuCMu1oBN<|^t;mKz3&)*)JN%HMPZ(Z)^pR|FhLWQCm^awk+PC&ae9Xobxa=y~qOypm?=J_sz+2N^giSP-pHkwXk^_6Zu z^jzFw>nNP8u>c2PTK?|v=l3S<^fqtpowoKl_ll9Qiwc(h)e&7|Cav}k+=fT#;w6b>N;kVz2Vuyi_3%v&z#&i4#_UnR!LQ zFiAtOvm_{@$tW|Vq(4Fdvh^?iourVGUCQn>+M!BUN~+2DneqBGgNkTz{G?|lAKay& z;D@bEh~MJpuXR3~^-9h)8EWKQ8u7lQq*%mCLVeYf+2Ry^=@d8;`KLundlQSKC~ zjpR-%m%%&G8SejF>U5j(&w{Gb-v1ciXR;UB7>*XC^f;j((mGCNOF?GU0h&D`+$gJ8 zTeQeqm5UMGe}1-!8!cMFcvO+U+Niv*90G$O464@UCO^1f9f!fJKfgL?V^2Toe?DuBdRVdZMvA4Ko-GreiYse91;e(e{fTZ6@j zCE%8N4y;K9lI^d3@XtezJNdz;JW;o`?XPtn$a*K|8jYhrkSO*^Ic7;G1l^Z@-yn;6 zShtate{nv|qt$ltdkAZDKO^5D&WWV(A|5J@@@5r_|*cjqTc(Cx39`_-Pm2o!=rE$}3ER zIaHBPI6{^*p~48cGW{)PNX&EMdXkjRsD>z)6kwS3jC({Eax@9msH0Co)&50dC=ysU zw^;xB**~}1CLn$5va>H=@x!dq?Oh1*pc67nI&pEvdzcfh0h5qqvMhK+P47rL1IoOZ zXfy>~`d#bZs5L`Z0D`xARUep^c>wFuju&dyrgYH%y}2Jh_TcyCD}BAwKz49al5y-~ zIZgeVTn1?fK$oBAHVBZ8+5cR2bnH9ARM0IXi-zBxIC9u4OP;h87Grvy$quhkY+AHR zSx30l@?yJA0REjgblM9)j%_q0?M5DQiZ>)U-*A0go%-NHqF~|v(!!Q7{QaiqFGX{A z#flZp|N6m+^DC08OQJ<-Hsza9oCmpDviUPxe)%o>t7fK?X-+%U`Z%?i>kfI;)@jrC0*v(BBP#Kgq*9raA z(KOKkWRg<{yI({rSSbNc;*8ET<9)!a3qa$ULs@jF2-J=P2@jwe0Loc_wZCc1y{8{` z+|9o?U+Fs?&R{)L3p6`2w2tPz%YNp7*6HVY4FaT-_wLJDrZ-8?7g;!>J-jG&P7k0{Gf02?J1w!H*WTMH--yRPAJI04Jl;6%`Z#T96?iK2zhH0j8sHP zvr+}JdbDZn4j-8kID>51nC-L(6ON5kUzr2>5>-KnmjzOH9zUn;!Mp92A$y{RaMr=X z@>kEEc*u7J6&riD6~!lzKr048GnGW8YWuianbU0~HB?VZoyW2xebIPipY;3ccYlPQ zGA!9f{{dIB-TdzxJ%CtV^QtRe__jk+IvB4$R@8@kp2~Wp7LkGuXzG|TLaxXAvBUED z^$tpdx?ME%PBv|<84>A`vV2+&gN=a#$b}e0(kWA|Dod6e`ova+TflL%rq+9V>!aT% z9JxO$PShBQjwSa&OUeXO<`lMq%l|i}QNGKs^~Z|x@~(e-{gBx)XI(V65To>Jj-k1Y z>p5#?l6qxiqIk>@IU-(f{@No zuw>5}jO8BeIGm4V{A_Wskg7lQ;&Uf9d+g5lI=SHJe0$5`%gr(4K&PNaSt|bB_%w|_ zM3QVHh}FeXs9CQ+M{QZA49b#J@bBV5a#&>@05+ywSd(;;`~2<6t4=@ck4>s7)b=jw z345H%_DS(5GA>@6U1&kbF+gy-IdaJLFD)MT!1g|ue*f=1E@KzQ_yK&jz*@G6o&kl- z!EPI}SezRCQ(hS4e%5#0*m=)2%Az3eA9WyW8QYA;qz<-P#6tO}`QXGt0XSw--SxEf zIZoShulK+H;<_+Pt?-Z)>68tfziURmzGA?fr~ZerEhlt69 zts5){h)h_rQw&n7S*VYiChP|19XRl5-o7wu=JuTwx-Gy_+wXkQcOMo_C)MRNn-47l zQz{Xe(aWh0-b2$r*{M3%+PojGon@@7~j1Ouo62R3;w>+rYd?mPY9qyCaj7gn1|)YPt-wEGFHi}$k$_K_FJ zV2Hrr{+xc^!%H5m*TwvG*S@So_(%Qa70qI?&3w~H1Xwek45|WA=ryn5WLn!h#y1^y zG8>pczqDcDxM3I&P&>T}{(V{44*vAf=Z)UHM<9Lcn~7tdpE>BVNM6zjYTYPGh z$&vA97;>iNOvED5roM6msZBq_;#HWNO=vG3se{{E(rUT649GL!x%E{W9Iq(ScGjC0 z%ip-8xFhX={}!%p$(C!@QwOFi>gAh1)How%!nCO(1i0jwQ_qP0@isBpe#X8e3V5Iu*&dL5Z@P;$ilj%c%-n(MnH|Iu5hj00k&BnI}8C^?Ow{y zmKpKK&NI5R4QYT?2`Ab5ihJ)Eal$!wZmpw!3!hJJcRcHqS}rFOx@df?K=i1pG5b{X zXt-mEecZ_Q_QSl62e2rw6qRAZ`}BosBNf{ysc}n_K7I+cgk$Dq*PL!|JGb`z2mf#) zJEl^)N$3WYcBSGW$UJa7EG>wE47^yG_vjZ!M%x7=k z`s#PXZ!Kt%3`Gk)6+BcE3oT1>yu031@FCRtB(V~OY1(>0O9ZWb%{-}Q6fr>u6mmbpEmFH1Q6I{`U zjAG9IXg$&l!w9KAlm;0PK((n!c53@?+#P^UX`?8}@S_q<8I@&~F$Xqy;KhP@;8b5y_7(TQ(Hsf=TfSZ>*vDGus~4>*&BBKA`- z$eNT@Y5of~i%g3s3vg#MnnhkW6QG8JY1(D66K{C^)=NeWtm|TGYS(|;<`}jcTcpUSl%cJA(D2V8XYX&=`MkkWyA_JjjAwTM*}M_ms>>a{b@bRuS>){6Sf za}8_=d|F3nGu;edtN%K3CW{;h75&piOw8b!V2aYast(=gIZ*EArH;P)wQGBK+UHR* zFyxrkojp!6-k}4#!g0^;FzYS(O^dkce4+ zObvKN9R$zx0O z4>@VTFhV)u-poA|u3Y+Ty#gtJ?$SMaFqh%6yhgW*7LAzZ3Xl9|F<-2+qn+W*dGFVI zyXw-H{%bGlcIwb$T2zhgS*e0~;sQKD)dZ0!iLl-mv$RwY@L8{Y{L$||%h{ebHNn)ItrI+nHG<xc=e?uS+x@B+>ONN$YA zZ#eXgo&)wj?8n;9v04Ku=B1B2^N^L%veI@X0aAQKEliBA0!HFhe_)^3QYBJK53kb; z+;=Rq_T!md#TMn`;!~0bUw}#Oh8VFY3l#uT01#&mY)U&&9nP;l`Qf(*^laW)9+UYS z`-;f<&*E-ygqQ*vifJF|F7G{Y+%(?#X5PFFSD8IF4qA}itqq4 zbGyJ<^WUxYyxkc?c*#B|e>Ws&bEvNPT$eOj(>?k58-JXO_xz>`0I{L#*6 zdu^WiUFk2U{qxl$US@&vXrv$w!4QDUPX`sFLf16{n_=d{yr+f5wbg2hkJwC|1o2e- zUMe~C)+)JiHhog-35n7Bai6|( zRpRdJA8O%vPL9JMEa<%96gr~s%RG>QCUqTlI5GWk5U4q?{hEYb%JY5X;xeaJ()y+n zC~5Inn-SX@O8l&XIj}wf-rA$Cd~4LGKVQVpt*VWaxi+2LSg!fF&6(_gBnk8wcb+eb zE?fL*^dLBYxqY^MeZ0&0oi7@CSNxl?{8$iut`7R#)#xDtp&C#u9LIrwgnCaLw|HE? z`e;W(-h`NL1Y zI(A;-u9NbL({4_#r+u2#e5bBBVeadacl4xSQZXM{p^w#?zEiEy*r5uGsH00zMT7_H zIZDE(C6b1$S|I}bb20^xPPmY$2(UrTpB{SYNoS4ERtbMg{axz;qo6YS)Pq*KRh!zj zcEK&i(paQCo^hFr^U{w~>dJsns+kZ*Ms7$2S_JJ#}e&U9KJ9w;wyG z;ukg7E&quc2et95k6y{|0C!Gpyv3d0{ASYVao-Lc87W9Q!H_4bJNZBgsSIj>`Kt+a zsWoz>2olkEQcIIwui365N#+Q6L#m9DUHuIQiar4i= ziuv~|nN0pUuuYS4{ADLUwRZ83L)!;gs5$RNZJK2cxPjW>wJ67JaKX< z_K1-?B9{^`N}2E$g!}qBk|bbE5P1Wg+wCwYOF0nBZJs>&?)T2`+G_V#Rfpy}Td4X{ zmqoR+uYGLy%h)%s%3^9`@wiFB;8hw=_z>Xyckw zZhP|&uP1{WLn4ET6i`M+tsG~%vNE3NX$plxSaZD#SW=UY@x_Xwy!+x z!uq7+6}8)A-Kn>|b6AJs;-z)jnd&+KJM#ML+K=%5R>?DgNF7ks=d>NzR}-T>;hdE( zZqpp8&3pa3>&5Kc%4vFmWHJ!5cs?%JA1?XvKMmHF+O&6ju9?uQFKb`DQEl8tB&C7F zVNemufy2IQm{SS1we54+-25I+k4hdRxqI3WCHo9Vhomm97tVp>bX z-Vi4<&i;A}ax&6Qoj$`PeNxK>HzWQn#T2W$C}=r-UXp<=5PE!i+tBt?uZS z`mxRv6H`XVU2yc2n$;`%lmwU)bpV3oI8@v<%yG#ikU=Bsgat_eHuj~CWS+pvTo&{zy^53RK_k~k``EQ-)NL}9h!wx62{lu}wWD#k0A^%(v$b~!e zyLEeM{!5GMa_`1;?WOyi@c89{l_T=_siMTfGMhbvg#|6)jISG?f0Xy*_^&@2{mM7P zM!2DPFj|y`P>w!*O%0uaIUVm%dQm+NSk_Xraht@@fDs0i=y!!%&)WF?8I+hcPKp^> z>)yB-b-*j-h$>IjWdYVEzth(*oi(%Xwh*T}FA}8sUoD^0`HM>jeq8{`X02T27O9F% z2u#RK^*%)OVX~urFKgw^qlC#gUr;8c@YH6mL>G#Cy$ML!{#ga1GKw#5W}d~LmSzAk z22hrCAeGy!=J31zd*P97_j;`{Ez0d_%lzg?vzA_|-1k+PLg8lN!f?L1a3&!h;J{Q4 zq^la91#&RmKeki_V=yqI!xM0S{vX%_i=HCk%I)cao%h{Q`<)OUkzN)K@@o0$mcl9S z08DANJ6!tJr*&SF4gE%6u3R+m;SY`pM zH!o<;gh?-E4b}OoID?jVAv)?)FXZ|+sTX!E#Tp-6+twd_x%2`+6}Tvi)$jGR0GixO zw_W{>>qe{Ay2)0#drp3J=&Ws4gKXEJz5V6Ho2 zNiWB7DjUxx83uG&$mc7tR=T=yC6FYyWNYBt?P#m~;F7 z94%YBM{7a#k&T)RBh-6JmPvhZ#I#f|YfBtd2heD{8Z?yXQ1e~)mL5bDL#W-)dbW=d z>s^paGUWF*CHe6rIjOxzjK1@nBTl$oyhjsfrjNH9!Op3itaf!p&V9Zl{+=J@9t7vD zY8d&`)+X%Wy$5$~%0AJpz2B8Rj;}Z|QdO{ftPEm-08Gkj12;|kaGTfT)}B|}&lzK3 z$8kiR!?&h>dgs^~7u*yqtPVztR22lu7`17QcP9r>YOB(~u1#!A2wulAET5`Z{qr~g03ZNKL_t)&S*quYb*o4$?ThM-LCB4@S@y<-KX%*}-zeETYTL#3 zb?7U7`I8UMuKM@Yue5X1BE3NDI==FD)E{ajOUjHCtcd&P(3>h5r+#Tt*3I}`Wn08` z+IK=g5O+!IKs{wx5D68+x`~`-`co@B2i7GVFX`lLKKsG{U3E}Nr}5j?V~y)uKNTI$ znz6F1lMDOh_58kY*)LD+^u^t{dhYkpnmHSP9&+>8!yjScSV3O%lpD#DCcTMya1xEj z_{b?D*R1k{ihtCa)S(W$`jT43Dk(#LAKh?LP_K|rVFU&w<+E%TkO5U}p&2Iwpt>RA zLw@_pbrE(^>+#2*d+doH?GzxT)9JA@_A76Zs4k3v2Vo(a_Z1_-rRdjzQkF`5qLv?2 z?;^xcqF4ZCK$*X%>>xWkg36q9Zz;Ktc6OuB7Vk~YkFq8N&&5ykTzm&AQ;>=lm24jJ z;D>`d=Ct}yT-St|>2>WdPu^NKCCG)%mgEH20RwoYurFM(au<;P9-xyl(IwRz55M)L z!`~{aT3-~5dcmBc6htC^wn-x3Iy`BTWinhvzO|2iYTR@De*UPu3T6?1sQjL?)%|7h zjEi5j$i!2$Zdd&&m2!Y30+6mK*zo?472AFEb-l2SH)c#6vGSHnA8i@r(R-;YD}Z}T0M!gKKxX$LlY z4s48jsrca|KD_awk$-QO*X+BdzQCSoJDit|ms*`c{Q8rT)^sRTA(d zNf}mh24S>_qZT_RIOAug#^aCtS5hT@CR2Q4$h&0UmxrC#yZ?4uncEGdxRZ@J_u$oD z#fCP#m`TK85L8s3=Gco@P>x;+Xe93)7jcHTU-L+9hEiXL4W`5#KuMIAODLCt?pY#x zLff7WB&})c092cAa^ zeZ2=)K3T7a-~HBssHwdlwW`*#wXL82&pVG#DZTZSP&5?`=cgdd^`e$VNz7y7Iy3%H zRpt`UsiG<3x>$*_`~1F4u{N>bwXLk7IrHcPrS3lp@)~S)#VOfle*1J9Af0p|UKxT= zs`;w-hb(SaA7fS@Kw9EBPU(N9est;b+pl=6K%|X&kjG7YQqi9JPyEc$nB0b$;`PFB zqVHeQU8%3tw2Mft2wTMg;<@+GJdX40v|MiWSZIvFzJ3rrQmqYu2o3)uv4w zQ7!n9^A1@YFDvcXhMV|Guq%O35pfcgGslD|dUM8--@2<;|N9cG*PB)f@rJTg-B zt6FV9;8vnyYJzAmrEO=xGoLml0AgM!)&GvSMjzc_|Lbu8sGn(j24zQo_wx1^F21Ae zht3fu&tB)fQRC#oZkwlX_x#w=@3QN8wd(=De}Cf7^T*u(&M}t+a+1N^A`gOLRq@_R z14RM8e1_5cVz7y>LE@jJ0b>L^<(W7BdEZpasNI?ws4{?Q-WhQP?)}H zULWxCf+fq|9k#GD{~N`y+Vx)MRolH#c=VpPkBfIF%$Rce54T=LU0*@c`D01*&zPsC`VEqTzUfCg3L;MULb2gcCaP`hY~XG1Us z6)6{zfoQVtjW6CcpnGp2i)zY0BimnGbz9l&+z?9$&M_mh7yNOn1};`-qX;2>HxMPy3k7iaS{MIk&Y_Z-bI1uX{Tr=B#V`fC zM4}=W8Zt~{rAj_&iTPEBXwkjj5o*QsslL>K_+}Ss)`wCz_5I(F0s9^DU&e&~+hO^TEVcIF$0Un38dTnoTZi745L-Kj+NuzO}xp%jfk5q+El=t5JRW!`J&v{p-aO z^W1oGOGpb7Um5Sx&p}Lht>4s@V^qhI!?7}=>}pdK_oRAN{5#p5j4zhnH#3D5cTPPK z_&tyvYZG5h80Gg(GY8@fpn^-6Bl*d5@0oZ@m*Tef)ur=yUAwCXc4iMO*|_$~n_fTk z!K7OrisUm03MQ&DmwZfA3f&cXQOwf>n2Zz(aaVkX)}{hpBq0>?B#5e%PihUSEGS(6 zng>&G#XuJ6M7jJ;a0%g5J3Qgji0>Y__xKswYSBoR($;%ktSFRTMeI(1W)xUUl)cjt){A0u>tD4~s@u`x21c4?guxQ*srXoF zW0eac#T-a*W*TP@E^L`R>E`!t*soRl(e*u0yY9EE2kNT_=9jI!{H}M8eW)V7CK4@l z#98#BniHx2i*X7Kjd&74NIPx3dDg=Ac;^!sFGqZcrHW+Qok#0v`ChJ_mO zy#ef4c>vPodDXWc_jS)c?c3LTImUVi(nV}hVOOVX#YVew!fS-x3tlo6(pI_;HZ&h+r zI8vB~aE>`Q3oS>q5;Y*v>^CBRG65lUYT6_PS*CUi_`^mT2xX8-5F!QC7DW0{ijpxa z422;nLsjKD^)AFKf~-UF-fus3%H%U>)&JV|ooY6? zUO}Ms^0$Wmh-Wd?`_V!54y1HayfW?c;}+j_>3gk1$#8Qn>_q@W;8MqjuI?jiAZE7yf4asPea1MG)faa}vY$ ze&);zjy!pr%j9isWEvDm`NN;SxX(hTY<1UWJZF>~F<^`7DHHT*KP>=5U^Un1h&u^Z z$*NFf3)7M+;-kSyLSz^ysge;#;8TX|OLI%}!SfsesL5bKvfrrZ?>?q`?|*D< zAa;Ges|OmY2R{1o+gqRf>a1H+PDLo3my+ku2hHi9nR)Z3#;0V6Ht-p+RO?Bcs$d_> zE+g^O+B2Dk2-Y&7YcpGv_|Vt|USj5#ahe3mK;!%}3Bgvp{)fNaln29{M)bYoTuk1;a|Z zWFn5}9`GM~qJUlXkT!iVC5|v>^BF0@2Mnq_2R0`I;01G2{YSkz=E&~*Uxj_$l&eNH z)O^`>-}>nR|J?d~(d@e)nRMEXNvI4(3b;;G%9|vS!7`Lskc0~A740ElM`et9F8hI& zmbF9#6xR^tjznkT7gZJX6}F>vN`k6d_km}oZr;stO6zCI?7GXY9{BYhcw^ec2cQ3L$Viq`BQutQiir}fr8ojatQS1`98GOM z6SWy7LL6Fa5-9awb;B^aPC?k1-=+Wty7e@*qp~WWF4TT&40+LV3(3u4Z@1=M zKN)+{)B&PpbvUQKu5+uwfYjfR|99bmKL;x}?NJm22s<8x6aZzgJpo|SEI>iMhA%5` zo>Y=j2kFt2F&r$T44`HCP&;9Kn^s{4s&hj&iD^X`Eq3}jARRfwvuS8OGlQt((!0X7$8^W z;&TAgJDDoDj04Ck=i^R^%{D$!Ipor;C)HsT*y^2-L>0w7@Oi|KnyDo6^0KPY&iKf;o8%f*}vwAO%rJoJv92pS0q9AsZ3UwNpTKz*j6Vtbk8S=c$;6whD=P zFYca2PH2sg72wjVUV9-8oZ3tjF(eraKuwtgPBNOf`Plyr>bJ*%Z{tCJ4LK7U97tEN z70uf_vP9Lh*Bv{4{fcFSn+H;Eu}U4KEE3Ig`&7^D5k2Y0R_D{>u>}5%3^gd+p>45S zF&e}#ioKu`2W;1a1XWb1>FB)~M{;jpr7Jbr_;+|c(~3k8HpkPcW+m-5o`2hW7j@5R z^}#M?+K|)xw|{TSL>H$voqpR3M?Jm1{FkDf0w(=Q1()c#5u=rM;%W*!kD z`%#yxR0KyYBdz|F)JE00r-39K21~jmL7E=mETG=HMlMWAwa6K4I>01vtT?lHa=g-k z_=bqruB7v)V^90Kzgl0#j^mUyw1SWS}^hQ z{ET(vs-%^E8B*3`oAu7;E3L=>E=2m+^=cH*@vb9}_VKT#;uJYgN{tG-CX9(sh6^QH z4nW#-Am%ZsP6wep4yiz-sJ#DG@}t#h!6=|>O@p72C?MV{Fa`AL<6n{{`}E)8SJ74K1mQIZZ-eN8APA} zYJimgHC_>fNV3JoH_rK~h32!2)w^yqTibT%OnYzkSNkryXV}aFNQ84-20<)5g6z?k zj_KE`ArTa2HK}4RcTBZ&`ULm-)KQ!aRQIM`0mjs^{iT_cNt*QZxM`wA#R*H=q9>Qb zpep4+MLfX&O{Lv%)q$to|G=sJPao6Tan|mN=I_v{*rXr!3S;3xj+2kTzplVW|QN*od3e?xBNrSl;k{sbG!+@0nNDW|O zEgQZ_iIE=^>31>*My`6fq%h&stabjImvSH#cfqTScsCsI-s#8gd&s*xa)2A0k&<0O zREOeqOCNk|{N>dz-1=Bah`EL8ESL-}8v-2J{iNxS9f-%281sa8w}}$cqm{9+s|ha2 zAyGaX-3vs2O3r>Vfh%*mmTWIMA4-`uD4p|{2}I_~b*9{BTA6fUb1ImMCEV)v?e|=D z!C&6FsAITj+KwFjUC(OTJ+P>1(}DNCdE&TbtA5%u6ouSyeli%z^B@>x;BcKN{%9AM zU+|cvSTZ3S)*3$p$5c3>UBxO_$bcmaNb^ejo(m~Y{=F*hvWirwyyuB`-FM!}=e^X-aem$z6Jpmh z8+Q+EW^CUV-h1V&cYnP8+CX8vD4d^mT!){p1mN=Myg1^AW*Oms8+|oy<|a~~<%Ccz z+V^=)RS?OPxirs{bKO9nu+A`N-o`*_qARdPZ>na%nBJs^0v!Z?;AX(1^zjN8oMe9N z?|=OGv_G`ld#9W+w!?vR6GaP=GOlf1k;g%AcHXXnIglZf?VN; z!EQFub|Y~jzME{aCL)RQ3x362X$qV#$fYBd$~$Apv8eg4CW_@)w*qNI`hg&?-4qO} z5&_s0bG+)fn`qU#-NsW#ynOv3?K=Kfv~LHRD2*FNet)f_V?T4%q9G4|c=r9PH?AoP z=cdBB&C+f-m!GXwAY6!4I`b3$bSz%P8EhF(5QCC!#=sl^=lBQ;pu_EpO zji=;q1bQt`sO@2;QF{Qc7v-mcCMq3BRfdvh?Dp`VN1ZtMLA73*JC3tmhuPJ2rtNSb zRZ;vDXQjNce|h-+8={jRzb6t%hMI=}^0+Jt$6iMniI^T+j1h5ElM>;uHSiXQn%!AQ zqLlfA$C}_yjVu!R4`rl3uY+`KBC*L1`)#RUU8=mkga&z*T@P&%AmAF6D^7qs8 zjSv7cC4`n4pN$0Qdzz?|@l^U5tm^A5XyPXps9Yi*T*5o$ujVsaoY@}FWXy$FMF3Kp z-PD2A*FN?CuDkV01)^a92yX8gOm&?-I~+*$PD#!+`sdJ|lOb8rm+MQ5&`FMkMrcM6 zb}=!xEipZ^OU?BB0$_9Qy~RSafU_|BmAgPE4G@(8o?s|JR!%mi>YqwLHanU3F)R4VR@wpOQ|_@CB&PWa|@^0f=n~dpU0LiW`pp zxaTn)J2t3JbZeu(GlA4fkNoG5?(3R4H7$!nqLhMcw;yb>$d)WU8>XFVU_!s7928L% zifBb?)IB>3HD-})i(TA=|4mo^x8zs+xDyGaG7-Sm$;oUHqU$3;v@~OoNISqQ@AG3* zxbL(o6)o@D=dWYVIOWt2yB4&Zw6#Iq^?B3pfo0Vj4two`_Xm8o{FbYoysDyTUfSWc zAe@i`!H}wGuX6%1z=IPXQ$YRoDCl*jk1R0OfnD;sA`tReW3`qr|DEVTk<_3U&Puk? zM~u+o%g8^o!4QRe*={4>=cj=NA+af1b6ubJ`klB>FQInXnexG%2BiL}{^0*!?_Kl! z4U>z)UO3`12#FL@Y@RvV)c~w5RiXl4I)D<)H*F`mn~Zs?x+~m8pc|EKK-*>-~8e7;Ty}#-C)EE6g2nTa5OEY zLppjxYvdaDk@RJfb%P6r3g8uaG#PtzQ%4P_2NFSH!&9??rk{1% z?_nU-mnuBdpQtO$Ci6+e3Em8YEhTw@sVoere5O4MJUcxZ6svwuHd5@i7%eA4DK zvQw0E=t-e+>}fS8^!MoR5Ye&Xx>|5gfsmT_I#tc=;9^kyRilJiPbE@@N#nGktQu#P zl}w;S%m}#Rd&D)tt4PIoAqLI{0H7xBvYdi8tByT)%+39~_a5IECef}o)K3q5`u+5a z#(g{d?(+Dm)}h>#NMLsYo;ckz7!=1kk~+Ht=yW!aY6o>~iTPxwVj{7ia}?h|T7y`- z!X#!&nIAb6lDsm7Lppcuih3p}MW9#wlu=DFLob}Bh zMJ5_Nb7^ZMywicy-@yBZANW42*?2->$aBI0jN;3yjFwXlN=6PmVV{1m($V)V)iEV( z6=fOH6<{VOog`wMb>N8xlI(I~mj2XoEl{@uts+I9C*Rsy2>d9M@>tMId%<+e7A-1I zANuNT2es>@58G46VsqERE{3|b*}oG$_cKu5gzrj!9yRqVx#|5}N~%=e3;u#*l?Qcf#;(@sW)NNNI(ZdoJ2% zAxl&+yYf2*#L|_ag5tExcUjOd%N9v%FFK)m$ zXe$-lf9!GQGwk-MxA5siEv9OLD2)=>r-1VNaweKe@~TcQKy^;pW&4ajA2>p>%NV+$>QdmnFhGr15FI&#kL}b z7?C#siROwn(KXP@{g1i|a7#9tQF5NWioQ#bML_md1h;gp)OV_OemqLrCmlh?>es5G z!G%$OonJzf47?>t&w+TFiRx0Ep(eeESKQ%GW6wV2^cVJRx%9A(k$ZSSoRnk7qwugS z+|e<*##yVDjCkyefwz^Gu5X@z>LAZZisa(iNydcM5qZnXk~2msPW0?CL;&X>A)Fb$ z2+H!$001BWNkl(Q{c#t55)nu!{4Y3g-=R5NuYrMLtJrMe%pv z_j~}0qa%Hy0I8ZFRBv))$K>99-ajt5{4LeT`HclYvAvBENOMK!E5Z2{qwhYwaOz_( z=SG|yp7|8z7?DL^D$H$Ui#U8l!-;#btaFNi9bg`P-GI6aOxmBOwgxcJwtf{rh*dg?eKw33HRiAPJcSz-#fOF+#oFJ!(E+KR zPK;^6{y(lb=)OedhHDB!UN|o#HKsuYK5Gs`dAa3JjP9+Ck^pGNt1mG?3XZ1S=W&)CUPVS1%CZI|3xGq7$1{0;nkw3N;puq z+3~zoFkMhsklwr3?c)wT=%9xWYTI=l?(Y1T9*x9As{Pb$99Q}o=y#>ddrzPK^@vHU zZXR4-zBvHlR3N{ZC!+A$Z%#K|W3}tRsR19V2}KPlkuwo13XLLR-C)-cu(N1h?5EWH!C?izEW1Yz)he(>~D)z6;e`C5E z05ig4G*#4hUE>ec6VlH_i7yK8jnV&%YT&-_(&uW%Y31~zIzhP&)TTjGPh|j1?fCli zQ-G9UsNCP?f(IVdR6DH3%Pnistljs0j=6K((Y^P2zm3y49QKU^8tdMQrL1DFS+l-B z{+;jsGY_-LJFR&|CI$ii|4Ijnk~s~k)FjtdG!2$&*wGuU*|7alaN^S> z$jVcf&6nx@e6&(&MN!3Rtq}vyvV$~$`W2tV;?rFzUlKnt4hnrM?MO()0uU>6Aypkn z<~Rj!elUF5ISNE~N)CN(XG5a}Qo>9{***T>*I&@}-JD?R_^6Wz7KQ=B0Y^pi5k!f} zu5LgjOUN!UDk&!ln&9?MZop9P-1@lMY%(Xh!&8$?u|>a-pGN(+#3-qmX0ci|i?u|{ z54gz4DI3uyAA@RWBQ`x5Dwg2jSaPLn~+V9XgyssB6T2$DjOPBCG zfY>gkDkl=JM86L}4%dV`j#IIUv663Qezo7sIWv!%UH0JhNmiYcNGBmD>ICweF`0=( zRU*WlWC#F~0f&?hrNzq$wak*4WP-26f}-H1gR|<7z9W;h`+%$!Oq|mAp2c0Dfm9G? z;$HFrr-6A}~x=ad(y~DyzBG@bndUUUB1O{==4oXQrV zTrU7Y&*5jr3)ba&5Q=z$h0>slwmNVgqT`ePH}~Ijt+U$T1xV@QOIZ>2U6^HMyf?!H?->)!9cukL4XAd!VE%=Cw-Nbc?x=n zUx{WNA?wt@m_=vDKSOq?y+6J}D3s+QfKq9boWy3aP!Whfk}qaFO+r8e2u~C6=}-9^ zN;M)@=TXL#_J{cxJK0>SV=ip23V4a6ljg7P1|yX%n(hA8Aw91jeaJyaFX+^)nJ6^P zeS&M(uFVew0)di}lFf}Rdb+LP%+(B~rKJVwbUNL-b?a(;uchnO^_)I;Mu(3V-*ruC z`O02Nh;dd5p`3IeT9ne!cca!|su)-nO9$mdR0*QaHS%xd!W|@PG0RO@&KpG!RdJqd z?@BjzJ4wWt+*aU9yS{vPvwWW>x=#y3qPcFI1tzzi0^;6>7Sc}DM*B; zP8zxT$ZZ|Ro%Ow@1f-mq>eEQC8`fo7z>D|Fi$Jg_B6X%2vJW+3rC(Em7tO-3%zhnA zLhwQZ1SLlH`Ai0QjUErh{FH$jaL4xx_FamM^v3ki=zhksiy!5&t=TxF)ate!ThQg%}0zo_@Lf%x_9ZczIh~fO;yzW zrIRB8_P6r0pmcffg)3I{{N|hKy%wb(zA)icio-j21^PhHb9m+vH;H);JkLOq`cGv| z2%N+0BijlQn-DqJF=Kp5&=3I-|CA}bHxeYZZ7KvKfR_~rWtDs*ak5n_Vhm}8do`$- zimf(Mag84+sTuE|3-nr>oyrRLv9bUptKF2749%Q4a!nsXo_2Z;eQoD;lL6AK%=E%8 zU%Ra4prTwim>2Ryg?)bZ6ZJuwi6&=|zYZw^4Y~&;=$c5p{JvTo1ngAkiU{<#404)T zs#0R+8FtYX{f<6RH726(2y5-HMVA1P%!r$1JD`tjCW@)zLN#pLFd^J*VlfvgHoIOt z3F&|vfJjb3ytuH{lH#HkOHVxd&W{7Rh2OMqk-I7ZiFjLR8z_ZRw*+=RW93Y9!-fq- zyf<33Xi>8m7N@#8T}9=r*=yFcs*0`dGUMx6Ef%j_x$oNW`0L`yisE=G3863q@|t;W zG#58$HGdSnLQ@@68Z}6g4cQcG!nx-g6EkJRpcsq9K#wK|D1jmtm0sk&RcyJmXcQhN zp1QpbhAIojpD&MVXGwHJ4t6@*xiXb^(M5l=+(H6V~EB$Wo?G}Wd(2RIJEI=D&l+|ewiXM$5{lK9-P zRl$1oVpE_@YdDfNAv5r3Ub8QANuNcIjG8V!!a#M<%4#P@`_*#C4MH;wqfRhv#IRrO zM{^jYIAcvYBFCREIIdGoa3_E#-<^4pR3MPQFqA&!v5tFoUe$e{PHT#rbzXgJr%pSS zvHrAnZEG*z-F?lvHC1n40KD!IT+H%4DNP=44{{2I|PRpaB;%mXcL&ip4^6zPNhLL4+(dTA9<9 z0KCZoX*Om$@`8@Da-&XIR=~%Jk?|o0)FN27YElV!91GT zN@AoZnQ~dlV2%%f@LJ+d&_N#>O{EM&o8AmW;(&NQ_mz?AJ`@Zo=xTOJl?V#t$O8Af zGtj52Cp!UbKQq_;rnQB}|6CJuprSJ1#Zyk2-z%LC#8ZjT64wbX&5hDxutVM|W3<>Jd_lUa=l+hV|! zG97ch&3J5Cn0X%)FymM7j4G}M;J#J&ShY!sy~Ae8} z!0Erf$pWdLnLhl%2Zak>xpHbW>~_ly#DfJ95X@ApO~no+xTuMx|0PUSO=KDrzWRA-wd{;$$>t8a;XhqwDf6KYpJ&Cd7*|vGgJ%Es41@?g&+%M`v_7xgAN&?Ps>TQpvEdtFYMEB8bCD%(#duk z?T6-_;_qhj#VJMs0Oz@$C!(7SfMx>=%ltQyD~s`>-@f`Q@*6PZ^w=0Veo@ z=P!|*XC+U;sJxu0er15a;Ijc1wfI!^D*9at zNVeIppg{YBDF~U6f&pk$CHM=(*vu8#wX8m*f_i#v6yTAuGHi*|8K8ZS<4OLd?8x3& zY%|!dfk40uSEXv7seWWDHzX@H@oEZUde&)60ylBrIFVQ0viWZO?&!zQV3BJ6No?~~ zCbQHkq(YPhe`@|xbk$I7!<3no7`?}rATQ(lF87JXD+0iMqRDD!=HzQiX>`8H`9!mA zGCLd0>*e`WXL|MUuG1N-KCoHT4dw;Y5Ds$FQUz9MfB?ghs6VAGK_(@9lxoEgpv2u) zPJZLpvRJPM3sd$FnTnXNgmK6~1TGlEcBok=LC7wxW`Inw58N8bzdV>lHGlTA41iE( zf@y^rt^?d~$o;J&Vf03YMx9|xntl1&DBsKU2Yp9m>sr2sN1#yvBO3?*RRr%a3U2xN zbgaV)2W9f=S}^5ENrzpsX0&C5N>9Q2~ktlzhP+K8vTyXl|V+zu8O7nml@;c zZ;J*S!>D9Ca9KzeEVcq=D%1D37`#o!h<{$)OShdA7x!)478sNCc-8&lAH}KFrc0nr zkF}bsR(s6GOs#P_o+hCV--nvyrYFqP)ojReu9B%Qg;oJF(RhWE3PSFbPe-ggimutl zp0Ttw0L9OLGeAlPho1>9LLOHQ@A6r|jUAC6VZq!GXQnO$_(udBwd6_ngjzg`Y2qZ7 z!3baQiZV*=@3Vt85=@o1$`1tUJ6@K<$@BoC`O8@rO+BSYL;C>DfFrsKsM$tO39ti6 z8qCyt>a(k8l-}>xq|8SHw0uzw{0gLXyVN2_CaR5ND@#l+T+4MJf>4U@SSB&yK-d>z zut+K-EdowVa(YIQRiaRBMA~;v$KJns2!k|0=XV1bcrxreQ?&0NcbnnTAQ-7+Ps;4+ z4O;gPfkit1$UB&A*p@NbfGXz_1q}QiEt-cTA*(n6B&xYdA56OOoC%+e`sI|`0#j4F z?zae}7BjtJ)ZQP(lbesu&v8Npp%mou9B5>iMC2^ZUBez^9N6biA||B8ppb=TV|s*z znuV>nl&CLC=$Qf>``#*)prXneSSa{XAXTiF4 z+h}bL2E4R8L;;eO?PW1T+0O_-SR4j7I7+PeSy#BR$$t$$%zR(r^H=`ts9cjSKP3A*iWf$^209+yA>{=|Jo%dU9}61I#V8_csTm zWUzF_m_OZk!1zSXra^hZR5&lpfS*pvqxmLMtCp)?FoX$_9?A&Dh@c1hKjjql2VW2f z3;-gqDW5G_L>7QjP$fccIai6FThv`h(4WiT-`kfV6qLo5`Sj-@C6N1QuVQUqKe2|!L*^UV}iycqe z^%Z=^elfg(s7xtTP_M9g9&s?Ji_Lb&^Bd9$7vfb8q$)#+!f=c6Z(X?HQt@u2UdC?) zKz+maTYD{8T;o-M)F4%Y@0P#x`d7{74Oa()$!K9%M)Na3Pc0~V95aHC#p2MnWJT$H zW}1(wQ4qHMjhX&e1XRI_MLP*S2#hjKC)At?}zZUI{H$7hD3e^)aV#kTkcVNQ}H z@0PK#kRTZWf9=jdwoBNg?n~-(Rn~wGgi)qWe6DiI+Gl5J9w#Z5${^Bz6~AczpT*G3 zsj}*;0#FQlGz>dqh2UJ#vNa8<+Mlce$CtTg1Go)blJy%Oy%xS(l*jh7$~j`6F@|mw zlcs8(WBWo8EVqmS^3le$_ivhpp#mgp9B#^UooKuu(&EXtF8uLo1){t@7B7j}sH-?_ zD-!-@8L6JEjOlu&ciejD#T!ajJ&+qo7v@D6gaR@*AE$_zU|MiZqv+~xbV2*w0JJBm zDd_8A^c&KMt6{6=`5X?U@03Kpg=#&M6&WULQV^~CBfw>ABZ3U^ed^=^0=inNB$yPM z)U>h|W!Q=#S|WG+oB$l&%L>RLgUd|6q>Nenxrqux+*tvo97`Ka_2+0ZD*?N4J1EG| zz$bg(-UO*%nT~~t+-SY4YLD5Z&|$uXF%;JuQ(JEsRB0lLqR2UGr(>%5s-}nqma0$W zlr`U@0Ep;KrwAnvTLu`}USy&?I-jlxRkv!^?v9rR&c0WHs9uBH3RI2#d%p)DQKWraNC3x20_A@8LC+B2e>$gJf_ zI1b7Qh-dm)DN34{`|HLL0w({nQxQ^ib@kZihO=`|lkJ-I} zGzi8^V%yB{DDa17ILf5_2FU(ue>I6D_|B@5~C{My@HMSRl8hoYpR>7DW(*g6Gpvt2s}7k&PZfNsF;Cg7YTod8GbB0L5}y|{Y-nQ-$XZd^F-BM5$iu`Nj* zJP=Z*$=Nh`Mwv< zwZ;(Q=j+c4hLQ3F+Csm^7%Pq1%zwM|qeovb`RH#h9%*)lZ4fFj5jh1gjw%yih56bX zAPMu$dBI@-#9nT7k$!E!%O0~X08Y%WM&G7qyZpjOEQW(;k|r9tBmiW2wP>A946NwS zXyUW;A<%dVfH5l%6A~Es!wN{E=<$Bw$TbmUeeu|XUz;%o*_OC6(BCL-k4VD{t`k}8 zk-~wSyEXF%~L%%DpD#q4`+bG-c7 zbdLjBvU*rEVcPb%6%wgoC)h|j86X*%WuAdC-!T>0V#KW!-fsx`|i8% zB>(=6iHY&szIw`CX)?QiZZcE1<=5)A>{_&_1CvtCQe~jQ}0nCt{>EcIV z@v&CVG{LkcK#3#Eyd;&K@^dxl#n%YS;5R{hhM`|i7K*TEVlUJ$1q6DQyK&5{QP#t* z3f}@`lOB{55(7CJp}n^l;GZyArnbPTN|-;hOBtCM=x}AAUYMSWi373$F>CuhpsDOS zgcoPxi+GD~fF?S-V_;lp6AWOE+RBlATXO*Q(s57;S!UFt-~eTtsbqbj{hn`VKHF-) z@t`#)pL*n9d}FRPwGaTbWS?9}-FBv(JM3(He0+){`gR1~bK#-?F+IKI_-4a27Y*g6 zmG;HlMV1tsY7XEEX0rMGK!k`9Gb_BFIz~k=;8v{n+ z9Z;h|M+yM}1#%Y@f<;B(WMGK_G8i)soS^wDeWrGZlm}V%9Bzx~jV3PzjTKbwqJd>b zucm%6mDi6Jg^+@c5a36~Bhs(p{FMN#-x}#Y?z?kTt`}XbJ~Q03&@hL&08<=bnY$|n zKW;|FR8Pf(o{h?HNli9W%Z7$VH(dUT@4w`*#rv&wW0dEuNi(@*PdHj;ccIvVWu)dxoV+~k{Q|Q%Ot)l!DsC#zC9ji>Ql&^!%Ygon!yZB;-WR6Oj_kke$2VOc#Q|}qERcpUuq+8L=6nV zCg|G)lp1xcaQ>HrPMJ28#sL)L#v@D|xFp4u{ALzzIO0NyBJ#!fyuMlGe$rrTa1ZKC z*UjvvBpb*_H=q5ye?4o};YVL9cPUvjPZeQ zeW$6*h*A?-QYo2PPQxXIOnMrXph*_!I zRfu6RbK|j=K%YmS0BEr!9R;*x?no3Nra9bKz}|I3!JXMTz@m;b6{+?c0L^J2fdV&A zWW@`wl=sJffeQc0)-{*d-ea0KomPv+NnHgv@ z+loQXznW@>lfeYU#TT|9GdZdmD%W8?Ikzz|Wkb*vAYdjG1TSDQvPKmEMI2_)-%xU7 zFJpNV8-O0*AhX7yL8Ks{%>|PJgjEqR__lN6fWNz_5NLepQSSDE%*kF#X}$^zG}w_# zKmvI<=g|fs+YBeEGZ6E(1zaWXGl}fW+o`+92O6W z{Fm-{02R9n!$X$=n4i)<2Li<+AVo8oBOAohiKPh>17ERYe+;e?0jF+Lc9d==G&ys) zR2YC=HGEFPMRvyMD*-$d!|RL{CY#(4XeZ<5$D~rLSE2Sad})HYh7FU)T!D=HPDMrl zWRYF+&$QR7IsquHYikUyC16_=)Z>@*XX^{?w-eKww#R`qI?G1)x%0d~|Jq5h4!wg>N1v+# zj5dlB10+8_&b4P*6tFnpH-VDCfi<$CC}5`TSB}HAH|3sD+acMKjyJ}(tB5;hk)j}Q z0M6`QIZ~j#WxxqcSnxuFSzO#C_~N)?5`t=24pD)Te!@&7rh-wnQVdUStZfl$K}i2R z5B`XP{>oTW%X1aHp3!O*RYs62AC_N6b_zI5xAmV|)4#nvF*B3(tdWmA^7?)L;q22_ zz546GLJRSOg$$ZyeXoG@Nxl&mUU}4&n>VdLXRwtGWX4yKYBs$8)W4lkzI`AqqD3v{ zHvt^Z2AAl=Gm1(8*gZ$gK#&HZiOJ+8_H#zSB$0LwZ1D4d5te~*z`R_oRPQsDzz?=t zfFBhL%>hD>ofh&UK7fLM8HO{=QjY9-IGiz8Y5)K zg+vRf-b6qu$3BB^mg#52(p~?9V{tUkNWq&SmA#{({9d;bec5ehQny_*d1n10ndxq; z_m&Mm>uYOH`td1Ga!D-c%PJs!g40jF)211a z*iv?-8A8enyxvqF>KP&w(3Pk^eFrKlh1YrjK(o?E=ppE1ZxNkMB}_-Yi@_^)t7-O= zuqfUfz+6TXT>C_B1O#DO@f;k(1y6sY`v!qKhi<+)m%W9$9H>&2a}mHsLSX1Y%`?_m zvc?!H-w{CtGehBF9!lLas88&{p#M6+q`s*?nK}-@jBK6{<@31d`xP9Z7n|$_7RocC zAMhn}F(tH6_`5C|Kb2h!0OukIG5#F>cmV8nPX^ONg) z>LOwWgg{yZXo$LtS?N0*n35$Cc?KHyWt2M6wH%9KGOR8G2!av#`c`X&sX%;=DuzP3 zBiAKRO{+i}oAW{Xr<%x2@PdATJSa4!A-W%BSt)>rVxq#h$Oh)e3#C&G$OxkR+DY1P zDPY3;5=fiSkx=3*g=yz4oX=3Q)tYK1F*8$n-k%0SEdrCFfro z?hBcqjD?sQ&MpLem=Aie(Ns(E*CLz5@!__48YRBH(n7}UHjp;(l4gk&Fn2)}1uKoP zW16W)bvENgBf6twkpq?&B^nUn^sR~Xwe%;M8~DBaZ_KXsfdQbi*)Gq5yOg+7*mEJ9 zWy!l5vQeH1oOpk=jmFPzYnaaVT2|}Vy8G<4-z}?8`tgY?sX7zYpja@~nx5pcpYyT` zNO$sx{@4At{pk(YzWsCC9-lmXXfSIIwKCI4$#;roJuDn&NK4^oEHg*cA_Ao_a|hf8 zF(3t6RXv_VsuNM<9~Ywpyb9V%@Psl8B)3E7@U=emq8<~J;pcz$K7XX=96~$u6Iu6w8KtkmQ#D4-72HYISN;BrdT1~}J zy}xe^sH{fFddBqHiRsLwW_C-`8EGxK`;0^X`E92hdF zK~%;R3V~3;YmY>l`WmL$f=$h1Da;fCiiDlS)3xW|%Fzrn>MV~(V77w`VF#;|Kh~s9 zg;^fM&U9jCC)2EzF24V`(JRh6=hY{>%JueN{Lb#ArLZ7xQvvBNp7zh*c-^UY-u14} zr1j2XyFlypnrSrbe?c}SfEckLFr~F1N>SG-d<5#8dh?fAkoo{UXlQ^(z@1MRrSag% zyRt(BQH`>MRhrP>%g=_RO)z7~Jva)C;RaFwEp0dYg>m{&O2+aka##}hGtx(en8oF& zysk`&#)Ee5?W?=^RbSAzuYhzXPya-o4?WMAAi8fK@qugp@uCOr|NHaue0Is=(L5O( z=!>RML9Z-W0)QAZ)soau5&pB2k%B{kiA;D=ED{~EA<-!o(pf_=xBWx&UL)A-5B31& zrA!)pb88>oKoQkrXq_3IYyjlp1wS*^X$`@S!8bgc9nV7weV8S|Il?F%KS5pIazKTF zDhjzGJmN($PZbyN4yv0+T?fRsgT|@Nz!!V=-kwg)%%&tu@_|i9*57-@rDvRbrFo`}pcdAO6^-jYem{`bBF=W*SXnQY+pj2CBS; z{GU|u-T{_S7Cpm9Kr8?yVuWn^3kYLsX*nQbphqM2Z2FU?vc%1xY!{A%W-b^h1BCk# zn6h4!d90Ky1O_b}4A`m^TaGpv9V`Em%Na?+_86By3=ifxkUZT400jO0)ju78Iiq=r zyFx$>i>7cIYFy|9-XG=4e%oSYYt~Cl*BrcH+%(-~Pb+D}>o*3{=bA&?x&f{kTG%2NdF zAOfudbrzh5L8&-E&{xgQpdkYkWTiYk||Nd-bh9sjJblpX>n25I8M_XH66fH?vi zcNB|yYc(G3fZ3y}0-e{B`aYuj1UCgJ?E#=13jLMg7Q|4ZrT{N#RGD8vGip*e=1u=fG>6$;7y+jeby(IKngYG0>-Y z5zjG|yT27x3uFY=-2SbX-g4_ZKQq(Yd_Y?7CpOA&nPQUUrrGp*RAxLFn9yJjNqHQ- z1*sCRZ3)t_c9lROHfQY(ZOv6qU83tl|1J9$^}oI&v5O!U+N*Fqa51=N5Q8Nk!aAMk z!U+1yj8QU*pymMUHlh8VO?#nisNLk&^O&fa?zR+Wt}X!}x|ZQQP#%yKfO`#VNh5O} z!c^`~?v&1UV)`x<$(|jbo4i-=4W(nhc=^cXfBn{1oKopP_aNM;80l`F4C_PPxN+mq z^5x5IUbFa7Z~NKL4!Z7pZ~DUIV-FwE?)97XR$gDSsPFWs4yvSzI-G{-fRnvyC3)uV zqfo=D!6YJufuEK*E4d3isG$##O=2JDBWm~(tT0#ad`O!t71GAj*( zJ1A!gyt&HgWuEDkk7^j;YoP3#HXAn#pg)xw2jRA&3ItFVAc&${g9o0QBO~j_#_B(( zT`qjB->j$8%NOr`%jrja^$n}wDDgbcM>lTV*jm1Pxvl@Opib@F&C9m%_zFn(v>A!o zbMv}&W8c61J15+~{$m$qX7e8p4)zmU$k_hRR+~!5mnsm)hvzW^MJ5^fCsAwap~8Q` z%A%x@Mr3{l3=*VC-Vdt4!l1(bQEpBae}{Gie_zn2LOP|-`chC2hA8l>5~GZsA*~96 zP*L!XK^)o>gtMZ8*fH>eV?=8c1Pu)XiTaU8T4tbJjj6pg={I^yf4cAT{nvc%`2Q9O z(;oi1F4*Q(K)Q!ceOa{sTR*x_t5oP0qGt(F*|D3XTN^ksT1ojzI?W~dA}s> z*K2jZz-`puWlp7-y^hg!@D^_#K&~ zfHV3XOKPhIzD5dcl~sQdRvAj9kR|({iRHR-dzdf~dn_>{%A;hM-K4ITFu?$LCq1v< zOPudBw`U^R7T9y*`)Rw?U-Zip20n7unJ1t2gB{I%_4%GR0u_+%d2>?QqPcvjYuBzF zz2V+F&iUyBA9}~s<6D-bY1UZ0BufTbv{EBB%DMCcX)JGI{F8tRG=u)eqIRihFO}WN zFN<#z3ib&AJre{I9RgXx3Ry-}5ZD*}plBYKrF4R$!TXehfEvZsrJyJU+A)g@`p2GU zh2Jop*LNMkU#q@&SFdNtwhrj_O-a`8B(qCK#~wbm^}$Qdea#!bh?8FVKA$FwvbaQ^ zehsf$TpWShA6|RdEw|ow;x8Wl@VVXY)@7#APwMtesT!Sr+9Z9d%d0ODv|BU~W`;n4 zIq`(J=pT*1*QLA6Z%w^|#&n>{q^g-W`uza@OYQt;>_NKQcJlO9ltCz|W~C znnJFQ6WU8&lLVoBb`ok!(eH@C8$HTH{gE1M!5XM4X)0m0Sj;6Z>;h(fa4IW-Hxopj zUTz0p7XHpvoY)Uc4hpwAC;-P!3s^DIgqS_ojA?I6%*^A>e%47J8yjAT&!_orOHSsguabppAAcdNtFTwPzmrUbs^@J4tSmq}OURHxD)U`pK(S zeEJ=)J^V$#S|G33g6?Jor1Nz8txt7wa&l3Be7wKhm~EJAea}7jJmZda_Z@rZBOiJ1 z*7nr?vz^XRJf>jL4R*zWv(= zZ@B+g`#qDbiGBB(eR;s}aO=}lu;>Zxmf7Car?2Z*v z8th?zs=5+lxl!n=1sNz*c#4gF)N=Z2P@Z?9WUI5iZni&G&rHA3tJmw@TCMf)e!qL& zmCt;}-gmEj(Sg5Mb?_?5K3kjTqb+07?VC0YE?sKOQnPeR#W;8T?#;(6`c6e)PJvzh1fiw-3E=WGX8-`NC}Ai#G#Y}81fKY}c+?X`6y>4Q9otm+X(*Co)%wD&aTc(*< zG_9F_lGJ-?TAyt;np+Qe^sMhZYsG#y?X_&_t*0INvfu8ap{#B@&qkmE(s?$ayQ@1l z-gx8a#`^Ys@0$G7@zb5j7tD4$f7HolM@-UP+!)@zXkfVCFuAdCn&cM4a#PC^Uzf>b zc`b8tERtVA;bJ~Ninwl6ZQfpCRR}d3*Rt4XJ*1Y#=6Pl^lbBv_rrzmo8QhX*&BvO} zbh?=gKQuHjcIy${xButar=3;-DpNAszFRbS@M2vk5if9A64Ni_o12<)a2_& + + net45;netcoreapp3.1;netstandard2.0 + RRQM.ico + true + RRQM.pfx + 5.5.0 + 若汝棋茗 + Copyright © 2021 若汝棋茗 + 介绍:这是一个扩展于RRQMSocket.RPC的XmlRpc组件,可以通过该组件直接创建XmlRpc服务解析器,让Web端、移动端可以跨语言调用RPC函数。功能支持XmlRpc全功能。 + +更新说明: +同步更新。 + +Demo:https://gitee.com/RRQM_OS/RRQMBox +API:https://gitee.com/RRQM_OS/RRQM/wikis/pages + https://gitee.com/dotnetchina/RRQMSocket + + true + RRQM.png + 若汝棋茗 + true + LICENSE + RPC;XmlRpc;Socket,IOCP + + + + bin\Debug\netstandard2.0\RRQMSocket.RPC.XmlRpc.xml + + + + + bin\Release\netstandard2.0\RRQMSocket.RPC.XmlRpc.xml + + + + + bin\Debug\net45\RRQMSocket.RPC.XmlRpc.xml + + + + + bin\Release\net45\RRQMSocket.RPC.XmlRpc.xml + + + + + bin\Debug\netcoreapp3.1\RRQMSocket.RPC.XmlRpc.xml + + + + + bin\Release\netcoreapp3.1\RRQMSocket.RPC.XmlRpc.xml + + + + + True + + + + True + + + + + + + + diff --git a/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcClient.cs b/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcClient.cs new file mode 100644 index 000000000..77ed19dd7 --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcClient.cs @@ -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 +{ + ///

+ /// XmlRpc客户端 + /// + public class XmlRpcClient : TcpClient, IRpcClient + { + /// + /// 构造函数 + /// + public XmlRpcClient() + { + singleWaitHandle = new WaitData(); + } + + private int maxPackageSize; + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return maxPackageSize; } + } + + private WaitData singleWaitHandle; + + private int timeout; + + /// + /// 载入配置 + /// + /// + 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)); + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T 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("调用错误"); + } + 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; + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + 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(); + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + public void Invoke(string method, InvokeOption invokeOption, params object[] parameters) + { + this.Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public T Invoke(string method, InvokeOption invokeOption, params object[] parameters) + { + return this.Invoke(method, invokeOption, ref parameters, null); + } + + /// + /// 处理数据 + /// + /// + /// + 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("超时接收"); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcParser.cs b/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcParser.cs new file mode 100644 index 000000000..a001de7ed --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcParser.cs @@ -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 +{ + /// + /// XmlRpc解析器 + /// + public class XmlRpcParser : TcpService, IRPCParser + { + private ActionMap actionMap; + + /// + /// 构造函数 + /// + public XmlRpcParser() + { + this.actionMap = new ActionMap(); + } + + /// + /// 服务键映射图 + /// + public ActionMap ActionMap { get { return this.actionMap; } } + + private int maxPackageSize; + + /// + /// 最大数据包长度 + /// + public int MaxPackageSize + { + get { return maxPackageSize; } + } + + /// + /// 函数映射 + /// + public MethodMap MethodMap { get; private set; } + + /// + /// 所属服务器 + /// + public RPCService RPCService { get; private set; } + + /// + /// 执行函数 + /// + public Action RRQMExecuteMethod { get; private set; } + + /// + /// 结束调用 + /// + /// + /// + 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); + } + } + + /// + /// 初始化 + /// + /// + /// + 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); + } + } + } + } + + /// + /// 取消注册服务 + /// + /// + /// + public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances) + { + } + + /// + /// 载入配置 + /// + /// + protected override void LoadConfig(ServiceConfig serviceConfig) + { + base.LoadConfig(serviceConfig); + this.maxPackageSize = (int)serviceConfig.GetValue(XmlRpcParserConfig.MaxPackageSizeProperty); + } + + /// + /// 设置执行委托 + /// + /// + public void SetExecuteMethod(Action executeMethod) + { + this.RRQMExecuteMethod = executeMethod; + } + + /// + /// 设置地图映射 + /// + /// + public void SetMethodMap(MethodMap methodMap) + { + this.MethodMap = methodMap; + } + + /// + /// 设置服务 + /// + /// + public void SetRPCService(RPCService service) + { + this.RPCService = service; + } + + /// + /// 初始化 + /// + /// + /// + 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 ps = new List(); + 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); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcSocketClient.cs b/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcSocketClient.cs new file mode 100644 index 000000000..75cde92df --- /dev/null +++ b/RRQMSocket.RPC.XmlRpc/Socket/XmlRpcSocketClient.cs @@ -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 +{ + /// + /// XmlRpc辅助类 + /// + public class XmlRpcSocketClient: SimpleSocketClient + { + /// + /// 禁用适配器赋值 + /// + /// + public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + throw new RRQMException($"{nameof(XmlRpcSocketClient)}不允许设置适配器。"); + } + + internal void SetAdapter(DataHandlingAdapter adapter) + { + base.SetDataHandlingAdapter(adapter); + } + } +} diff --git a/RRQMSocket.RPC/Delegete.cs b/RRQMSocket.RPC/Delegete.cs new file mode 100644 index 000000000..4a4b7ef54 --- /dev/null +++ b/RRQMSocket.RPC/Delegete.cs @@ -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 +{ + /// + /// 收到字节数据 + /// + /// + /// + /// + public delegate void RRQMReceivedProcotolEventHandler(object sender, short? procotol, ByteBlock byteBlock); +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Attribute/RPCAttribute.cs b/RRQMSocket.RPC/Global/Attribute/RPCAttribute.cs new file mode 100644 index 000000000..a95c615db --- /dev/null +++ b/RRQMSocket.RPC/Global/Attribute/RPCAttribute.cs @@ -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 +{ + /// + /// RPC方法属性基类 + /// + public abstract class RPCAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/InvokeStatus.cs b/RRQMSocket.RPC/Global/Commond/InvokeStatus.cs new file mode 100644 index 000000000..10c28f66f --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/InvokeStatus.cs @@ -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 +{ + /// + /// 调用状态 + /// + public enum InvokeStatus : byte + { + /// + /// 就绪 + /// + Ready, + + /// + /// 未找到服务 + /// + UnFound, + + /// + /// 不可用 + /// + UnEnable, + + /// + /// 成功调用 + /// + Success, + + /// + /// 终止执行 + /// + Abort, + + /// + /// 调用内部异常 + /// + InvocationException, + + /// + /// 其他异常 + /// + Exception + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/MethodInstance.cs b/RRQMSocket.RPC/Global/Commond/MethodInstance.cs new file mode 100644 index 000000000..113eb1be9 --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/MethodInstance.cs @@ -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 +{ + /// + /// RPC函数实例 + /// + public class MethodInstance + { + /// + /// 执行此RPC的实例 + /// + public IServerProvider Provider { get; internal set; } + + /// + /// RPC函数 + /// + public MethodInfo Method { get; internal set; } + + /// + /// RPC属性集合 + /// + public RPCAttribute[] RPCAttributes { get; internal set; } + + /// + /// 方法唯一令箭 + /// + public int MethodToken { get; internal set; } + + /// + /// 返回值类型,无返回值时为Null + /// + public Type ReturnType { get; internal set; } + + /// + /// 参数类型集合,已处理out及ref,无参数时为空集合, + /// + public Type[] ParameterTypes { get; internal set; } + + /// + /// 参数集合 + /// + public ParameterInfo[] Parameters { get; internal set; } + + /// + /// 参数名集合 + /// + public string[] ParameterNames { get; internal set; } + + /// + /// 是否异步执行 + /// + public bool Async { get; internal set; } + + /// + /// 是否有引用类型 + /// + public bool IsByRef { get; internal set; } + + /// + /// 是否可用 + /// + public bool IsEnable { get; internal set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/MethodInvoker.cs b/RRQMSocket.RPC/Global/Commond/MethodInvoker.cs new file mode 100644 index 000000000..864971c2e --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/MethodInvoker.cs @@ -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 +{ + /// + /// 函数调用信使 + /// + public class MethodInvoker + { + /// + /// 返回值 + /// + public object ReturnParameter { get; set; } + + /// + /// 参数值集合 + /// + public object[] Parameters { get; set; } + + /// + /// 获取调用状态 + /// + public InvokeStatus Status { get; set; } + + /// + /// 状态消息 + /// + public string StatusMessage { get; set; } + + /// + /// 可以传递其他类型的数据容器 + /// + public object Flag { get; set; } + + /// + /// 此函数执行者 + /// + public object Caller { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/MethodMap.cs b/RRQMSocket.RPC/Global/Commond/MethodMap.cs new file mode 100644 index 000000000..cf369ad60 --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/MethodMap.cs @@ -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 +{ + /// + /// 函数映射图 + /// + public class MethodMap + { + internal MethodMap() + { + this.methodMap = new ConcurrentDictionary(); + } + + private ConcurrentDictionary methodMap; + + internal void Add(MethodInstance methodInstance) + { + this.methodMap.TryAdd(methodInstance.MethodToken, methodInstance); + } + + /// + /// 通过methodToken获取函数实例 + /// + /// + /// + /// + 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 keys = new List(); + 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; + } + + /// + /// 获取所有服务函数实例 + /// + /// + public MethodInstance[] GetAllMethodInstances() + { + return this.methodMap.Values.ToArray(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/RPCParserCollection.cs b/RRQMSocket.RPC/Global/Commond/RPCParserCollection.cs new file mode 100644 index 000000000..1ff891b8c --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/RPCParserCollection.cs @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; + +namespace RRQMSocket.RPC +{ + /// + /// RPCParser集合 + /// + [DebuggerDisplay("Count")] + public class RPCParserCollection : IEnumerable + { + private ConcurrentDictionary parsers = new ConcurrentDictionary(); + + /// + /// 数量 + /// + public int Count { get { return parsers.Count; } } + + /// + /// 获取IRPCParser + /// + /// + /// + public IRPCParser this[string key] { get { return this.parsers[key]; } } + + /// + /// 获取IRPCParser + /// + /// + /// + /// + public bool TryGetRPCParser(string key, out IRPCParser parser) + { + return this.parsers.TryGetValue(key, out parser); + } + + internal void Add(string key, IRPCParser parser) + { + if (this.parsers.Values.Contains(parser)) + { + throw new RRQMRPCException("重复添加解析器"); + } + + this.parsers.TryAdd(key, parser); + } + + internal bool TryRemove(string key, out IRPCParser parser) + { + return this.parsers.TryRemove(key, out parser); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.parsers.Values.GetEnumerator(); + } + + /// + /// 返回枚举对象 + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + return this.parsers.Values.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/ReadOnlyDictionary.cs b/RRQMSocket.RPC/Global/Commond/ReadOnlyDictionary.cs new file mode 100644 index 000000000..1ab419dd9 --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/ReadOnlyDictionary.cs @@ -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 System.Collections; +using System.Collections.Generic; + +namespace RRQMSocket.RPC +{ + /// + /// 只读字典 + /// + /// + /// + public class ReadOnlyDictionary : IEnumerable> + { + private Dictionary dic = new Dictionary(); + + /// + /// 值集合 + /// + public ICollection Values { get { return this.dic.Values; } } + + /// + /// 键集合 + /// + public ICollection Keys { get { return this.dic.Keys; } } + + internal void Add(TKey key, TValue value) + { + dic.Add(key, value); + } + + internal bool Remove(TKey key) + { + return dic.Remove(key); + } + + internal void Clear() + { + dic.Clear(); + } + + /// + /// 键值对数目 + /// + public int Count { get { return this.dic.Count; } } + + /// + /// 尝试获取值 + /// + /// + /// + /// + public bool TryGetValue(TKey key, out TValue value) + { + return this.dic.TryGetValue(key, out value); + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator> GetEnumerator() + { + return this.dic.GetEnumerator(); + } + + /// + /// 迭代器 + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + return this.dic.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/ReadOnlyList.cs b/RRQMSocket.RPC/Global/Commond/ReadOnlyList.cs new file mode 100644 index 000000000..a1a404a6b --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/ReadOnlyList.cs @@ -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; +using System.Collections; +using System.Collections.Generic; + +namespace RRQMSocket.RPC +{ + /// + /// 只读 + /// + /// + public class ReadOnlyList : IEnumerable + { + private List list = new List(); + + internal void Add(T block) + { + list.Add(block); + } + + internal void AddRange(IEnumerable collection) + { + list.AddRange(collection); + } + + internal void Remove(T block) + { + list.Remove(block); + } + + internal void RemoveAt(int index) + { + list.RemoveAt(index); + } + + internal void RemoveAll(Predicate 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 collection) + { + list.InsertRange(index, collection); + } + + /// + /// 返回迭代器 + /// + /// + public IEnumerator GetEnumerator() + { + return this.list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.list.GetEnumerator(); + } + + /// + /// 获取对象 + /// + /// + /// + public T this[int index] { get { return list[index]; } } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/ServerProvider.cs b/RRQMSocket.RPC/Global/Commond/ServerProvider.cs new file mode 100644 index 000000000..a6b0ea34e --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/ServerProvider.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Reflection; + +namespace RRQMSocket.RPC +{ + /// + /// RPC范围类 + /// + public abstract class ServerProvider:IServerProvider + { + /// + /// 默认复刻程序集 + /// + public static Assembly DefaultAssembly { get; set; } + + /// + /// 该服务所属的服务器 + /// + public RPCService RPCService { get; set; } + + /// + /// RPC即将进入, + /// 若是想放弃本次执行,请抛出 + /// + /// + /// + /// + public virtual void RPCEnter(IRPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance) + { + } + + /// + /// 执行RPC发生错误 + /// + /// + /// + /// + public virtual void RPCError(IRPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance) + { + } + + /// + /// RPC方法执行完成 + /// + /// + /// + /// + public virtual void RPCLeave(IRPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance) + { + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Commond/ServerProviderCollection.cs b/RRQMSocket.RPC/Global/Commond/ServerProviderCollection.cs new file mode 100644 index 000000000..b9e5969ad --- /dev/null +++ b/RRQMSocket.RPC/Global/Commond/ServerProviderCollection.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System.Diagnostics; + +namespace RRQMSocket.RPC +{ + /// + /// 服务集合 + /// + [DebuggerDisplay("{Count}")] + public class ServerProviderCollection : IEnumerable, IEnumerable + { + /// + /// 服务数量 + /// + public int Count { get { return this.servers.Count; } } + + private List servers = new List(); + + internal void Add(IServerProvider serverProvider) + { + foreach (var server in this.servers) + { + if (serverProvider.GetType().FullName == server.GetType().FullName) + { + throw new RRQMRPCException("相同类型的服务已添加"); + } + } + if (ServerProvider.DefaultAssembly == null) + { + ServerProvider.DefaultAssembly = serverProvider.GetType().Assembly; + } + servers.Add(serverProvider); + } + + internal void Remove(Type serverType) + { + foreach (var server in this.servers) + { + if (serverType.FullName == server.GetType().FullName) + { + this.servers.Remove(server); + return; + } + } + } + + /// + /// 返回枚举 + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + return this.servers.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.servers.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Exceptions/RRQMAbandonRPCException.cs b/RRQMSocket.RPC/Global/Exceptions/RRQMAbandonRPCException.cs new file mode 100644 index 000000000..c16b3b0ff --- /dev/null +++ b/RRQMSocket.RPC/Global/Exceptions/RRQMAbandonRPCException.cs @@ -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.RPC +{ + /// + /// 放弃RPC执行 + /// + + public class RRQMAbandonRPCException : RRQMException + { + /// + /// 构造函数 + /// + /// 是否反馈信息 + /// 信息 + public RRQMAbandonRPCException(bool feedback, string message) : base(message) + { + this.Feedback = feedback; + } + + /// + /// 构造函数 + /// + /// 信息 + public RRQMAbandonRPCException(string message) : this(true, message) + { + } + + /// + /// 构造函数 + /// + public RRQMAbandonRPCException() : this(true, null) + { + } + + /// + /// 是否反馈信息 + /// + public bool Feedback { get; private set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Exceptions/RRQMRPCException.cs b/RRQMSocket.RPC/Global/Exceptions/RRQMRPCException.cs new file mode 100644 index 000000000..5c234ef73 --- /dev/null +++ b/RRQMSocket.RPC/Global/Exceptions/RRQMRPCException.cs @@ -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.RPC +{ + /* + 若汝棋茗 + */ + + /// + /// RPC异常 + /// + + public class RRQMRPCException : RRQMException + { + /// + /// + /// + public RRQMRPCException() : base() { } + + /// + /// + /// + /// + public RRQMRPCException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMRPCException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMRPCException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Exceptions/RRQMRPCInvokeException.cs b/RRQMSocket.RPC/Global/Exceptions/RRQMRPCInvokeException.cs new file mode 100644 index 000000000..c0ef6b986 --- /dev/null +++ b/RRQMSocket.RPC/Global/Exceptions/RRQMRPCInvokeException.cs @@ -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.RPC +{ + /// + /// RPC调用异常 + /// + + public class RRQMRPCInvokeException : RRQMException + { + /// + /// + /// + public RRQMRPCInvokeException() : base() { } + + /// + /// + /// + /// + public RRQMRPCInvokeException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMRPCInvokeException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMRPCInvokeException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Interface/IServerProvider.cs b/RRQMSocket.RPC/Global/Interface/IServerProvider.cs new file mode 100644 index 000000000..3c8c78e80 --- /dev/null +++ b/RRQMSocket.RPC/Global/Interface/IServerProvider.cs @@ -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 System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RRQMSocket.RPC +{ + /// + /// RRQM的RPC服务接口 + /// + public interface IServerProvider + { + /// + /// 该服务所属的服务器 + /// + RPCService RPCService { get; set; } + + /// + /// RPC即将进入, + /// 若是想放弃本次执行,请抛出 + /// + /// + /// + /// + void RPCEnter(IRPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance); + + /// + /// 执行RPC发生错误 + /// + /// + /// + /// + void RPCError(IRPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance); + + /// + /// RPC方法执行完成 + /// + /// + /// + /// + void RPCLeave(IRPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance); + } +} diff --git a/RRQMSocket.RPC/Global/Parser/IRPCParser.cs b/RRQMSocket.RPC/Global/Parser/IRPCParser.cs new file mode 100644 index 000000000..f142d63e3 --- /dev/null +++ b/RRQMSocket.RPC/Global/Parser/IRPCParser.cs @@ -0,0 +1,75 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// RPC解析器 + /// + public interface IRPCParser : IDisposable + { + /// + /// 获取函数映射图 + /// + MethodMap MethodMap { get; } + + /// + /// 包含此解析器的服务器实例 + /// + RPCService RPCService { get; } + + /// + /// 执行函数 + /// + Action RRQMExecuteMethod { get; } + + /// + /// 注册服务 + /// + /// + /// + void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances); + + /// + /// 取消注册服务 + /// + /// + /// + void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances); + + /// + /// 结束调用 + /// + /// + /// + void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance); + + /// + /// 设置函数映射 + /// + /// + void SetMethodMap(MethodMap methodMap); + + /// + /// 设置服务 + /// + /// + void SetRPCService(RPCService service); + + /// + /// 设置执行函数 + /// + /// + void SetExecuteMethod(Action executeMethod); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/Global/Service/RPCService.cs b/RRQMSocket.RPC/Global/Service/RPCService.cs new file mode 100644 index 000000000..214f45310 --- /dev/null +++ b/RRQMSocket.RPC/Global/Service/RPCService.cs @@ -0,0 +1,336 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 RRQMCore.Exceptions; +using RRQMSocket.RPC.RRQMRPC; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace RRQMSocket.RPC +{ + /// + /// RPC服务器类 + /// + public class RPCService : IDisposable + { + /// + /// 构造函数 + /// + public RPCService() + { + this.ServerProviders = new ServerProviderCollection(); + this.RPCParsers = new RPCParserCollection(); + this.MethodMap = new MethodMap(); + } + + /// + /// 获取函数映射图实例 + /// + public MethodMap MethodMap { get; private set; } + + /// + /// 获取RPC解析器集合 + /// + public RPCParserCollection RPCParsers { get; private set; } + + /// + /// 服务实例集合 + /// + public ServerProviderCollection ServerProviders { get; private set; } + + /// + /// 添加RPC解析器 + /// + /// 名称 + /// 解析器实例 + public void AddRPCParser(string key, IRPCParser parser) + { + this.RPCParsers.Add(key, parser); + parser.SetRPCService(this); + parser.SetExecuteMethod(PreviewExecuteMethod); + parser.SetMethodMap(this.MethodMap); + } + + /// + /// 添加RPC解析器 + /// + /// 名称 + /// 解析器实例 + /// 是否应用已注册服务 + public void AddRPCParser(string key, IRPCParser parser, bool applyServer) + { + this.RPCParsers.Add(key, parser); + parser.SetRPCService(this); + parser.SetExecuteMethod(PreviewExecuteMethod); + parser.SetMethodMap(this.MethodMap); + + if (applyServer) + { + Dictionary> pairs = new Dictionary>(); + + MethodInstance[] instances = this.MethodMap.GetAllMethodInstances(); + + foreach (var item in instances) + { + if (!pairs.ContainsKey(item.Provider)) + { + pairs.Add(item.Provider, new List()); + } + + pairs[item.Provider].Add(item); + } + foreach (var item in pairs.Keys) + { + parser.OnRegisterServer(item, pairs[item].ToArray()); + } + } + } + + /// + /// 释放资源 + /// + public void Dispose() + { + foreach (var item in this.RPCParsers) + { + item.Dispose(); + } + this.RPCParsers = null; + } + + /// + /// 注册所有服务 + /// + /// 返回搜索到的服务数 + public int RegisterAllServer() + { + Type[] types = (AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(s => s.GetTypes()).Where(p => typeof(ServerProvider).IsAssignableFrom(p) && p.IsAbstract == false)).ToArray(); + + foreach (Type type in types) + { + ServerProvider serverProvider = Activator.CreateInstance(type) as ServerProvider; + RegisterServer(serverProvider); + } + return types.Length; + } + + /// + /// 注册服务 + /// + /// + /// 返回T实例 + public IServerProvider RegisterServer() where T : IServerProvider + { + IServerProvider serverProvider = (IServerProvider)Activator.CreateInstance(typeof(T)); + this.RegisterServer(serverProvider); + return serverProvider; + } + + /// + /// 注册服务 + /// + /// + /// + public IServerProvider RegisterServer(Type providerType) + { + if (!typeof(IServerProvider).IsAssignableFrom(providerType)) + { + throw new RRQMRPCException("类型不相符"); + } + IServerProvider serverProvider = (IServerProvider)Activator.CreateInstance(providerType); + this.RegisterServer(serverProvider); + return serverProvider; + } + + /// + /// 注册服务 + /// + /// + public void RegisterServer(IServerProvider serverProvider) + { + serverProvider.RPCService = this; + this.ServerProviders.Add(serverProvider); + + if (this.RPCParsers.Count == 0) + { + throw new RRQMRPCException("请至少添加一种RPC解析器"); + } + MethodInstance[] methodInstances = Tools.GetMethodInstances(serverProvider, true); + + foreach (var item in methodInstances) + { + this.MethodMap.Add(item); + } + foreach (var parser in this.RPCParsers) + { + parser.OnRegisterServer(serverProvider, methodInstances); + } + } + + /// + /// 移除RPC解析器 + /// + /// + /// + public void RemoveRPCParser(string key, out IRPCParser parser) + { + if (!this.RPCParsers.TryRemove(key, out parser)) + { + throw new RRQMException("没有找到该解析器"); + } + } + + /// + /// 设置服务方法可用性 + /// + /// 方法名 + /// 可用性 + /// + public void SetMethodEnable(int methodToken, bool enable) + { + if (this.MethodMap.TryGet(methodToken, out MethodInstance methodInstance)) + { + methodInstance.IsEnable = enable; + } + else + { + throw new RRQMRPCException("未找到该方法"); + } + } + + /// + /// 获取解析器 + /// + /// + /// + /// + public bool TryGetRPCParser(string parserKey, out IRPCParser parser) + { + return this.RPCParsers.TryGetRPCParser(parserKey, out parser); + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer(IServerProvider provider) + { + return this.UnregisterServer(provider.GetType()); + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer(Type providerType) + { + if (!typeof(IServerProvider).IsAssignableFrom(providerType)) + { + throw new RRQMRPCException("类型不相符"); + } + this.ServerProviders.Remove(providerType); + if (this.MethodMap.RemoveServer(providerType, out IServerProvider serverProvider, out MethodInstance[] instances)) + { + foreach (var parser in this.RPCParsers) + { + parser.OnUnregisterServer(serverProvider, instances); + } + + return instances.Length; + } + return 0; + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer() where T : ServerProvider + { + return this.UnregisterServer(typeof(T)); + } + + private void ExecuteMethod(bool isAsync, IRPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance) + { + if (methodInvoker.Status == InvokeStatus.Ready && methodInstance != null) + { + try + { + methodInstance.Provider.RPCEnter(parser, methodInvoker, methodInstance); + if (isAsync) + { + dynamic task = methodInstance.Method.Invoke(methodInstance.Provider, methodInvoker.Parameters); + task.Wait(); + if (methodInstance.ReturnType != null) + { + methodInvoker.ReturnParameter = task.Result; + } + } + else + { + methodInvoker.ReturnParameter = methodInstance.Method.Invoke(methodInstance.Provider, methodInvoker.Parameters); + } + methodInstance.Provider.RPCLeave(parser, methodInvoker, methodInstance); + methodInvoker.Status = InvokeStatus.Success; + } + catch (RRQMAbandonRPCException e) + { + methodInvoker.Status = InvokeStatus.Abort; + methodInvoker.StatusMessage = "函数被阻止执行,信息:" + e.Message; + } + catch (TargetInvocationException e) + { + methodInvoker.Status = InvokeStatus.InvocationException; + if (e.InnerException != null) + { + methodInvoker.StatusMessage = "函数内部发生异常,信息:" + e.InnerException.Message; + } + else + { + methodInvoker.StatusMessage = "函数内部发生异常,信息:未知"; + } + methodInstance.Provider.RPCError(parser, methodInvoker, methodInstance); + } + catch (Exception e) + { + methodInvoker.Status = InvokeStatus.Exception; + methodInvoker.StatusMessage = e.Message; + methodInstance.Provider.RPCError(parser, methodInvoker, methodInstance); + } + } + + parser.OnEndInvoke(methodInvoker, methodInstance); + } + + private void PreviewExecuteMethod(IRPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance) + { + if (methodInstance != null && methodInstance.Async) + { + Task.Run(() => + { + ExecuteMethod(true, parser, methodInvoker, methodInstance); + }); + } + else + { + ExecuteMethod(false, parser, methodInvoker, methodInstance); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/LICENSE b/RRQMSocket.RPC/LICENSE new file mode 100644 index 000000000..5a9bb6217 --- /dev/null +++ b/RRQMSocket.RPC/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license 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. diff --git a/RRQMSocket.RPC/RRQM.ico b/RRQMSocket.RPC/RRQM.ico new file mode 100644 index 0000000000000000000000000000000000000000..6465fb16e389ed1804d54b368018596580c6672e GIT binary patch literal 249918 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

&cP)Tdhs88a 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 + /// RPC方法标记属性类 + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Event | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public sealed class RRQMRPCAttribute : RPCAttribute + { + ///

+ /// 构造函数 + /// + public RRQMRPCAttribute() + { + } + + /// + /// 构造函数 + /// + /// 指定键 + public RRQMRPCAttribute(string memberKey) + { + } + + /// + /// 注册键 + /// + public string MemberKey { get; private set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCCallBackMethodAttribute.cs b/RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCCallBackMethodAttribute.cs new file mode 100644 index 000000000..9a2d60b46 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCCallBackMethodAttribute.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RRQMRPC +{ + /// + /// RPC方法标记属性类 + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public sealed class RRQMRPCCallBackMethodAttribute : RPCAttribute + { + /// + /// 构造函数 + /// + /// 指定函数键 + public RRQMRPCCallBackMethodAttribute(int methodToken) + { + this.MethodToken = methodToken; + } + + /// + /// 注册键 + /// + public int MethodToken { get; private set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCMemberAttribute.cs b/RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCMemberAttribute.cs new file mode 100644 index 000000000..3cd017626 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCMemberAttribute.cs @@ -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 System; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// 标识参数类 + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class RRQMRPCMemberAttribute : RPCAttribute + { + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/CellCode.cs b/RRQMSocket.RPC/RRQMRPC/Common/CellCode.cs new file mode 100644 index 000000000..d8b7c6df3 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/CellCode.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RRQMRPC +{ + /// + /// 生成的单元代码 + /// + + public class CellCode + { + /// + /// 类名 + /// + public string Name { get; set; } + + /// + /// 代码本体 + /// + public string Code { get; set; } + + /// + /// 代码类型 + /// + public CodeType CodeType { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/CodeGenerator.cs b/RRQMSocket.RPC/RRQMRPC/Common/CodeGenerator.cs new file mode 100644 index 000000000..c95030922 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/CodeGenerator.cs @@ -0,0 +1,502 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Generic; +using System.Reflection; +using System.Text; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// 代码生成器 + /// + public class CodeGenerator + { + internal CodeGenerator() + { + codeString = new StringBuilder(); + } + + internal static string GetAssemblyInfo(string assemblyName, string version) + { + CodeGenerator codeMap = new CodeGenerator(); + codeMap.AppendAssemblyInfo(assemblyName, version); + return codeMap.codeString.ToString(); + } + + private StringBuilder codeString; + + internal MethodInfo[] Methods { get; set; } + internal string ClassName { get; set; } + internal static string Namespace { get; set; } + internal static PropertyCodeGenerator PropertyCode { get; set; } + + internal string GetCode() + { + codeString.AppendLine("using System;"); + codeString.AppendLine("using RRQMSocket.RPC;"); + codeString.AppendLine("using RRQMSocket.RPC.RRQMRPC;"); + codeString.AppendLine("using RRQMCore.Exceptions;"); + codeString.AppendLine("using System.Collections.Generic;"); + codeString.AppendLine("using System.Diagnostics;"); + codeString.AppendLine("using System.Text;"); + codeString.AppendLine("using System.Threading.Tasks;"); + codeString.AppendLine(string.Format("namespace {0}", Namespace)); + codeString.AppendLine("{"); + this.GetInterface("I" + this.ClassName); + this.GetClass(this.ClassName); + codeString.AppendLine("}");//空间结束 + + return codeString.ToString(); + } + + private void GetInterface(string interfaceName) + { + codeString.AppendLine(string.Format("public interface {0}", interfaceName));//类开始 + codeString.AppendLine("{"); + codeString.AppendLine("IRpcClient Client{get;}"); + AppendInterfaceMethods(); + codeString.AppendLine("}");//类结束 + } + + private void GetClass(string className) + { + codeString.AppendLine(string.Format("public class {0} :I{0}", className));//类开始 + codeString.AppendLine("{"); + codeString.AppendLine($"public {className}(IRpcClient client)"); + codeString.AppendLine("{"); + codeString.AppendLine("this.Client=client;"); + codeString.AppendLine("}"); + AppendProperties(); + AppendMethods(); + codeString.AppendLine("}");//类结束 + } + + private void AppendAssemblyInfo(string assemblyName, string version) + { + codeString.AppendLine("using System.Reflection;"); + codeString.AppendLine("using System.Runtime.CompilerServices;"); + codeString.AppendLine("using System.Runtime.InteropServices;"); + codeString.AppendLine("[assembly: AssemblyTitle(\"RRQMRPC\")]"); + codeString.AppendLine("[assembly: AssemblyProduct(\"RRQMRPC\")]"); + codeString.AppendLine("[assembly: AssemblyCopyright(\"Copyright © 2020 若汝棋茗\")]"); + codeString.AppendLine("[assembly: ComVisible(false)]"); + + codeString.AppendLine(string.Format("[assembly: AssemblyVersion(\"{0}\")]", version)); + codeString.AppendLine(string.Format("[assembly: AssemblyFileVersion(\"{0}\")]", version.ToString())); + } + + private void AppendProperties() + { + codeString.AppendLine("public IRpcClient Client{get;private set; }"); + } + + internal string GetName(Type type) + { + return PropertyCode.GetTypeFullName(type); + } + + private void AppendMethods() + { + if (Methods != null) + { + foreach (MethodInfo method in Methods) + { + bool isReturn; + bool isOut = false; + bool isRef = false; + string methodName = method.GetCustomAttribute().MemberKey == null ? method.Name : method.GetCustomAttribute().MemberKey; + + if (method.ReturnType.FullName == "System.Void" || method.ReturnType.FullName == "System.Threading.Tasks.Task") + { + isReturn = false; + codeString.Append(string.Format("public void {0} ", methodName)); + } + else + { + isReturn = true; + codeString.Append(string.Format("public {0} {1} ", this.GetName(method.ReturnType), methodName)); + } + codeString.Append("(");//方法参数 + + ParameterInfo[] parameters = method.GetParameters(); + + for (int i = 0; i < parameters.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + if (parameters[i].ParameterType.Name.Contains("&")) + { + if (parameters[i].IsOut) + { + isOut = true; + codeString.Append(string.Format("out {0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name)); + } + else + { + isRef = true; + codeString.Append(string.Format("ref {0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name)); + } + } + else + { + codeString.Append(string.Format("{0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name)); + } + + if (parameters[i].HasDefaultValue) + { + object defaultValue = parameters[i].DefaultValue; + if (defaultValue == null) + { + codeString.Append(string.Format("=null")); + } + else if (defaultValue.ToString() == string.Empty) + { + codeString.Append(string.Format("=\"\"")); + } + else if (defaultValue.GetType() == typeof(string)) + { + codeString.Append(string.Format("=\"{0}\"", defaultValue)); + } + else if (typeof(ValueType).IsAssignableFrom(defaultValue.GetType())) + { + codeString.Append(string.Format("={0}", defaultValue)); + } + } + } + if (parameters.Length > 0) + { + codeString.Append(","); + } + codeString.AppendLine("InvokeOption invokeOption = null)"); + + codeString.AppendLine("{");//方法开始 + + codeString.AppendLine("if(Client==null)"); + codeString.AppendLine("{"); + codeString.AppendLine("throw new RRQMRPCException(\"IRPCClient为空,请先初始化或者进行赋值\");"); + codeString.AppendLine("}"); + + codeString.Append($"object[] parameters = new object[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut) + { + codeString.Append($"default({this.GetName(parameter.ParameterType)})"); + } + else + { + codeString.Append(parameter.Name); + } + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + + if (isOut || isRef) + { + codeString.Append($"Type[] types = new Type[]"); + codeString.Append("{"); + foreach (ParameterInfo parameter in parameters) + { + codeString.Append($"typeof({this.GetName(parameter.ParameterType)})"); + if (parameter != parameters[parameters.Length - 1]) + { + codeString.Append(","); + } + } + codeString.AppendLine("};"); + } + + if (isReturn) + { + if (isOut || isRef) + { + codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", this.GetName(method.ReturnType))); + codeString.Append("("); + codeString.Append(string.Format("\"{0}\"", methodName)); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append(string.Format("{0} returnData=Client.Invoke<{0}>", this.GetName(method.ReturnType))); + codeString.Append("("); + codeString.Append(string.Format("\"{0}\"", methodName)); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + else + { + if (isOut || isRef) + { + codeString.Append("Client.Invoke("); + codeString.Append(string.Format("\"{0}\"", methodName)); + codeString.AppendLine(",invokeOption,ref parameters,types);"); + } + else + { + codeString.Append("Client.Invoke("); + codeString.Append(string.Format("\"{0}\"", methodName)); + codeString.AppendLine(",invokeOption, parameters);"); + } + } + if (isOut || isRef) + { + codeString.AppendLine("if(parameters!=null)"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, this.GetName(parameters[i].ParameterType), i)); + } + codeString.AppendLine("}"); + if (isOut) + { + codeString.AppendLine("else"); + codeString.AppendLine("{"); + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].IsOut) + { + codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, this.GetName(parameters[i].ParameterType))); + } + } + codeString.AppendLine("}"); + } + } + + if (isReturn) + { + codeString.AppendLine("return returnData;"); + } + + codeString.AppendLine("}"); + + //以下生成异步 + if (!isOut && !isRef)//没有out或者ref + { + if (method.ReturnType.FullName == "System.Void" || method.ReturnType.FullName == "System.Threading.Tasks.Task") + { + isReturn = false; + codeString.Append(string.Format("public async void {0} ", methodName + "Async")); + } + else + { + isReturn = true; + codeString.Append(string.Format("public async Task<{0}> {1} ", this.GetName(method.ReturnType), methodName + "Async")); + } + + codeString.Append("(");//方法参数 + + for (int i = 0; i < parameters.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(string.Format("{0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name)); + if (parameters[i].DefaultValue != System.DBNull.Value) + { + object defaultValue = parameters[i].DefaultValue; + if (defaultValue == null) + { + codeString.Append(string.Format("=null")); + } + else if (defaultValue.ToString() == string.Empty) + { + codeString.Append(string.Format("=\"\"")); + } + else if (defaultValue.GetType() == typeof(string)) + { + codeString.Append(string.Format("=\"{0}\"", defaultValue)); + } + else if (typeof(ValueType).IsAssignableFrom(defaultValue.GetType())) + { + codeString.Append(string.Format("={0}", defaultValue)); + } + } + } + + if (parameters.Length > 0) + { + codeString.Append(","); + } + codeString.AppendLine("InvokeOption invokeOption = null)"); + codeString.AppendLine("{");//方法开始 + codeString.AppendLine("if(Client==null)"); + codeString.AppendLine("{"); + codeString.AppendLine("throw new RRQMRPCException(\"RPCClient为空,请先初始化或者进行赋值\");"); + codeString.AppendLine("}"); + if (isReturn) + { + codeString.AppendLine("return await Task.Run(() =>{"); + codeString.Append(string.Format("return {0}(", methodName)); + } + else + { + codeString.AppendLine("await Task.Run(() =>{"); + codeString.Append(string.Format("{0}(", methodName)); + } + + for (int i = 0; i < parameters.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(string.Format("{0}", parameters[i].Name)); + } + if (parameters.Length > 0) + { + codeString.Append(","); + } + codeString.Append("invokeOption);"); + codeString.AppendLine("});"); + codeString.AppendLine("}"); + } + } + } + } + + private void AppendInterfaceMethods() + { + if (Methods != null) + { + foreach (MethodInfo method in Methods) + { + bool isOut = false; + bool isRef = false; + string methodName = method.GetCustomAttribute().MemberKey == null ? method.Name : method.GetCustomAttribute().MemberKey; + + if (method.ReturnType.FullName == "System.Void" || method.ReturnType.FullName == "System.Threading.Tasks.Task") + { + codeString.Append(string.Format(" void {0} ", methodName)); + } + else + { + codeString.Append(string.Format(" {0} {1} ", this.GetName(method.ReturnType), methodName)); + } + codeString.Append("(");//方法参数 + + ParameterInfo[] parameters = method.GetParameters(); + + for (int i = 0; i < parameters.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + if (parameters[i].ParameterType.Name.Contains("&")) + { + if (parameters[i].IsOut) + { + isOut = true; + codeString.Append(string.Format("out {0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name)); + } + else + { + isRef = true; + codeString.Append(string.Format("ref {0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name)); + } + } + else + { + codeString.Append(string.Format("{0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name)); + } + + if (parameters[i].HasDefaultValue) + { + object defaultValue = parameters[i].DefaultValue; + if (defaultValue == null) + { + codeString.Append(string.Format("=null")); + } + else if (defaultValue.ToString() == string.Empty) + { + codeString.Append(string.Format("=\"\"")); + } + else if (defaultValue.GetType() == typeof(string)) + { + codeString.Append(string.Format("=\"{0}\"", defaultValue)); + } + else if (typeof(ValueType).IsAssignableFrom(defaultValue.GetType())) + { + codeString.Append(string.Format("={0}", defaultValue)); + } + } + } + if (parameters.Length > 0) + { + codeString.Append(","); + } + codeString.AppendLine("InvokeOption invokeOption = null);"); + + if (!isOut && !isRef)//没有out或者ref + { + if (method.ReturnType.FullName == "System.Void" || method.ReturnType.FullName == "System.Threading.Tasks.Task") + { + codeString.Append(string.Format("void {0} ", methodName + "Async")); + } + else + { + codeString.Append(string.Format("Task<{0}> {1} ", this.GetName(method.ReturnType), methodName + "Async")); + } + + codeString.Append("(");//方法参数 + + for (int i = 0; i < parameters.Length; i++) + { + if (i > 0) + { + codeString.Append(","); + } + + codeString.Append(string.Format("{0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name)); + if (parameters[i].DefaultValue != System.DBNull.Value) + { + object defaultValue = parameters[i].DefaultValue; + if (defaultValue == null) + { + codeString.Append(string.Format("=null")); + } + else if (defaultValue.ToString() == string.Empty) + { + codeString.Append(string.Format("=\"\"")); + } + else if (defaultValue.GetType() == typeof(string)) + { + codeString.Append(string.Format("=\"{0}\"", defaultValue)); + } + else if (typeof(ValueType).IsAssignableFrom(defaultValue.GetType())) + { + codeString.Append(string.Format("={0}", defaultValue)); + } + } + } + + if (parameters.Length > 0) + { + codeString.Append(","); + } + codeString.AppendLine("InvokeOption invokeOption = null);"); + } + } + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/CodeType.cs b/RRQMSocket.RPC/RRQMRPC/Common/CodeType.cs new file mode 100644 index 000000000..3cd6d332d --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/CodeType.cs @@ -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 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// 代码类型 + /// + + public enum CodeType + { + /// + /// 类代码 + /// + ClassArgs, + + /// + /// 服务代码 + /// + Service + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/FeedbackType.cs b/RRQMSocket.RPC/RRQMRPC/Common/FeedbackType.cs new file mode 100644 index 000000000..7d43447f1 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/FeedbackType.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RRQMRPC +{ + /// + /// 反馈类型 + /// + public enum FeedbackType : byte + { + /// + /// 仅发送 + /// + OnlySend, + + /// + /// 等待,直到发送抵达 + /// + WaitSend, + + /// + /// 等待,直到调用完成 + /// + WaitInvoke + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/InvokeOption.cs b/RRQMSocket.RPC/RRQMRPC/Common/InvokeOption.cs new file mode 100644 index 000000000..6a61dc12b --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/InvokeOption.cs @@ -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 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// RPC调用设置 + /// + public class InvokeOption + { + private static InvokeOption onlySend; + + private static InvokeOption waitInvoke; + + private static InvokeOption waitSend; + + private int timeout = 5000; + + static InvokeOption() + { + onlySend = new InvokeOption(); + onlySend.FeedbackType = FeedbackType.OnlySend; + + waitSend = new InvokeOption(); + waitSend.FeedbackType = FeedbackType.WaitSend; + + waitInvoke = new InvokeOption(); + waitInvoke.FeedbackType = FeedbackType.WaitInvoke; + } + /// + /// 默认设置。 + /// Timeout=5000 ms + /// + public static InvokeOption OnlySend { get { return onlySend; } } + /// + /// 默认设置。 + /// Timeout=5000 ms + /// + public static InvokeOption WaitInvoke { get { return waitInvoke; } } + + /// + /// 默认设置。 + /// Timeout=5000 ms + /// + public static InvokeOption WaitSend { get { return waitSend; } } + /// + /// 调用反馈 + /// + public FeedbackType FeedbackType { get; set; } + + /// + /// 调用超时, + /// min=1000,默认5000 ms + /// + public int Timeout + { + get { return timeout; } + set + { + if (value < 1000) + { + value = 1000; + } + timeout = value; + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/MethodItem.cs b/RRQMSocket.RPC/RRQMRPC/Common/MethodItem.cs new file mode 100644 index 000000000..2a61fb865 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/MethodItem.cs @@ -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.RRQMRPC +{ + /// + /// 方法体 + /// + public class MethodItem + { + /// + /// 服务名称 + /// + public string ServerName { get; internal set; } + + /// + /// 方法唯一标识 + /// + public int MethodToken { get; internal set; } + + /// + /// 方法名 + /// + public string Method { get; internal set; } + + /// + /// 是否含有Out或Ref + /// + public bool IsOutOrRef { get; internal set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/MethodStore.cs b/RRQMSocket.RPC/RRQMRPC/Common/MethodStore.cs new file mode 100644 index 000000000..273730776 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/MethodStore.cs @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Generic; +using System.Linq; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// 函数仓库 + /// + public class MethodStore + { + internal MethodStore() + { + this.tokenToMethodItem = new Dictionary(); + this.methodKeyToMethodItem = new Dictionary(); + this.propertyDic = new Dictionary(); + this.genericTypeDic = new Dictionary(); + } + + private Dictionary tokenToMethodItem; + private Dictionary methodKeyToMethodItem; + internal Dictionary propertyDic; + internal Dictionary genericTypeDic; + + /// + /// 获取所有的方法 + /// + /// + public string[] GetMethods() + { + return methodKeyToMethodItem.Keys.ToArray(); + } + + /// + /// 添加 + /// + /// + internal void AddMethodItem(MethodItem methodItem) + { + tokenToMethodItem.Add(methodItem.MethodToken, methodItem); + methodKeyToMethodItem.Add(methodItem.Method, methodItem); + } + + /// + /// 添加 + /// + /// + internal void RemoveMethodItem(int methodToken) + { + if (tokenToMethodItem.TryGetValue(methodToken, out MethodItem methodItem)) + { + tokenToMethodItem.Remove(methodToken); + methodKeyToMethodItem.Remove(methodItem.Method); + } + } + + /// + /// 获取所有 + /// + /// + public List GetAllMethodItem() + { + return this.tokenToMethodItem.Values.ToList(); + } + + /// + /// 获取函数服务 + /// + /// + /// + /// + public bool TryGetMethodItem(string method, out MethodItem methodItem) + { + return methodKeyToMethodItem.TryGetValue(method, out methodItem); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/PropertyCodeGenerator.cs b/RRQMSocket.RPC/RRQMRPC/Common/PropertyCodeGenerator.cs new file mode 100644 index 000000000..9ddbe4ce6 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/PropertyCodeGenerator.cs @@ -0,0 +1,324 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// 代码辅助类 + /// + public class PropertyCodeGenerator + { + private static readonly string[] listType = { "List`1", "HashSet`1", "IList`1", "ISet`1", "ICollection`1", "IEnumerable`1" }; + + private static readonly string[] dicType = { "Dictionary`2", "IDictionary`2" }; + + private static readonly Type intType = typeof(int); + private static readonly Type byteType = typeof(byte); + private static readonly Type shortType = typeof(short); + private static readonly Type longType = typeof(long); + + /// + /// 构造函数 + /// + public PropertyCodeGenerator(string nameSpace, MethodStore methodStore) + { + codeString = new StringBuilder(); + this.nameSpace = nameSpace; + this.propertyDic = methodStore.propertyDic; + this.genericTypeDic = methodStore.genericTypeDic; + } + + /// + /// 获取属性代码 + /// + public string GetPropertyCode() + { + codeString.Clear(); + + codeString.AppendLine("using System;"); + codeString.AppendLine("using RRQMSocket.RPC;"); + codeString.AppendLine("using RRQMCore.Exceptions;"); + codeString.AppendLine("using System.Collections.Generic;"); + codeString.AppendLine("using System.Diagnostics;"); + codeString.AppendLine("using System.Text;"); + codeString.AppendLine("using System.Threading.Tasks;"); + + codeString.AppendLine(string.Format("namespace {0}", nameSpace)); + + codeString.AppendLine("{"); + foreach (var item in propertyDic.Values) + { + codeString.AppendLine(item); + } + codeString.AppendLine("}"); + return codeString.ToString(); + } + + private StringBuilder codeString; + private string nameSpace; + private Dictionary propertyDic; + private Dictionary genericTypeDic; + + internal void AddTypeString(Type type) + { + if (type.IsByRef) + { + type = type.GetRefOutType(); + } + + if (!type.IsPrimitive && type != typeof(string)) + { + if (type.IsArray) + { + AddTypeString(type.GetElementType()); + } + else if (type.IsGenericType) + { + Type[] types = type.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType); + } + + if (listType.Contains(type.Name)) + { + string typeInnerString = this.GetTypeFullName(types[0]); + string typeString = $"System.Collections.Generic.{type.Name.Replace("`1", string.Empty)}<{typeInnerString}>"; + if (!genericTypeDic.ContainsKey(type)) + { + genericTypeDic.Add(type, typeString); + } + } + else if (dicType.Contains(type.Name)) + { + string keyString = this.GetTypeFullName(types[0]); + string valueString = this.GetTypeFullName(types[1]); + string typeString = $"System.Collections.Generic.{type.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>"; + if (!genericTypeDic.ContainsKey(type)) + { + genericTypeDic.Add(type, typeString); + } + } + } + else if (type.IsInterface || type.IsAbstract) + { + throw new RRQMRPCException("服务参数类型不允许接口或抽象类"); + } + else if (type.IsEnum) + { + Type baseType = Enum.GetUnderlyingType(type); + StringBuilder stringBuilder = new StringBuilder(); + if (baseType == byteType) + { + stringBuilder.AppendLine($"public enum {type.Name}:byte"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(byte)item},"); + } + } + else if (baseType == shortType) + { + stringBuilder.AppendLine($"public enum {type.Name}:short"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(short)item},"); + } + } + else if (baseType == intType) + { + stringBuilder.AppendLine($"public enum {type.Name}:int"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(int)item},"); + } + } + else if (baseType == longType) + { + stringBuilder.AppendLine($"public enum {type.Name}:long"); + stringBuilder.AppendLine("{"); + Array array = Enum.GetValues(type); + foreach (object item in array) + { + string enumString = item.ToString(); + stringBuilder.AppendLine($"{enumString}={(long)item},"); + } + } + + stringBuilder.AppendLine("}"); + if (!propertyDic.ContainsKey(type)) + { + propertyDic.Add(type, stringBuilder.ToString()); + } + } + else if (type.IsClass) + { + if (type.Assembly == ServerProvider.DefaultAssembly || type.GetCustomAttribute() != null) + { + StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.AppendLine(""); + stringBuilder.AppendLine($"public class {type.Name}"); + if (type.BaseType != typeof(object)) + { + AddTypeString(type.BaseType); + if (type.BaseType.IsGenericType) + { + Type[] types = type.BaseType.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType); + } + if (listType.Contains(type.BaseType.Name)) + { + string typeString = this.GetTypeFullName(types[0]); + stringBuilder.Append($":{type.BaseType.Name.Replace("`1", string.Empty)}<{typeString}>"); + } + else if (dicType.Contains(type.BaseType.Name)) + { + string keyString = this.GetTypeFullName(types[0]); + string valueString = this.GetTypeFullName(types[1]); + stringBuilder.Append($": {type.BaseType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>"); + } + } + else if (type.BaseType.IsClass) + { + stringBuilder.AppendLine($": {this.GetTypeFullName(type.BaseType)}"); + } + } + stringBuilder.AppendLine("{"); + PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.GetProperty | BindingFlags.SetProperty); + + foreach (PropertyInfo itemProperty in propertyInfos) + { + AddTypeString(itemProperty.PropertyType); + if (propertyDic.ContainsKey(itemProperty.PropertyType)) + { + stringBuilder.Append($"public {itemProperty.PropertyType.Name} {itemProperty.Name}"); + } + else if (itemProperty.PropertyType.IsGenericType) + { + Type[] types = itemProperty.PropertyType.GetGenericArguments(); + foreach (Type itemType in types) + { + AddTypeString(itemType); + } + + if (listType.Contains(itemProperty.PropertyType.Name)) + { + string typeString = this.GetTypeFullName(types[0]); + stringBuilder.Append($"public {itemProperty.PropertyType.Name.Replace("`1", string.Empty)}<{typeString}> {itemProperty.Name}"); + } + else if (dicType.Contains(itemProperty.PropertyType.Name)) + { + string keyString = this.GetTypeFullName(types[0]); + string valueString = this.GetTypeFullName(types[1]); + stringBuilder.Append($"public {itemProperty.PropertyType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}> {itemProperty.Name}"); + } + } + else + { + AddTypeString(itemProperty.PropertyType); + stringBuilder.Append($"public {itemProperty.PropertyType.FullName} {itemProperty.Name}"); + } + + stringBuilder.AppendLine("{get;set;}"); + } + + stringBuilder.AppendLine("}"); + + if (!propertyDic.ContainsKey(type)) + { + propertyDic.Add(type, stringBuilder.ToString()); + } + } + } + } + } + + /// + /// 获取类型全名 + /// + /// + /// + public string GetTypeFullName(Type type) + { + if (type.FullName == null) + { + return type.Name.Replace("&", string.Empty); + } + else if (type == typeof(void)) + { + return null; + } + else if (typeof(Task).IsAssignableFrom(type)) + { + Type[] ts = type.GetGenericArguments(); + if (ts.Length == 1) + { + return ts[0].Name; + } + else + { + return type.Name; + } + } + else if (type.IsArray) + { + Type elementType = type.GetElementType(); + return this.GetTypeFullName(elementType) + "[]"; + } + + if (type.IsByRef) + { + string typeName = type.FullName.Replace("&", string.Empty); + type = Type.GetType(typeName); + if (type == null && ServerProvider.DefaultAssembly != null) + { + type = ServerProvider.DefaultAssembly.GetType(typeName); + } + } + + if (type.IsPrimitive || type == typeof(string)) + { + return type.FullName; + } + else if (listType.Contains(type.Name) || dicType.Contains(type.Name)) + { + return genericTypeDic[type]; + } + else if (propertyDic.ContainsKey(type)) + { + return this.nameSpace + "." + type.Name; + } + else + { + return type.FullName; + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/RpcCompiler.cs b/RRQMSocket.RPC/RRQMRPC/Common/RpcCompiler.cs new file mode 100644 index 000000000..f84df0bb4 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/RpcCompiler.cs @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +#if NET45_OR_GREATER + +using Microsoft.CSharp; +using RRQMCore.Log; +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// RPC编译 + /// + public static class RpcCompiler + { + private static List RefStrings = new List(); + + /// + /// 添加编译引用 + /// + /// + public static void AddRef(string refPath) + { + if (!RefStrings.Contains(refPath)) + { + RefStrings.Add(refPath); + } + } + + /// + /// 添加编译引用 + /// + /// + public static void AddRef(Type type) + { + AddRef(type.Assembly.FullName); + } + + /// + /// 清除引用 + /// + public static void ClearRef() + { + RefStrings.Clear(); + } + + /// + /// 编译代码 + /// + /// + /// + /// + public static void CompileCode(string fullPath, string[] codes) + { + CSharpCodeProvider codeProvider = new CSharpCodeProvider(); + CompilerParameters compilerParameters = new CompilerParameters(); + + compilerParameters.OutputAssembly = fullPath; + + compilerParameters.GenerateExecutable = false; + compilerParameters.GenerateInMemory = false; + compilerParameters.ReferencedAssemblies.Add("System.dll"); + compilerParameters.ReferencedAssemblies.Add("mscorlib.dll"); + compilerParameters.ReferencedAssemblies.Add(typeof(ILog).Assembly.Location); + compilerParameters.ReferencedAssemblies.Add(typeof(RPCService).Assembly.Location); + + foreach (var item in RefStrings) + { + compilerParameters.ReferencedAssemblies.Add(item); + } + + CompilerResults cr = codeProvider.CompileAssemblyFromSource(compilerParameters, codes); + if (cr.Errors.HasErrors) + { + StringBuilder stringBuilder = new StringBuilder(); + + foreach (CompilerError err in cr.Errors) + { + stringBuilder.AppendLine(err.ErrorText); + } + + throw new RRQMRPCException(stringBuilder.ToString()); + } + } + } +} + +#endif \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/RpcContext.cs b/RRQMSocket.RPC/RRQMRPC/Common/RpcContext.cs new file mode 100644 index 000000000..43542211a --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/RpcContext.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Run; +using System.Collections.Generic; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// RPC传输类 + /// + public class RpcContext : WaitResult + { + internal int MethodToken; + internal string ID; + internal byte Feedback; + internal byte[] ReturnParameterBytes; + internal List ParametersBytes; + + internal void Serialize(ByteBlock byteBlock) + { + byteBlock.Write(this.Sign); + byteBlock.Write(this.Status); + byteBlock.Write(this.Feedback); + byteBlock.Write(this.MethodToken); + byteBlock.Write(this.ID); + byteBlock.Write(this.Message); + byteBlock.WriteBytesPackage(this.ReturnParameterBytes); + + if (this.ParametersBytes != null && this.ParametersBytes.Count > 0) + { + byteBlock.Write((byte)this.ParametersBytes.Count); + foreach (byte[] item in this.ParametersBytes) + { + byteBlock.WriteBytesPackage(item); + } + } + else + { + byteBlock.Write((byte)0); + } + } + + internal static RpcContext Deserialize(ByteBlock byteBlock) + { + RpcContext context = new RpcContext(); + context.Sign = byteBlock.ReadInt32(); + context.Status = byteBlock.ReadByte(); + context.Feedback = byteBlock.ReadByte(); + context.MethodToken = byteBlock.ReadInt32(); + context.ID = byteBlock.ReadString(); + context.Message = byteBlock.ReadString(); + context.ReturnParameterBytes = byteBlock.ReadBytesPackage(); + + context.ParametersBytes = new List(); + byte countPar = byteBlock.ReadByte(); + + for (int i = 0; i < countPar; i++) + { + context.ParametersBytes.Add(byteBlock.ReadBytesPackage()); + } + return context; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/RpcProxyInfo.cs b/RRQMSocket.RPC/RRQMRPC/Common/RpcProxyInfo.cs new file mode 100644 index 000000000..85b40ee14 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/RpcProxyInfo.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System.Collections.Generic; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// RPC代理文件程序 + /// + public class RpcProxyInfo : WaitResult + { + /// + /// 程序名 + /// + public string AssemblyName { get; internal set; } + + /// + /// 数据 + /// + public byte[] AssemblyData { get; internal set; } + + /// + /// 版本号 + /// + public string Version { get; internal set; } + + /// + /// 源代码 + /// + public List Codes { get; internal set; } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Common/Tools.cs b/RRQMSocket.RPC/RRQMRPC/Common/Tools.cs new file mode 100644 index 000000000..0855df8bb --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Common/Tools.cs @@ -0,0 +1,240 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 RRQMCore.Helper; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace RRQMSocket.RPC.RRQMRPC +{ + internal static class Tools + { + internal static void GetRPCMethod( + MethodInstance[] methodInstances, + string nameSpaceOld, + ref MethodStore methodStore, + Version version, + ref RpcProxyInfo proxyInfo) + { + string nameSpace = string.IsNullOrEmpty(nameSpaceOld) ? "RRQMRPC" : $"RRQMRPC.{nameSpaceOld}"; + List refs = new List(); + + PropertyCodeGenerator propertyCode = new PropertyCodeGenerator(nameSpace, methodStore); + + foreach (MethodInstance methodInstance in methodInstances) + { + foreach (RPCAttribute att in methodInstance.RPCAttributes) + { + if (att is RRQMRPCAttribute attribute) + { + if (methodInstance.ReturnType != null) + { + refs.Add(methodInstance.ReturnType.Assembly.Location); + propertyCode.AddTypeString(methodInstance.ReturnType); + } + foreach (var type in methodInstance.ParameterTypes) + { + refs.Add(type.Assembly.Location); + propertyCode.AddTypeString(type); + } + + break; + } + } + } + +#if NET45_OR_GREATER + foreach (var item in refs) + { + RpcCompiler.AddRef(item); + } +#endif + List methods = new List(); + string className = null; + + foreach (MethodInstance methodInstance in methodInstances) + { + foreach (RPCAttribute att in methodInstance.RPCAttributes) + { + if (att is RRQMRPCAttribute attribute) + { + MethodItem methodItem = new MethodItem(); + methodItem.IsOutOrRef = methodInstance.IsByRef; + methodItem.MethodToken = methodInstance.MethodToken; + methodItem.ServerName = methodInstance.Provider.GetType().Name; + methodItem.Method = string.IsNullOrEmpty(attribute.MemberKey) ? methodInstance.Method.Name : attribute.MemberKey; + try + { + methodStore.AddMethodItem(methodItem); + } + catch + { + throw new RRQMRPCKeyException($"方法键为{methodItem.Method}的服务已注册"); + } + + if (className == null) + { + className = methodInstance.Provider.GetType().Name; + } + else if (className != methodInstance.Provider.GetType().Name) + { + throw new RRQMRPCException("方法来源于不同服务"); + } + methods.Add(methodInstance.Method); + break; + } + } + } + + CodeGenerator.Namespace = nameSpace; + CodeGenerator.PropertyCode = propertyCode; + + CodeGenerator codeMap = new CodeGenerator(); + codeMap.ClassName = className; + codeMap.Methods = methods.ToArray(); + + CellCode cellCode = new CellCode(); + cellCode.Name = className; + cellCode.CodeType = CodeType.Service; + cellCode.Code = codeMap.GetCode(); + + if (proxyInfo.Codes == null) + { + proxyInfo.Codes = new List(); + } + proxyInfo.Codes.Add(cellCode); + + CellCode argesCode = proxyInfo.Codes.FirstOrDefault(a => a.Name == "ClassArgs"); + if (argesCode == null) + { + argesCode = new CellCode(); + argesCode.Name = "ClassArgs"; + argesCode.CodeType = CodeType.ClassArgs; + argesCode.Code = propertyCode.GetPropertyCode(); + proxyInfo.Codes.Add(argesCode); + } + else + { + argesCode.Code = propertyCode.GetPropertyCode(); + } + + proxyInfo.AssemblyName = $"{nameSpace}.dll"; + proxyInfo.Version = version == null ? "1.0.0.0" : version.ToString(); + } + + private static int nullReturnNullParameters = 1000000000; + private static int nullReturnExistParameters = 300000000; + private static int ExistReturnNullParameters = 500000000; + private static int ExistReturnExistParameters = 700000000; + + internal static MethodInstance[] GetMethodInstances(IServerProvider serverProvider, bool isSetToken) + { + List instances = new List(); + + MethodInfo[] methodInfos = serverProvider.GetType().GetMethods(); + + foreach (MethodInfo method in methodInfos) + { + if (method.IsGenericMethod) + { + continue; + } + IEnumerable attributes = method.GetCustomAttributes(true); + if (attributes.Count() > 0) + { + MethodInstance methodInstance = new MethodInstance(); + methodInstance.Provider = serverProvider; + methodInstance.Method = method; + methodInstance.RPCAttributes = attributes.ToArray(); + methodInstance.IsEnable = true; + methodInstance.Parameters = method.GetParameters(); + List names = new List(); + foreach (var parameterInfo in methodInstance.Parameters) + { + names.Add(parameterInfo.Name); + } + methodInstance.ParameterNames = names.ToArray(); + if (typeof(Task).IsAssignableFrom(method.ReturnType)) + { + methodInstance.Async = true; + } + + ParameterInfo[] parameters = method.GetParameters(); + List types = new List(); + foreach (var parameter in parameters) + { + types.Add(parameter.ParameterType.GetRefOutType()); + if (parameter.ParameterType.IsByRef) + { + methodInstance.IsByRef = true; + } + } + methodInstance.ParameterTypes = types.ToArray(); + + if (method.ReturnType == typeof(void) || method.ReturnType == typeof(Task)) + { + methodInstance.ReturnType = null; + + if (isSetToken) + { + if (parameters.Length == 0) + { + methodInstance.MethodToken = ++nullReturnNullParameters; + } + else + { + methodInstance.MethodToken = ++nullReturnExistParameters; + } + } + } + else + { + if (methodInstance.Async) + { + Type[] ts = method.ReturnType.GetGenericArguments(); + if (ts.Length == 1) + { + methodInstance.ReturnType = ts[0]; + } + else + { + methodInstance.ReturnType = null; + } + } + else + { + methodInstance.ReturnType = method.ReturnType; + } + + if (isSetToken) + { + if (parameters.Length == 0) + { + methodInstance.MethodToken = ++ExistReturnNullParameters; + } + else + { + methodInstance.MethodToken = ++ExistReturnExistParameters; + } + } + } + instances.Add(methodInstance); + } + } + + return instances.ToArray(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Config/TcpRpcClientConfig.cs b/RRQMSocket.RPC/RRQMRPC/Config/TcpRpcClientConfig.cs new file mode 100644 index 000000000..ae762bb61 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Config/TcpRpcClientConfig.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RRQMRPC +{ + /// + /// TcpRPCClient配置 + /// + public class TcpRpcClientConfig : ProtocolClientConfig + { + /// + /// 代理文件令箭 + /// + public string ProxyToken + { + get { return (string)GetValue(ProxyTokenProperty); } + set { SetValue(ProxyTokenProperty, value); } + } + + /// + /// 代理文件令箭, 所需类型 + /// + public static readonly DependencyProperty ProxyTokenProperty = + DependencyProperty.Register("ProxyToken", typeof(string), typeof(TcpRpcClientConfig), null); + + /// + /// 序列化转换器 + /// + public SerializeConverter SerializeConverter + { + get { return (SerializeConverter)GetValue(SerializeConverterProperty); } + set { SetValue(SerializeConverterProperty, value); } + } + + /// + /// 序列化转换器, 所需类型 + /// + public static readonly DependencyProperty SerializeConverterProperty = + DependencyProperty.Register("SerializeConverter", typeof(SerializeConverter), typeof(TcpRpcClientConfig), new BinarySerializeConverter()); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Config/TcpRpcParserConfig.cs b/RRQMSocket.RPC/RRQMRPC/Config/TcpRpcParserConfig.cs new file mode 100644 index 000000000..2c2e467fb --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Config/TcpRpcParserConfig.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// RRQMRPC解析器配置 + /// + public class TcpRpcParserConfig : ProtocolServiceConfig + { + /// + /// 序列化转换器 + /// + public SerializeConverter SerializeConverter + { + get { return (SerializeConverter)GetValue(SerializeConverterProperty); } + set { SetValue(SerializeConverterProperty, value); } + } + + /// + /// 序列化转换器, 所需类型 + /// + public static readonly DependencyProperty SerializeConverterProperty = + DependencyProperty.Register("SerializeConverter", typeof(SerializeConverter), typeof(TcpRpcParserConfig), new BinarySerializeConverter()); + + /// + /// 代理源文件命名空间 + /// + public string NameSpace + { + get { return (string)GetValue(NameSpaceProperty); } + set { SetValue(NameSpaceProperty, value); } + } + + /// + /// 代理源文件命名空间, 所需类型 + /// + public static readonly DependencyProperty NameSpaceProperty = + DependencyProperty.Register("NameSpace", typeof(string), typeof(TcpRpcParserConfig), null); + + /// + /// RPC代理版本 + /// + public Version RPCVersion + { + get { return (Version)GetValue(RPCVersionProperty); } + set { SetValue(RPCVersionProperty, value); } + } + + /// + /// RPC代理版本, 所需类型 + /// + public static readonly DependencyProperty RPCVersionProperty = + DependencyProperty.Register("RPCVersion", typeof(Version), typeof(TcpRpcParserConfig), null); + + /// + /// 代理令箭,当客户端获取代理文件时需验证令箭 + /// + public string ProxyToken + { + get { return (string)GetValue(ProxyTokenProperty); } + set { SetValue(ProxyTokenProperty, value); } + } + + /// + /// 代理令箭,当客户端获取代理文件时需验证令箭, 所需类型 + /// + public static readonly DependencyProperty ProxyTokenProperty = + DependencyProperty.Register("ProxyToken", typeof(string), typeof(TcpRpcParserConfig), null); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Config/UdpRpcClientConfig.cs b/RRQMSocket.RPC/RRQMRPC/Config/UdpRpcClientConfig.cs new file mode 100644 index 000000000..4b43db44d --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Config/UdpRpcClientConfig.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RRQMRPC +{ + /// + /// UdpRpc + /// + public class UdpRpcClientConfig : UdpSessionConfig + { + /// + /// 代理文件令箭 + /// + public string ProxyToken + { + get { return (string)GetValue(ProxyTokenProperty); } + set { SetValue(ProxyTokenProperty, value); } + } + + /// + /// 代理文件令箭, 所需类型 + /// + public static readonly DependencyProperty ProxyTokenProperty = + DependencyProperty.Register("ProxyToken", typeof(string), typeof(UdpRpcClientConfig), null); + + /// + /// 序列化转换器 + /// + public SerializeConverter SerializeConverter + { + get { return (SerializeConverter)GetValue(SerializeConverterProperty); } + set { SetValue(SerializeConverterProperty, value); } + } + + /// + /// 序列化转换器, 所需类型 + /// + public static readonly DependencyProperty SerializeConverterProperty = + DependencyProperty.Register("SerializeConverter", typeof(SerializeConverter), typeof(UdpRpcClientConfig), new BinarySerializeConverter()); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Config/UdpRpcParserConfig.cs b/RRQMSocket.RPC/RRQMRPC/Config/UdpRpcParserConfig.cs new file mode 100644 index 000000000..961114725 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Config/UdpRpcParserConfig.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// UdpRPCParser + /// + public class UdpRpcParserConfig : UdpSessionConfig + { + /// + /// 代理源文件命名空间, 所需类型 + /// + public static readonly DependencyProperty NameSpaceProperty = + DependencyProperty.Register("NameSpace", typeof(string), typeof(UdpRpcParserConfig), null); + + /// + /// 代理令箭,当客户端获取代理文件时需验证令箭, 所需类型 + /// + public static readonly DependencyProperty ProxyTokenProperty = + DependencyProperty.Register("ProxyToken", typeof(string), typeof(UdpRpcParserConfig), null); + + /// + /// RPC代理版本, 所需类型 + /// + public static readonly DependencyProperty RPCVersionProperty = + DependencyProperty.Register("RPCVersion", typeof(Version), typeof(UdpRpcParserConfig), null); + + /// + /// 序列化转换器, 所需类型 + /// + public static readonly DependencyProperty SerializeConverterProperty = + DependencyProperty.Register("SerializeConverter", typeof(SerializeConverter), typeof(UdpRpcParserConfig), new BinarySerializeConverter()); + + /// + /// 代理源文件命名空间 + /// + public string NameSpace + { + get { return (string)GetValue(NameSpaceProperty); } + set { SetValue(NameSpaceProperty, value); } + } + + /// + /// 代理令箭,当客户端获取代理文件时需验证令箭 + /// + public string ProxyToken + { + get { return (string)GetValue(ProxyTokenProperty); } + set { SetValue(ProxyTokenProperty, value); } + } + + /// + /// RPC代理版本 + /// + public Version RPCVersion + { + get { return (Version)GetValue(RPCVersionProperty); } + set { SetValue(RPCVersionProperty, value); } + } + + /// + /// 序列化转换器 + /// + public SerializeConverter SerializeConverter + { + get { return (SerializeConverter)GetValue(SerializeConverterProperty); } + set { SetValue(SerializeConverterProperty, value); } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCKeyException.cs b/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCKeyException.cs new file mode 100644 index 000000000..664e01f79 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCKeyException.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RPC.RRQMRPC +{ + /// + /// RPC添加方法键异常 + /// + public class RRQMRPCKeyException : RRQMException + { + /// + /// + /// + public RRQMRPCKeyException() : base() { } + + /// + /// + /// + /// + public RRQMRPCKeyException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMRPCKeyException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMRPCKeyException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCNoRegisterException.cs b/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCNoRegisterException.cs new file mode 100644 index 000000000..2b1eab6c5 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCNoRegisterException.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RPC.RRQMRPC +{ + /// + /// RPC无注册异常 + /// + public class RRQMRPCNoRegisterException : RRQMException + { + /// + /// + /// + public RRQMRPCNoRegisterException() : base() { } + + /// + /// + /// + /// + public RRQMRPCNoRegisterException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMRPCNoRegisterException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMRPCNoRegisterException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMSerializationException.cs b/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMSerializationException.cs new file mode 100644 index 000000000..665337c4e --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMSerializationException.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RPC.RRQMRPC +{ + /// + /// 序列化异常类 + /// + public class RRQMSerializationException : RRQMException + { + /// + /// + /// + public RRQMSerializationException() : base() { } + + /// + /// + /// + /// + public RRQMSerializationException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMSerializationException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMSerializationException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Interface/IRRQMRpcClient.cs b/RRQMSocket.RPC/RRQMRPC/Interface/IRRQMRpcClient.cs new file mode 100644 index 000000000..e44d3f94e --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Interface/IRRQMRpcClient.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// 客户端RPC接口 + /// + public interface IRRQMRpcClient : IRpcClient + { + /// + /// 获取ID + /// + string ID { get; } + + /// + /// 日志记录器 + /// + ILog Logger { get; } + + /// + /// 获取内存池实例 + /// + BytePool BytePool { get; } + + /// + /// 序列化生成器 + /// + SerializeConverter SerializeConverter { get; } + + /// + /// 获取远程服务器RPC服务文件 + /// + /// + /// + /// + RpcProxyInfo GetProxyInfo(); + + /// + /// 服务发现完成后 + /// + event RRQMMessageEventHandler ServiceDiscovered; + + /// + /// 发现服务 + /// + /// 是否触发初始化事件 + /// 已发现的服务 + MethodItem[] DiscoveryService(bool isTrigger = true); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Interface/IRRQMRpcParser.cs b/RRQMSocket.RPC/RRQMRPC/Interface/IRRQMRpcParser.cs new file mode 100644 index 000000000..273664229 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Interface/IRRQMRpcParser.cs @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System.Collections.Generic; +using System.Net; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// RRQMRPC接口 + /// + public interface IRRQMRpcParser + { + /// + /// 内存池实例 + /// + BytePool BytePool { get; } + + /// + /// 获取生成的代理代码 + /// + CellCode[] Codes { get; } + + /// + /// 代理源文件命名空间 + /// + string NameSpace { get; } + + /// + /// 获取代理文件实例 + /// + RpcProxyInfo ProxyInfo { get; } + + /// + /// 函数库 + /// + MethodStore MethodStore { get; } + + /// + /// 代理令箭,当客户端获取代理文件时需验证令箭 + /// + string ProxyToken { get; } + + /// + /// RPC代理版本 + /// + Version RPCVersion { get; } + + /// + /// 序列化转换器 + /// + SerializeConverter SerializeConverter { get; } + + /// + /// 获取代理文件 + /// + /// 代理令箭 + /// 调用作用者,TCP模式下派生自,UDP模式下是 + /// + RpcProxyInfo GetProxyInfo(string proxyToken, object caller); + + /// + /// 执行函数 + /// + /// 函数内容 + /// 调用作用者,TCP模式下派生自,UDP模式下是 + void ExecuteContext(RpcContext context, object caller); + + /// + /// 获取注册函数 + /// + /// + /// 调用作用者,TCP模式下派生自,UDP模式下是 + /// + List GetRegisteredMethodItems(string proxyToken, object caller); + +#if NET45_OR_GREATER + + /// + /// 编译代理 + /// + /// 存放目标文件夹 + void CompilerProxy(string targetDic = ""); + +#endif + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Interface/IRpcClient.cs b/RRQMSocket.RPC/RRQMRPC/Interface/IRpcClient.cs new file mode 100644 index 000000000..3818f6592 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Interface/IRpcClient.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// 客户端RPC接口 + /// + public interface IRpcClient : IDisposable + { + /// + /// 函数式调用 + /// + /// 函数名 + /// 参数 + /// RPC调用设置 + /// + /// + /// + /// + void Invoke(string method, InvokeOption invokeOption, params object[] parameters); + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// RPC调用设置 + /// + /// + /// + /// + /// 服务器返回结果 + T Invoke(string method, InvokeOption invokeOption, params object[] parameters); + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// + /// RPC调用设置 + /// + /// + /// + /// + /// 服务器返回结果 + T Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types); + + /// + /// 函数式调用 + /// + /// 方法名 + /// 参数 + /// + /// RPC调用设置 + /// + /// + /// + /// + void Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Serialization/BinarySerializeConverter.cs b/RRQMSocket.RPC/RRQMRPC/Serialization/BinarySerializeConverter.cs new file mode 100644 index 000000000..3aab3a98b --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Serialization/BinarySerializeConverter.cs @@ -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 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using RRQMCore.Serialization; +using System; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// 二进制序列化器,默认最大可序列化1K byte的大小 + /// + public class BinarySerializeConverter : SerializeConverter + { +#pragma warning disable CS1591 // XML 注释跟随抽象类 + + public override object DeserializeParameter(byte[] parameterBytes, Type parameterType) + { + if (parameterBytes == null) + { + return null; + } + return SerializeConvert.RRQMBinaryDeserialize(parameterBytes, 0, parameterType); + } + + public override byte[] SerializeParameter(object parameter) + { + if (parameter == null) + { + return null; + } + return SerializeConvert.RRQMBinarySerialize(parameter, true); + } + +#pragma warning restore CS1591 + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Serialization/JsonSerializeConverter.cs b/RRQMSocket.RPC/RRQMRPC/Serialization/JsonSerializeConverter.cs new file mode 100644 index 000000000..ad47d5156 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Serialization/JsonSerializeConverter.cs @@ -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.XREF.Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// Json序列化转化器 + /// + public class JsonSerializeConverter : RRQMSocket.RPC.RRQMRPC.SerializeConverter + { + /// + /// 反序列化 + /// + /// + /// + /// + public override object DeserializeParameter(byte[] parameterBytes, Type parameterType) + { + if (parameterBytes == null) + { + return null; + } + return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(parameterBytes), parameterType); + } + + /// + /// 序列化 + /// + /// + /// + public override byte[] SerializeParameter(object parameter) + { + if (parameter == null) + { + return null; + } + return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(parameter)); + } + } +} diff --git a/RRQMSocket.RPC/RRQMRPC/Serialization/SerializeConverter.cs b/RRQMSocket.RPC/RRQMRPC/Serialization/SerializeConverter.cs new file mode 100644 index 000000000..cd175ae6e --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Serialization/SerializeConverter.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.RRQMRPC +{ + /// + /// 序列化转换器 + /// + public abstract class SerializeConverter + { + /// + /// 序列化RPC方法返回值参数 + /// + /// + /// + public abstract byte[] SerializeParameter(object parameter); + + /// + /// 反序列化传输对象 + /// + /// + /// + /// + public abstract object DeserializeParameter(byte[] parameterBytes, Type parameterType); + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Serialization/XmlSerializeConverter.cs b/RRQMSocket.RPC/RRQMRPC/Serialization/XmlSerializeConverter.cs new file mode 100644 index 000000000..8eff4a7ac --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Serialization/XmlSerializeConverter.cs @@ -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 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using RRQMCore.Serialization; +using System; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// Xml序列化 + /// + public class XmlSerializeConverter : SerializeConverter + { +#pragma warning disable CS1591 // XML 注释 + + public override object DeserializeParameter(byte[] parameterBytes, Type parameterType) + { + if (parameterBytes == null) + { + return null; + } + return SerializeConvert.XmlDeserializeFromBytes(parameterBytes, parameterType); + } + + public override byte[] SerializeParameter(object parameter) + { + if (parameter == null) + { + return null; + } + return SerializeConvert.XmlSerializeToBytes(parameter); + } + +#pragma warning restore CS1591 + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Socket/RpcSocketClient .cs b/RRQMSocket.RPC/RRQMRPC/Socket/RpcSocketClient .cs new file mode 100644 index 000000000..f37969dea --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Socket/RpcSocketClient .cs @@ -0,0 +1,474 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using RRQMCore.Run; +using RRQMCore.Serialization; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// RPC服务器辅助类 + /// + public class RpcSocketClient : ProtocolSocketClient + { + static RpcSocketClient() + { + AddUsedProtocol(100, "请求RPC代理文件"); + AddUsedProtocol(101, "RPC调用"); + AddUsedProtocol(102, "获取注册服务"); + AddUsedProtocol(103, "ID调用客户端"); + AddUsedProtocol(104, "RPC回调"); + for (short i = 105; i < 110; i++) + { + AddUsedProtocol(i, "保留协议"); + } + } + + internal Func IDAction; + + internal RRQMReceivedProcotolEventHandler Received; + + internal SerializeConverter serializeConverter; + + internal RRQMWaitHandle waitHandle; + + /// + /// 构造函数 + /// + public RpcSocketClient() + { + waitHandle = new RRQMWaitHandle(); + } + + /// + /// 回调RPC + /// + /// + /// + /// + /// + /// + public T CallBack(int methodToken, InvokeOption invokeOption = null, params object[] parameters) + { + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + + context.MethodToken = methodToken; + + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.serializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + + this.InternalSend(104, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + finally + { + byteBlock.Dispose(); + } + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + return default(T); + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + return default(T); + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCCallBackMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("客户端未开启反向RPC"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"调用异常,信息:{resultContext.Message}"); + } + + try + { + return (T)this.serializeConverter.DeserializeParameter(resultContext.ReturnParameterBytes, typeof(T)); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + } + default: + return default(T); + } + } + + /// + /// 回调RPC + /// + /// + /// + /// + public void CallBack(int methodToken, InvokeOption invokeOption = null, params object[] parameters) + { + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + + context.MethodToken = methodToken; + + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.serializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + + this.InternalSend(104, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + finally + { + byteBlock.Dispose(); + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + return; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + return; + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCCallBackMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("客户端未开启反向RPC"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"调用异常,信息:{resultContext.Message}"); + } + return; + } + default: + return; + } + } + + /// + /// 回调RPC + /// + /// + /// + /// + public byte[] CallBack(RpcContext invokeContext, int timeout) + { + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = invokeContext.MethodToken; + + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + + try + { + context.Feedback = invokeContext.Feedback; + + context.ParametersBytes = invokeContext.ParametersBytes; + context.Serialize(byteBlock); + + this.InternalSend(104, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + finally + { + byteBlock.Dispose(); + } + switch (invokeContext.Feedback) + { + case 0: + { + this.waitHandle.Destroy(waitData); + return null; + } + case 1: + { + waitData.Wait(timeout * 1000); + + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + return null; + } + case 2: + { + waitData.Wait(timeout * 1000); + + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCCallBackMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("客户端未开启反向RPC"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"调用异常,信息:{resultContext.Message}"); + } + + return resultContext.ReturnParameterBytes; + } + default: + return null; + } + } + + /// + /// 内部发送器 + /// + /// + /// + /// + /// + internal void InternalSend(short procotol, byte[] buffer, int offset, int length) + { + base.InternalSend(procotol, buffer, offset, length); + } + + /// + /// 处理协议数据 + /// + /// + /// + protected sealed override void HandleProtocolData(short? procotol, ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = (int)byteBlock.Position; + switch (procotol) + { + case 100:/*100,请求RPC文件*/ + { + try + { + string proxyToken = Encoding.UTF8.GetString(buffer, 2, r - 2); + byte[] data = SerializeConvert.RRQMBinarySerialize(((IRRQMRpcParser)this.Service).GetProxyInfo(proxyToken, this), true); + this.InternalSend(100, data, 0, data.Length); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 100, 错误详情:{e.Message}"); + } + break; + } + case 101:/*函数调用*/ + { + try + { + byteBlock.Pos = 2; + RpcContext content = RpcContext.Deserialize(byteBlock); + if (content.Feedback == 1) + { + List ps = content.ParametersBytes; + + ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength); + try + { + content.ParametersBytes = null; + content.Status = 1; + content.Serialize(returnByteBlock); + this.InternalSend(101, returnByteBlock.Buffer, 0, (int)returnByteBlock.Length); + } + finally + { + content.ParametersBytes = ps; + returnByteBlock.Dispose(); + } + } + ((IRRQMRpcParser)this.Service).ExecuteContext(content, this); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 101, 错误详情:{e.Message}"); + } + break; + } + case 102:/*获取注册服务*/ + { + try + { + string proxyToken = Encoding.UTF8.GetString(buffer, 2, r - 2); + byte[] data = SerializeConvert.RRQMBinarySerialize(((IRRQMRpcParser)this.Service).GetRegisteredMethodItems(proxyToken, this), true); + this.InternalSend(102, data, 0, data.Length); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 102, 错误详情:{e.Message}"); + } + break; + } + case 103:/*ID调用客户端*/ + { + Task.Run(() => + { + try + { + byteBlock.Pos = 2; + RpcContext content = RpcContext.Deserialize(byteBlock); + content = this.IDAction(this, content); + + ByteBlock retuenByteBlock = this.BytePool.GetByteBlock(this.BufferLength); + try + { + content.Serialize(retuenByteBlock); + this.InternalSend(103, retuenByteBlock.Buffer, 0, (int)retuenByteBlock.Length); + } + finally + { + byteBlock.Dispose(); + } + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 103, 错误详情:{e.Message}"); + } + }); + break; + } + case 104:/*回调函数调用*/ + { + try + { + byteBlock.Pos = 2; + RpcContext content = RpcContext.Deserialize(byteBlock); + this.waitHandle.SetRun(content); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 104, 错误详情:{e.Message}"); + } + break; + } + default: + RPCHandleDefaultData(procotol, byteBlock); + break; + } + } + + /// + /// RPC处理其余协议 + /// + /// + /// + protected virtual void RPCHandleDefaultData(short? procotol, ByteBlock byteBlock) + { + this.OnHandleDefaultData(procotol, byteBlock); + } + + /// + /// 处理其余协议的事件触发 + /// + /// + /// + protected void OnHandleDefaultData(short? procotol, ByteBlock byteBlock) + { + Received?.Invoke(this, procotol, byteBlock); + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Socket/TcpParser.cs b/RRQMSocket.RPC/RRQMRPC/Socket/TcpParser.cs new file mode 100644 index 000000000..ad032c681 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Socket/TcpParser.cs @@ -0,0 +1,374 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 System; +using System.Collections.Generic; +using System.IO; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// TcpRPCParser泛型类型 + /// + /// + public class TcpParser : ProtocolService, IRPCParser, IRRQMRpcParser where TClient : RpcSocketClient, new() + { + /// + /// 构造函数 + /// + public TcpParser() + { + this.methodStore = new MethodStore(); + this.proxyInfo = new RpcProxyInfo(); + } + +#pragma warning disable + + public MethodMap MethodMap { get; private set; } + + public RPCService RPCService { get; private set; } + + public Action RRQMExecuteMethod { get; private set; } + + public CellCode[] Codes { get => this.proxyInfo == null ? null : this.proxyInfo.Codes.ToArray(); } + + public string NameSpace { get; private set; } + + public RpcProxyInfo ProxyInfo { get => proxyInfo; } + + public string ProxyToken { get; private set; } + + public Version RPCVersion { get; private set; } + + public SerializeConverter SerializeConverter { get; private set; } + + private MethodStore methodStore; + + private RpcProxyInfo proxyInfo; + + public MethodStore MethodStore { get => methodStore; } + + public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance) + { + RpcContext context = (RpcContext)methodInvoker.Flag; + if (context.Feedback != 2) + { + return; + } + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + try + { + switch (methodInvoker.Status) + { + case InvokeStatus.Ready: + { + break; + } + + case InvokeStatus.UnFound: + { + context.Status = 2; + break; + } + case InvokeStatus.Success: + { + if (methodInstance.MethodToken > 50000000) + { + context.ReturnParameterBytes = this.SerializeConverter.SerializeParameter(methodInvoker.ReturnParameter); + } + else + { + context.ReturnParameterBytes = null; + } + + if (methodInstance.IsByRef) + { + context.ParametersBytes = new List(); + foreach (var item in methodInvoker.Parameters) + { + context.ParametersBytes.Add(this.SerializeConverter.SerializeParameter(item)); + } + } + else + { + context.ParametersBytes = null; + } + + context.Status = 1; + break; + } + case InvokeStatus.Abort: + { + context.Status = 4; + context.Message = methodInvoker.StatusMessage; + break; + } + case InvokeStatus.UnEnable: + { + context.Status = 3; + break; + } + case InvokeStatus.InvocationException: + { + context.Status = 5; + context.Message = methodInvoker.StatusMessage; + break; + } + case InvokeStatus.Exception: + { + context.Status = 6; + context.Message = methodInvoker.StatusMessage; + break; + } + default: + break; + } + + context.Serialize(byteBlock); + ((RpcSocketClient)methodInvoker.Caller).InternalSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, ex.Message); + } + finally + { + byteBlock.Dispose(); + } + } + + public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances) + { + Tools.GetRPCMethod(methodInstances, this.NameSpace, ref this.methodStore, this.RPCVersion, ref this.proxyInfo); + } + + public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances) + { + foreach (var item in methodInstances) + { + this.methodStore.RemoveMethodItem(item.MethodToken); + } + + CellCode cellCode = null; + foreach (var item in this.proxyInfo.Codes) + { + if (item.Name == provider.GetType().Name) + { + cellCode = item; + break; + } + } + if (cellCode != null) + { + this.proxyInfo.Codes.Remove(cellCode); + } + } + + public void SetExecuteMethod(Action executeMethod) + { + this.RRQMExecuteMethod = executeMethod; + } + + public void SetMethodMap(MethodMap methodMap) + { + this.MethodMap = methodMap; + } + + public void SetRPCService(RPCService service) + { + this.RPCService = service; + } + +#if NET45_OR_GREATER + + /// + /// 编译代理 + /// + /// 存放目标文件夹 + public void CompilerProxy(string targetDic = "") + { + string assemblyInfo = CodeGenerator.GetAssemblyInfo(this.proxyInfo.AssemblyName, this.proxyInfo.Version); + List codesString = new List(); + codesString.Add(assemblyInfo); + foreach (var item in this.proxyInfo.Codes) + { + codesString.Add(item.Code); + } + RpcCompiler.CompileCode(Path.Combine(targetDic, this.proxyInfo.AssemblyName), codesString.ToArray()); + } + +#endif + + protected override void OnCreateSocketCliect(TClient socketClient, CreateOption createOption) + { + if (createOption.NewCreate) + { + socketClient.IDAction = this.IDInvoke; + socketClient.Received = this.OnReceived; + socketClient.serializeConverter = this.SerializeConverter; + } + } + + private void OnReceived(object sender, short? procotol, ByteBlock byteBlock) + { + this.Received?.Invoke(sender, procotol, byteBlock); + } + + public virtual RpcProxyInfo GetProxyInfo(string proxyToken, object caller) + { + RpcProxyInfo proxyInfo = new RpcProxyInfo(); + if (this.ProxyToken == proxyToken) + { + proxyInfo.AssemblyData = this.ProxyInfo.AssemblyData; + proxyInfo.AssemblyName = this.ProxyInfo.AssemblyName; + proxyInfo.Codes = this.ProxyInfo.Codes; + proxyInfo.Version = this.ProxyInfo.Version; + proxyInfo.Status = 1; + } + else + { + proxyInfo.Status = 2; + proxyInfo.Message = "令箭不正确"; + } + + return proxyInfo; + } + + public virtual void ExecuteContext(RpcContext context, object caller) + { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.Caller = caller; + methodInvoker.Flag = context; + if (this.MethodMap.TryGet(context.MethodToken, out MethodInstance methodInstance)) + { + try + { + if (methodInstance.IsEnable) + { + object[] ps = new object[methodInstance.ParameterTypes.Length]; + for (int i = 0; i < methodInstance.ParameterTypes.Length; i++) + { + ps[i] = this.SerializeConverter.DeserializeParameter(context.ParametersBytes[i], methodInstance.ParameterTypes[i]); + } + methodInvoker.Parameters = ps; + } + else + { + methodInvoker.Status = InvokeStatus.UnEnable; + } + } + catch (Exception ex) + { + methodInvoker.Status = InvokeStatus.Exception; + methodInvoker.StatusMessage = ex.Message; + } + + this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance); + } + else + { + methodInvoker.Status = InvokeStatus.UnFound; + this.RRQMExecuteMethod.Invoke(this, methodInvoker, null); + } + } + + protected override void LoadConfig(ServiceConfig ServiceConfig) + { + base.LoadConfig(ServiceConfig); + this.SerializeConverter = (SerializeConverter)ServiceConfig.GetValue(TcpRpcParserConfig.SerializeConverterProperty); + this.ProxyToken = (string)ServiceConfig.GetValue(TcpRpcParserConfig.ProxyTokenProperty); + this.NameSpace = (string)ServiceConfig.GetValue(TcpRpcParserConfig.NameSpaceProperty); + this.RPCVersion = (Version)ServiceConfig.GetValue(TcpRpcParserConfig.RPCVersionProperty); + } + + public virtual List GetRegisteredMethodItems(string proxyToken, object caller) + { + if (proxyToken == this.ProxyToken) + { + return this.methodStore.GetAllMethodItem(); + } + return null; + } + + private RpcContext IDInvoke(RpcSocketClient socketClient, RpcContext context) + { + if (this.TryGetSocketClient(context.ID, out TClient targetsocketClient)) + { + try + { + context.ReturnParameterBytes = targetsocketClient.CallBack(context, 5); + context.Status = 1; + } + catch (Exception ex) + { + context.Status = 3; + context.Message = ex.Message; + } + } + else + { + context.Status = 2; + } + + return context; + } + +#pragma warning disable + + /// + /// 收到协议数据 + /// + public event RRQMReceivedProcotolEventHandler Received; + + /// + /// 回调RPC + /// + /// 返回值 + /// ID + /// 函数唯一标识 + /// 调用设置 + /// 参数 + /// + public T CallBack(string id, int methodToken, InvokeOption invokeOption = null, params object[] parameters) + { + if (this.SocketClients.TryGetSocketClient(id, out TClient socketClient)) + { + return socketClient.CallBack(methodToken, invokeOption, parameters); + } + else + { + throw new RRQMRPCException("未找到该客户端"); + } + } + + /// + /// 回调RPC + /// + /// ID + /// 函数唯一标识 + /// 调用设置 + /// 参数 + public void CallBack(string id, int methodToken, InvokeOption invokeOption = null, params object[] parameters) + { + if (this.SocketClients.TryGetSocketClient(id, out TClient socketClient)) + { + socketClient.CallBack(methodToken, invokeOption, parameters); + } + else + { + throw new RRQMRPCException("未找到该客户端"); + } + } + + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcClient.cs b/RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcClient.cs new file mode 100644 index 000000000..8c62e7bbf --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcClient.cs @@ -0,0 +1,1201 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 RRQMCore.ByteManager; +using RRQMCore.Exceptions; +using RRQMCore.Log; +using RRQMCore.Run; +using RRQMCore.Serialization; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// TcpRPCClient + /// + public class TcpRpcClient : ProtocolClient, IRRQMRpcClient + { + private MethodMap methodMap; + + private MethodStore methodStore; + + private RpcProxyInfo proxyFile; + + private ServerProviderCollection serverProviders; + + private WaitData singleWaitData; + + private RRQMWaitHandle waitHandle; + + static TcpRpcClient() + { + AddUsedProtocol(100, "请求RPC代理文件"); + AddUsedProtocol(101, "RPC调用"); + AddUsedProtocol(102, "获取注册服务"); + AddUsedProtocol(103, "ID调用客户端"); + AddUsedProtocol(104, "RPC回调"); + + for (short i = 105; i < 110; i++) + { + AddUsedProtocol(i, "保留协议"); + } + } + + /// + /// 构造函数 + /// + public TcpRpcClient() + { + this.methodMap = new MethodMap(); + this.serverProviders = new ServerProviderCollection(); + this.methodStore = new MethodStore(); + this.singleWaitData = new WaitData(); + this.waitHandle = new RRQMWaitHandle(); + } + + /// + /// 收到协议数据 + /// + public event RRQMReceivedProcotolEventHandler Received; + + /// + /// RPC初始化后 + /// + public event RRQMMessageEventHandler ServiceDiscovered; + + /// + /// 获取反向RPC映射图 + /// + public MethodMap MethodMap + { + get { return methodMap; } + } + + /// + /// 序列化生成器 + /// + public SerializeConverter SerializeConverter { get; private set; } + + /// + /// 获取反向RPC服务实例 + /// + public ServerProviderCollection ServerProviders + { + get { return serverProviders; } + } + + /// + /// 获取远程服务器RPC服务文件 + /// + /// + /// + public RpcProxyInfo GetProxyInfo() + { + string proxyToken = (string)this.ClientConfig.GetValue(TcpRpcClientConfig.ProxyTokenProperty); + byte[] data = Encoding.UTF8.GetBytes(string.IsNullOrEmpty(proxyToken) ? string.Empty : proxyToken); + this.InternalSend(100, data, 0, data.Length); + this.singleWaitData.Wait(1000 * 10); + + if (this.proxyFile == null) + { + throw new RRQMTimeoutException("获取引用文件超时"); + } + else if (this.proxyFile.Status == 2) + { + throw new RRQMRPCException(this.proxyFile.Message); + } + return this.proxyFile; + } + + /// + /// 发现服务 + /// + /// 是否触发初始化事件 + /// 已发现的服务 + public MethodItem[] DiscoveryService(bool isTrigger = true) + { + lock (locker) + { + if (!this.Online) + { + base.Connect(); + } + try + { + this.methodStore = null; + string proxyToken = (string)this.clientConfig.GetValue(TcpRpcClientConfig.ProxyTokenProperty); + byte[] data = new byte[0]; + if (!string.IsNullOrEmpty(proxyToken)) + { + data = Encoding.UTF8.GetBytes(proxyToken); + } + this.InternalSend(102, data, 0, data.Length); + } + catch (Exception ex) + { + throw ex; + } + this.singleWaitData.Wait(1000 * 10); + if (this.methodStore == null) + { + throw new RRQMRPCException("初始化超时"); + } + + if (isTrigger) + { + this.OnServiceDiscovered(new MesEventArgs("success")); + } + return this.methodStore.GetAllMethodItem().ToArray(); + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + /// + /// + public T Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (!this.methodStore.TryGetMethodItem(method, out MethodItem methodItem)) + { + throw new RRQMRPCNoRegisterException($"服务名为{method}的服务未找到注册信息"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodItem.MethodToken; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.InternalSendAsync(101, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + case FeedbackType.WaitSend: + case FeedbackType.WaitInvoke: + { + this.InternalSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + default: + break; + } + + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else + { + return default; + } + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("该方法已被禁用"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"服务器已阻止本次行为,信息:{resultContext.Message}"); + } + else if (resultContext.Status == 5) + { + throw new RRQMRPCInvokeException("函数执行异常,详细信息:" + resultContext.Message); + } + else if (resultContext.Status == 6) + { + throw new RRQMRPCException($"函数异常,信息:{resultContext.Message}"); + } + if (methodItem.IsOutOrRef) + { + try + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = this.SerializeConverter.DeserializeParameter(resultContext.ParametersBytes[i], types[i]); + } + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + } + else + { + parameters = null; + } + try + { + return (T)this.SerializeConverter.DeserializeParameter(resultContext.ReturnParameterBytes, typeof(T)); + } + catch (Exception ex) + { + throw ex; + } + } + default: + return default; + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + /// + public void Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (!this.methodStore.TryGetMethodItem(method, out MethodItem methodItem)) + { + throw new RRQMRPCNoRegisterException($"服务名为{method}的服务未找到注册信息"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodItem.MethodToken; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.InternalSendAsync(101, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + case FeedbackType.WaitSend: + case FeedbackType.WaitInvoke: + { + this.InternalSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + default: + break; + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + break; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + break; + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("该方法已被禁用"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"服务器已阻止本次行为,信息:{resultContext.Message}"); + } + else if (resultContext.Status == 5) + { + throw new RRQMRPCInvokeException("函数执行异常,详细信息:" + resultContext.Message); + } + else if (resultContext.Status == 6) + { + throw new RRQMRPCException($"函数异常,信息:{resultContext.Message}"); + } + if (methodItem.IsOutOrRef) + { + try + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = this.SerializeConverter.DeserializeParameter(resultContext.ParametersBytes[i], types[i]); + } + } + catch (Exception ex) + { + throw ex; + } + } + else + { + parameters = null; + } + break; + } + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public void Invoke(string method, InvokeOption invokeOption, params object[] parameters) + { + if (!this.methodStore.TryGetMethodItem(method, out MethodItem methodItem)) + { + throw new RRQMRPCNoRegisterException($"服务名为{method}的服务未找到注册信息"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodItem.MethodToken; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.InternalSendAsync(101, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + case FeedbackType.WaitSend: + case FeedbackType.WaitInvoke: + { + this.InternalSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + default: + break; + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + break; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + break; + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("该方法已被禁用"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"服务器已阻止本次行为,信息:{resultContext.Message}"); + } + else if (resultContext.Status == 5) + { + throw new RRQMRPCInvokeException("函数执行异常,详细信息:" + resultContext.Message); + } + else if (resultContext.Status == 6) + { + throw new RRQMRPCException($"函数异常,信息:{resultContext.Message}"); + } + break; + } + default: + break; + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + /// + public T Invoke(string method, InvokeOption invokeOption, params object[] parameters) + { + if (!this.methodStore.TryGetMethodItem(method, out MethodItem methodItem)) + { + throw new RRQMRPCNoRegisterException($"服务名为{method}的服务未找到注册信息"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodItem.MethodToken; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.InternalSendAsync(101, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + case FeedbackType.WaitSend: + case FeedbackType.WaitInvoke: + { + this.InternalSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + break; + default: + break; + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else + { + return default; + } + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("该方法已被禁用"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"服务器已阻止本次行为,信息:{resultContext.Message}"); + } + else if (resultContext.Status == 5) + { + throw new RRQMRPCInvokeException("函数执行异常,详细信息:" + resultContext.Message); + } + else if (resultContext.Status == 6) + { + throw new RRQMRPCException($"函数异常,信息:{resultContext.Message}"); + } + + try + { + return (T)this.SerializeConverter.DeserializeParameter(resultContext.ReturnParameterBytes, typeof(T)); + } + catch (Exception ex) + { + throw ex; + } + } + default: + return default; + } + } + + /// + /// RPC调用 + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string id, int methodToken, InvokeOption invokeOption, params object[] parameters) + { + if (string.IsNullOrEmpty(id)) + { + throw new RRQMRPCException("目标ID不能为null或empty"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodToken; + context.ID = id; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + this.InternalSend(103, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + } + break; + + case FeedbackType.WaitSend: + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该客户端ID"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException(resultContext.Message); + } + } + break; + + default: + break; + } + } + + /// + /// RPC调用 + /// + /// 客户端ID + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string id, int methodToken, InvokeOption invokeOption, params object[] parameters) + { + if (string.IsNullOrEmpty(id)) + { + throw new RRQMRPCException("目标ID不能为null或empty"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodToken; + context.ID = id; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + this.InternalSend(103, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = (RpcContext)waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该客户端ID"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException(resultContext.Message); + } + + try + { + return (T)this.SerializeConverter.DeserializeParameter(resultContext.ReturnParameterBytes, typeof(T)); + } + catch (Exception ex) + { + throw ex; + } + } + default: + return default; + } + } + + /// + /// 注册服务 + /// + /// + /// 返回T实例 + public ServerProvider RegisterServer() where T : ServerProvider + { + ServerProvider serverProvider = (ServerProvider)Activator.CreateInstance(typeof(T)); + this.RegisterServer(serverProvider); + return serverProvider; + } + + /// + /// 注册服务 + /// + /// + /// + public ServerProvider RegisterServer(Type providerType) + { + if (!typeof(ServerProvider).IsAssignableFrom(providerType)) + { + throw new RRQMRPCException("类型不相符"); + } + ServerProvider serverProvider = (ServerProvider)Activator.CreateInstance(providerType); + this.RegisterServer(serverProvider); + return serverProvider; + } + + /// + /// 注册服务 + /// + /// + public void RegisterServer(ServerProvider serverProvider) + { + this.ServerProviders.Add(serverProvider); + MethodInfo[] methodInfos = serverProvider.GetType().GetMethods(); + foreach (MethodInfo method in methodInfos) + { + if (method.IsGenericMethod) + { + continue; + } + RRQMRPCCallBackMethodAttribute attribute = method.GetCustomAttribute(); + + if (attribute != null) + { + MethodInstance methodInstance = new MethodInstance(); + methodInstance.MethodToken = attribute.MethodToken; + methodInstance.Provider = serverProvider; + methodInstance.Method = method; + methodInstance.RPCAttributes = new RPCAttribute[] { attribute }; + methodInstance.IsEnable = true; + methodInstance.Parameters = method.GetParameters(); + List names = new List(); + foreach (var parameterInfo in methodInstance.Parameters) + { + names.Add(parameterInfo.Name); + } + methodInstance.ParameterNames = names.ToArray(); + if (typeof(Task).IsAssignableFrom(method.ReturnType)) + { + methodInstance.Async = true; + } + + ParameterInfo[] parameters = method.GetParameters(); + List types = new List(); + foreach (var parameter in parameters) + { + if (parameter.ParameterType.IsByRef) + { + throw new RRQMRPCException("反向RPC方法不支持out或ref"); + } + types.Add(parameter.ParameterType); + } + methodInstance.ParameterTypes = types.ToArray(); + + if (method.ReturnType == typeof(void)) + { + methodInstance.ReturnType = null; + } + else + { + if (methodInstance.Async) + { + methodInstance.ReturnType = method.ReturnType.GetGenericArguments()[0]; + } + else + { + methodInstance.ReturnType = method.ReturnType; + } + } + + try + { + this.MethodMap.Add(methodInstance); + } + catch + { + throw new RRQMRPCKeyException("MethodToken必须唯一"); + } + } + } + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer(ServerProvider provider) + { + return this.UnregisterServer(provider.GetType()); + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer(Type providerType) + { + if (!typeof(ServerProvider).IsAssignableFrom(providerType)) + { + throw new RRQMRPCException("类型不相符"); + } + this.ServerProviders.Remove(providerType); + if (this.MethodMap.RemoveServer(providerType, out IServerProvider serverProvider, out MethodInstance[] instances)) + { + return instances.Length; + } + return 0; + } + + /// + /// 移除注册服务 + /// + /// + /// + public int UnregisterServer() where T : ServerProvider + { + return this.UnregisterServer(typeof(T)); + } + + /// + /// 协议数据 + /// + /// + /// + protected sealed override void HandleProtocolData(short? procotol, ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + switch (procotol) + { + case 100:/* 100表示获取RPC引用文件上传状态返回*/ + { + try + { + proxyFile = SerializeConvert.RRQMBinaryDeserialize(buffer, 2); + this.singleWaitData.Set(); + } + catch + { + proxyFile = null; + } + + break; + } + + case 101:/*函数调用*/ + { + try + { + byteBlock.Pos = 2; + RpcContext result = RpcContext.Deserialize(byteBlock); + this.waitHandle.SetRun(result.Sign, result); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 101, 错误详情:{e.Message}"); + } + break; + } + case 102:/*获取服务*/ + { + try + { + List methodItems = SerializeConvert.RRQMBinaryDeserialize>(buffer, 2); + this.methodStore = new MethodStore(); + if (methodItems != null) + { + foreach (var item in methodItems) + { + this.methodStore.AddMethodItem(item); + } + } + this.singleWaitData.Set(); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 102, 错误详情:{e.Message}"); + } + break; + } + case 103:/*ID函数调用*/ + { + try + { + byteBlock.Pos = 2; + RpcContext result = RpcContext.Deserialize(byteBlock); + this.waitHandle.SetRun(result.Sign, result); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 103, 错误详情:{e.Message}"); + } + break; + } + case 104:/*反向函数调用*/ + { + Task.Run(() => + { + byteBlock.Pos = 2; + RpcContext rpcContext = RpcContext.Deserialize(byteBlock); + ByteBlock block = this.BytePool.GetByteBlock(this.BufferLength); + try + { + rpcContext = this.OnExecuteCallBack(rpcContext); + rpcContext.Serialize(block); + this.InternalSend(104, block.Buffer, 0, (int)block.Length); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 104, 错误详情:{e.Message}"); + } + finally + { + block.Dispose(); + } + }); + + break; + } + default: + { + RPCHandleDefaultData(procotol, byteBlock); + break; + } + } + } + + /// + /// 加载配置 + /// + /// + protected override void LoadConfig(TcpClientConfig clientConfig) + { + base.LoadConfig(clientConfig); + this.SetDataHandlingAdapter(new FixedHeaderDataHandlingAdapter()); + this.SerializeConverter = (SerializeConverter)clientConfig.GetValue(TcpRpcClientConfig.SerializeConverterProperty); + } + + /// + /// 处理其余协议的事件触发 + /// + /// + /// + protected void OnHandleDefaultData(short? procotol, ByteBlock byteBlock) + { + Received?.Invoke(this, procotol, byteBlock); + } + + /// + /// RPC完成初始化后 + /// + /// + protected virtual void OnServiceDiscovered(MesEventArgs args) + { + try + { + this.ServiceDiscovered?.Invoke(this, args); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, $"在事件{nameof(ServiceDiscovered)}中发生异常", ex); + } + } + + /// + /// RPC处理其余协议 + /// + /// + /// + protected virtual void RPCHandleDefaultData(short? procotol, ByteBlock byteBlock) + { + OnHandleDefaultData(procotol, byteBlock); + } + + private RpcContext OnExecuteCallBack(RpcContext rpcContext) + { + if (this.methodMap != null) + { + if (this.methodMap.TryGet(rpcContext.MethodToken, out MethodInstance methodInstance)) + { + try + { + object[] ps = new object[rpcContext.ParametersBytes.Count]; + for (int i = 0; i < rpcContext.ParametersBytes.Count; i++) + { + ps[i] = this.SerializeConverter.DeserializeParameter(rpcContext.ParametersBytes[i], methodInstance.ParameterTypes[i]); + } + object result = methodInstance.Method.Invoke(methodInstance.Provider, ps); + if (result != null) + { + rpcContext.ReturnParameterBytes = this.SerializeConverter.SerializeParameter(result); + } + rpcContext.Status = 1; + } + catch (Exception ex) + { + rpcContext.Status = 4; + rpcContext.Message = ex.Message; + } + } + else + { + rpcContext.Status = 2; + } + } + else + { + rpcContext.Status = 3; + } + + rpcContext.ParametersBytes = null; + return rpcContext; + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcParser.cs b/RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcParser.cs new file mode 100644 index 000000000..e42e027ae --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Socket/TcpRpcParser.cs @@ -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.RRQMRPC +{ + /// + /// TCP RPC解释器 + /// + public class TcpRpcParser : TcpParser + { + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcClient.cs b/RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcClient.cs new file mode 100644 index 000000000..2d9fd0263 --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcClient.cs @@ -0,0 +1,712 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using RRQMCore.Run; +using RRQMCore.Serialization; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// UDP协议客户端 + /// + public class UdpRpcClient : UdpSession, IRRQMRpcClient + { + private MethodStore methodStore; + private RpcProxyInfo proxyFile; + private WaitData singleWaitData; + private RRQMWaitHandle waitHandle; + private WaitResult waitResult; + + /// + /// 发现服务后 + /// + public event RRQMMessageEventHandler ServiceDiscovered; + + /// + /// 构造函数 + /// + public UdpRpcClient() + { + this.waitHandle = new RRQMWaitHandle(); + this.SerializeConverter = new BinarySerializeConverter(); + this.waitResult = new WaitResult(); + this.singleWaitData = new WaitData(); + } + + /// + /// 返回ID + /// + public string ID => null; + + /// + /// 序列化生成器 + /// + public SerializeConverter SerializeConverter { get; set; } + + /// + /// 获取远程服务器RPC服务文件 + /// + /// + /// + /// + public RpcProxyInfo GetProxyInfo() + { + int count = 0; + while (count < 3) + { + lock (this) + { + byte[] datas; + string proxyToken = (string)this.ServiceConfig.GetValue(UdpRpcClientConfig.ProxyTokenProperty); + if (proxyToken == null) + { + datas = new byte[0]; + } + else + { + datas = Encoding.UTF8.GetBytes(proxyToken); + } + this.UDPSend(100, datas, 0, datas.Length); + this.singleWaitData.Wait(5000); + if (this.proxyFile != null) + { + return this.proxyFile; + } + } + count++; + } + + return null; + } + + /// + /// 发现服务 + /// + /// 是否触发初始化事件 + /// 已发现的服务 + public MethodItem[] DiscoveryService(bool isTrigger = true) + { + if (this.ServerState != ServerState.Running) + { + throw new RRQMRPCException("UDP端需要先绑定本地监听端口"); + } + + int count = 0; + while (count < 3) + { + lock (this) + { + try + { + this.methodStore = null; + + string proxyToken = (string)this.ServiceConfig.GetValue(UdpRpcClientConfig.ProxyTokenProperty); + byte[] data = new byte[0]; + if (!string.IsNullOrEmpty(proxyToken)) + { + data = Encoding.UTF8.GetBytes(proxyToken); + } + + this.UDPSend(102, data, 0, data.Length); + this.singleWaitData.Wait(1000 * 5); + if (this.methodStore != null) + { + if (isTrigger) + { + this.OnServiceDiscovered(new MesEventArgs("success")); + } + return this.methodStore.GetAllMethodItem().ToArray(); + } + } + catch (Exception e) + { + throw new RRQMRPCException(e.Message); + } + } + count++; + } + throw new RRQMTimeoutException("初始化超时"); + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + /// + public T Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (!this.methodStore.TryGetMethodItem(method, out MethodItem methodItem)) + { + throw new RRQMException($"服务名为{method}的服务未找到注册信息"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodItem.MethodToken; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + this.UDPSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + finally + { + byteBlock.Dispose(); + } + + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else + { + return default; + } + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("该方法已被禁用"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"服务器已阻止本次行为,信息:{resultContext.Message}"); + } + else if (resultContext.Status == 5) + { + throw new RRQMRPCInvokeException("函数执行异常,详细信息:" + resultContext.Message); + } + else if (resultContext.Status == 6) + { + throw new RRQMRPCException($"函数异常,信息:{resultContext.Message}"); + } + if (methodItem.IsOutOrRef) + { + try + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = this.SerializeConverter.DeserializeParameter(resultContext.ParametersBytes[i], types[i]); + } + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + } + else + { + parameters = null; + } + try + { + return (T)this.SerializeConverter.DeserializeParameter(resultContext.ReturnParameterBytes, typeof(T)); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + } + default: + return default; + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public void Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types) + { + if (!this.methodStore.TryGetMethodItem(method, out MethodItem methodItem)) + { + throw new RRQMException($"服务名为{method}的服务未找到注册信息"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodItem.MethodToken; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + this.UDPSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + finally + { + byteBlock.Dispose(); + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + break; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + break; + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("该方法已被禁用"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"服务器已阻止本次行为,信息:{resultContext.Message}"); + } + else if (resultContext.Status == 5) + { + throw new RRQMRPCInvokeException("函数执行异常,详细信息:" + resultContext.Message); + } + else if (resultContext.Status == 6) + { + throw new RRQMRPCException($"函数异常,信息:{resultContext.Message}"); + } + if (methodItem.IsOutOrRef) + { + try + { + for (int i = 0; i < parameters.Length; i++) + { + parameters[i] = this.SerializeConverter.DeserializeParameter(resultContext.ParametersBytes[i], types[i]); + } + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + } + else + { + parameters = null; + } + break; + } + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + public void Invoke(string method, InvokeOption invokeOption, params object[] parameters) + { + if (!this.methodStore.TryGetMethodItem(method, out MethodItem methodItem)) + { + throw new RRQMException($"服务名为{method}的服务未找到注册信息"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodItem.MethodToken; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + this.UDPSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + finally + { + byteBlock.Dispose(); + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + break; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + break; + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("该方法已被禁用"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"服务器已阻止本次行为,信息:{resultContext.Message}"); + } + else if (resultContext.Status == 5) + { + throw new RRQMRPCInvokeException("函数执行异常,详细信息:" + resultContext.Message); + } + else if (resultContext.Status == 6) + { + throw new RRQMRPCException($"函数异常,信息:{resultContext.Message}"); + } + break; + } + default: + break; + } + } + + /// + /// RPC调用 + /// + /// 方法名 + /// 调用配置 + /// 参数 + /// + /// + /// + /// + /// + public T Invoke(string method, InvokeOption invokeOption, params object[] parameters) + { + if (!this.methodStore.TryGetMethodItem(method, out MethodItem methodItem)) + { + throw new RRQMException($"服务名为{method}的服务未找到注册信息"); + } + RpcContext context = new RpcContext(); + WaitData waitData = this.waitHandle.GetWaitData(context); + context.MethodToken = methodItem.MethodToken; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + if (invokeOption == null) + { + invokeOption = InvokeOption.WaitInvoke; + } + try + { + context.Feedback = (byte)invokeOption.FeedbackType; + List datas = new List(); + foreach (object parameter in parameters) + { + datas.Add(this.SerializeConverter.SerializeParameter(parameter)); + } + context.ParametersBytes = datas; + context.Serialize(byteBlock); + this.UDPSend(101, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + finally + { + byteBlock.Dispose(); + } + switch (invokeOption.FeedbackType) + { + case FeedbackType.OnlySend: + { + this.waitHandle.Destroy(waitData); + return default; + } + case FeedbackType.WaitSend: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else + { + return default; + } + } + case FeedbackType.WaitInvoke: + { + waitData.Wait(invokeOption.Timeout); + RpcContext resultContext = waitData.WaitResult; + this.waitHandle.Destroy(waitData); + + if (resultContext.Status == 0) + { + throw new RRQMTimeoutException("等待结果超时"); + } + else if (resultContext.Status == 2) + { + throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod"); + } + else if (resultContext.Status == 3) + { + throw new RRQMRPCException("该方法已被禁用"); + } + else if (resultContext.Status == 4) + { + throw new RRQMRPCException($"服务器已阻止本次行为,信息:{resultContext.Message}"); + } + else if (resultContext.Status == 5) + { + throw new RRQMRPCInvokeException("函数执行异常,详细信息:" + resultContext.Message); + } + else if (resultContext.Status == 6) + { + throw new RRQMRPCException($"函数异常,信息:{resultContext.Message}"); + } + + try + { + return (T)this.SerializeConverter.DeserializeParameter(resultContext.ReturnParameterBytes, typeof(T)); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + } + default: + return default; + } + } + + + /// + /// 密封数据 + /// + /// + /// + protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = (int)byteBlock.Position; + int procotol = BitConverter.ToInt16(buffer, 0); + switch (procotol) + { + case 100:/* 100表示获取RPC引用文件上传状态返回*/ + { + try + { + proxyFile = SerializeConvert.RRQMBinaryDeserialize(buffer, 2); + this.singleWaitData.Set(); + } + catch + { + proxyFile = null; + } + + break; + } + + case 101:/*函数调用返回数据对象*/ + { + try + { + byteBlock.Pos = 2; + RpcContext result = RpcContext.Deserialize(byteBlock); + this.waitHandle.SetRun(result.Sign, result); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 101, 错误详情:{e.Message}"); + } + break; + } + + case 102:/*连接初始化返回数据对象*/ + { + try + { + List methodItems = SerializeConvert.RRQMBinaryDeserialize>(buffer, 2); + this.methodStore = new MethodStore(); + foreach (var item in methodItems) + { + this.methodStore.AddMethodItem(item); + } + + this.singleWaitData.Set(); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 102, 错误详情:{e.Message}"); + } + break; + } + } + } + + private void UDPSend(short procotol, byte[] buffer, int offset, int length) + { + ByteBlock byteBlock = this.BytePool.GetByteBlock(length + 2); + try + { + byteBlock.Write(BitConverter.GetBytes(procotol)); + byteBlock.Write(buffer, offset, length); + this.Send(byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, ex.Message); + } + finally + { + byteBlock.Dispose(); + } + } + + private void UDPSend(short procotol) + { + this.UDPSend(procotol, new byte[0], 0, 0); + } + + /// + /// RPC完成初始化后 + /// + /// + protected virtual void OnServiceDiscovered(MesEventArgs args) + { + try + { + this.ServiceDiscovered?.Invoke(this, args); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, $"在事件{nameof(ServiceDiscovered)}中发生异常", ex); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcParser.cs b/RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcParser.cs new file mode 100644 index 000000000..6e0e87bbd --- /dev/null +++ b/RRQMSocket.RPC/RRQMRPC/Socket/UdpRpcParser.cs @@ -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.Log; +using RRQMCore.Serialization; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; + +namespace RRQMSocket.RPC.RRQMRPC +{ + /// + /// UDP RPC解释器 + /// + public class UdpRpcParser : UdpSession, IRPCParser, IRRQMRpcParser + { + /// + /// 构造函数 + /// + public UdpRpcParser() + { + this.methodStore = new MethodStore(); + this.proxyInfo = new RpcProxyInfo(); + } + +#pragma warning disable + public MethodMap MethodMap { get; private set; } + + public RPCService RPCService { get; private set; } + + public Action RRQMExecuteMethod { get; private set; } + + public CellCode[] Codes { get => this.proxyInfo == null ? null : this.proxyInfo.Codes.ToArray(); } + + public string NameSpace { get; private set; } + + public RpcProxyInfo ProxyInfo { get => proxyInfo; } + + public string ProxyToken { get; private set; } + + public Version RPCVersion { get; private set; } + + public SerializeConverter SerializeConverter { get; private set; } + + private MethodStore methodStore; + + private RpcProxyInfo proxyInfo; + + public MethodStore MethodStore => this.methodStore; + + public void SetExecuteMethod(Action executeMethod) + { + this.RRQMExecuteMethod = executeMethod; + } + + public void SetMethodMap(MethodMap methodMap) + { + this.MethodMap = methodMap; + } + + public void SetRPCService(RPCService service) + { + this.RPCService = service; + } + + public virtual RpcProxyInfo GetProxyInfo(string proxyToken, object caller) + { + RpcProxyInfo proxyInfo = new RpcProxyInfo(); + if (this.ProxyToken == proxyToken) + { + proxyInfo.AssemblyData = this.ProxyInfo.AssemblyData; + proxyInfo.AssemblyName = this.ProxyInfo.AssemblyName; + proxyInfo.Codes = this.ProxyInfo.Codes; + proxyInfo.Version = this.ProxyInfo.Version; + proxyInfo.Status = 1; + } + else + { + proxyInfo.Status = 2; + proxyInfo.Message = "令箭不正确"; + } + + return proxyInfo; + } + + public virtual void ExecuteContext(RpcContext context, object caller) + { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.Caller = caller; + methodInvoker.Flag = context; + if (this.MethodMap.TryGet(context.MethodToken, out MethodInstance methodInstance)) + { + try + { + if (methodInstance.IsEnable) + { + object[] ps = new object[methodInstance.ParameterTypes.Length]; + for (int i = 0; i < methodInstance.ParameterTypes.Length; i++) + { + ps[i] = this.SerializeConverter.DeserializeParameter(context.ParametersBytes[i], methodInstance.ParameterTypes[i]); + } + methodInvoker.Parameters = ps; + } + else + { + methodInvoker.Status = InvokeStatus.UnEnable; + } + } + catch (Exception ex) + { + methodInvoker.Status = InvokeStatus.Exception; + methodInvoker.StatusMessage = ex.Message; + } + + this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance); + } + else + { + methodInvoker.Status = InvokeStatus.UnFound; + this.RRQMExecuteMethod.Invoke(this, methodInvoker, null); + } + } + + protected override void LoadConfig(ServiceConfig ServiceConfig) + { + base.LoadConfig(ServiceConfig); + this.SerializeConverter = (SerializeConverter)ServiceConfig.GetValue(UdpRpcParserConfig.SerializeConverterProperty); + this.ProxyToken = (string)ServiceConfig.GetValue(UdpRpcParserConfig.ProxyTokenProperty); + this.NameSpace = (string)ServiceConfig.GetValue(UdpRpcParserConfig.NameSpaceProperty); + this.RPCVersion = (Version)ServiceConfig.GetValue(UdpRpcParserConfig.RPCVersionProperty); + } + + public virtual List GetRegisteredMethodItems(string proxyToken, object caller) + { + return this.methodStore.GetAllMethodItem(); + } + + public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances) + { + Tools.GetRPCMethod(methodInstances, this.NameSpace, ref this.methodStore, this.RPCVersion, ref this.proxyInfo); + } + + public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances) + { + foreach (var item in methodInstances) + { + this.methodStore.RemoveMethodItem(item.MethodToken); + } + + CellCode cellCode = null; + foreach (var item in this.proxyInfo.Codes) + { + if (item.Name == provider.GetType().Name) + { + cellCode = item; + break; + } + } + if (cellCode != null) + { + this.proxyInfo.Codes.Remove(cellCode); + } + } + + public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance) + { + RpcContext context = (RpcContext)methodInvoker.Flag; + if (context.Feedback != 2) + { + return; + } + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + try + { + switch (methodInvoker.Status) + { + case InvokeStatus.Ready: + { + break; + } + + case InvokeStatus.UnFound: + { + context.Status = 2; + break; + } + case InvokeStatus.Success: + { + if (methodInstance.MethodToken > 50000000) + { + context.ReturnParameterBytes = this.SerializeConverter.SerializeParameter(methodInvoker.ReturnParameter); + } + else + { + context.ReturnParameterBytes = null; + } + + if (methodInstance.IsByRef) + { + context.ParametersBytes = new List(); + foreach (var item in methodInvoker.Parameters) + { + context.ParametersBytes.Add(this.SerializeConverter.SerializeParameter(item)); + } + } + else + { + context.ParametersBytes = null; + } + + context.Status = 1; + break; + } + case InvokeStatus.Abort: + { + context.Status = 4; + context.Message = methodInvoker.StatusMessage; + break; + } + case InvokeStatus.UnEnable: + { + context.Status = 3; + break; + } + case InvokeStatus.InvocationException: + { + context.Status = 5; + context.Message = methodInvoker.StatusMessage; + break; + } + case InvokeStatus.Exception: + { + context.Status = 6; + context.Message = methodInvoker.StatusMessage; + break; + } + default: + break; + } + + context.Serialize(byteBlock); + this.UDPSend(101, (EndPoint)methodInvoker.Caller, byteBlock.Buffer, 0, byteBlock.Len); + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, ex.Message); + } + finally + { + byteBlock.Dispose(); + } + } + +#pragma warning restore + + private void UDPSend(short procotol, EndPoint endPoint, byte[] buffer, int offset, int length) + { + ByteBlock byteBlock = this.BytePool.GetByteBlock(length + 2); + try + { + byteBlock.Write(BitConverter.GetBytes(procotol)); + byteBlock.Write(buffer, offset, length); + this.SendTo(byteBlock.Buffer, 0, byteBlock.Len, endPoint); + } + finally + { + byteBlock.Dispose(); + } + } + + private void UDPSend(short procotol, EndPoint endPoint, byte[] buffer) + { + this.UDPSend(procotol, endPoint, buffer, 0, buffer.Length); + } + + /// + /// 密封处理 + /// + /// + /// + protected sealed override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + short procotol = BitConverter.ToInt16(buffer, 0); + + switch (procotol) + { + case 100:/*100,请求RPC文件*/ + { + try + { + string proxyToken = Encoding.UTF8.GetString(buffer, 2, r - 2); + this.UDPSend(100, remoteEndPoint, SerializeConvert.RRQMBinarySerialize(this.GetProxyInfo(proxyToken, remoteEndPoint), true)); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"UDP错误代码: 100, 错误详情:{e.Message}"); + } + break; + } + + case 101:/*函数式调用*/ + { + try + { + byteBlock.Pos = 2; + RpcContext content = RpcContext.Deserialize(byteBlock); + if (content.Feedback == 1) + { + List ps = content.ParametersBytes; + + ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength); + try + { + content.ParametersBytes = null; + content.Status = 1; + content.Serialize(returnByteBlock); + this.UDPSend(101, remoteEndPoint, returnByteBlock.Buffer, 0, (int)returnByteBlock.Length); + } + finally + { + content.ParametersBytes = ps; + returnByteBlock.Dispose(); + } + } + this.ExecuteContext(content, remoteEndPoint); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 101, 错误详情:{e.Message}"); + } + break; + } + case 102:/*连接初始化*/ + { + try + { + string proxyToken = Encoding.UTF8.GetString(buffer, 2, r - 2); + UDPSend(102, remoteEndPoint, SerializeConvert.RRQMBinarySerialize(this.GetRegisteredMethodItems(proxyToken, remoteEndPoint), true)); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"错误代码: 102, 错误详情:{e.Message}"); + } + break; + } + } + } + +#if NET45_OR_GREATER + + /// + /// 编译代理 + /// + /// 存放目标文件夹 + public void CompilerProxy(string targetDic = "") + { + string assemblyInfo = CodeGenerator.GetAssemblyInfo(this.proxyInfo.AssemblyName, this.proxyInfo.Version); + List codesString = new List(); + codesString.Add(assemblyInfo); + foreach (var item in this.proxyInfo.Codes) + { + codesString.Add(item.Code); + } + RpcCompiler.CompileCode(Path.Combine(targetDic, this.proxyInfo.AssemblyName), codesString.ToArray()); + } + +#endif + } +} \ No newline at end of file diff --git a/RRQMSocket.RPC/RRQMSocket.RPC.csproj b/RRQMSocket.RPC/RRQMSocket.RPC.csproj new file mode 100644 index 000000000..522903a7f --- /dev/null +++ b/RRQMSocket.RPC/RRQMSocket.RPC.csproj @@ -0,0 +1,72 @@ + + + net45;netcoreapp3.1;netstandard2.0 + RRQM.ico + true + RRQM.pfx + 5.5.0 + 若汝棋茗 + Copyright © 2021 若汝棋茗 + 介绍:这是一个高性能的RPC微服务框架,支持异步调用、权限管理、错误状态返回、服务回调等。在空载函数执行时,10万次调用仅3.8秒,在不返回状态时,仅0.9秒。 + +更新说明: +修改:服务类ServerProvider改为IServerProvider接口。 +修改:RRQMRPC下多数含有“RPC”的类改为“Rpc”驼峰拼写。 +增加:序列化方式中增加JsonSerializeConverter。 + +Demo:https://gitee.com/RRQM_OS/RRQMBox +API:https://gitee.com/RRQM_OS/RRQM/wikis/pages + https://gitee.com/dotnetchina/RRQMSocket + + true + RRQM.png + 若汝棋茗 + true + LICENSE + RPC,TCP,UDP,IOCP + + + + bin\Debug\netstandard2.0\RRQMSocket.RPC.xml + + + + + bin\Release\netstandard2.0\RRQMSocket.RPC.xml + + + + + bin\Debug\net45\RRQMSocket.RPC.xml + + + + + bin\Release\net45\RRQMSocket.RPC.xml + + + + + bin\Debug\netcoreapp3.1\RRQMSocket.RPC.xml + + + + + bin\Release\netcoreapp3.1\RRQMSocket.RPC.xml + + + + + True + + + + True + + + + + + + + diff --git a/RRQMSocket.sln b/RRQMSocket.sln new file mode 100644 index 000000000..d07992e15 --- /dev/null +++ b/RRQMSocket.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30804.86 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket", "RRQMSocket\RRQMSocket.csproj", "{2869A094-BBB1-4F15-A54D-581BC927E92E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.FileTransfer", "RRQMSocket.FileTransfer\RRQMSocket.FileTransfer.csproj", "{717FB0F1-3DA3-4A70-9502-8BAA8A949672}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.Http", "RRQMSocket.Http\RRQMSocket.Http.csproj", "{94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.RPC", "RRQMSocket.RPC\RRQMSocket.RPC.csproj", "{E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.RPC.JsonRpc", "RRQMSocket.RPC.JsonRpc\RRQMSocket.RPC.JsonRpc.csproj", "{CDED55FF-86BF-47CC-926C-069B1AE6E680}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.RPC.WebApi", "RRQMSocket.RPC.WebApi\RRQMSocket.RPC.WebApi.csproj", "{313AC178-2193-4B2A-8D1D-748EDE6E55BE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.RPC.XmlRpc", "RRQMSocket.RPC.XmlRpc\RRQMSocket.RPC.XmlRpc.csproj", "{61179122-C51F-47AC-8E2A-D124AF4E3DF5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2869A094-BBB1-4F15-A54D-581BC927E92E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2869A094-BBB1-4F15-A54D-581BC927E92E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2869A094-BBB1-4F15-A54D-581BC927E92E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2869A094-BBB1-4F15-A54D-581BC927E92E}.Release|Any CPU.Build.0 = Release|Any CPU + {717FB0F1-3DA3-4A70-9502-8BAA8A949672}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {717FB0F1-3DA3-4A70-9502-8BAA8A949672}.Debug|Any CPU.Build.0 = Debug|Any CPU + {717FB0F1-3DA3-4A70-9502-8BAA8A949672}.Release|Any CPU.ActiveCfg = Release|Any CPU + {717FB0F1-3DA3-4A70-9502-8BAA8A949672}.Release|Any CPU.Build.0 = Release|Any CPU + {94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}.Release|Any CPU.Build.0 = Release|Any CPU + {E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}.Release|Any CPU.Build.0 = Release|Any CPU + {CDED55FF-86BF-47CC-926C-069B1AE6E680}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CDED55FF-86BF-47CC-926C-069B1AE6E680}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CDED55FF-86BF-47CC-926C-069B1AE6E680}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CDED55FF-86BF-47CC-926C-069B1AE6E680}.Release|Any CPU.Build.0 = Release|Any CPU + {313AC178-2193-4B2A-8D1D-748EDE6E55BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {313AC178-2193-4B2A-8D1D-748EDE6E55BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {313AC178-2193-4B2A-8D1D-748EDE6E55BE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {313AC178-2193-4B2A-8D1D-748EDE6E55BE}.Release|Any CPU.Build.0 = Release|Any CPU + {61179122-C51F-47AC-8E2A-D124AF4E3DF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61179122-C51F-47AC-8E2A-D124AF4E3DF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61179122-C51F-47AC-8E2A-D124AF4E3DF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61179122-C51F-47AC-8E2A-D124AF4E3DF5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DB787235-A13A-4A3D-B5A8-5DFEB6511EEE} + EndGlobalSection +EndGlobal diff --git a/RRQMSocket/BaseSocket.cs b/RRQMSocket/BaseSocket.cs new file mode 100644 index 000000000..e94f424c4 --- /dev/null +++ b/RRQMSocket/BaseSocket.cs @@ -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.Log; +using System; + +namespace RRQMSocket +{ + /// + /// 通讯基类 + /// + public abstract class BaseSocket : ISocket, IDisposable + { + internal int bufferLength; + internal ILog logger; + + /// + /// 判断是否已释放资源 + /// + protected bool disposable = false; + + /// + /// 锁 + /// + protected object locker = new object(); + + /// + /// 数据交互缓存池限制 + /// + public int BufferLength + { + get { return bufferLength; } + } + + /// + /// 日志记录器 + /// + public ILog Logger + { + get { return logger; } + } + + /// + /// 释放资源 + /// + public virtual void Dispose() + { + this.disposable = true; + } + } +} \ No newline at end of file diff --git a/RRQMSocket/ClassDiagram.cd b/RRQMSocket/ClassDiagram.cd new file mode 100644 index 000000000..16d3c4384 --- /dev/null +++ b/RRQMSocket/ClassDiagram.cd @@ -0,0 +1,516 @@ + + + + + + AAAAAAAAAAAAAAABAAABEAAAAQAAAAAAAAAAAAAAAIA= + + + + + + AAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAA= + Common\AsyncResult.cs + + + + + + AAAAQAAAACiACAAiAAABAAAAAEAAACAAAAVAAAAAIFA= + Common\AsyncSender.cs + + + + + + + AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAACAAAAAAAAAAA= + Common\CreateOption.cs + + + + + + AAAAAAAAAAAAQAAEAAAAAAAAKAAAAAAAAAAAAAAAAAE= + Common\IPHost.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAACAAABAAAAA= + Common\ProcotolHelper.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Config\ClientConfig.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Config\ProtocolClientConfig.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAEIAAAAAAAAAAAAAA= + Config\ProtocolServerConfig.cs + + + + + + AAAIAAAAAAIAAAAAAgQgAAAAAAAAAAAAAIABAAQAAAA= + Config\RRQMConfig.cs + + + + + + AAIAAAAAAAAAABCAQAAAAAAAAAAAAAAAQAAgAAAAAAA= + Config\ServerConfig.cs + + + + + + AACAAAAAAAAAAQAAgQAEAAAAAAQAEBAgAAAABACgAAA= + Config\TcpClientConfig.cs + + + + + + AQAIAAAAAAAAQAAAAAgQAAAAIAAAAAAAAAAAQCAAAAA= + Config\TcpServerConfig.cs + + + + + + wAAAgAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAA= + Config\TokenClientConfig.cs + + + + + + wAAAgAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAA= + Config\TokenServerConfig.cs + + + + + + BAAAAAAAAgAAAAAACAAAAAAAAAAAAAACAAAAAAAAAAA= + Config\UdpSessionConfig.cs + + + + + + IAAAKAABAAIAAAAAAEAAAAAAAAIAAAAIAAAAAAIgAAA= + DataAdapter\DataHandlingAdapter.cs + + + + + + gEgAJEAAAAQAAAABAAAAAAAAAAIAACAEAAAAAABAAAA= + DataAdapter\FixedHeaderDataHandlingAdapter.cs + + + + + + gACAIEAAAAAAAAABAAAAAAAAAAIAAAAEAAAAAAAAAAA= + DataAdapter\FixedSizeDataHandlingAdapter.cs + + + + + + gAAAIAAAAAAAAAAAAAAABAAAAAIAAAAAAAAAgAAAAAA= + DataAdapter\JsonStringDataHandlingAdapter.cs + + + + + + AAAAIAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAA= + DataAdapter\NormalDataHandlingAdapter.cs + + + + + + gEAAIEAAAAAAAAAAAAAAAAAAgAIAAAAAAgAAAAEAAAI= + DataAdapter\TerminatorDataHandlingAdapter.cs + + + + + + AAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + EventArgs\BytesEventArgs.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAA= + EventArgs\MesEventArgs.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAA= + EventArgs\ReturnBytesEventArgs.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Exceptions\RRQMNotConnectedException.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Exceptions\RRQMOverlengthException.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Exceptions\RRQMTimeoutException.cs + + + + + + AABAAAABAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAA= + InternalClass\BufferQueue.cs + + + + + + AAAAAAAAASAAAAAAAAAAAAAAAAAAACAAACEAIAAAAAA= + InternalClass\BufferQueueGroup.cs + + + + + + + AAAAAQAAACABQAAACAAAAASAQAAAAAAAAAAEACAAAQA= + InternalClass\SocketCliectCollection.cs + + + + + + + AAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Logger\Log.cs + + + + + + + AYAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAABAAA= + ParameterClass\VerifyOption.cs + + + + + + AABAAAAAACBAAAAAEELAAACAEAAAACAAAAAAABQBAAA= + TCP\Client\ProtocolClient.cs + + + + + + AAAAAAABAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAA= + TCP\Client\SimpleProtocolClient.cs + + + + + + AAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQAAAA= + TCP\Client\SimpleTcpClient.cs + + + + + + AAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA= + TCP\Client\SimpleTokenClient.cs + + + + + + QAzBAAAAiCgACgQAAEIEUYWAKBgICAAEGCBBBEQhADA= + TCP\Client\TcpClient.cs + + + + + + + AAAEgAAAAABAgAAAAAAEAICAAAAAAACAAAAAAAAAAgA= + TCP\Client\TokenClient.cs + + + + + + BAAAAAAAAABAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAA= + TCP\Service\ProtocolService.cs + + + + + + AAAAAAABAAAQQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + TCP\Service\SimpleProtocolService.cs + + + + + + AAAAAAABAAAQQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + TCP\Service\SimpleTcpService.cs + + + + + + AAAAAAABAAAQQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + TCP\Service\SimpleTokenService.cs + + + + + + AUJgAAEACKBgQBCBQkCUABCAUAAEAhIILIAEKAEgKCA= + TCP\Service\TcpService.cs + + + + + + + AAAEgAAAAAAAAAABAAAEAACAAAAAAACAAAAAgAAAAAA= + TCP\Service\TokenService.cs + + + + + + BABgAAAAAABAAAAAEEDAAAAAEAAAAAAAAAAAABQAAAA= + TCP\SocketClient\ProtocolSocketClient.cs + + + + + + AAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAQAAAAA= + TCP\SocketClient\SimpleProtocolSocketClient.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQAAAA= + TCP\SocketClient\SimpleSocketClient.cs + + + + + + BghAAAAAAChggAQAAEIEUQSAKABIQEAKCAADACQgAhA= + TCP\SocketClient\SocketClient.cs + + + + + + + AAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA= + UDP\SimpleUdpSession.cs + + + + + + AERgAAAASCAAAACACEIAgBiAOACMABIEKAABAAQkIBA= + UDP\UdpSession.cs + + + + + + + BAAAAAAAACIAIAAAAAAABAAAAEAAAAAAAAAAAAQAIAA= + BaseSocket.cs + + + + + + + AACAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAABAAAAAAAA= + Common\AsyncByte.cs + + + + + + BAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAABAAAAAA= + InternalClass\ClientBuffer.cs + + + + + + AAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Interface\_ITcpService.cs + + + + + + AABAAAAAAAAAAAAAAEAAAAAAKAAAAAAACAAAAAAgAAA= + Interface\IClient.cs + + + + + + AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Interface\IHandleBuffer.cs + + + + + + AAAAAAAACCAAAACAAAAAAAAAAAAAABAAIAAAAAAgIAA= + Interface\IService.cs + + + + + + AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA= + Interface\ISocket.cs + + + + + + AAAAAAAAAAAAgAAAAAAAAACAAAAAQAAAAAAAAAAAAAA= + Interface\ISocketClient.cs + + + + + + AAAAAAAAAAAAAAAAAAAEEQQAAAAAAAAAAAAAAAAAAAA= + Interface\ITcpClient.cs + + + + + + AQJAAAAAAAAAAAAAAEAQAAAAQAAAAAAABAAEIAAAAAA= + Interface\ITcpService.cs + + + + + + AAAAAAAACAAAAAAAAAAAAIAAAAgAAAAAAAAAAAAAAAA= + Interface\IUserClient.cs + + + + + + AASAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Interface\IUserTcpClient.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Pool\Interface\IClientGroup.cs + + + + + + AAAAAAAAAAIAEAAAIEAAEAACAAAAAAAAAQAAAAAgAAA= + Pool\Interface\IConnectionPool.cs + + + + + + AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAIAAAAAAECAAA= + Enum\ServerState.cs + + + + + + AAAAAAAAAAAAAAAAAAEAAAAQAAAAAAAAAAAAAAAAAAA= + DelegateCollection.cs + + + + + + AAAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + DelegateCollection.cs + + + + + + AAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAA= + DelegateCollection.cs + + + + + + AAABAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + DelegateCollection.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAACAAA= + DelegateCollection.cs + + + + \ No newline at end of file diff --git a/RRQMSocket/Common/AsyncByte.cs b/RRQMSocket/Common/AsyncByte.cs new file mode 100644 index 000000000..59d58aba3 --- /dev/null +++ b/RRQMSocket/Common/AsyncByte.cs @@ -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 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace RRQMSocket +{ + /// + /// 异步字节 + /// + internal struct AsyncByte + { + internal int offset; + internal int length; + internal byte[] buffer; + } +} \ No newline at end of file diff --git a/RRQMSocket/Common/AsyncResult.cs b/RRQMSocket/Common/AsyncResult.cs new file mode 100644 index 000000000..10f7fbad9 --- /dev/null +++ b/RRQMSocket/Common/AsyncResult.cs @@ -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 +{ + /// + /// 异步执行结果 + /// + public class AsyncResult + { + /// + /// 异步状态 + /// + public bool Status { get; set; } + + /// + /// 消息 + /// + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket/Common/AsyncSender.cs b/RRQMSocket/Common/AsyncSender.cs new file mode 100644 index 000000000..5131ad597 --- /dev/null +++ b/RRQMSocket/Common/AsyncSender.cs @@ -0,0 +1,199 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; +using System.Collections.Concurrent; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace RRQMSocket +{ + internal class AsyncSender : IDisposable + { + private readonly ConcurrentQueue asyncBytes; + + private readonly SocketAsyncEventArgs sendEventArgs; + + private readonly Thread sendThread; + + private readonly EventWaitHandle waitHandle; + + private byte[] buffer = new byte[1024 * 1024]; + + private bool dispose; + + private ILog logger; + + private bool sending; + + private Socket socket; + + internal AsyncSender(Socket socket, EndPoint endPoint, ILog logger) + { + sendEventArgs = new SocketAsyncEventArgs(); + sendEventArgs.Completed += this.SendEventArgs_Completed; + this.socket = socket; + this.sendEventArgs.RemoteEndPoint = endPoint; + this.logger = logger; + asyncBytes = new ConcurrentQueue(); + waitHandle = new AutoResetEvent(false); + this.sendThread = new Thread(this.BeginSend); + this.sendThread.IsBackground = true; + this.sendThread.Name = "AsyncSendThread"; + this.sendThread.Start(); + } + + public void AsyncSend(byte[] buffer, int offset, int length) + { + AsyncByte asyncByte = new AsyncByte(); + asyncByte.buffer = buffer; + asyncByte.offset = offset; + asyncByte.length = length; + this.asyncBytes.Enqueue(asyncByte); + if (!this.sending) + { + this.sending = true; + this.waitHandle.Set(); + } + } + + public void Dispose() + { + this.dispose = true; + this.waitHandle.Set(); + this.waitHandle.Dispose(); + this.sendEventArgs.Dispose(); + } + + internal void SetBufferLength(int len) + { + this.buffer = new byte[len]; + } + + private void BeginSend() + { + while (!this.dispose) + { + try + { + if (this.tryGet(out AsyncByte asyncByte)) + { + this.sendEventArgs.SetBuffer(asyncByte.buffer, asyncByte.offset, asyncByte.length); + + if (!this.socket.SendAsync(this.sendEventArgs)) + { + // 同步发送时处理发送完成事件 + this.ProcessSend(sendEventArgs); + } + else + { + this.waitHandle.WaitOne(); + } + } + else + { + this.sending = false; + this.waitHandle.WaitOne(); + } + } + catch (Exception ex) + { + this.logger.Debug(LogType.Error, this, "异步发送错误。", ex); + } + } + } + + /// + /// 发送完成时处理函数 + /// + /// 与发送完成操作相关联的SocketAsyncEventArg对象 + private void ProcessSend(SocketAsyncEventArgs e) + { + try + { + if (e.SocketError != SocketError.Success) + { + this.logger.Debug(LogType.Error, this, "异步发送错误。"); + } + } + catch + { + } + } + + private void SendEventArgs_Completed(object sender, SocketAsyncEventArgs e) + { + if (e.LastOperation == SocketAsyncOperation.Send) + { + ProcessSend(e); + if (!dispose) + { + this.waitHandle.Set(); + } + } + } + + private bool tryGet(out AsyncByte asyncByteDe) + { + int len = 0; + int surLen = buffer.Length; + while (true) + { + if (this.asyncBytes.TryPeek(out AsyncByte asyncB)) + { + if (surLen > asyncB.length) + { + if (this.asyncBytes.TryDequeue(out AsyncByte asyncByte)) + { + Array.Copy(asyncByte.buffer, asyncByte.offset, buffer, len, asyncByte.length); + len += asyncByte.length; + surLen -= asyncByte.length; + } + } + else if (asyncB.length > buffer.Length) + { + if (len > 0) + { + break; + } + else + { + asyncByteDe = asyncB; + return true; + } + } + else + { + break; + } + } + else + { + if (len > 0) + { + break; + } + else + { + asyncByteDe = default; + return false; + } + } + } + asyncByteDe = new AsyncByte(); + asyncByteDe.buffer = buffer; + asyncByteDe.length = len; + return true; + } + } +} \ No newline at end of file diff --git a/RRQMSocket/Common/CreateOption.cs b/RRQMSocket/Common/CreateOption.cs new file mode 100644 index 000000000..55616f7ef --- /dev/null +++ b/RRQMSocket/Common/CreateOption.cs @@ -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 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace RRQMSocket +{ + /// + /// 创建设置 + /// + public class CreateOption + { + /// + /// 判断该T是否为新建对象, + /// true:首次创建。false:从对象池获得 + /// + public bool NewCreate { get; internal set; } + + /// + /// 获取或设置该T的ID + /// + public string ID { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket/Common/IPHost.cs b/RRQMSocket/Common/IPHost.cs new file mode 100644 index 000000000..60ea6748b --- /dev/null +++ b/RRQMSocket/Common/IPHost.cs @@ -0,0 +1,96 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System; +using System.Net; +using System.Net.Sockets; + +namespace RRQMSocket +{ + /// + /// IP解析映射 + /// + public class IPHost + { + /// + /// 从字符串获取ip和port + /// + public IPHost(string ipHost) + { + try + { + int r = ipHost.LastIndexOf(":"); + this.IP = ipHost.Substring(0, r); + this.Port = Convert.ToInt32(ipHost.Substring(r + 1, ipHost.Length - (r + 1))); + this.EndPoint = new IPEndPoint(IPAddress.Parse(this.IP), this.Port); + if (this.IP.Contains(":")) + { + this.AddressFamily = AddressFamily.InterNetworkV6; + } + else + { + this.AddressFamily = AddressFamily.InterNetwork; + } + } + catch + { + throw new RRQMException("IPHost不合法"); + } + } + + /// + /// 从IPAddress和端口号 + /// + /// + /// + public IPHost(IPAddress iPAddress, int port) : this($"{iPAddress}:{port}") + { + } + + /// + /// 从端口号创建 + /// + /// + public IPHost(int port) : this($"0.0.0.0:{port}") + { + } + + /// + /// IP + /// + public string IP { get; private set; } + + /// + /// 端口号 + /// + public int Port { get; private set; } + + /// + /// 寻址方案 + /// + public AddressFamily AddressFamily { get; private set; } + + /// + /// 终结点 + /// + public EndPoint EndPoint { get; private set; } + + /// + /// 返回对象字符串 + /// + /// + public override string ToString() + { + return EndPoint == null ? null : EndPoint.ToString(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/Common/ProcotolHelper.cs b/RRQMSocket/Common/ProcotolHelper.cs new file mode 100644 index 000000000..b2d5c29d9 --- /dev/null +++ b/RRQMSocket/Common/ProcotolHelper.cs @@ -0,0 +1,200 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System.Net.Sockets; + +namespace RRQMSocket +{ + /// + /// RRQM协议助手 + /// + public class ProcotolHelper + { + /// + /// 构造函数 + /// + /// + /// + public ProcotolHelper(ITcpClient client, bool separateThread) + { + this.mainSocket = client.MainSocket; + this.bytePool = client.BytePool; + this.separateThread = separateThread; + + if (separateThread) + { + this.asyncSender = new AsyncSender(client.MainSocket, client.MainSocket.RemoteEndPoint, client.Logger); + } + } + + private Socket mainSocket; + private BytePool bytePool; + private AsyncSender asyncSender; + private bool separateThread; + + #region 同步方法 + + /// + /// 发送简单协议 + /// + /// + public void SocketSend(short procotol) + { + this.SocketSend(procotol, new byte[0], 0, 0); + } + + /// + /// 发送字节 + /// + /// + /// + public void SocketSend(short procotol, byte[] dataBuffer) + { + this.SocketSend(procotol, dataBuffer, 0, dataBuffer.Length); + } + + /// + /// 发送协议流 + /// + /// + /// + public void SocketSend(short procotol, ByteBlock dataByteBlock) + { + this.SocketSend(procotol, dataByteBlock.Buffer, 0, (int)dataByteBlock.Length); + } + + /// + /// 发送字节 + /// + /// + /// + /// + /// + /// + public void SocketSend(short procotol, byte[] dataBuffer, int offset, int length, bool reserved = false) + { + int dataLen; + if (reserved) + { + dataLen = length - 4; + byte[] lenBytes1 = BitConverter.GetBytes(dataLen); + byte[] agreementBytes1 = BitConverter.GetBytes(procotol); + Array.Copy(lenBytes1, 0, dataBuffer, offset, 4); + Array.Copy(agreementBytes1, 0, dataBuffer, 4 + offset, 2); + this.mainSocket.Send(dataBuffer, 0, length, SocketFlags.None); + return; + } + dataLen = length + 2; + ByteBlock byteBlock = this.bytePool.GetByteBlock(dataLen + 4); + byte[] lenBytes = BitConverter.GetBytes(dataLen); + byte[] agreementBytes = BitConverter.GetBytes(procotol); + + byteBlock.Write(lenBytes); + byteBlock.Write(agreementBytes); + if (length > 0) + { + byteBlock.Write(dataBuffer, offset, length); + } + try + { + this.mainSocket.Send(byteBlock.Buffer, 0, byteBlock.Len, SocketFlags.None); + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + } + + #endregion 同步方法 + + #region 异步方法 + + /// + /// 发送简单协议 + /// + /// + public void SocketSendAsync(short procotol) + { + this.SocketSendAsync(procotol, new byte[0], 0, 0); + } + + /// + /// 发送字节 + /// + /// + /// + public void SocketSendAsync(short procotol, byte[] dataBuffer) + { + this.SocketSendAsync(procotol, dataBuffer, 0, dataBuffer.Length); + } + + /// + /// 发送协议流 + /// + /// + /// + public void SocketSendAsync(short procotol, ByteBlock dataByteBlock) + { + this.SocketSendAsync(procotol, dataByteBlock.Buffer, 0, dataByteBlock.Len); + } + + /// + /// 发送字节 + /// + /// + /// + /// + /// + public void SocketSendAsync(short procotol, byte[] dataBuffer, int offset, int length) + { + int dataLen; + dataLen = length - offset + 2; + ByteBlock byteBlock = this.bytePool.GetByteBlock(dataLen + 4); + byte[] lenBytes = BitConverter.GetBytes(dataLen); + byte[] agreementBytes = BitConverter.GetBytes(procotol); + + byteBlock.Write(lenBytes); + byteBlock.Write(agreementBytes); + if (length > 0) + { + byteBlock.Write(dataBuffer, offset, length); + } + try + { + byte[] data = byteBlock.ToArray(); + if (this.separateThread) + { + this.asyncSender.AsyncSend(data, 0, data.Length); + } + else + { + this.mainSocket.BeginSend(data, 0, data.Length, SocketFlags.None, null, null); + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + } + + #endregion 异步方法 + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/ClientConfig.cs b/RRQMSocket/Config/ClientConfig.cs new file mode 100644 index 000000000..443941a1a --- /dev/null +++ b/RRQMSocket/Config/ClientConfig.cs @@ -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 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace RRQMSocket +{ + /// + /// 客户端配置 + /// + public class ClientConfig : RRQMConfig + { + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/ProtocolClientConfig.cs b/RRQMSocket/Config/ProtocolClientConfig.cs new file mode 100644 index 000000000..c9c482d17 --- /dev/null +++ b/RRQMSocket/Config/ProtocolClientConfig.cs @@ -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 +{ + /// + /// 协议客户端配置 + /// + public class ProtocolClientConfig : TokenClientConfig + { + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/ProtocolServiceConfig.cs b/RRQMSocket/Config/ProtocolServiceConfig.cs new file mode 100644 index 000000000..dcd3ae872 --- /dev/null +++ b/RRQMSocket/Config/ProtocolServiceConfig.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// 协议服务配置 + /// + public class ProtocolServiceConfig : TokenServiceConfig + { + /// + /// 是否能重新设置ID + /// + public bool CanResetID + { + get { return (bool)GetValue(CanResetIDProperty); } + set { SetValue(CanResetIDProperty, value); } + } + + /// + /// 是否能重新设置ID,所需类型 + /// + public static readonly DependencyProperty CanResetIDProperty = + DependencyProperty.Register("CanResetID", typeof(bool), typeof(ProtocolServiceConfig), true); + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/RRQMConfig.cs b/RRQMSocket/Config/RRQMConfig.cs new file mode 100644 index 000000000..0ab687df0 --- /dev/null +++ b/RRQMSocket/Config/RRQMConfig.cs @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 RRQMCore.Dependency; +using RRQMCore.Log; + +namespace RRQMSocket +{ + /// + /// 配置文件基类 + /// + public class RRQMConfig : RRQMDependencyObject + { + /// + /// 日志记录器 + /// + public ILog Logger + { + get { return (ILog)GetValue(LoggerProperty); } + set { SetValue(LoggerProperty, value); } + } + + /// + /// 日志记录器依赖属性,所需类型 + /// + public static readonly DependencyProperty LoggerProperty = + DependencyProperty.Register("Logger", typeof(ILog), typeof(RRQMConfig), new Log()); + + /// + /// 内存池最大尺寸 + /// + public long BytePoolMaxSize + { + get { return (long)GetValue(BytePoolMaxSizeProperty); } + set { SetValue(BytePoolMaxSizeProperty, value); } + } + + /// + /// 内存池最大尺寸依赖属性,所需类型 + /// + public static readonly DependencyProperty BytePoolMaxSizeProperty = + DependencyProperty.Register("BytePoolMaxSize", typeof(long), typeof(RRQMConfig), 1024 * 1024 * 512L); + + /// + /// 内存池块最大尺寸 + /// + public int BytePoolMaxBlockSize + { + get { return (int)GetValue(BytePoolMaxBlockSizeProperty); } + set { SetValue(BytePoolMaxBlockSizeProperty, value); } + } + + /// + /// 内存池块最大尺寸,所需类型 + /// + public static readonly DependencyProperty BytePoolMaxBlockSizeProperty = + DependencyProperty.Register("BytePoolMaxBlockSize", typeof(int), typeof(RRQMConfig), 1024 * 1024 * 20); + + /// + /// 缓存池容量 + /// + public int BufferLength + { + get { return (int)GetValue(BufferLengthProperty); } + set { SetValue(BufferLengthProperty, value); } + } + + /// + /// 缓存池容量,所需类型 + /// + public static readonly DependencyProperty BufferLengthProperty = + DependencyProperty.Register("BufferLength", typeof(int), typeof(RRQMConfig), 1024); + + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/ServiceConfig.cs b/RRQMSocket/Config/ServiceConfig.cs new file mode 100644 index 000000000..2eb3e9e3e --- /dev/null +++ b/RRQMSocket/Config/ServiceConfig.cs @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// 服务器配置 + /// + public class ServiceConfig : RRQMConfig + { + /// + /// 多线程数量 + /// + public int ThreadCount + { + get { return (int)GetValue(ThreadCountProperty); } + set { SetValue(ThreadCountProperty, value); } + } + + /// + /// 多线程数量依赖属性,所需类型 + /// + public static readonly DependencyProperty ThreadCountProperty = + DependencyProperty.Register("ThreadCount", typeof(int), typeof(ServiceConfig), 1); + + /// + /// 监听IP和端口号组 + /// + public IPHost[] ListenIPHosts + { + get { return (IPHost[])GetValue(ListenIPHostsProperty); } + set { SetValue(ListenIPHostsProperty, value); } + } + + /// + /// IP和端口号依赖属性,所需类型数组 + /// + public static readonly DependencyProperty ListenIPHostsProperty = + DependencyProperty.Register("ListenIPHosts", typeof(IPHost[]), typeof(ServiceConfig), null); + + /// + /// 名称 + /// + public string ServerName + { + get { return (string)GetValue(ServerNameProperty); } + set { SetValue(ServerNameProperty, value); } + } + + /// + /// 名称,所需类型 + /// + public static readonly DependencyProperty ServerNameProperty = + DependencyProperty.Register("ServerName", typeof(string), typeof(ServiceConfig), "RRQMServer"); + + /// + /// 独立线程接收 + /// + public bool SeparateThreadReceive + { + get { return (bool)GetValue(SeparateThreadReceiveProperty); } + set { SetValue(SeparateThreadReceiveProperty, value); } + } + + /// + /// 独立线程接收, + /// 所需类型 + /// + public static readonly DependencyProperty SeparateThreadReceiveProperty = + DependencyProperty.Register("SeparateThreadReceive", typeof(bool), typeof(ServiceConfig), false); + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/TcpClientConfig.cs b/RRQMSocket/Config/TcpClientConfig.cs new file mode 100644 index 000000000..454f76c25 --- /dev/null +++ b/RRQMSocket/Config/TcpClientConfig.cs @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Dependency; + +namespace RRQMSocket +{ + /// + /// TcpClient配置 + /// + public class TcpClientConfig : ClientConfig + { + /// + /// 数据处理适配器 + /// + public DataHandlingAdapter DataHandlingAdapter + { + get { return (DataHandlingAdapter)GetValue(DataHandlingAdapterProperty); } + set { SetValue(DataHandlingAdapterProperty, value); } + } + + /// + /// 数据处理适配器,所需类型 + /// + public static readonly DependencyProperty DataHandlingAdapterProperty = + DependencyProperty.Register("DataHandlingAdapter", typeof(DataHandlingAdapter), typeof(TcpClientConfig), new NormalDataHandlingAdapter()); + + /// + /// 远程IPHost + /// + public IPHost RemoteIPHost + { + get { return (IPHost)GetValue(RemoteIPHostProperty); } + set { SetValue(RemoteIPHostProperty, value); } + } + + /// + /// 远程IPHost,所需类型 + /// + public static readonly DependencyProperty RemoteIPHostProperty = + DependencyProperty.Register("RemoteIPHost", typeof(IPHost), typeof(TcpClientConfig), null); + + /// + /// 内存池实例 + /// + public BytePool BytePool + { + get { return (BytePool)GetValue(BytePoolProperty); } + set { SetValue(BytePoolProperty, value); } + } + + /// + /// 内存池实例,所需类型 + /// + public static readonly DependencyProperty BytePoolProperty = + DependencyProperty.Register("BytePool", typeof(BytePool), typeof(TcpClientConfig), new BytePool()); + + /// + /// 仅发送,即不开启接收线程, + /// 同时不会感知断开操作。 + /// + public bool OnlySend + { + get { return (bool)GetValue(OnlySendProperty); } + set { SetValue(OnlySendProperty, value); } + } + + /// + /// 仅发送,即不开启接收线程, + /// 同时不会感知断开操作,所需类型 + /// + public static readonly DependencyProperty OnlySendProperty = + DependencyProperty.Register("OnlySend", typeof(bool), typeof(TcpClientConfig), false); + + /// + /// 在异步发送时,使用独立线程发送 + /// + public bool SeparateThreadSend + { + get { return (bool)GetValue(SeparateThreadSendProperty); } + set { SetValue(SeparateThreadSendProperty, value); } + } + + /// + /// 在异步发送时,使用独立线程发送,所需类型 + /// + public static readonly DependencyProperty SeparateThreadSendProperty = + DependencyProperty.Register("SeparateThreadSend", typeof(bool), typeof(TcpClientConfig), false); + + /// + /// 独立线程接收 + /// + public bool SeparateThreadReceive + { + get { return (bool)GetValue(SeparateThreadReceiveProperty); } + set { SetValue(SeparateThreadReceiveProperty, value); } + } + + /// + /// 独立线程接收, + /// 所需类型 + /// + public static readonly DependencyProperty SeparateThreadReceiveProperty = + DependencyProperty.Register("SeparateThreadReceive", typeof(bool), typeof(TcpClientConfig), false); + + /// + /// 独立线程发送缓存区 + /// + public int SeparateThreadSendBufferLength + { + get { return (int)GetValue(SeparateThreadSendBufferLengthProperty); } + set { SetValue(SeparateThreadSendBufferLengthProperty, value); } + } + + /// + /// 独立线程发送缓存区,所需类型 + /// + public static readonly DependencyProperty SeparateThreadSendBufferLengthProperty = + DependencyProperty.Register("SeparateThreadSendBufferLength", typeof(int), typeof(TcpClientConfig), 1024); + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/TcpServiceConfig.cs b/RRQMSocket/Config/TcpServiceConfig.cs new file mode 100644 index 000000000..e7b1eb442 --- /dev/null +++ b/RRQMSocket/Config/TcpServiceConfig.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// Tcp服务配置 + /// + public class TcpServiceConfig : ServiceConfig + { + /// + /// 挂起连接队列的最大长度。默认为100 + /// + public int Backlog + { + get { return (int)GetValue(BacklogProperty); } + set { SetValue(BacklogProperty, value); } + } + + /// + /// 挂起连接队列的最大长度,所需类型 + /// + public static readonly DependencyProperty BacklogProperty = + DependencyProperty.Register("Backlog", typeof(int), typeof(TcpServiceConfig), 100); + + /// + /// 最大可连接数,默认为10000 + /// + public int MaxCount + { + get { return (int)GetValue(MaxCountProperty); } + set { SetValue(MaxCountProperty, value); } + } + + /// + /// 最大可连接数,默认为10000,所需类型 + /// + public static readonly DependencyProperty MaxCountProperty = + DependencyProperty.Register("MaxCount", typeof(int), typeof(TcpServiceConfig), 10000); + + /// + /// 获取或设置清理无数据交互的SocketClient,默认60*1000 ms。如果不想清除,可使用-1。 + /// + public int ClearInterval + { + get { return (int)GetValue(ClearIntervalProperty); } + set { SetValue(ClearIntervalProperty, value); } + } + + /// + /// 获取或设置清理无数据交互的SocketClient,默认60*1000 ms。如果不想清除,可使用-1。 + /// 所需类型 + /// + public static readonly DependencyProperty ClearIntervalProperty = + DependencyProperty.Register("ClearInterval", typeof(int), typeof(TcpServiceConfig), 60*1000); + + /// + /// 统计类型,可叠加位域 + /// + public ClearType ClearType + { + get { return (ClearType)GetValue(ClearTypeProperty); } + set { SetValue(ClearTypeProperty, value); } + } + + /// + /// 统计类型,可叠加位域 + /// 所需类型 + /// + public static readonly DependencyProperty ClearTypeProperty = + DependencyProperty.Register("ClearType", typeof(ClearType), typeof(TcpServiceConfig), ClearType.Send | ClearType.Receive); + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/TokenClientConfig.cs b/RRQMSocket/Config/TokenClientConfig.cs new file mode 100644 index 000000000..791951464 --- /dev/null +++ b/RRQMSocket/Config/TokenClientConfig.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// TokenClient配置 + /// + public class TokenClientConfig : TcpClientConfig + { + /// + /// 连接令箭,当为null或空时,重置为默认值“rrqm” + /// + public string VerifyToken + { + get { return (string)GetValue(VerifyTokenProperty); } + set + { + SetValue(VerifyTokenProperty, value); + } + } + + /// + /// 连接令箭,当为null或空时,重置为默认值“rrqm”, 所需类型 + /// + public static readonly DependencyProperty VerifyTokenProperty = + DependencyProperty.Register("VerifyToken", typeof(string), typeof(TokenClientConfig), "rrqm"); + + /// + /// 验证超时时间,默认为3秒; + /// + public int VerifyTimeout + { + get { return (int)GetValue(VerifyTimeoutProperty); } + set + { + SetValue(VerifyTimeoutProperty, value); + } + } + + /// + /// 验证超时时间,默认为3000ms, 所需类型 + /// + public static readonly DependencyProperty VerifyTimeoutProperty = + DependencyProperty.Register("VerifyTimeout", typeof(int), typeof(TokenClientConfig), 3000); + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/TokenServiceConfig.cs b/RRQMSocket/Config/TokenServiceConfig.cs new file mode 100644 index 000000000..1b03130af --- /dev/null +++ b/RRQMSocket/Config/TokenServiceConfig.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// TokenTcp服务配置 + /// + public class TokenServiceConfig : TcpServiceConfig + { + /// + /// 连接令箭,当为null或空时,重置为默认值“rrqm” + /// + public string VerifyToken + { + get { return (string)GetValue(VerifyTokenProperty); } + set + { + SetValue(VerifyTokenProperty, value); + } + } + + /// + /// 连接令箭,当为null或空时,重置为默认值“rrqm”, 所需类型 + /// + public static readonly DependencyProperty VerifyTokenProperty = + DependencyProperty.Register("VerifyToken", typeof(string), typeof(TokenServiceConfig), "rrqm"); + + /// + /// 验证超时时间,默认为3000ms; + /// + public int VerifyTimeout + { + get { return (int)GetValue(VerifyTimeoutProperty); } + set + { + SetValue(VerifyTimeoutProperty, value); + } + } + + /// + /// 验证超时时间,默认为3000ms, 所需类型 + /// + public static readonly DependencyProperty VerifyTimeoutProperty = + DependencyProperty.Register("VerifyTimeout", typeof(int), typeof(TokenServiceConfig), 3000); + } +} \ No newline at end of file diff --git a/RRQMSocket/Config/UdpSessionConfig.cs b/RRQMSocket/Config/UdpSessionConfig.cs new file mode 100644 index 000000000..53a7bb277 --- /dev/null +++ b/RRQMSocket/Config/UdpSessionConfig.cs @@ -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.Dependency; +using System.Net; + +namespace RRQMSocket +{ + /// + /// UDP服务器配置 + /// + public class UdpSessionConfig : ServiceConfig + { + /// + /// 默认远程节点 + /// + public EndPoint DefaultRemotePoint + { + get { return (EndPoint)GetValue(DefaultRemotePointProperty); } + set { SetValue(DefaultRemotePointProperty, value); } + } + + /// + /// 默认远程节点, 所需类型 + /// + public static readonly DependencyProperty DefaultRemotePointProperty = + DependencyProperty.Register("DefaultRemotePoint", typeof(EndPoint), typeof(UdpSessionConfig), null); + + /// + /// 使用绑定 + /// + public bool UseBind + { + get { return (bool)GetValue(UseBindProperty); } + set { SetValue(UseBindProperty, value); } + } + + /// + /// 使用绑定, 所需类型 + /// + public static readonly DependencyProperty UseBindProperty = + DependencyProperty.Register("UseBind", typeof(bool), typeof(UdpSessionConfig), false); + } +} \ No newline at end of file diff --git a/RRQMSocket/DataAdapter/DataAdapterTester.cs b/RRQMSocket/DataAdapter/DataAdapterTester.cs new file mode 100644 index 000000000..6277feb1a --- /dev/null +++ b/RRQMSocket/DataAdapter/DataAdapterTester.cs @@ -0,0 +1,201 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace RRQMSocket +{ + /// + /// 数据处理适配器测试 + /// + public class DataAdapterTester : IDisposable + { + private readonly ConcurrentQueue asyncBytes; + + private readonly Thread sendThread; + + private readonly EventWaitHandle waitHandle; + + private DataHandlingAdapter adapter; + + private bool sending; + + private bool dispose; + + private int bufferLength; + + private DataAdapterTester() + { + asyncBytes = new ConcurrentQueue(); + waitHandle = new AutoResetEvent(false); + this.sendThread = new Thread(this.BeginSend); + this.sendThread.IsBackground = true; + this.sendThread.Name = "DataAdapterTesterThread"; + this.sendThread.Start(); + } + + /// + /// 获取测试器 + /// + /// + /// + /// + /// + /// + public static DataAdapterTester CreateTester(DataHandlingAdapter adapter, Action receivedCallBack, ILog logger, int bufferLength = 1024) + { + DataAdapterTester tester = new DataAdapterTester(); + tester.adapter = adapter; + tester.bufferLength = bufferLength; + + adapter.Logger = logger; + adapter.SendCallBack = tester.SendCallback; + adapter.BytePool = new BytePool(); + adapter.ReceivedCallBack = receivedCallBack; + + return tester; + } + + /// + /// 模拟发送 + /// + /// + /// + /// + public void SimSend(byte[] buffer, int offset, int length) + { + adapter.Send(buffer, offset, length, false); + } + + /// + /// 模拟发送 + /// + /// + public void SimSend(byte[] buffer) + { + this.SimSend(buffer, 0, buffer.Length); + } + + private void BeginSend() + { + while (!this.dispose) + { + if (this.tryGet(out List byteBlocks)) + { + this.sending = true; + + foreach (var block in byteBlocks) + { + try + { + this.adapter.Received(block); + } + finally + { + block.Dispose(); + } + } + } + else + { + this.sending = false; + this.waitHandle.WaitOne(); + } + } + } + + private bool tryGet(out List byteBlocks) + { + byteBlocks = new List(); + + ByteBlock block = null; + + while (true) + { + if (this.asyncBytes.TryDequeue(out AsyncByte asyncByte)) + { + if (block == null) + { + block = this.adapter.BytePool.GetByteBlock(bufferLength); + byteBlocks.Add(block); + } + + int surLen = block.Capacity - (int)block.Position; + if (surLen >= asyncByte.length) + { + block.Write(asyncByte.buffer, asyncByte.offset, asyncByte.length); + } + else + { + block.Write(asyncByte.buffer, asyncByte.offset, surLen); + + int surDataLen = asyncByte.length - surLen; + int offset = asyncByte.offset + surLen; + + while (surDataLen > 0) + { + block = this.adapter.BytePool.GetByteBlock(bufferLength); + byteBlocks.Add(block); + int len = Math.Min(surDataLen, bufferLength); + block.Write(asyncByte.buffer, offset, len); + surDataLen -= len; + offset += len; + } + + break; + } + } + else + { + if (byteBlocks.Count > 0) + { + break; + } + else + { + return false; + } + } + } + return true; + } + + private void SendCallback(byte[] buffer, int offset, int length, bool isAsync) + { + AsyncByte asyncByte = new AsyncByte(); + asyncByte.buffer = new byte[length]; + + Array.Copy(buffer, offset, asyncByte.buffer, 0, length); + asyncByte.offset = 0; + asyncByte.length = length; + this.asyncBytes.Enqueue(asyncByte); + if (!this.sending) + { + this.waitHandle.Set(); + } + } + + /// + /// 释放 + /// + public void Dispose() + { + this.dispose = true; + this.waitHandle.Set(); + this.waitHandle.Dispose(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/DataAdapter/DataHandlingAdapter.cs b/RRQMSocket/DataAdapter/DataHandlingAdapter.cs new file mode 100644 index 000000000..6623712a6 --- /dev/null +++ b/RRQMSocket/DataAdapter/DataHandlingAdapter.cs @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 System; + +namespace RRQMSocket +{ + /// + /// 数据处理适配器 + /// + public abstract class DataHandlingAdapter + { + /// + /// 内存池 + /// + protected internal BytePool BytePool { get; internal set; } + + /// + /// 日志记录器 + /// + protected internal ILog Logger { get; internal set; } + + /// + /// 当接收数据处理完成后,回调该函数执行接收 + /// + internal Action ReceivedCallBack { get; set; } + + /// + /// 当接收数据处理完成后,回调该函数执行发送 + /// + internal Action SendCallBack { get; set; } + + /// + /// 当接收到数据后预先处理数据,然后调用处理数据 + /// + /// 数据流 + protected abstract void PreviewReceived(ByteBlock byteBlock); + + /// + /// 处理已经经过预先处理后的数据 + /// + /// + /// + protected void GoReceived(ByteBlock byteBlock, object obj) + { + try + { + this.ReceivedCallBack.Invoke(byteBlock, obj); + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, ex.Message, ex); + } + } + + /// + /// 当发送数据前预先处理数据 + /// + /// 数据 + /// 偏移 + /// 长度 + /// 是否使用IOCP发送 + protected abstract void PreviewSend(byte[] buffer, int offset, int length, bool isAsync); + + /// + /// 发送已经经过预先处理后的数据 + /// + /// + /// + /// + /// 是否使用IOCP发送 + protected void GoSend(byte[] buffer, int offset, int length, bool isAsync) + { + this.SendCallBack.Invoke(buffer, offset, length, isAsync); + } + + internal void Received(ByteBlock byteBlock) + { + this.PreviewReceived(byteBlock); + } + + internal void Send(byte[] buffer, int offset, int length, bool isAsync) + { + this.PreviewSend(buffer, offset, length, isAsync); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/DataAdapter/FixedHeaderDataHandlingAdapter.cs b/RRQMSocket/DataAdapter/FixedHeaderDataHandlingAdapter.cs new file mode 100644 index 000000000..6e40f1ab2 --- /dev/null +++ b/RRQMSocket/DataAdapter/FixedHeaderDataHandlingAdapter.cs @@ -0,0 +1,279 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; + +namespace RRQMSocket +{ + /// + /// 固定包头数据处理器 + /// + public class FixedHeaderDataHandlingAdapter : DataHandlingAdapter + { + private int maxSizeHeader = 1024 * 1024 * 10; + + /// + /// 获取或设置包头的最大值(默认为10Mb) + /// + public int MaxSizeHeader + { + get { return maxSizeHeader; } + set { maxSizeHeader = value; } + } + + private int minSizeHeader = 0; + + /// + /// 获取或设置包头的最小值(默认为0) + /// + public int MinSizeHeader + { + get { return minSizeHeader; } + set { minSizeHeader = value; } + } + + private FixedHeaderType fixedHeaderType = FixedHeaderType.Int; + + /// + /// 设置包头类型,默认为int + /// + public FixedHeaderType FixedHeaderType + { + get { return fixedHeaderType; } + set { fixedHeaderType = value; } + } + + /// + /// 临时包 + /// + private ByteBlock tempByteBlock; + + /// + /// 包剩余长度 + /// + private int surPlusLength = 0; + + /// + /// 协议临时包 + /// + private byte[] agreementTempBytes; + + /// + /// 当接收到数据时处理数据 + /// + /// 数据流 + protected override void PreviewReceived(ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + + if (agreementTempBytes != null) + { + SeamPackage(buffer, r); + } + else if (this.tempByteBlock == null) + { + SplitPackage(buffer, 0, r); + } + else + { + if (surPlusLength == r) + { + this.tempByteBlock.Write(buffer, 0, surPlusLength); + PreviewHandle(this.tempByteBlock); + this.tempByteBlock = null; + surPlusLength = 0; + } + else if (surPlusLength < r) + { + this.tempByteBlock.Write(buffer, 0, surPlusLength); + PreviewHandle(this.tempByteBlock); + this.tempByteBlock = null; + SplitPackage(buffer, surPlusLength, r); + } + else + { + this.tempByteBlock.Write(buffer, 0, r); + surPlusLength -= r; + } + } + } + + /// + /// 缝合包 + /// + /// + /// + private void SeamPackage(byte[] buffer, int r) + { + ByteBlock byteBlock = this.BytePool.GetByteBlock(r + agreementTempBytes.Length); + byteBlock.Write(agreementTempBytes); + byteBlock.Write(buffer, 0, r); + r += agreementTempBytes.Length; + agreementTempBytes = null; + SplitPackage(byteBlock.Buffer, 0, r); + byteBlock.Dispose(); + } + + /// + /// 分解包 + /// + /// + /// + /// + private void SplitPackage(byte[] dataBuffer, int index, int r) + { + while (index < r) + { + if (r - index <= (byte)this.fixedHeaderType) + { + agreementTempBytes = new byte[r - index]; + Array.Copy(dataBuffer, index, agreementTempBytes, 0, agreementTempBytes.Length); + return; + } + int length = 0; + + switch (this.fixedHeaderType) + { + case FixedHeaderType.Byte: + length = dataBuffer[index]; + break; + + case FixedHeaderType.Ushort: + length = BitConverter.ToUInt16(dataBuffer, index); + break; + + case FixedHeaderType.Int: + length = BitConverter.ToInt32(dataBuffer, index); + break; + } + + if (length < 0) + { + Logger.Debug(LogType.Error, this, "接收数据长度错误,已放弃接收"); + return; + } + else if (length < this.minSizeHeader) + { + Logger.Debug(LogType.Error, this, "接收数据长度小于设定值,已放弃接收"); + return; + } + else if (length > this.maxSizeHeader) + { + Logger.Debug(LogType.Error, this, "接收数据长度大于设定值,已放弃接收"); + return; + } + + int recedSurPlusLength = r - index - (byte)this.fixedHeaderType; + if (recedSurPlusLength >= length) + { + ByteBlock byteBlock = this.BytePool.GetByteBlock(length); + byteBlock.Write(dataBuffer, index + (byte)this.fixedHeaderType, length); + PreviewHandle(byteBlock); + surPlusLength = 0; + } + else//半包 + { + this.tempByteBlock = this.BytePool.GetByteBlock(length); + surPlusLength = length - recedSurPlusLength; + this.tempByteBlock.Write(dataBuffer, index + (byte)this.fixedHeaderType, recedSurPlusLength); + } + index += (length + (byte)this.fixedHeaderType); + } + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + this.GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// 当发送数据前处理数据 + /// + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync) + { + if (length < this.MinSizeHeader) + { + throw new RRQMException("发送数据小于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + if (length > this.MaxSizeHeader) + { + throw new RRQMException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送"); + } + + ByteBlock byteBlock = null; + byte[] lenBytes = null; + + switch (this.fixedHeaderType) + { + case FixedHeaderType.Byte: + { + byte dataLen = (byte)(length - offset); + byteBlock = this.BytePool.GetByteBlock(dataLen + 1); + lenBytes = new byte[] { dataLen }; + break; + } + case FixedHeaderType.Ushort: + { + ushort dataLen = (ushort)(length - offset); + byteBlock = this.BytePool.GetByteBlock(dataLen + 2); + lenBytes = BitConverter.GetBytes(dataLen); + break; + } + case FixedHeaderType.Int: + { + int dataLen = length - offset; + byteBlock = this.BytePool.GetByteBlock(dataLen + 4); + lenBytes = BitConverter.GetBytes(dataLen); + break; + } + } + + try + { + byteBlock.Write(lenBytes); + byteBlock.Write(buffer, offset, length); + if (isAsync) + { + byte[] data = byteBlock.ToArray(); + this.GoSend(data, 0, data.Length, isAsync);//使用ByteBlock时不能异步发送 + } + else + { + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len, isAsync); + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/DataAdapter/FixedSizeDataHandlingAdapter.cs b/RRQMSocket/DataAdapter/FixedSizeDataHandlingAdapter.cs new file mode 100644 index 000000000..934e2db8b --- /dev/null +++ b/RRQMSocket/DataAdapter/FixedSizeDataHandlingAdapter.cs @@ -0,0 +1,159 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; + +namespace RRQMSocket +{ + /// + /// 固定长度数据处理器 + /// + public class FixedSizeDataHandlingAdapter : DataHandlingAdapter + { + /// + /// 构造函数 + /// + /// 数据包的长度 + public FixedSizeDataHandlingAdapter(int fixedSize) + { + this.FixedSize = fixedSize; + } + + /// + /// 获取已设置的数据包的长度 + /// + public int FixedSize { get; private set; } + + /// + /// 临时包 + /// + private ByteBlock tempByteBlock; + + /// + /// 包剩余长度 + /// + private int surPlusLength = 0; + + /// + /// 预处理 + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int r = byteBlock.Len; + if (this.tempByteBlock == null) + { + SplitPackage(buffer, 0, r); + } + else + { + if (surPlusLength == r) + { + this.tempByteBlock.Write(buffer, 0, surPlusLength); + PreviewHandle(this.tempByteBlock); + this.tempByteBlock = null; + surPlusLength = 0; + } + else if (surPlusLength < r) + { + this.tempByteBlock.Write(buffer, 0, surPlusLength); + PreviewHandle(this.tempByteBlock); + this.tempByteBlock = null; + SplitPackage(buffer, surPlusLength, r); + } + else + { + this.tempByteBlock.Write(buffer, 0, r); + surPlusLength -= r; + } + } + } + + private void SplitPackage(byte[] dataBuffer, int index, int r) + { + while (index < r) + { + if (r - index >= this.FixedSize) + { + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.FixedSize); + byteBlock.Write(dataBuffer, index, this.FixedSize); + PreviewHandle(byteBlock); + surPlusLength = 0; + } + else//半包 + { + this.tempByteBlock = this.BytePool.GetByteBlock(this.FixedSize); + surPlusLength = this.FixedSize - (r - index); + this.tempByteBlock.Write(dataBuffer, index, r - index); + } + index += this.FixedSize; + } + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + this.GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// 预处理 + /// + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync) + { + int dataLen = length - offset; + if (dataLen > this.FixedSize) + { + throw new RRQMOverlengthException("发送的数据包长度大于FixedSize"); + } + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.FixedSize); + + byteBlock.Write(buffer, offset, length); + for (int i = (int)byteBlock.Position; i < this.FixedSize; i++) + { + byteBlock.Buffer[i] = 0; + } + byteBlock.SetLength(this.FixedSize); + try + { + if (isAsync) + { + byte[] data = byteBlock.ToArray(); + this.GoSend(data, 0, data.Length, true);//使用ByteBlock时不能异步发送 + } + else + { + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len, false); + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/DataAdapter/JsonStringDataHandlingAdapter.cs b/RRQMSocket/DataAdapter/JsonStringDataHandlingAdapter.cs new file mode 100644 index 000000000..1e11ea0d5 --- /dev/null +++ b/RRQMSocket/DataAdapter/JsonStringDataHandlingAdapter.cs @@ -0,0 +1,135 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Text; +using System.Text.RegularExpressions; + +namespace RRQMSocket +{ + /// + /// Json字符串数据处理解析器(该解析器由网友"明月"提供) + /// + public class JsonStringDataHandlingAdapter : DataHandlingAdapter + { + private ByteBlock Temp; + + /// + /// 预解析 + /// + /// + protected override void PreviewReceived(ByteBlock byteBlock) + { + byte[] buffer = byteBlock.Buffer; + int length = byteBlock.Len; + + //Console.WriteLine("----------------接收的新数据-------------------"); + if (Temp != null) + { + Temp.Write(byteBlock.Buffer, 0, length); + buffer = Temp.Buffer; + length = (int)Temp.Length; + } + + string msg = Encoding.UTF8.GetString(buffer, 0, length); + if (msg.Contains("}{")) + { + //Console.WriteLine("----------------发生粘包-------------------"); + string[] mes = Regex.Split(msg, "}{"); + for (int i = 0; i < mes.Length; i++) + { + string str = mes[i]; + if (i == 0) + { + str += "}"; + } + else if (i == mes.Length - 1) + { + str = "{" + str; + int start = StringCount(str, "{"); + int end = StringCount(str, "}"); + if (start == end) + { + if (Temp != null) + { + Temp = null; + } + } + else + { + byte[] surPlus = Encoding.UTF8.GetBytes(str); + + if (Temp != null) + { + Temp = null; + } + //Temp = BytePool.GetByteBlock(1024*1024*10); + Temp = BytePool.GetByteBlock(length); + + Temp.Write(surPlus); + //Console.WriteLine("----------------数据不完整-------------------"); + break; + } + } + else + { + str = "{" + str + "}"; + } + //Console.WriteLine(str); + PreviewHandle(str); + } + } + else if (msg[0] == '{' && msg[1] == '}') + { + Temp = null; + PreviewHandle(msg); + } + else + { + if (Temp == null) + { + Temp = BytePool.GetByteBlock(length); + Temp.Write(byteBlock.Buffer, 0, length); + } + + Temp.Write(byteBlock.Buffer, 0, length); + } + } + + /// + /// 预发送封装 + /// + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync) + { + this.GoSend(buffer, offset, length, isAsync); + } + + private int StringCount(string source, string match) + { + int count = 0; + if (source.Contains(match)) + { + string temp = source.Replace(match, ""); + count = (source.Length - temp.Length) / match.Length; + } + return count; + } + + private void PreviewHandle(string msg) + { + GoReceived(null, msg); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/DataAdapter/NormalDataHandlingAdapter.cs b/RRQMSocket/DataAdapter/NormalDataHandlingAdapter.cs new file mode 100644 index 000000000..d5bf9d0d5 --- /dev/null +++ b/RRQMSocket/DataAdapter/NormalDataHandlingAdapter.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// 普通数据处理器 + /// + public class NormalDataHandlingAdapter : DataHandlingAdapter + { + /// + /// 当接收到数据时处理数据 + /// + /// 数据流 + protected override void PreviewReceived(ByteBlock byteBlock) + { + this.GoReceived(byteBlock, null); + } + + /// + /// 当发送数据前处理数据 + /// + /// 数据 + /// 偏移 + /// 长度 + /// + protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync) + { + this.GoSend(buffer, offset, length, isAsync); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/DataAdapter/TerminatorDataHandlingAdapter.cs b/RRQMSocket/DataAdapter/TerminatorDataHandlingAdapter.cs new file mode 100644 index 000000000..7e724173d --- /dev/null +++ b/RRQMSocket/DataAdapter/TerminatorDataHandlingAdapter.cs @@ -0,0 +1,220 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; +using System.Collections.Generic; +using System.Text; + +namespace RRQMSocket +{ + /// + /// 终止字符处理器 + /// + public class TerminatorDataHandlingAdapter : DataHandlingAdapter + { + /// + /// 构造函数 + /// + /// + /// + public TerminatorDataHandlingAdapter(int maxSize, string terminator) : this(maxSize, 0, Encoding.UTF8.GetBytes(terminator)) + { + } + + /// + /// 构造函数 + /// + /// + /// + /// + public TerminatorDataHandlingAdapter(int maxSize, string terminator, Encoding encoding) + : this(maxSize, 0, encoding.GetBytes(terminator)) + { + } + + /// + /// 构造函数 + /// + /// + /// + /// + public TerminatorDataHandlingAdapter(int maxSize, int minSize, byte[] terminatorCode) + { + this.maxSize = maxSize; + this.minSize = minSize; + this.terminatorCode = terminatorCode; + } + + private byte[] terminatorCode; + + private int maxSize = 1024; + + /// + /// 在未找到终止因子时,允许的最大长度,默认1024 + /// + public int MaxSize + { + get { return maxSize; } + set { maxSize = value; } + } + + private int minSize = 0; + + /// + /// 即使找到了终止因子,也不会结束,默认0 + /// + public int MinSize + { + get { return minSize; } + set { minSize = value; } + } + + private bool reserveTerminatorCode; + + /// + /// 保留终止因子 + /// + public bool ReserveTerminatorCode + { + get { return reserveTerminatorCode; } + set { reserveTerminatorCode = value; } + } + + private ByteBlock tempByteBlock; + + /// + /// 预处理 + /// + /// + 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.Buffer; + r = (int)this.tempByteBlock.Position; + } + + List indexes = buffer.IndexOfInclude(0,r, this.terminatorCode); + if (indexes.Count == 0) + { + if (r > 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(r * 2); + this.tempByteBlock.Write(buffer, 0, r); + } + } + else + { + int startIndex = 0; + foreach (int lastIndex in indexes) + { + int length; + if (this.reserveTerminatorCode) + { + length = lastIndex - startIndex + 1; + } + else + { + length = lastIndex - startIndex - this.terminatorCode.Length + 1; + } + + ByteBlock packageByteBlock = this.BytePool.GetByteBlock(length); + packageByteBlock.Write(buffer, startIndex, length); + + string mes = Encoding.UTF8.GetString(packageByteBlock.Buffer, 0, (int)packageByteBlock.Position); + + this.PreviewHandle(packageByteBlock); + startIndex = lastIndex + 1; + } + if (this.tempByteBlock != null) + { + this.tempByteBlock.Dispose(); + this.tempByteBlock = null; + } + if (startIndex < r) + { + this.tempByteBlock = this.BytePool.GetByteBlock((r - startIndex) * 2); + this.tempByteBlock.Write(buffer, startIndex, r - startIndex); + } + } + } + + private void PreviewHandle(ByteBlock byteBlock) + { + try + { + this.GoReceived(byteBlock, null); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// 预处理 + /// + /// + /// + /// + /// + protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync) + { + if (length>this.maxSize) + { + throw new RRQMException("发送的数据长度大于适配器设定的最大值,接收方可能会抛弃。"); + } + int dataLen = length - offset + this.terminatorCode.Length; + ByteBlock byteBlock = this.BytePool.GetByteBlock(dataLen); + byteBlock.Write(buffer, offset, length); + byteBlock.Write(this.terminatorCode); + + try + { + if (isAsync) + { + byte[] data = byteBlock.ToArray(); + this.GoSend(data, 0, data.Length, isAsync);//使用ByteBlock时不能异步发送 + } + else + { + this.GoSend(byteBlock.Buffer, 0, byteBlock.Len, isAsync); + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + byteBlock.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/DelegateCollection.cs b/RRQMSocket/DelegateCollection.cs new file mode 100644 index 000000000..626d4265f --- /dev/null +++ b/RRQMSocket/DelegateCollection.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 RRQMSocket; +using System.Net; + +/// +/// 显示信息 +/// +/// +/// +public delegate void RRQMMessageEventHandler(object sender, MesEventArgs e); + +/// +/// ByteBlock +/// +/// +/// +public delegate void RRQMByteBlockEventHandler(object sender, ByteBlock e); + +/// +/// UDP接收 +/// +/// +/// +public delegate void RRQMUDPByteBlockEventHandler(EndPoint endpoint, ByteBlock e); + +/// +/// 字节数据 +/// +/// +/// +public delegate void RRQMBytesEventHandler(object sender, BytesEventArgs e); + +/// +/// 字节数据 +/// +/// +/// +public delegate void RRQMReturnBytesEventHandler(object sender, ReturnBytesEventArgs e); \ No newline at end of file diff --git a/RRQMSocket/Enum/ClearType.cs b/RRQMSocket/Enum/ClearType.cs new file mode 100644 index 000000000..d82632120 --- /dev/null +++ b/RRQMSocket/Enum/ClearType.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using System; + +namespace RRQMSocket +{ + /// + /// 清理统计类型 + /// + [Flags] + public enum ClearType + { + /// + /// 从发送统计 + /// + Send = 1, + + /// + /// 从接收统计 + /// + Receive = 2 + } +} \ No newline at end of file diff --git a/RRQMSocket/Enum/FixedHeaderType.cs b/RRQMSocket/Enum/FixedHeaderType.cs new file mode 100644 index 000000000..e4876356f --- /dev/null +++ b/RRQMSocket/Enum/FixedHeaderType.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// 固定包头类型 + /// + public enum FixedHeaderType : byte + { + /// + /// 以1Byte标识长度,最长接收255 + /// + Byte = 1, + + /// + /// 以2Byte标识长度,最长接收65535 + /// + Ushort = 2, + + /// + /// 以4Byte标识长度,最长接收2147483647 + /// + Int = 4 + } +} \ No newline at end of file diff --git a/RRQMSocket/Enum/ServerState.cs b/RRQMSocket/Enum/ServerState.cs new file mode 100644 index 000000000..5e0265ced --- /dev/null +++ b/RRQMSocket/Enum/ServerState.cs @@ -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 +{ + /// + /// 服务器状态 + /// + public enum ServerState + { + /// + /// 无状态,指示为初建 + /// + None, + + /// + /// 正在运行 + /// + Running, + + /// + /// 已停止 + /// + Stopped, + + /// + /// 已释放 + /// + Disposed + } +} \ No newline at end of file diff --git a/RRQMSocket/EventArgs/BytesEventArgs.cs b/RRQMSocket/EventArgs/BytesEventArgs.cs new file mode 100644 index 000000000..c8f529324 --- /dev/null +++ b/RRQMSocket/EventArgs/BytesEventArgs.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// 字节事件 + /// + public class BytesEventArgs : RRQMEventArgs + { + /// + /// 构造函数 + /// + /// + public BytesEventArgs(byte[] data) + { + this.ReceivedDataBytes = data; + } + + /// + /// 字节数组 + /// + public byte[] ReceivedDataBytes { get; private set; } + } +} \ No newline at end of file diff --git a/RRQMSocket/EventArgs/MesEventArgs.cs b/RRQMSocket/EventArgs/MesEventArgs.cs new file mode 100644 index 000000000..7f05d54a6 --- /dev/null +++ b/RRQMSocket/EventArgs/MesEventArgs.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// 消息事件 + /// + public class MesEventArgs : RRQMEventArgs + { + /// + /// 构造函数 + /// + /// + public MesEventArgs(string mes) + { + this.Message = mes; + } + + /// + /// 直接构造函数 + /// + public MesEventArgs() + { + } + + /// + /// 消息 + /// + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket/EventArgs/ReturnBytesEventArgs.cs b/RRQMSocket/EventArgs/ReturnBytesEventArgs.cs new file mode 100644 index 000000000..c63832ad9 --- /dev/null +++ b/RRQMSocket/EventArgs/ReturnBytesEventArgs.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +namespace RRQMSocket +{ + /// + /// 允许返回的字节 + /// + public class ReturnBytesEventArgs : BytesEventArgs + { + /// + /// 构造函数 + /// + /// + public ReturnBytesEventArgs(byte[] receivedData) : base(receivedData) + { + } + + /// + /// 返回字节 + /// + public byte[] ReturnDataBytes { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket/Exceptions/RRQMNotConnectedException.cs b/RRQMSocket/Exceptions/RRQMNotConnectedException.cs new file mode 100644 index 000000000..e0da099c8 --- /dev/null +++ b/RRQMSocket/Exceptions/RRQMNotConnectedException.cs @@ -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 +{ + /* + 若汝棋茗 + */ + + /// + /// 未连接异常 + /// + + public class RRQMNotConnectedException : RRQMException + { + /// + /// + /// + public RRQMNotConnectedException() : base() { } + + /// + /// + /// + /// + public RRQMNotConnectedException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMNotConnectedException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMNotConnectedException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket/Exceptions/RRQMOverlengthException.cs b/RRQMSocket/Exceptions/RRQMOverlengthException.cs new file mode 100644 index 000000000..892c78c20 --- /dev/null +++ b/RRQMSocket/Exceptions/RRQMOverlengthException.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// 超长异常 + /// + public class RRQMOverlengthException : RRQMException + { + /// + /// + /// + public RRQMOverlengthException() : base() { } + + /// + /// + /// + /// + public RRQMOverlengthException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMOverlengthException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMOverlengthException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket/Exceptions/RRQMTimeoutException.cs b/RRQMSocket/Exceptions/RRQMTimeoutException.cs new file mode 100644 index 000000000..74ad7bbbd --- /dev/null +++ b/RRQMSocket/Exceptions/RRQMTimeoutException.cs @@ -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 +{ + /// + /// 超时异常 + /// + + public class RRQMTimeoutException : RRQMException + { + /// + /// + /// + public RRQMTimeoutException() : base() { } + + /// + /// + /// + /// + public RRQMTimeoutException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMTimeoutException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMTimeoutException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket/Exceptions/RRQMTokenVerifyException.cs b/RRQMSocket/Exceptions/RRQMTokenVerifyException.cs new file mode 100644 index 000000000..42e291a7d --- /dev/null +++ b/RRQMSocket/Exceptions/RRQMTokenVerifyException.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// 验证令箭异常 + /// + public class RRQMTokenVerifyException : RRQMException + { + /// + /// + /// + public RRQMTokenVerifyException() : base() { } + + /// + /// + /// + /// + public RRQMTokenVerifyException(string message) : base(message) { } + + /// + /// + /// + /// + /// + public RRQMTokenVerifyException(string message, System.Exception inner) : base(message, inner) { } + + /// + /// + /// + /// + /// + protected RRQMTokenVerifyException(System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/IClient.cs b/RRQMSocket/Interface/IClient.cs new file mode 100644 index 000000000..2bd694993 --- /dev/null +++ b/RRQMSocket/Interface/IClient.cs @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; +using System.Net.Sockets; + +namespace RRQMSocket +{ + /// + /// 终端接口 + /// + public interface IClient : IDisposable + { + /// + /// IP地址 + /// + string IP { get; } + + /// + /// 端口号 + /// + int Port { get; } + + /// + /// 主通信器 + /// + Socket MainSocket { get; } + + /// + /// 内存池实例 + /// + BytePool BytePool { get; } + + /// + /// 日志记录器 + /// + ILog Logger { get; } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + /// + /// + void Send(byte[] buffer, int offset, int length); + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + void Send(byte[] buffer); + + /// + /// 发送流中的有效数据 + /// + /// + /// + /// + /// + void Send(ByteBlock byteBlock); + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + void SendAsync(byte[] buffer, int offset, int length); + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + void SendAsync(byte[] buffer); + + /// + /// IOCP发送流中的有效数据 + /// + /// + /// + /// + /// + void SendAsync(ByteBlock byteBlock); + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/IHandleBuffer.cs b/RRQMSocket/Interface/IHandleBuffer.cs new file mode 100644 index 000000000..dc711cc32 --- /dev/null +++ b/RRQMSocket/Interface/IHandleBuffer.cs @@ -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.ByteManager; + +namespace RRQMSocket +{ + /// + /// 处理数据 + /// + public interface IHandleBuffer + { + /// + /// 处理数据 + /// + /// + void HandleBuffer(ByteBlock byteBlock); + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/IService.cs b/RRQMSocket/Interface/IService.cs new file mode 100644 index 000000000..37503ab90 --- /dev/null +++ b/RRQMSocket/Interface/IService.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; + +namespace RRQMSocket +{ + /// + /// 服务器接口 + /// + public interface IService : IDisposable + { + /// + /// 获取默认内存池实例 + /// + BytePool BytePool { get; } + + /// + /// 服务器状态 + /// + ServerState ServerState { get; } + + /// + /// 获取服务器配置 + /// + ServiceConfig ServiceConfig { get; } + + /// + /// 名称 + /// + string ServerName { get; } + + /// + /// 配置服务器 + /// + /// 配置 + /// + void Setup(ServiceConfig serverConfig); + + /// + /// 配置服务器 + /// + /// + /// + void Setup(int port); + + /// + /// 启动 + /// + /// + /// + /// + void Start(); + + /// + /// 停止 + /// + /// + void Stop(); + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/ISocket.cs b/RRQMSocket/Interface/ISocket.cs new file mode 100644 index 000000000..bfebfdceb --- /dev/null +++ b/RRQMSocket/Interface/ISocket.cs @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +using RRQMCore.Log; +using System; + +namespace RRQMSocket +{ + /// + /// Socket基接口 + /// + public interface ISocket : IDisposable + { + /// + /// 数据交互缓存池限制 + /// + int BufferLength { get; } + + /// + /// 日志记录器 + /// + ILog Logger { get; } + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/ISocketClient.cs b/RRQMSocket/Interface/ISocketClient.cs new file mode 100644 index 000000000..e4882a062 --- /dev/null +++ b/RRQMSocket/Interface/ISocketClient.cs @@ -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 +{ + /// + /// 服务器辅助类接口 + /// + public interface ISocketClient : ITcpClient + { + /// + /// 用于索引的ID + /// + string ID { get; } + + /// + /// 标记 + /// + object Flag { get; set; } + + /// + /// 包含此辅助类的主服务器类 + /// + _ITcpService Service { get; } + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/ITcpClient.cs b/RRQMSocket/Interface/ITcpClient.cs new file mode 100644 index 000000000..98b62b3e6 --- /dev/null +++ b/RRQMSocket/Interface/ITcpClient.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Net.Sockets; + +namespace RRQMSocket +{ + /// + /// TCP客户端接口 + /// + public interface ITcpClient : IClient + { + /// + /// 判断是否在线 + /// + bool Online { get; } + + /// + /// IP及端口号 + /// + string Name { get; } + + /// + /// 数据处理适配器 + /// + DataHandlingAdapter DataHandlingAdapter { get; } + + /// + /// 禁用发送或接收 + /// + /// + void Shutdown(SocketShutdown how); + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/ITcpService.cs b/RRQMSocket/Interface/ITcpService.cs new file mode 100644 index 000000000..ba0e9a1fb --- /dev/null +++ b/RRQMSocket/Interface/ITcpService.cs @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Collections.Generic; + +namespace RRQMSocket +{ + /// + /// TCP系列服务器接口 + /// + public interface ITcpService : IService where TClient : ISocketClient + { + /// + /// 获取最大可连接数 + /// + int MaxCount { get; } + + /// + /// 获取当前连接的所有客户端 + /// + SocketCliectCollection SocketClients { get; } + + /// + /// 获取清理无数据交互的SocketClient,默认60。如果不想清除,可使用-1。 + /// + int ClearInterval { get; } + + /// + /// 客户端成功连接时 + /// + event RRQMMessageEventHandler ClientConnected; + + /// + /// 有用户断开连接的时候 + /// + event RRQMMessageEventHandler ClientDisconnected; + + /// + /// 根据ID判断SocketClient是否存在 + /// + /// + /// + bool SocketClientExist(string id); + + /// + /// 尝试获取TClient + /// + /// ID + /// TClient + /// + bool TryGetSocketClient(string id, out TClient socketClient); + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + void Send(string id, byte[] buffer); + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + void Send(string id, byte[] buffer, int offset, int length); + + /// + /// 发送流中的有效数据 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + void Send(string id, ByteBlock byteBlock); + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + void SendAsync(string id, byte[] buffer); + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + void SendAsync(string id, byte[] buffer, int offset, int length); + + /// + /// 发送流中的有效数据 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + void SendAsync(string id, ByteBlock byteBlock); + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/IUserClient.cs b/RRQMSocket/Interface/IUserClient.cs new file mode 100644 index 000000000..c5437963d --- /dev/null +++ b/RRQMSocket/Interface/IUserClient.cs @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System; + +namespace RRQMSocket +{ + /// + /// 用户终端接口 + /// + public interface IUserClient + { + /// + /// 连接服务器 + /// + /// + void Connect(); + + /// + /// 异步连接服务器 + /// + /// + /// + void ConnectAsync(Action callback = null); + + /// + /// 配置服务器 + /// + /// + /// + void Setup(TcpClientConfig clientConfig); + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/IUserTcpClient.cs b/RRQMSocket/Interface/IUserTcpClient.cs new file mode 100644 index 000000000..e37908c26 --- /dev/null +++ b/RRQMSocket/Interface/IUserTcpClient.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// TCP客户端终端接口 + /// + public interface IUserTcpClient : ITcpClient, IUserClient + { + /// + /// 仅发送,即不会开启接收线程。 + /// + bool OnlySend { get; } + + /// + /// 客户端配置 + /// + TcpClientConfig ClientConfig { get; } + + /// + /// 断开连接 + /// + void Disconnect(); + } +} \ No newline at end of file diff --git a/RRQMSocket/Interface/_ITcpService.cs b/RRQMSocket/Interface/_ITcpService.cs new file mode 100644 index 000000000..c6bca54b8 --- /dev/null +++ b/RRQMSocket/Interface/_ITcpService.cs @@ -0,0 +1,27 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +{ + /// + /// TCP服务器辅助接口 + /// + public interface _ITcpService : IService + { + /// + /// 重新设置ID + /// + /// + /// + void ResetID(string oldID, string newID); + } +} \ No newline at end of file diff --git a/RRQMSocket/InternalClass/BufferQueue.cs b/RRQMSocket/InternalClass/BufferQueue.cs new file mode 100644 index 000000000..315dc0872 --- /dev/null +++ b/RRQMSocket/InternalClass/BufferQueue.cs @@ -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 System.Collections.Concurrent; + +namespace RRQMSocket +{ + /// + /// buffer队列 + /// + internal class BufferQueue + { + internal BufferQueue() + { + queue = new ConcurrentQueue(); + } + + private ConcurrentQueue queue; + + internal void Enqueue(ClientBuffer item) + { + this.queue.Enqueue(item); + } + + internal bool TryDequeue(out ClientBuffer result) + { + return this.queue.TryDequeue(out result); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/InternalClass/BufferQueueGroup.cs b/RRQMSocket/InternalClass/BufferQueueGroup.cs new file mode 100644 index 000000000..e94855527 --- /dev/null +++ b/RRQMSocket/InternalClass/BufferQueueGroup.cs @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System.Threading; + +namespace RRQMSocket +{ + internal class BufferQueueGroup : IDisposable + { + internal Thread Thread; + internal BufferQueue bufferAndClient; + internal EventWaitHandle waitHandleBuffer; + internal bool isWait; + internal BytePool bytePool; + + public void Dispose() + { + if (bufferAndClient != null) + { + while (bufferAndClient.TryDequeue(out _)) + { + } + } + + if (waitHandleBuffer != null) + { + waitHandleBuffer.Set(); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/InternalClass/ClientBuffer.cs b/RRQMSocket/InternalClass/ClientBuffer.cs new file mode 100644 index 000000000..a3cf7f420 --- /dev/null +++ b/RRQMSocket/InternalClass/ClientBuffer.cs @@ -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.ByteManager; +using System.Net; + +namespace RRQMSocket +{ + /// + /// 处理 + /// + public struct ClientBuffer + { + internal IHandleBuffer client; + internal ByteBlock byteBlock; + internal EndPoint endPoint; + } +} \ No newline at end of file diff --git a/RRQMSocket/InternalClass/SocketCliectCollection.cs b/RRQMSocket/InternalClass/SocketCliectCollection.cs new file mode 100644 index 000000000..7f2cf12b1 --- /dev/null +++ b/RRQMSocket/InternalClass/SocketCliectCollection.cs @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Collections.Generic; +using System.Diagnostics; + +namespace RRQMSocket +{ + /// + /// 客户端集合 + /// + [DebuggerDisplay("Count={Count}")] + public class SocketCliectCollection : IDisposable where T : ISocketClient + { + private RRQMCore.SnowflakeIDGenerator iDGenerator = new RRQMCore.SnowflakeIDGenerator(4); + + /// + /// 数量 + /// + public int Count { get { return this.tokenDic.Count; } } + + private ConcurrentDictionary tokenDic = new ConcurrentDictionary(); + + internal bool TryAdd(T socketClient) + { + return this.tokenDic.TryAdd(socketClient.ID, socketClient); + } + + internal string GetDefaultID() + { + return iDGenerator.NextID().ToString(); + } + + /// + /// 获取ID集合 + /// + /// + public IEnumerable GetIDs() + { + return this.tokenDic.Keys; + } + + internal bool TryRemove(string id) + { + return this.tokenDic.TryRemove(id, out _); + } + + /// + /// 尝试获取实例 + /// + /// + /// + /// + public bool TryGetSocketClient(string id, out T socketClient) + { + return this.tokenDic.TryGetValue(id, out socketClient); + } + + /// + /// 根据ID判断SocketClient是否存在 + /// + /// + /// + public bool SocketClientExist(string id) + { + if (tokenDic.ContainsKey(id)) + { + return true; + } + return false; + } + + /// + /// 获取SocketClient + /// + /// + /// + public T this[string id] + { + get + { + T t; + this.TryGetSocketClient(id, out t); + return t; + } + } + + /// + /// 释放客户端 + /// + public void Dispose() + { + foreach (var item in this.tokenDic.Keys) + { + if (this.tokenDic.TryGetValue(item, out T value)) + { + value.Dispose(); + } + } + this.tokenDic.Clear(); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/LICENSE b/RRQMSocket/LICENSE new file mode 100644 index 000000000..5a9bb6217 --- /dev/null +++ b/RRQMSocket/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license 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. diff --git a/RRQMSocket/Logger/Log.cs b/RRQMSocket/Logger/Log.cs new file mode 100644 index 000000000..4fd0191fa --- /dev/null +++ b/RRQMSocket/Logger/Log.cs @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; + +namespace RRQMSocket +{ + /// + /// 日志记录器 + /// + public class Log : ILog + { + /// + /// 记录日志 + /// + /// + /// + /// + public void Debug(LogType logType, object source, string message) + { + Console.WriteLine($"类型:{logType},消息:{message}"); + } + + /// + /// 记录日志 + /// + /// + /// + /// + /// + public void Debug(LogType logType, object source, string message, Exception exception) + { + Console.WriteLine($"类型:{logType},消息:{message},堆:{exception.StackTrace}"); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/ParameterClass/VerifyOption.cs b/RRQMSocket/ParameterClass/VerifyOption.cs new file mode 100644 index 000000000..991a57b1e --- /dev/null +++ b/RRQMSocket/ParameterClass/VerifyOption.cs @@ -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 +{ + /// + /// Token连接验证 + /// + public class VerifyOption + { + /// + /// 令箭 + /// + public string Token { get; internal set; } + + /// + /// 是否接受 + /// + public bool Accept { get; set; } + + /// + /// 不接受时,返回客户端信息 + /// + public string ErrorMessage { get; set; } + + /// + /// 标记,会同步至TcpSocketClient + /// + public object Flag { get; set; } + } +} \ No newline at end of file diff --git a/RRQMSocket/Pool/Interface/IClientGroup.cs b/RRQMSocket/Pool/Interface/IClientGroup.cs new file mode 100644 index 000000000..c0c05fe4e --- /dev/null +++ b/RRQMSocket/Pool/Interface/IClientGroup.cs @@ -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.Pool +{ + /// + /// 终端组 + /// + public interface IClientGroup + { + } +} \ No newline at end of file diff --git a/RRQMSocket/Pool/Interface/IConnectionPool.cs b/RRQMSocket/Pool/Interface/IConnectionPool.cs new file mode 100644 index 000000000..3c70ba85b --- /dev/null +++ b/RRQMSocket/Pool/Interface/IConnectionPool.cs @@ -0,0 +1,91 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using RRQMCore.Pool; +using System.Collections.Generic; + +namespace RRQMSocket.Pool +{ + /// + /// 连接池接口 + /// + public interface IConnectionPool : IObjectPool where T : IUserTcpClient + { + /// + /// 当池中的客户都端发生错误时 + /// + event RRQMMessageEventHandler OnClientError; + + /// + /// 日志记录器 + /// + ILog Logger { get; set; } + + /// + /// 获取内存池实例 + /// + BytePool BytePool { get; } + + /// + /// 对象池容量 + /// + int Capacity { get; } + + /// + /// 发生错误的客户端列表 + /// + List ErrorClientList { get; } + + /// + /// 获取即将在下一次通信的客户端单体 + /// + /// + T GetNextClient(); + + /// + /// 补充成员 + /// + /// + void Replenish(T client); + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + /// + /// + void Send(byte[] buffer, int offset, int length); + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + void Send(byte[] buffer); + + /// + /// 发送流中的有效数据 + /// + /// + /// + /// + /// + void Send(ByteBlock byteBlock); + } +} \ No newline at end of file diff --git a/RRQMSocket/Pool/TcpConnectionPool.cs b/RRQMSocket/Pool/TcpConnectionPool.cs new file mode 100644 index 000000000..0ae8acc71 --- /dev/null +++ b/RRQMSocket/Pool/TcpConnectionPool.cs @@ -0,0 +1,248 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +//using System; +//using System.Collections.Concurrent; +//using System.Collections.Generic; + +//namespace RRQMSocket.Pool +//{ +// /// +// /// 连接池 +// /// +// public class TcpConnectionPool : IConnectionPool where T : TcpClient +// { +// private TcpConnectionPool() +// { +// this.Logger = new Log(); +// this.ErrorClientList = new List(); +// this.queue = new ConcurrentQueue(); +// } + +// /// +// /// 创建连接池 +// /// +// /// 容量 +// public static TcpConnectionPool CreatConnectionPool(int capacity) +// { +// return CreatConnectionPool(capacity, new BytePool(1024 * 1024 * 1000, 1024 * 1024 * 20), null, null); +// } + +// /// +// /// 创建连接池 +// /// +// /// 容量 +// /// 当每个连接单元被初始化时回调 +// /// +// public static TcpConnectionPool CreatConnectionPool(int capacity, Action onClientIniCallback) +// { +// return CreatConnectionPool(capacity, new BytePool(1024 * 1024 * 1000, 1024 * 1024 * 20), onClientIniCallback, null); +// } + +// /// +// /// 创建连接池 +// /// +// /// 容量 +// /// 指定内存池实例 +// /// 当每个连接单元被初始化时回调 +// /// 创建单元时构造函数参数 +// /// +// public static TcpConnectionPool CreatConnectionPool(int capacity, BytePool bytePool, Action onClientIniCallback, params object[] args) +// { +// if (capacity < 1) +// { +// throw new RRQMException("容量不可小于1"); +// } + +// TcpConnectionPool connectionPool = new TcpConnectionPool(); +// connectionPool.BytePool = bytePool; +// connectionPool.Capacity = capacity; +// for (int i = 0; i < capacity; i++) +// { +// T client = (T)Activator.CreateInstance(typeof(T), args); +// connectionPool.queue.Enqueue(client); +// onClientIniCallback?.Invoke(client); +// } +// return connectionPool; +// } + +// /// +// /// 连接到服务器 +// /// +// /// +// /// 连接成功数 +// public int Connect(IPHost iPHost) +// { +// int count = 0; +// int successCount = 0; +// while (count < this.Capacity) +// { +// T client; +// if (this.queue.TryDequeue(out client)) +// { +// try +// { +// client.Connect(iPHost); +// successCount++; +// } +// finally +// { +// this.queue.Enqueue(client); +// } +// } +// count++; +// } +// return successCount; +// } + +// private ConcurrentQueue queue; + +// /// +// /// 当池中的客户端发生错误时 +// /// +// public event RRQMMessageEventHandler OnClientError; + +// /// +// /// 发生错误的客户端列表 +// /// +// public List ErrorClientList { get; private set; } + +// /// +// /// 对象池容量 +// /// +// public int Capacity { get; private set; } + +// /// +// /// 日志记录器 +// /// +// public ILog Logger { get; set; } + +// /// +// /// 可使用数量 +// /// +// public int FreeSize { get { return this.queue.Count; } } + +// /// +// /// 获取内存池实例 +// /// +// public BytePool BytePool { get; private set; } + +// /// +// /// 获取即将在下一次通信的客户端单体 +// /// +// /// +// public T GetNextClient() +// { +// T client; +// this.queue.TryPeek(out client); +// return client; +// } + +// /// +// /// 补充成员 +// /// +// /// +// public void Replenish(T client) +// { +// this.queue.Enqueue(client); +// this.Capacity++; +// } + +// /// +// /// 发送字节流 +// /// +// /// +// /// +// /// +// /// +// public void Send(byte[] buffer) +// { +// this.Send(buffer, 0, buffer.Length); +// } + +// /// +// /// 发送流中的有效数据 +// /// +// /// +// /// +// /// +// /// +// public void Send(ByteBlock byteBlock) +// { +// this.Send(byteBlock.Buffer, 0, byteBlock.Len); +// } + +// /// +// /// 发送字节流 +// /// +// /// +// /// +// /// +// /// +// /// +// /// +// public void Send(byte[] buffer, int offset, int length) +// { +// int count = 0; +// while (true) +// { +// T client; +// if (this.queue.TryDequeue(out client)) +// { +// try +// { +// client.Send(buffer, offset, length); +// this.queue.Enqueue(client); +// break; +// } +// catch (Exception ex) +// { +// this.ErrorClientList.Add(client); +// Logger.Debug(LogType.Warning, client, ex.Message); +// this.OnClientError?.Invoke(client, new MesEventArgs(ex.Message)); +// } +// } +// if (++count > this.FreeSize) +// { +// throw new RRQMException(); +// } +// } +// } + +// /// +// /// 清空池中对象 +// /// +// public void Clear() +// { +// T client; +// while (this.queue.TryDequeue(out client)) +// { +// client.Dispose(); +// } +// foreach (var item in this.ErrorClientList) +// { +// item.Dispose(); +// } +// this.ErrorClientList.Clear(); +// } + +// /// +// /// 释放资源 +// /// +// public void Dispose() +// { +// this.Clear(); +// } +// } +//} \ No newline at end of file diff --git a/RRQMSocket/RRQM.ico b/RRQMSocket/RRQM.ico new file mode 100644 index 0000000000000000000000000000000000000000..6465fb16e389ed1804d54b368018596580c6672e GIT binary patch literal 249918 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

&cP)Tdhs88a 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 + + net45;netcoreapp3.1;netstandard2.0 + RRQM.ico + true + RRQM.pfx + 5.5.0 + 若汝棋茗 + Copyright © 2021 若汝棋茗 + IOCP,TCP,UDP,Socket + 介绍:RRQMSocket是一个整合性的、超轻量级的网络通信框架。它具有高并发、事件订阅、插件式扩展、自动活性检测、多线程处理等特点,让使用者能够更加简单的、快速的搭建网络框架。 + +更新说明: +优化:架构接口。 +修改:ClearInterval单位由“秒”调整为“毫秒”。 +修改:BufferLength默认值调整为64Kb。 + +API:https://gitee.com/RRQM_OS/RRQM/wikis/pages +Demo:https://gitee.com/RRQM_OS/RRQMBox + https://gitee.com/dotnetchina/RRQMSocket + + true + RRQM.png + 若汝棋茗 + true + LICENSE + + + + bin\Debug\netstandard2.0\RRQMSocket.xml + + + + + bin\Release\netstandard2.0\RRQMSocket.xml + + + + + bin\Debug\net45\RRQMSocket.xml + + + + + bin\Release\net45\RRQMSocket.xml + + + + + bin\Debug\net461\RRQMSocket.xml + + + + + bin\Release\net461\RRQMSocket.xml + + + + + bin\Debug\netcoreapp3.1\RRQMSocket.xml + + + + + bin\Release\netcoreapp3.1\RRQMSocket.xml + + + + + + + + + + + True + + + + True + + + + + + + + diff --git a/RRQMSocket/TCP/Client/ProtocolClient.cs b/RRQMSocket/TCP/Client/ProtocolClient.cs new file mode 100644 index 000000000..b530296e1 --- /dev/null +++ b/RRQMSocket/TCP/Client/ProtocolClient.cs @@ -0,0 +1,325 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace RRQMSocket +{ + ///

+ /// 协议客户端 + /// + public abstract class ProtocolClient : TokenClient + { + private static readonly Dictionary usedProtocol = new Dictionary(); + + private ProcotolHelper procotolHelper; + + private EventWaitHandle waitHandle; + + /// + /// 构造函数 + /// + public ProtocolClient() + { + waitHandle = new AutoResetEvent(false); + } + + /// + /// 释放资源 + /// + public override void Dispose() + { + base.Dispose(); + this.waitHandle.Dispose(); + } + + /// + /// 重新设置ID,并且同步到服务器 + /// + /// + public override void ResetID(string id) + { + this.procotolHelper.SocketSend(0, Encoding.UTF8.GetBytes(id)); + if (this.waitHandle.WaitOne(5000)) + { + return; + } + throw new RRQMException("同步ID超时"); + } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + /// + /// + public sealed override void Send(byte[] buffer, int offset, int length) + { + this.procotolHelper.SocketSend(-1, buffer, offset, length); + } + + /// + /// 发送字节 + /// + /// + /// + public void Send(short procotol, byte[] buffer) + { + this.Send(procotol, buffer, 0, buffer.Length); + } + + /// + /// 发送字节 + /// + /// + /// + /// + /// + public void Send(short procotol, byte[] buffer, int offset, int length) + { + if (!usedProtocol.ContainsKey(procotol)) + { + this.InternalSend(procotol, buffer, offset, length); + } + else + { + StringBuilder stringBuilder = new StringBuilder(); + foreach (var item in usedProtocol.Keys) + { + stringBuilder.AppendLine($"协议{item}已被使用,描述为:{usedProtocol[item]}"); + } + throw new RRQMException(stringBuilder.ToString()); + } + } + + /// + /// 发送协议流 + /// + /// + /// + public void Send(short procotol, ByteBlock dataByteBlock) + { + this.Send(procotol, dataByteBlock.Buffer, 0, (int)dataByteBlock.Length); + } + + /// + /// 发送协议状态 + /// + /// + public void Send(short procotol) + { + this.Send(procotol, new byte[0], 0, 0); + } + + /// + /// 发送字节流(仍然为同步发送) + /// + /// + /// + /// + public sealed override void SendAsync(byte[] buffer, int offset, int length) + { + this.procotolHelper.SocketSendAsync(-1, buffer, offset, length); + } + + /// + /// 发送字节 + /// + /// + /// + /// + /// + public void SendAsync(short procotol, byte[] buffer, int offset, int length) + { + if (!usedProtocol.ContainsKey(procotol)) + { + this.InternalSend(procotol, buffer, offset, length); + } + else + { + StringBuilder stringBuilder = new StringBuilder(); + foreach (var item in usedProtocol.Keys) + { + stringBuilder.AppendLine($"协议{item}已被使用,描述为:{usedProtocol[item]}"); + } + throw new RRQMException(stringBuilder.ToString()); + } + } + + /// + /// 添加已被使用的协议 + /// + /// + /// + protected static void AddUsedProtocol(short procotol, string describe) + { + usedProtocol.Add(procotol, describe); + } + + /// + /// 收到协议数据,由于性能考虑, + /// byteBlock数据源并未剔除协议数据, + /// 所以真实数据起点为2, + /// 长度为Length-2。 + /// + /// + /// + protected abstract void HandleProtocolData(short? procotol, ByteBlock byteBlock); + + /// + /// 密封方法 + /// + /// + /// + protected sealed override void HandleReceivedData(ByteBlock byteBlock, object obj) + { + short procotol = BitConverter.ToInt16(byteBlock.Buffer, 0); + switch (procotol) + { + case 0: + { + try + { + string id = Encoding.UTF8.GetString(byteBlock.Buffer, 2, byteBlock.Len - 2); + base.ResetID(id); + this.waitHandle.Set(); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, "重置ID错误", ex); + } + break; + } + case -1: + { + try + { + HandleProtocolData(null, byteBlock); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, "处理无协议数据异常", ex); + } + break; + } + default: + { + try + { + HandleProtocolData(procotol, byteBlock); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, "处理协议数据异常", ex); + } + break; + } + } + } + + /// + /// 内部发送,不会进行协议检测 + /// + /// + /// + /// + /// + /// + protected void InternalSend(short procotol, byte[] buffer, int offset, int length, bool reserved = false) + { + if (procotol > 0) + { + this.procotolHelper.SocketSend(procotol, buffer, offset, length, reserved); + } + else + { + throw new RRQMException("小等于0的协议为系统使用协议"); + } + } + + /// + /// 内部发送,不会进行协议检测 + /// + /// + /// + /// + protected void InternalSend(short procotol, ByteBlock byteBlock, bool reserved = false) + { + this.InternalSend(procotol, byteBlock.Buffer, 0, byteBlock.Len, reserved); + } + + /// + /// 内部发送,不会进行协议检测 + /// + /// + /// + /// + /// + protected void InternalSendAsync(short procotol, byte[] buffer, int offset, int length) + { + if (procotol > 0) + { + this.procotolHelper.SocketSendAsync(procotol, buffer, offset, length); + } + else + { + throw new RRQMException("小等于0的协议为系统使用协议"); + } + } + + /// + /// 内部发送,不会进行协议检测 + /// + /// + /// + protected void InternalSendAsync(short procotol, ByteBlock byteBlock) + { + this.InternalSendAsync(procotol, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 载入配置,协议客户端数据处理适配器不可更改。 + /// + /// + protected override void LoadConfig(TcpClientConfig clientConfig) + { + base.LoadConfig(clientConfig); + if (clientConfig.DataHandlingAdapter is FixedHeaderDataHandlingAdapter adapter) + { + adapter.FixedHeaderType = FixedHeaderType.Int; + this.SetDataHandlingAdapter(adapter); + } + else + { + this.SetDataHandlingAdapter(new FixedHeaderDataHandlingAdapter()); + } + } + + /// + /// 连接到服务器时 + /// + /// + protected override void OnConnectedService(MesEventArgs e) + { + this.procotolHelper = new ProcotolHelper(this, this.SeparateThreadSend); + base.OnConnectedService(e); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Client/SimpleProtocolClient.cs b/RRQMSocket/TCP/Client/SimpleProtocolClient.cs new file mode 100644 index 000000000..6c09136b9 --- /dev/null +++ b/RRQMSocket/TCP/Client/SimpleProtocolClient.cs @@ -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 RRQMCore.ByteManager; +using System; + +namespace RRQMSocket +{ + /// + /// 协议客户端 + /// + public class SimpleProtocolClient : ProtocolClient + { + /// + /// 接收到数据 + /// + public event Action Received; + + /// + /// 处理协议数据 + /// + /// + /// + protected sealed override void HandleProtocolData(short? procotol, ByteBlock byteBlock) + { + this.Received?.Invoke(procotol, byteBlock); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Client/SimpleTcpClient.cs b/RRQMSocket/TCP/Client/SimpleTcpClient.cs new file mode 100644 index 000000000..470f6607f --- /dev/null +++ b/RRQMSocket/TCP/Client/SimpleTcpClient.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; + +namespace RRQMSocket +{ + /// + /// 简单TCP客户端 + /// + public class SimpleTcpClient : TcpClient + { + /// + /// 接收到数据 + /// + public event Action Received; + + /// + /// 接收数据 + /// + /// + /// + protected sealed override void HandleReceivedData(ByteBlock byteBlock, object obj) + { + OnReceived(byteBlock, obj); + } + + /// + /// 接收到数据 + /// + /// + /// + protected virtual void OnReceived(ByteBlock byteBlock, object obj) + { + this.Received?.Invoke(byteBlock, obj); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Client/SimpleTokenClient.cs b/RRQMSocket/TCP/Client/SimpleTokenClient.cs new file mode 100644 index 000000000..885808065 --- /dev/null +++ b/RRQMSocket/TCP/Client/SimpleTokenClient.cs @@ -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 RRQMCore.ByteManager; +using System; + +namespace RRQMSocket +{ + /// + /// 简单Token客户端 + /// + public class SimpleTokenClient : TokenClient + { + /// + /// 接收到数据 + /// + public event Action Received; + + /// + /// 接收数据 + /// + /// + /// + protected sealed override void HandleReceivedData(ByteBlock byteBlock, object obj) + { + this.Received?.Invoke(byteBlock, obj); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Client/TcpClient.cs b/RRQMSocket/TCP/Client/TcpClient.cs new file mode 100644 index 000000000..5f7ebee4e --- /dev/null +++ b/RRQMSocket/TCP/Client/TcpClient.cs @@ -0,0 +1,636 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace RRQMSocket +{ + /// + /// TCP客户端 + /// + public abstract class TcpClient : BaseSocket, IUserTcpClient, IClient, IHandleBuffer + { + /// + /// 客户端配置 + /// + protected TcpClientConfig clientConfig; + + private AsyncSender asyncSender; + + private BytePool bytePool; + + private DataHandlingAdapter dataHandlingAdapter; + + private Socket mainSocket; + private bool online; + + private bool onlySend; + + private BufferQueueGroup queueGroup; + + private SocketAsyncEventArgs receiveEventArgs; + + private bool separateThreadReceive; + private bool separateThreadSend; + /// + /// 成功连接到服务器 + /// + public event RRQMMessageEventHandler ConnectedService; + + /// + /// 断开连接 + /// + public event RRQMMessageEventHandler DisconnectedService; + + /// + /// 获取内存池实例 + /// + public BytePool BytePool + { + get { return bytePool; } + } + + /// + /// 客户端配置 + /// + public TcpClientConfig ClientConfig + { + get { return clientConfig; } + } + + /// + /// 数据处理适配器 + /// + public DataHandlingAdapter DataHandlingAdapter + { + get { return dataHandlingAdapter; } + } + + /// + /// IPv4地址 + /// + public string IP { get; private set; } + + /// + /// 主通信器 + /// + public Socket MainSocket + { + get { return mainSocket; } + internal set + { + mainSocket = value; + } + } + + /// + /// IP及端口 + /// + public string Name => $"{this.IP}:{this.Port}"; + /// + /// 判断是否已连接 + /// + public bool Online { get { return this.online; } } + + /// + /// 仅发送,即不会开启接收线程。 + /// + public bool OnlySend + { + get { return onlySend; } + } + + /// + /// 端口号 + /// + public int Port { get; private set; } + /// + /// 在异步发送时,使用独立线程发送 + /// + public bool SeparateThreadSend + { + get { return separateThreadSend; } + } + + /// + /// 连接到服务器 + /// + public virtual void Connect() + { + if (this.disposable) + { + throw new RRQMException("无法利用已释放对象"); + } + if (this.clientConfig == null) + { + throw new ArgumentNullException("配置文件不能为空。"); + } + IPHost iPHost = this.clientConfig.RemoteIPHost; + if (iPHost == null) + { + throw new ArgumentNullException("iPHost不能为空。"); + } + if (!this.Online) + { + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + PreviewConnect(socket); + socket.Connect(iPHost.EndPoint); + this.mainSocket = socket; + Start(); + } + } + + /// + /// 异步连接服务器 + /// + /// + public async void ConnectAsync(Action callback = null) + { + await Task.Run(() => + { + try + { + this.Connect(); + if (callback != null) + { + AsyncResult result = new AsyncResult(); + result.Status = true; + callback.Invoke(result); + } + } + catch (Exception ex) + { + if (callback != null) + { + AsyncResult result = new AsyncResult(); + result.Status = false; + result.Message = ex.Message; + callback.Invoke(result); + } + } + }); + } + + /// + /// 断开连接 + /// + public virtual void Disconnect() + { + this.online = false; + if (this.mainSocket != null) + { + this.mainSocket.Dispose(); + } + if (this.queueGroup != null) + { + this.queueGroup.Dispose(); + } + if (this.asyncSender != null) + { + this.asyncSender.Dispose(); + this.asyncSender = null; + } + } + + /// + /// 断开链接并释放资源 + /// + public override void Dispose() + { + this.online = false; + if (this.mainSocket != null) + { + this.mainSocket.Dispose(); + } + if (this.queueGroup != null) + { + this.queueGroup.Dispose(); + } + if (this.asyncSender != null) + { + this.asyncSender.Dispose(); + this.asyncSender = null; + } + base.Dispose(); + } + + /// + /// 处理数据 + /// + public void HandleBuffer(ByteBlock byteBlock) + { + try + { + if (this.dataHandlingAdapter == null) + { + throw new RRQMException("数据处理适配器为空"); + } + this.dataHandlingAdapter.Received(byteBlock); + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, "在处理数据时发生错误", ex); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + public virtual void Send(byte[] buffer) + { + this.Send(buffer, 0, buffer.Length); + } + + /// + /// 发送流中的有效数据 + /// + /// + /// + /// + /// + public virtual void Send(ByteBlock byteBlock) + { + this.Send(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(byte[] buffer, int offset, int length) + { + this.dataHandlingAdapter.Send(buffer, offset, length, false); + } + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + public virtual void SendAsync(byte[] buffer, int offset, int length) + { + this.dataHandlingAdapter.Send(buffer, offset, length, true); + } + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + public virtual void SendAsync(byte[] buffer) + { + this.SendAsync(buffer, 0, buffer.Length); + } + + /// + /// IOCP发送流中的有效数据 + /// + /// + /// + /// + /// + public virtual void SendAsync(ByteBlock byteBlock) + { + this.SendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 配置服务器 + /// + /// + /// + public void Setup(TcpClientConfig clientConfig) + { + this.clientConfig = clientConfig; + this.LoadConfig(this.clientConfig); + } + + /// + /// 禁用发送或接收 + /// + /// + public void Shutdown(SocketShutdown how) + { + if (this.mainSocket != null) + { + mainSocket.Shutdown(how); + } + } + + internal void Start() + { + this.ReadIpPort(); + this.OnConnectedService(new MesEventArgs()); + + if (!this.onlySend) + { + if (this.separateThreadReceive) + { + queueGroup = new BufferQueueGroup(); + queueGroup.Thread = new Thread(BeginHandleBuffer);//处理用户的消息 + queueGroup.waitHandleBuffer = new AutoResetEvent(false); + queueGroup.bufferAndClient = new BufferQueue(); + queueGroup.Thread.IsBackground = true; + queueGroup.Thread.Name = "客户端处理线程"; + queueGroup.Thread.Start(); + } + + this.receiveEventArgs = new SocketAsyncEventArgs(); + this.receiveEventArgs.Completed += EventArgs_Completed; + BeginReceive(); + } + if (this.separateThreadSend) + { + if (this.asyncSender != null) + { + this.asyncSender.Dispose(); + } + this.asyncSender = new AsyncSender(this.MainSocket, this.MainSocket.RemoteEndPoint, this.Logger); + this.asyncSender.SetBufferLength((int)this.clientConfig.GetValue(TcpClientConfig.SeparateThreadSendBufferLengthProperty)); + } + } + + /// + /// 处理已接收到的数据。 + /// 覆盖父类方法将不触发OnReceived事件。 + /// + /// + /// + protected abstract void HandleReceivedData(ByteBlock byteBlock, object obj); + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(TcpClientConfig clientConfig) + { + if (clientConfig == null) + { + throw new RRQMException("配置文件为空"); + } + if (clientConfig.BytePool != null) + { + clientConfig.BytePool.MaxSize = clientConfig.BytePoolMaxSize; + clientConfig.BytePool.MaxBlockSize = clientConfig.BytePoolMaxBlockSize; + this.bytePool = clientConfig.BytePool; + } + else + { + throw new ArgumentNullException("内存池不能为空"); + } + this.logger = (ILog)clientConfig.GetValue(RRQMConfig.LoggerProperty); + this.bufferLength = (int)clientConfig.GetValue(RRQMConfig.BufferLengthProperty); + this.SetDataHandlingAdapter(clientConfig.DataHandlingAdapter); + this.onlySend = clientConfig.OnlySend; + this.separateThreadSend = clientConfig.SeparateThreadSend; + this.separateThreadReceive = clientConfig.SeparateThreadReceive; + } + + /// + /// 连接到服务器 + /// + /// + protected virtual void OnConnectedService(MesEventArgs e) + { + this.online = true; + this.ConnectedService?.Invoke(this, e); + } + + /// + /// 断开连接 + /// + /// + protected virtual void OnDisconnectedService(MesEventArgs e) + { + this.online = false; + this.DisconnectedService?.Invoke(this, e); + } + + /// + /// 在Socket初始化对象后,Connect之前调用。 + /// 可用于设置Socket参数。 + /// 父类方法可覆盖。 + /// + /// + protected virtual void PreviewConnect(Socket socket) + { + } + + /// + /// 设置数据处理适配器 + /// + /// + protected virtual void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + if (adapter == null) + { + throw new RRQMException("数据处理适配器为空"); + } + adapter.BytePool = this.bytePool; + adapter.Logger = this.Logger; + adapter.ReceivedCallBack = this.HandleReceivedData; + adapter.SendCallBack = this.Sent; + this.dataHandlingAdapter = adapter; + } + + private void BeginHandleBuffer() + { + while (true) + { + if (disposable || !this.online) + { + break; + } + ClientBuffer clientBuffer; + if (queueGroup.bufferAndClient.TryDequeue(out clientBuffer)) + { + clientBuffer.client.HandleBuffer(clientBuffer.byteBlock); + } + else + { + queueGroup.isWait = true; + queueGroup.waitHandleBuffer.WaitOne(); + } + } + } + + /// + /// 启动消息接收 + /// + private void BeginReceive() + { + try + { + ByteBlock byteBlock = this.bytePool.GetByteBlock(this.BufferLength); + this.receiveEventArgs.UserToken = byteBlock; + this.receiveEventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Buffer.Length); + if (!this.MainSocket.ReceiveAsync(this.receiveEventArgs)) + { + ProcessReceived(this.receiveEventArgs); + } + } + catch (Exception ex) + { + this.OnDisconnectedService(new MesEventArgs(ex.Message)); + } + } + + private void EventArgs_Completed(object sender, SocketAsyncEventArgs e) + { + try + { + if (e.LastOperation == SocketAsyncOperation.Receive) + { + ProcessReceived(e); + } + else + { + this.OnDisconnectedService(new MesEventArgs("BreakOut")); + } + } + catch (Exception ex) + { + this.OnDisconnectedService(new MesEventArgs(ex.Message)); + } + } + + private void ProcessReceived(SocketAsyncEventArgs e) + { + if (e.SocketError == SocketError.Success && e.BytesTransferred > 0) + { + if (this.separateThreadReceive) + { + ClientBuffer clientBuffer = new ClientBuffer(); + clientBuffer.client = this; + clientBuffer.byteBlock = (ByteBlock)e.UserToken; + clientBuffer.byteBlock.SetLength(e.BytesTransferred); + queueGroup.bufferAndClient.Enqueue(clientBuffer); + if (queueGroup.isWait) + { + queueGroup.isWait = false; + queueGroup.waitHandleBuffer.Set(); + } + } + else + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + this.HandleBuffer(byteBlock); + } + + try + { + ByteBlock newByteBlock = this.bytePool.GetByteBlock(this.bufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length); + + if (!this.MainSocket.ReceiveAsync(e)) + { + ProcessReceived(e); + } + } + catch + { + } + } + else + { + this.OnDisconnectedService(new MesEventArgs("BreakOut")); + } + } + + private void ReadIpPort() + { + if (MainSocket == null) + { + this.IP = null; + this.Port = -1; + return; + } + + string ipport; + if (MainSocket.Connected && MainSocket.RemoteEndPoint != null) + { + ipport = MainSocket.RemoteEndPoint.ToString(); + } + else if (MainSocket.IsBound && MainSocket.LocalEndPoint != null) + { + ipport = MainSocket.LocalEndPoint.ToString(); + } + else + { + return; + } + + int r = ipport.LastIndexOf(":"); + this.IP = ipport.Substring(0, r); + this.Port = Convert.ToInt32(ipport.Substring(r + 1, ipport.Length - (r + 1))); + } + + private void Sent(byte[] buffer, int offset, int length, bool isAsync) + { + if (!this.Online) + { + throw new RRQMNotConnectedException("该实例已断开"); + } + + if (isAsync) + { + if (separateThreadSend) + { + this.asyncSender.AsyncSend(buffer, offset, length); + } + else + { + this.mainSocket.BeginSend(buffer, offset, length, SocketFlags.None, null, null); + } + } + else + { + while (length > 0) + { + int r = MainSocket.Send(buffer, offset, length, SocketFlags.None); + if (r == 0 && length > 0) + { + throw new RRQMException("发送数据不完全"); + } + offset += r; + length -= r; + } + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Client/TokenClient.cs b/RRQMSocket/TCP/Client/TokenClient.cs new file mode 100644 index 000000000..3a2486c48 --- /dev/null +++ b/RRQMSocket/TCP/Client/TokenClient.cs @@ -0,0 +1,163 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Net.Sockets; +using System.Text; +using System.Threading; + +namespace RRQMSocket +{ + /// + /// 需要验证的TCP客户端 + /// + public abstract class TokenClient : TcpClient + { + private string verifyToken = "rrqm"; + + /// + /// 验证令箭 + /// + public string VerifyToken + { + get { return verifyToken; } + } + + private string id; + + /// + /// 获取服务器分配的ID + /// + public string ID + { + get { return id; } + } + + private int verifyTimeout; + + /// + /// 验证超时时间,默认为3000ms; + /// + public int VerifyTimeout + { + get { return verifyTimeout; } + } + + /// + /// 重新设置ID,但是不会同步到服务器 + /// + /// + public virtual void ResetID(string id) + { + this.id = id; + } + + /// + /// 连接到服务器 + /// + /// + /// + /// + public override void Connect() + { + if (this.clientConfig == null) + { + throw new ArgumentNullException("配置文件不能为空。"); + } + IPHost iPHost = this.clientConfig.RemoteIPHost; + if (iPHost == null) + { + throw new ArgumentNullException("iPHost不能为空。"); + } + + if (this.disposable) + { + throw new RRQMException("无法重新利用已释放对象"); + } + + if (this.Online) + { + return; + } + + try + { + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + PreviewConnect(socket); + socket.Connect(iPHost.EndPoint); + this.MainSocket = socket; + this.MainSocket.Send(Encoding.UTF8.GetBytes(this.verifyToken == null ? string.Empty : this.verifyToken)); + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + + int waitCount = 0; + while (waitCount < this.verifyTimeout / 10) + { + if (this.MainSocket.Available > 0) + { + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + try + { + int r = this.MainSocket.Receive(byteBlock.Buffer); + if (r > 0) + { + if (byteBlock.Buffer[0] == 1) + { + this.id = Encoding.UTF8.GetString(byteBlock.Buffer, 1, r - 1); + Start(); + return; + } + else if (byteBlock.Buffer[0] == 2) + { + this.MainSocket.Dispose(); + throw new RRQMTokenVerifyException(Encoding.UTF8.GetString(byteBlock.Buffer, 1, r - 1)); + } + else if (byteBlock.Buffer[0] == 3) + { + this.MainSocket.Dispose(); + throw new RRQMException("连接数量已达到服务器设定最大值"); + } + } + } + finally + { + byteBlock.Dispose(); + } + } + waitCount++; + Thread.Sleep(10); + } + + this.MainSocket.Dispose(); + throw new RRQMTimeoutException("验证Token超时"); + } + + /// + /// 加载配置 + /// + /// + protected override void LoadConfig(TcpClientConfig clientConfig) + { + base.LoadConfig(clientConfig); + this.verifyToken = (string)clientConfig.GetValue(TokenClientConfig.VerifyTokenProperty); + this.verifyTimeout = (int)clientConfig.GetValue(TokenClientConfig.VerifyTimeoutProperty); + if (string.IsNullOrEmpty(this.verifyToken)) + { + this.verifyToken = "rrqm"; + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Service/ProtocolService.cs b/RRQMSocket/TCP/Service/ProtocolService.cs new file mode 100644 index 000000000..4b3097fa2 --- /dev/null +++ b/RRQMSocket/TCP/Service/ProtocolService.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; +using System.Text; + +namespace RRQMSocket +{ + /// + /// 协议服务器 + /// + public abstract class ProtocolService : TokenService where TClient : ProtocolSocketClient, new() + { + private bool canResetID; + + /// + /// 重置ID + /// + /// + /// + public override void ResetID(string oldID, string newID) + { + if (!canResetID) + { + throw new RRQMException("服务器不允许修改ID"); + } + base.ResetID(oldID, newID); + if (this.TryGetSocketClient(newID, out TClient client)) + { + client.procotolHelper.SocketSend(0, Encoding.UTF8.GetBytes(newID)); + } + else + { + throw new RRQMException("新ID不可用,请清理客户端重新修改ID"); + } + } + + /// + /// 加载配置 + /// + /// + protected override void LoadConfig(ServiceConfig serverConfig) + { + base.LoadConfig(serverConfig); + this.canResetID = (bool)serverConfig.GetValue(ProtocolServiceConfig.CanResetIDProperty); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Service/SimpleProtocolService.cs b/RRQMSocket/TCP/Service/SimpleProtocolService.cs new file mode 100644 index 000000000..27c0f66d5 --- /dev/null +++ b/RRQMSocket/TCP/Service/SimpleProtocolService.cs @@ -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.ByteManager; +using System; + +namespace RRQMSocket +{ + /// + /// 简单协议服务器 + /// + public class SimpleProtocolService : ProtocolService + { + /// + /// 处理数据 + /// + public event Action Received; + + /// + /// 成功连接后创建(或从对象池中获得)辅助类, + /// 用户可以在该方法中再进行自定义设置, + /// 但是如果该对象是从对象池获得的话,为避免重复设定某些值, + /// 例如事件等,请先判断CreatOption.NewCreat值再做处理。 + /// + public event Action CreateSocketCliect; + + /// + /// 接收辅助类 + /// + /// + /// + protected override void OnCreateSocketCliect(SimpleProtocolSocketClient tcpSocketClient, CreateOption createOption) + { + this.CreateSocketCliect?.Invoke(tcpSocketClient, createOption); + if (createOption.NewCreate) + { + tcpSocketClient.OnReceived = this.OnReceive; + } + } + + private void OnReceive(SimpleProtocolSocketClient socketClient, short? procotol, ByteBlock byteBlock) + { + this.Received?.Invoke(socketClient, procotol, byteBlock); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Service/SimpleTcpService.cs b/RRQMSocket/TCP/Service/SimpleTcpService.cs new file mode 100644 index 000000000..1892caa68 --- /dev/null +++ b/RRQMSocket/TCP/Service/SimpleTcpService.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; + +namespace RRQMSocket +{ + /// + /// 若汝棋茗内置TCP验证服务器 + /// + public class SimpleTcpService : TcpService + { + /// + /// 处理数据 + /// + public event Action Received; + + /// + /// 成功连接后创建(或从对象池中获得)辅助类, + /// 用户可以在该方法中再进行自定义设置, + /// 但是如果该对象是从对象池获得的话,为避免重复设定某些值, + /// 例如事件等,请先判断CreatOption.NewCreat值再做处理。 + /// + public event Action CreateSocketCliect; + + /// + /// 成功连接后创建(或从对象池中获得)辅助类, + /// 用户可以在该方法中再进行自定义设置, + /// 但是如果该对象是从对象池获得的话,为避免重复设定某些值, + /// 例如事件等,请先判断CreatOption.NewCreat值再做处理。 + /// + /// + /// + protected override void OnCreateSocketCliect(SimpleSocketClient tcpSocketClient, CreateOption creatOption) + { + this.CreateSocketCliect?.Invoke(tcpSocketClient, creatOption); + if (creatOption.NewCreate) + { + tcpSocketClient.OnReceived = this.OnReceive; + } + } + + private void OnReceive(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj) + { + this.Received?.Invoke(socketClient, byteBlock, obj); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Service/SimpleTokenService.cs b/RRQMSocket/TCP/Service/SimpleTokenService.cs new file mode 100644 index 000000000..0451912e7 --- /dev/null +++ b/RRQMSocket/TCP/Service/SimpleTokenService.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; + +namespace RRQMSocket +{ + /// + /// 简单Token服务器 + /// + public class SimpleTokenService : TokenService + { + /// + /// 处理数据 + /// + public event Action Received; + + /// + /// 成功连接后创建(或从对象池中获得)辅助类, + /// 用户可以在该方法中再进行自定义设置, + /// 但是如果该对象是从对象池获得的话,为避免重复设定某些值, + /// 例如事件等,请先判断CreatOption.NewCreat值再做处理。 + /// + public event Action CreateSocketCliect; + + /// + /// 成功连接后创建(或从对象池中获得)辅助类, + /// 用户可以在该方法中再进行自定义设置, + /// 但是如果该对象是从对象池获得的话,为避免重复设定某些值, + /// 例如事件等,请先判断CreatOption.NewCreat值再做处理。 + /// + /// + /// + protected override void OnCreateSocketCliect(SimpleSocketClient tcpSocketClient, CreateOption creatOption) + { + this.CreateSocketCliect?.Invoke(tcpSocketClient, creatOption); + if (creatOption.NewCreate) + { + tcpSocketClient.OnReceived = this.OnReceive; + } + } + + private void OnReceive(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj) + { + this.Received?.Invoke(socketClient, byteBlock, obj); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Service/TcpService.cs b/RRQMSocket/TCP/Service/TcpService.cs new file mode 100644 index 000000000..4a99f5751 --- /dev/null +++ b/RRQMSocket/TCP/Service/TcpService.cs @@ -0,0 +1,655 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using RRQMCore.Pool; +using System; +using System.Collections.Generic; +using System.Net.Sockets; +using System.Threading; + +namespace RRQMSocket +{ + /// + /// TCP服务器 + /// + public abstract class TcpService : BaseSocket, ITcpService, _ITcpService where TClient : SocketClient, new() + { + /// + /// 构造函数 + /// + public TcpService() + { + this.socketClients = new SocketCliectCollection(); + this.socketClientPool = new ObjectPool(); + } + + #region 属性 + + private int clearInterval; + private IPHost[] listenIPHosts; + private Socket[] listenSockets; + private int maxCount; + private string name; + private ServerState serverState; + private ServiceConfig serviceConfig; + private SocketCliectCollection socketClients; + + /// + /// 获取默认内存池 + /// + public BytePool BytePool { get { return BytePool.Default; } } + + /// + /// 获取清理无数据交互的SocketClient,默认60。如果不想清除,可使用-1。 + /// + public int ClearInterval + { + get { return clearInterval; } + } + + /// + /// 获取监听的地址组 + /// + public IPHost[] ListenIPHosts + { + get { return listenIPHosts; } + } + + /// + /// 获取正在监听的socket组 + /// + public Socket[] ListenSockets + { + get { return listenSockets; } + } + + /// + /// 最大可连接数 + /// + public int MaxCount + { + get { return maxCount; } + } + + /// + /// 服务器名称 + /// + public string ServerName + { + get { return name; } + } + + /// + /// 服务器状态 + /// + public ServerState ServerState + { + get { return serverState; } + } + + /// + /// 获取服务器配置 + /// + public ServiceConfig ServiceConfig { get { return serviceConfig; } } + + /// + /// 获取当前连接的所有客户端 + /// + public SocketCliectCollection SocketClients + { + get { return socketClients; } + } + + #endregion 属性 + + #region 变量 + + internal ClearType clearType; + internal bool separateThreadReceive; + internal ObjectPool socketClientPool; + private int backlog; + private BufferQueueGroup[] bufferQueueGroups; + private Thread threadClearClient; + + #endregion 变量 + + #region 事件 + + /// + /// 有用户连接的时候 + /// + public event RRQMMessageEventHandler ClientConnected; + + /// + /// 有用户断开连接的时候 + /// + public event RRQMMessageEventHandler ClientDisconnected; + + /// + /// 在客户端连接时 + /// + /// + /// + protected virtual void OnClientConnected(TClient client, MesEventArgs e) + { + this.ClientConnected?.Invoke(client, e); + } + + /// + /// 客户端断开连接 + /// + /// + /// + protected virtual void OnClientDisconnected(TClient client, MesEventArgs e) + { + this.ClientDisconnected?.Invoke(client, e); + } + + #endregion 事件 + + /// + /// 关闭服务器并释放服务器资源 + /// + public override void Dispose() + { + base.Dispose(); + if (this.listenSockets != null) + { + foreach (var item in this.listenSockets) + { + item.Dispose(); + } + } + this.listenSockets = null; + this.listenIPHosts = null; + + this.SocketClients.Dispose(); + if (bufferQueueGroups != null) + { + foreach (var item in bufferQueueGroups) + { + item.Dispose(); + } + } + + this.serverState = ServerState.Disposed; + } + + /// + /// 重新设置ID + /// + /// + /// + /// + public virtual void ResetID(string oldID, string newID) + { + if (!this.socketClients.TryGetSocketClient(oldID, out TClient client)) + { + throw new RRQMException("oldID不存在"); + } + if (this.socketClients.TryRemove(oldID)) + { + client.id = newID; + if (!this.socketClients.TryAdd(client)) + { + throw new RRQMException("ID重复"); + } + } + else + { + throw new RRQMException("oldID不存在"); + } + } + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + public virtual void Send(string id, byte[] buffer) + { + this.Send(id, buffer, 0, buffer.Length); + } + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(string id, byte[] buffer, int offset, int length) + { + this.SocketClients[id].Send(buffer, offset, length); + } + + /// + /// 发送流中的有效数据 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + public virtual void Send(string id, ByteBlock byteBlock) + { + this.Send(id, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + public virtual void SendAsync(string id, byte[] buffer) + { + this.SendAsync(id, buffer, 0, buffer.Length); + } + + /// + /// 发送字节流 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + /// + /// + public virtual void SendAsync(string id, byte[] buffer, int offset, int length) + { + this.SocketClients[id].SendAsync(buffer, offset, length); + } + + /// + /// 发送流中的有效数据 + /// + /// 用于检索TcpSocketClient + /// + /// + /// + /// + /// + public virtual void SendAsync(string id, ByteBlock byteBlock) + { + this.SendAsync(id, byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 配置服务器 + /// + /// + public virtual void Setup(ServiceConfig serviceConfig) + { + this.serviceConfig = serviceConfig; + this.LoadConfig(serviceConfig); + } + + /// + /// 配置服务器 + /// + /// + public virtual void Setup(int port) + { + TcpServiceConfig serviceConfig = new TcpServiceConfig(); + serviceConfig.ListenIPHosts = new IPHost[] { new IPHost(port) }; + this.Setup(serviceConfig); + } + + /// + /// 根据ID判断SocketClient是否存在 + /// + /// + /// + public bool SocketClientExist(string id) + { + return this.SocketClients.SocketClientExist(id); + } + + /// + /// 启动服务 + /// + /// + /// + /// + public virtual void Start() + { + IPHost[] iPHosts = (IPHost[])this.ServiceConfig.GetValue(ServiceConfig.ListenIPHostsProperty); + if (iPHosts == null) + { + throw new RRQMException("IPHosts为空,无法绑定"); + } + switch (this.serverState) + { + case ServerState.None: + { + this.BeginListen(iPHosts); + this.BeginClearAndHandle(); + break; + } + case ServerState.Running: + { + return; + } + case ServerState.Stopped: + { + this.BeginListen(iPHosts); + break; + } + case ServerState.Disposed: + { + throw new RRQMException("无法重新利用已释放对象"); + } + } + this.listenIPHosts = iPHosts; + this.serverState = ServerState.Running; + } + + /// + /// 停止服务器,可重新启动 + /// + public virtual void Stop() + { + if (listenSockets != null) + { + foreach (var item in listenSockets) + { + item.Dispose(); + } + } + this.listenSockets = null; + this.listenIPHosts = null; + + this.SocketClients.Dispose(); + + this.serverState = ServerState.Stopped; + } + + /// + /// 尝试获取TClient + /// + /// ID + /// TClient + /// + public bool TryGetSocketClient(string id, out TClient socketClient) + { + return this.socketClients.TryGetSocketClient(id, out socketClient); + } + + internal virtual void PreviewCreateSocketCliect(Socket socket, BufferQueueGroup queueGroup) + { + try + { + if (this.SocketClients.Count > this.maxCount) + { + this.Logger.Debug(LogType.Error, this, "连接客户端数量已达到设定最大值"); + socket.Close(); + socket.Dispose(); + return; + } + + TClient client = this.socketClientPool.GetObject(); + if (client.NewCreate) + { + client.queueGroup = queueGroup; + client.Service = this; + client.logger = this.Logger; + client.clearType = this.clearType; + client.separateThreadReceive = this.separateThreadReceive; + } + + client.MainSocket = socket; + client.ReadIpPort(); + client.bufferLength = this.BufferLength; + + CreateOption creatOption = new CreateOption(); + creatOption.NewCreate = client.NewCreate; + + creatOption.ID = this.SocketClients.GetDefaultID(); + + this.OnCreateSocketCliect(client, creatOption); + client.id = creatOption.ID; + + if (!this.socketClients.TryAdd(client)) + { + throw new RRQMException("ID重复"); + } + + client.BeginReceive(); + OnClientConnected(client, null); + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, $"在接收客户端时发生错误,信息:{ex.Message}"); + } + } + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(ServiceConfig serviceConfig) + { + if (serviceConfig == null) + { + throw new RRQMException("配置文件为空"); + } + this.maxCount = (int)serviceConfig.GetValue(TcpServiceConfig.MaxCountProperty); + this.clearInterval = (int)serviceConfig.GetValue(TcpServiceConfig.ClearIntervalProperty); + this.backlog = (int)serviceConfig.GetValue(TcpServiceConfig.BacklogProperty); + this.logger = (ILog)serviceConfig.GetValue(RRQMConfig.LoggerProperty); + this.bufferLength = (int)serviceConfig.GetValue(RRQMConfig.BufferLengthProperty); + this.name = serviceConfig.ServerName; + this.clearType = (ClearType)serviceConfig.GetValue(TcpServiceConfig.ClearTypeProperty); + this.separateThreadReceive = serviceConfig.SeparateThreadReceive; + this.socketClientPool.Capacity = this.maxCount; + } + + /// + /// 成功连接后创建(或从对象池中获得)辅助类, + /// 用户可以在该方法中再进行自定义设置, + /// 但是如果该对象是从对象池获得的话,为避免重复设定某些值, + /// 例如事件等,请先判断CreatOption.NewCreate值再做处理。 + /// + /// + /// + protected abstract void OnCreateSocketCliect(TClient socketClient, CreateOption createOption); + + /// + /// 在Socket初始化对象后,Bind之前调用。 + /// 可用于设置Socket参数。 + /// 父类方法可覆盖。 + /// + /// + protected virtual void PreviewBind(Socket socket) + { + } + + private void Args_Completed(object sender, SocketAsyncEventArgs e) + { + if (e.LastOperation == SocketAsyncOperation.Accept) + { + ProcessAccept(e); + } + } + + private void BeginClearAndHandle() + { + threadClearClient = new Thread(ClearClient); + threadClearClient.IsBackground = true; + threadClearClient.Name = "ClearClient"; + threadClearClient.Start(); + + this.bufferQueueGroups = new BufferQueueGroup[this.ServiceConfig.ThreadCount]; + for (int i = 0; i < this.ServiceConfig.ThreadCount; i++) + { + BufferQueueGroup bufferQueueGroup = new BufferQueueGroup(); + bufferQueueGroup.bytePool = new BytePool(this.ServiceConfig.BytePoolMaxSize, this.ServiceConfig.BytePoolMaxBlockSize); + bufferQueueGroups[i] = bufferQueueGroup; + + if (this.separateThreadReceive) + { + bufferQueueGroup.Thread = new Thread(Handle);//处理用户的消息 + bufferQueueGroup.waitHandleBuffer = new AutoResetEvent(false); + bufferQueueGroup.bufferAndClient = new BufferQueue(); + bufferQueueGroup.Thread.IsBackground = true; + bufferQueueGroup.Thread.Name = i + "-Num Handler"; + bufferQueueGroup.Thread.Start(bufferQueueGroup); + } + } + } + + private void BeginListen(IPHost[] iPHosts) + { + try + { + this.listenSockets = new Socket[iPHosts.Length]; + int i = 0; + foreach (var iPHost in iPHosts) + { + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + this.listenSockets[i++] = socket; + PreviewBind(socket); + socket.Bind(iPHost.EndPoint); + socket.Listen(this.backlog); + } + } + catch (Exception ex) + { + throw ex; + } + + foreach (var socket in this.listenSockets) + { + SocketAsyncEventArgs e = new SocketAsyncEventArgs(); + e.UserToken = socket; + e.Completed += this.Args_Completed; + if (!socket.AcceptAsync(e)) + { + ProcessAccept(e); + } + } + } + + private void ClearClient() + { + while (true) + { + Thread.Sleep(1000); + if (disposable) + { + break; + } + else + { + long tick = DateTime.Now.Ticks / 10000000; + IEnumerable collection = this.SocketClients.GetIDs(); + foreach (var token in collection) + { + if (this.SocketClients.TryGetSocketClient(token, out TClient client)) + { + if (this.clearInterval > 0) + { + client.GetTimeout(this.clearInterval / 1000, tick); + } + + if (client.breakOut) + { + try + { + client.Dispose(); + if (this.SocketClients.TryRemove(token)) + { + this.socketClientPool.DestroyObject(client); + this.OnClientDisconnected(client, new MesEventArgs("breakOut")); + } + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, $"在检验客户端时发生错误,信息:{ex.Message}"); + } + } + } + } + } + } + } + + private void Handle(object o) + { + BufferQueueGroup queueGroup = (BufferQueueGroup)o; + while (true) + { + if (disposable) + { + break; + } + ClientBuffer clientBuffer; + if (queueGroup.bufferAndClient.TryDequeue(out clientBuffer)) + { + clientBuffer.client.HandleBuffer(clientBuffer.byteBlock); + } + else + { + queueGroup.isWait = true; + queueGroup.waitHandleBuffer.WaitOne(); + } + } + } + + private void ProcessAccept(SocketAsyncEventArgs e) + { + try + { + if (!this.disposable) + { + if (e.SocketError == SocketError.Success && e.AcceptSocket != null) + { + try + { + Socket newSocket = e.AcceptSocket; + PreviewCreateSocketCliect(newSocket, this.bufferQueueGroups[this.SocketClients.Count % this.bufferQueueGroups.Length]); + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, "接收新连接错误", ex); + } + } + e.AcceptSocket = null; + if (!((Socket)e.UserToken).AcceptAsync(e)) + { + ProcessAccept(e); + } + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/Service/TokenService.cs b/RRQMSocket/TCP/Service/TokenService.cs new file mode 100644 index 000000000..8c91a0213 --- /dev/null +++ b/RRQMSocket/TCP/Service/TokenService.cs @@ -0,0 +1,173 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace RRQMSocket +{ + /// + /// 需要验证的TCP服务器 + /// + public abstract class TokenService : TcpService where TClient : SocketClient, new() + { + private string verifyToken; + + /// + /// 连接令箭 + /// + public string VerifyToken + { + get { return verifyToken; } + } + + private int verifyTimeout; + + /// + /// 验证超时时间,默认为3000ms + /// + public int VerifyTimeout + { + get { return verifyTimeout; } + } + + /// + /// 载入配置 + /// + /// + protected override void LoadConfig(ServiceConfig ServiceConfig) + { + base.LoadConfig(ServiceConfig); + this.verifyTimeout = (int)ServiceConfig.GetValue(TokenServiceConfig.VerifyTimeoutProperty); + this.verifyToken = (string)ServiceConfig.GetValue(TokenServiceConfig.VerifyTokenProperty); + if (string.IsNullOrEmpty(this.verifyToken)) + { + this.verifyToken = "rrqm"; + } + } + + internal override void PreviewCreateSocketCliect(Socket socket, BufferQueueGroup queueGroup) + { + Task.Run(async () => + { + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + int waitCount = 0; + while (waitCount < this.verifyTimeout/ 10) + { + if (socket.Available > 0) + { + try + { + int r = socket.Receive(byteBlock.Buffer); + + VerifyOption verifyOption = new VerifyOption(); + verifyOption.Token = Encoding.UTF8.GetString(byteBlock.Buffer, 0, r); + this.OnVerifyToken(verifyOption); + + if (verifyOption.Accept) + { + if (this.SocketClients.Count > this.MaxCount) + { + byteBlock.Write((byte)3); + this.Logger.Debug(LogType.Error, this, "连接客户端数量已达到设定最大值"); + socket.Send(byteBlock.Buffer, 0, 1, SocketFlags.None); + socket.Dispose(); + return; + } + else + { + TClient client = this.socketClientPool.GetObject(); + client.Flag = verifyOption.Flag; + if (client.NewCreate) + { + client.queueGroup = queueGroup; + client.Service = this; + client.logger = this.Logger; + client.clearType = this.clearType; + client.separateThreadReceive = this.separateThreadReceive; + } + client.MainSocket = socket; + client.ReadIpPort(); + client.bufferLength = this.bufferLength; + + CreateOption creatOption = new CreateOption(); + creatOption.NewCreate = client.NewCreate; + + creatOption.ID = this.SocketClients.GetDefaultID(); + + this.OnCreateSocketCliect(client, creatOption); + client.id = creatOption.ID; + + if (!this.SocketClients.TryAdd(client)) + { + throw new RRQMException("ID重复"); + } + + client.BeginReceive(); + byteBlock.Write((byte)1); + byteBlock.Write(Encoding.UTF8.GetBytes(client.ID)); + socket.Send(byteBlock.Buffer, 0, byteBlock.Len, SocketFlags.None); + OnClientConnected(client, null); + + return; + } + } + else + { + byteBlock.Write((byte)2); + if (verifyOption.ErrorMessage != null) + { + byteBlock.Write(Encoding.UTF8.GetBytes(verifyOption.ErrorMessage)); + } + socket.Send(byteBlock.Buffer, 0, byteBlock.Len, SocketFlags.None); + socket.Dispose(); + return; + } + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, $"在验证客户端连接时发生错误,信息:{ex.Message}"); + } + finally + { + byteBlock.Dispose(); + } + } + waitCount++; + await Task.Delay(10); + } + + socket.Dispose(); + }); + } + + /// + /// 当验证Token时 + /// + /// + protected virtual void OnVerifyToken(VerifyOption verifyOption) + { + if (verifyOption.Token == this.verifyToken) + { + verifyOption.Accept = true; + } + else + { + verifyOption.ErrorMessage = "Token不受理"; + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/SocketClient/ProtocolSocketClient.cs b/RRQMSocket/TCP/SocketClient/ProtocolSocketClient.cs new file mode 100644 index 000000000..1df22d1e7 --- /dev/null +++ b/RRQMSocket/TCP/SocketClient/ProtocolSocketClient.cs @@ -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.Exceptions; +using RRQMCore.Log; +using System; +using System.Collections.Generic; +using System.Text; + +namespace RRQMSocket +{ + /// + /// 协议辅助类 + /// + public abstract class ProtocolSocketClient : SocketClient + { + /// + /// 辅助发送器 + /// + internal ProcotolHelper procotolHelper; + + private static readonly Dictionary usedProtocol = new Dictionary(); + + /// + /// 发送字节 + /// + /// + /// + public void Send(short procotol, byte[] buffer) + { + this.Send(procotol, buffer, 0, buffer.Length); + } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + /// + /// + public sealed override void Send(byte[] buffer, int offset, int length) + { + this.procotolHelper.SocketSend(-1, buffer, offset, length); + } + + /// + /// 发送字节 + /// + /// + /// + /// + /// + public void Send(short procotol, byte[] buffer, int offset, int length) + { + if (!usedProtocol.ContainsKey(procotol)) + { + this.InternalSend(procotol, buffer, offset, length); + } + else + { + StringBuilder stringBuilder = new StringBuilder(); + foreach (var item in usedProtocol.Keys) + { + stringBuilder.AppendLine($"协议{item}已被使用,描述为:{usedProtocol[item]}"); + } + throw new RRQMException(stringBuilder.ToString()); + } + } + + /// + /// 发送协议流 + /// + /// + /// + public void Send(short procotol, ByteBlock dataByteBlock) + { + this.Send(procotol, dataByteBlock.Buffer, 0, (int)dataByteBlock.Length); + } + + /// + /// 发送协议状态 + /// + /// + public void Send(short procotol) + { + this.Send(procotol, new byte[0], 0, 0); + } + + /// + /// 发送字节流(仍然为同步发送) + /// + /// + /// + /// + public sealed override void SendAsync(byte[] buffer, int offset, int length) + { + this.procotolHelper.SocketSend(-1, buffer, offset, length); + } + + /// + /// 发送字节 + /// + /// + /// + /// + /// + public void SendAsync(short procotol, byte[] buffer, int offset, int length) + { + if (!usedProtocol.ContainsKey(procotol)) + { + this.InternalSend(procotol, buffer, offset, length); + } + else + { + StringBuilder stringBuilder = new StringBuilder(); + foreach (var item in usedProtocol.Keys) + { + stringBuilder.AppendLine($"协议{item}已被使用,描述为:{usedProtocol[item]}"); + } + throw new RRQMException(stringBuilder.ToString()); + } + } + + /// + /// 发送字节 + /// + /// + /// + public void SocketSend(short procotol, byte[] dataBuffer) + { + this.Send(procotol, dataBuffer, 0, dataBuffer.Length); + } + + /// + /// 添加已被使用的协议 + /// + /// + /// + protected static void AddUsedProtocol(short procotol, string describe) + { + usedProtocol.Add(procotol, describe); + } + + /// + /// 收到协议数据,由于性能考虑, + /// byteBlock数据源并未剔除协议数据, + /// 所以真实数据起点为2, + /// 长度为Length-2。 + /// + /// + /// + protected abstract void HandleProtocolData(short? procotol, ByteBlock byteBlock); + + /// + /// 密封方法 + /// + /// + /// + protected sealed override void HandleReceivedData(ByteBlock byteBlock, object obj) + { + short procotol = BitConverter.ToInt16(byteBlock.Buffer, 0); + switch (procotol) + { + case 0: + { + try + { + string id = Encoding.UTF8.GetString(byteBlock.Buffer, 2, byteBlock.Len - 2); + base.ResetID(id); + this.procotolHelper.SocketSend(0, Encoding.UTF8.GetBytes(this.id)); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, "重置ID错误", ex); + } + + break; + } + case -1: + { + try + { + byte[] data = new byte[byteBlock.Len - 2]; + byteBlock.Position = 2; + byteBlock.Read(data); + HandleProtocolData(null, byteBlock); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, "处理无协议数据异常", ex); + } + break; + } + default: + { + HandleProtocolData(procotol, byteBlock); + break; + } + } + } + + /// + /// 内部发送,不会进行协议检测 + /// + /// + /// + /// + /// + /// + protected void InternalSend(short procotol, byte[] buffer, int offset, int length, bool reserved = false) + { + if (procotol > 0) + { + this.procotolHelper.SocketSend(procotol, buffer, offset, length, reserved); + } + else + { + throw new RRQMException("小等于0的协议为系统使用协议"); + } + } + + /// + /// 内部发送,不会进行协议检测 + /// + /// + /// + /// + protected void InternalSend(short procotol, ByteBlock byteBlock, bool reserved = false) + { + this.InternalSend(procotol, byteBlock.Buffer, 0, byteBlock.Len, reserved); + } + + /// + /// 接收之前 + /// + protected override void OnBeforeReceive() + { + base.OnBeforeReceive(); + this.procotolHelper = new ProcotolHelper(this, false); + if (this.DataHandlingAdapter is FixedHeaderDataHandlingAdapter adapter) + { + adapter.FixedHeaderType = FixedHeaderType.Int; + } + else + { + this.SetDataHandlingAdapter(new FixedHeaderDataHandlingAdapter()); + } + } + + /// + /// 重新设置ID + /// + /// + protected override void ResetID(string id) + { + this.Service.ResetID(this.id, id); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/SocketClient/SimpleProtocolSocketClient.cs b/RRQMSocket/TCP/SocketClient/SimpleProtocolSocketClient.cs new file mode 100644 index 000000000..52fc0bce8 --- /dev/null +++ b/RRQMSocket/TCP/SocketClient/SimpleProtocolSocketClient.cs @@ -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 RRQMCore.ByteManager; +using System; + +namespace RRQMSocket +{ + /// + /// SimpleProtocolSocketClient + /// + public class SimpleProtocolSocketClient : ProtocolSocketClient + { + /// + /// 收到消息 + /// + public Action OnReceived; + + /// + /// 处理协议数据 + /// + /// + /// + protected override void HandleProtocolData(short? procotol, ByteBlock byteBlock) + { + this.OnReceived.Invoke(this, procotol, byteBlock); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/SocketClient/SimpleSocketClient.cs b/RRQMSocket/TCP/SocketClient/SimpleSocketClient.cs new file mode 100644 index 000000000..30e8d6335 --- /dev/null +++ b/RRQMSocket/TCP/SocketClient/SimpleSocketClient.cs @@ -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 RRQMCore.ByteManager; +using System; + +namespace RRQMSocket +{ + /// + /// 服务器辅助类 + /// + public class SimpleSocketClient : SocketClient + { + /// + /// 收到消息 + /// + public Action OnReceived; + + /// + /// 处理数据 + /// + /// + /// + protected sealed override void HandleReceivedData(ByteBlock byteBlock, object obj) + { + this.OnReceived?.Invoke(this, byteBlock, obj); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/TCP/SocketClient/SocketClient.cs b/RRQMSocket/TCP/SocketClient/SocketClient.cs new file mode 100644 index 000000000..ea34a9994 --- /dev/null +++ b/RRQMSocket/TCP/SocketClient/SocketClient.cs @@ -0,0 +1,545 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using RRQMCore.Pool; +using System; +using System.Net.Sockets; + +namespace RRQMSocket +{ + /// + /// 服务器辅助类 + /// + public abstract class SocketClient : BaseSocket, ISocketClient, IHandleBuffer, IPoolObject + { + internal bool breakOut; + internal ClearType clearType; + internal string id; + internal long lastTick; + internal BufferQueueGroup queueGroup; + internal bool separateThreadReceive; + private DataHandlingAdapter dataHandlingAdapter; + private SocketAsyncEventArgs eventArgs; + private Socket mainSocket; + + /// + /// 获取内存池实例 + /// + public BytePool BytePool { get { return this.queueGroup == null ? null : this.queueGroup.bytePool; } } + + /// + /// 数据处理适配器 + /// + public DataHandlingAdapter DataHandlingAdapter + { + get { return dataHandlingAdapter; } + } + + /// + /// 标记 + /// + public object Flag { get; set; } + + /// + /// 用于索引的ID + /// + public string ID + { + get { return id; } + } + + /// + /// IPv4地址 + /// + public string IP { get; protected set; } + + /// + /// 主通信器 + /// + public Socket MainSocket + { + get { return mainSocket; } + internal set + { + mainSocket = value; + } + } + + /// + /// IP及端口 + /// + public string Name => $"{this.IP}:{this.Port}"; + + /// + /// 是否为新建对象 + /// + public bool NewCreate { get; set; } + + /// + /// 判断该实例是否还在线 + /// + public bool Online { get { return !this.breakOut; } } + + /// + /// 端口号 + /// + public int Port { get; protected set; } + + /// + /// 包含此辅助类的主服务器类 + /// + public _ITcpService Service { get; internal set; } + + /// + /// 初次创建对象,效应相当于构造函数,父类方法可覆盖 + /// + public virtual void Create() + { + + } + + /// + /// 在断开连接时销毁对象,父类方法不可覆盖 + /// + public virtual void Destroy() + { + this.MainSocket = null; + this.dataHandlingAdapter = null; + } + + /// + /// 完全释放资源 + /// + public override void Dispose() + { + base.Dispose(); + if (this.mainSocket != null) + { + this.mainSocket.Dispose(); + } + if (this.eventArgs != null) + { + this.eventArgs.Dispose(); + this.eventArgs = null; + } + this.breakOut = true; + } + + /// + /// 处理数据 + /// + /// + public void HandleBuffer(ByteBlock byteBlock) + { + try + { + if (this.dataHandlingAdapter == null) + { + throw new RRQMException("数据处理适配器为空"); + } + this.dataHandlingAdapter.Received(byteBlock); + } + catch (Exception ex) + { + Logger.Debug(LogType.Error, this, "在处理数据时发生错误", ex); + } + finally + { + byteBlock.Dispose(); + } + } + + /// + /// 读取IP、Port + /// + public void ReadIpPort() + { + if (MainSocket == null) + { + this.IP = null; + this.Port = -1; + return; + } + + string ipport; + if (MainSocket.Connected && MainSocket.RemoteEndPoint != null) + { + ipport = MainSocket.RemoteEndPoint.ToString(); + } + else if (MainSocket.IsBound && MainSocket.LocalEndPoint != null) + { + ipport = MainSocket.LocalEndPoint.ToString(); + } + else + { + return; + } + + int r = ipport.LastIndexOf(":"); + this.IP = ipport.Substring(0, r); + this.Port = Convert.ToInt32(ipport.Substring(r + 1, ipport.Length - (r + 1))); + } + + /// + /// 重新获取,父类方法不可覆盖 + /// + public virtual void Recreate() + { + this.breakOut = false; + this.disposable = false; + } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + public virtual void Send(byte[] buffer) + { + this.Send(buffer, 0, buffer.Length); + } + + /// + /// 发送字节流 + /// + /// + /// + /// + /// + /// + /// + public virtual void Send(byte[] buffer, int offset, int length) + { + this.dataHandlingAdapter.Send(buffer, offset, length, false); + } + + /// + /// 发送流中的有效数据 + /// + /// + /// + /// + /// + public virtual void Send(ByteBlock byteBlock) + { + this.Send(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + public virtual void SendAsync(byte[] buffer, int offset, int length) + { + this.dataHandlingAdapter.Send(buffer, offset, length, true); + } + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + public virtual void SendAsync(byte[] buffer) + { + this.SendAsync(buffer, 0, buffer.Length); + } + + /// + /// IOCP发送流中的有效数据 + /// + /// + /// + /// + /// + public virtual void SendAsync(ByteBlock byteBlock) + { + this.SendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 设置数据处理适配器 + /// + /// + public virtual void SetDataHandlingAdapter(DataHandlingAdapter adapter) + { + if (adapter == null) + { + throw new RRQMException("数据处理适配器为空"); + } + adapter.BytePool = this.BytePool; + adapter.Logger = this.Logger; + adapter.ReceivedCallBack = this.HandleReceivedData; + adapter.SendCallBack = this.Sent; + this.dataHandlingAdapter = adapter; + } + + /// + /// 禁用发送或接收 + /// + /// + public void Shutdown(SocketShutdown how) + { + this.breakOut = true; + if (this.MainSocket != null) + { + MainSocket.Shutdown(how); + } + } + + /// + /// 启动消息接收 + /// + internal void BeginReceive() + { + try + { + this.OnBeforeReceive(); + eventArgs = new SocketAsyncEventArgs(); + eventArgs.Completed += this.EventArgs_Completed; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + eventArgs.UserToken = byteBlock; + eventArgs.SetBuffer(byteBlock.Buffer, 0, byteBlock.Buffer.Length); + if (!MainSocket.ReceiveAsync(eventArgs)) + { + ProcessReceived(eventArgs); + } + this.lastTick = DateTime.Now.Ticks; + } + catch + { + this.breakOut = true; + } + } + + /// + /// 测试是否在线 + /// + internal void GetTimeout(int time, long nowTick) + { + if (nowTick - this.lastTick / 10000000 > time) + { + this.breakOut = true; + } + + try + { + this.OnPerSecond(); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, $"在{nameof(OnPerSecond)}中发生异常", ex); + } + } + + /// + /// 处理已接收到的数据 + /// + /// + /// + protected abstract void HandleReceivedData(ByteBlock byteBlock, object obj); + + /// + /// 在接收之前 + /// + protected virtual void OnBeforeReceive() + { + if (this.dataHandlingAdapter == null) + { + this.SetDataHandlingAdapter(new NormalDataHandlingAdapter()); + } + } + + /// + /// 每一秒执行 + /// + protected virtual void OnPerSecond() + { + } + + /// + /// 重新设置ID + /// + /// + protected virtual void ResetID(string id) + { + this.Service.ResetID(this.id, id); + } + + /// + /// 等待接收 + /// + protected virtual void WaitReceive() + { + } + + private void EventArgs_Completed(object sender, SocketAsyncEventArgs e) + { + try + { + if (e.LastOperation == SocketAsyncOperation.Receive) + { + ProcessReceived(e); + } + else if (e.LastOperation == SocketAsyncOperation.Send) + { + ProcessSend(e); + } + else + { + this.breakOut = true; + } + } + catch + { + this.breakOut = true; + } + } + + private void ProcessReceived(SocketAsyncEventArgs e) + { + if (!this.disposable) + { + if (e.SocketError == SocketError.Success && e.BytesTransferred > 0) + { + if (this.clearType.HasFlag(ClearType.Receive)) + { + this.lastTick = DateTime.Now.Ticks; + } + + if (this.separateThreadReceive) + { + ClientBuffer clientBuffer = new ClientBuffer(); + clientBuffer.client = this; + clientBuffer.byteBlock = (ByteBlock)e.UserToken; + clientBuffer.byteBlock.SetLength(e.BytesTransferred); + queueGroup.bufferAndClient.Enqueue(clientBuffer); + if (queueGroup.isWait) + { + queueGroup.isWait = false; + queueGroup.waitHandleBuffer.Set(); + } + } + else + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + this.HandleBuffer(byteBlock); + } + + try + { + WaitReceive(); + } + catch (Exception ex) + { + this.Logger.Debug(LogType.Error, this, ex.Message); + } + try + { + ByteBlock newByteBlock = this.BytePool.GetByteBlock(this.BufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length); + + if (!MainSocket.ReceiveAsync(e)) + { + ProcessReceived(e); + } + } + catch + { + } + } + else + { + this.breakOut = true; + } + } + else + { + this.breakOut = true; + } + } + + /// + /// 发送完成时处理函数 + /// + /// 与发送完成操作相关联的SocketAsyncEventArg对象 + private void ProcessSend(SocketAsyncEventArgs e) + { + if (e.SocketError == SocketError.Success) + { + e.Dispose(); + } + else + { + this.Logger.Debug(LogType.Error, this, "异步发送错误。"); + } + } + + private void Sent(byte[] buffer, int offset, int length, bool isAsync) + { + if (!this.Online) + { + throw new RRQMNotConnectedException("该实例已断开"); + } + try + { + if (isAsync) + { + SocketAsyncEventArgs sendEventArgs = new SocketAsyncEventArgs(); + sendEventArgs.Completed += EventArgs_Completed; + sendEventArgs.SetBuffer(buffer, offset, length); + sendEventArgs.RemoteEndPoint = this.MainSocket.RemoteEndPoint; + if (!this.MainSocket.SendAsync(sendEventArgs)) + { + // 同步发送时处理发送完成事件 + this.ProcessSend(sendEventArgs); + } + } + else + { + int r = 0; + while (length > 0) + { + r = MainSocket.Send(buffer, offset, length, SocketFlags.None); + if (r == 0 && length > 0) + { + throw new RRQMException("发送数据不完全"); + } + offset += r; + length -= r; + } + } + + if (this.clearType.HasFlag(ClearType.Send)) + { + this.lastTick = DateTime.Now.Ticks; + } + } + catch (Exception e) + { + throw new RRQMException(e.Message); + } + } + } +} \ No newline at end of file diff --git a/RRQMSocket/UDP/SimpleUdpSession.cs b/RRQMSocket/UDP/SimpleUdpSession.cs new file mode 100644 index 000000000..d4888d500 --- /dev/null +++ b/RRQMSocket/UDP/SimpleUdpSession.cs @@ -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 RRQMCore.ByteManager; +using System.Net; + +namespace RRQMSocket +{ + /// + /// 若汝棋茗内置UDP会话 + /// + public class SimpleUdpSession : UdpSession + { + /// + /// 当收到数据时 + /// + public event RRQMUDPByteBlockEventHandler Received; + + /// + /// 处理数据 + /// + /// + /// + protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock) + { + Received?.Invoke(remoteEndPoint, byteBlock); + } + } +} \ No newline at end of file diff --git a/RRQMSocket/UDP/UdpSession.cs b/RRQMSocket/UDP/UdpSession.cs new file mode 100644 index 000000000..d583cbd51 --- /dev/null +++ b/RRQMSocket/UDP/UdpSession.cs @@ -0,0 +1,496 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Log; +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace RRQMSocket +{ + /// + /// TCP服务器 + /// + public abstract class UdpSession : BaseSocket, IService, IClient + { + internal bool separateThreadReceive; + + private BufferQueueGroup[] bufferQueueGroups; + + private EndPoint defaultRemotePoint; + + private Socket mainSocket; + + private string name; + + private long recivedCount; + + private SocketAsyncEventArgs recviveEventArg; + + private ServiceConfig serverConfig; + + private ServerState serverState; + + /// + /// 获取默认内存池 + /// + public BytePool BytePool { get { return BytePool.Default; } } + + /// + /// 默认远程节点 + /// + public EndPoint DefaultRemotePoint + { + get { return defaultRemotePoint; } + } + + /// + /// IPv4地址 + /// + public string IP { get; private set; } + + /// + /// 主通信器 + /// + public Socket MainSocket + { + get { return mainSocket; } + internal set + { + mainSocket = value; + } + } + + /// + /// IP及端口号 + /// + public string Name { get { return $"{this.IP}:{this.Port}"; } } + + /// + /// 端口号 + /// + public int Port { get; private set; } + + /// + /// 服务器名称 + /// + public string ServerName + { + get { return name; } + } + + /// + /// 获取服务器状态 + /// + public ServerState ServerState + { + get { return serverState; } + } + + /// + /// 获取配置 + /// + public ServiceConfig ServiceConfig + { + get { return serverConfig; } + } + + /// + /// 关闭服务器并释放服务器资源 + /// + public override void Dispose() + { + base.Dispose(); + this.Stop(); + if (this.bufferQueueGroups != null) + { + foreach (var item in bufferQueueGroups) + { + item.Dispose(); + } + bufferQueueGroups = null; + } + this.serverState = ServerState.Disposed; + } + + /// + /// 向默认终结点发送 + /// + /// + /// + /// + public void Send(byte[] buffer, int offset, int length) + { + if (this.DefaultRemotePoint == null) + { + throw new RRQMException("默认终结点为空"); + } + this.SendTo(buffer, offset, length, this.defaultRemotePoint); + } + + /// + /// 向默认终结点发送 + /// + /// + public void Send(byte[] buffer) + { + this.Send(buffer, 0, buffer.Length); + } + + /// + /// 向默认终结点发送 + /// + /// + public void Send(ByteBlock byteBlock) + { + this.Send(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + public virtual void SendAsync(byte[] buffer, int offset, int length) + { + this.SendAsync(buffer, offset, length, this.defaultRemotePoint); + } + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + /// + /// + /// + public virtual void SendAsync(byte[] buffer, int offset, int length, EndPoint remoteEP) + { + this.mainSocket.BeginSendTo(buffer, offset, length, SocketFlags.None, remoteEP, null, null); + } + + /// + /// IOCP发送 + /// + /// + /// + /// + /// + public virtual void SendAsync(byte[] buffer) + { + this.SendAsync(buffer, 0, buffer.Length); + } + + /// + /// IOCP发送流中的有效数据 + /// + /// + /// + /// + /// + public virtual void SendAsync(ByteBlock byteBlock) + { + this.SendAsync(byteBlock.Buffer, 0, byteBlock.Len); + } + + /// + /// 发送 + /// + /// + /// + /// + /// + public void SendTo(byte[] buffer, int offset, int length, EndPoint remoteEP) + { + this.mainSocket.SendTo(buffer, offset, length, SocketFlags.None, remoteEP); + } + + /// + /// 配置服务 + /// + /// + public void Setup(ServiceConfig serverConfig) + { + this.serverConfig = serverConfig; + this.LoadConfig(this.serverConfig); + } + + /// + /// 通过端口配置 + /// + /// + public void Setup(int port) + { + UdpSessionConfig serverConfig = new UdpSessionConfig(); + serverConfig.ListenIPHosts = new IPHost[] { new IPHost(port) }; + this.Setup(serverConfig); + } + + /// + /// 启动服务 + /// + public void Start() + { + if (this.serverState == ServerState.Disposed) + { + throw new RRQMException("无法重新利用已释放对象"); + } + + bool useBind = (bool)this.serverConfig.GetValue(UdpSessionConfig.UseBindProperty); + + if (useBind) + { + IPHost[] iPHosts = (IPHost[])this.serverConfig.GetValue(ServiceConfig.ListenIPHostsProperty); + + if (iPHosts == null || iPHosts.Length != 1) + { + throw new RRQMException("ListenIPHosts为空或不明确,无法绑定"); + } + switch (this.serverState) + { + case ServerState.None: + { + this.BeginReceive(iPHosts[0]); + BeginThread(); + break; + } + case ServerState.Running: + break; + + case ServerState.Stopped: + { + this.BeginReceive(iPHosts[0]); + break; + } + case ServerState.Disposed: + { + throw new RRQMException("无法再次利用已释放对象"); + } + } + } + else + { + this.mainSocket = new Socket(SocketType.Dgram, ProtocolType.Udp); + } + this.serverState = ServerState.Running; + } + + /// + /// 停止服务器 + /// + public void Stop() + { + if (this.mainSocket != null) + { + this.mainSocket.Dispose(); + } + + this.serverState = ServerState.Stopped; + } + + /// + /// 处理已接收到的数据 + /// + /// + /// + protected abstract void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock); + + /// + /// 加载配置 + /// + /// + protected virtual void LoadConfig(ServiceConfig serverConfig) + { + if (serverConfig == null) + { + throw new RRQMException("配置文件为空"); + } + this.logger = serverConfig.Logger; + this.defaultRemotePoint = (EndPoint)serverConfig.GetValue(UdpSessionConfig.DefaultRemotePointProperty); + this.bufferLength = serverConfig.BufferLength; + this.name = serverConfig.ServerName; + this.separateThreadReceive = (bool)serverConfig.GetValue(UdpSessionConfig.SeparateThreadReceiveProperty); + } + + /// + /// 在Socket初始化对象后,Bind之前调用。 + /// 可用于设置Socket参数。 + /// 父类方法可覆盖。 + /// + /// + protected virtual void PreviewBind(Socket socket) + { + } + + private void BeginReceive(IPHost iPHost) + { + Socket socket = new Socket(iPHost.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + PreviewBind(socket); + socket.Bind(iPHost.EndPoint); + this.MainSocket = socket; + this.ReadIpPort(); + this.recviveEventArg = new SocketAsyncEventArgs(); + this.recviveEventArg.Completed += this.IO_Completed; + ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength); + this.recviveEventArg.UserToken = byteBlock; + this.recviveEventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Buffer.Length); + this.recviveEventArg.RemoteEndPoint = iPHost.EndPoint; + if (!this.MainSocket.ReceiveFromAsync(this.recviveEventArg)) + { + ProcessReceive(this.recviveEventArg); + } + } + + private void BeginThread() + { + bufferQueueGroups = new BufferQueueGroup[serverConfig.ThreadCount]; + for (int i = 0; i < serverConfig.ThreadCount; i++) + { + BufferQueueGroup bufferQueueGroup = new BufferQueueGroup(); + bufferQueueGroups[i] = bufferQueueGroup; + bufferQueueGroup.bytePool = new BytePool(this.serverConfig.BytePoolMaxSize, this.serverConfig.BytePoolMaxBlockSize); + bufferQueueGroup.waitHandleBuffer = new AutoResetEvent(false); + bufferQueueGroup.bufferAndClient = new BufferQueue(); + + if (this.separateThreadReceive) + { + bufferQueueGroup.Thread = new Thread(Handle);//处理用户的消息 + bufferQueueGroup.Thread.IsBackground = true; + bufferQueueGroup.Thread.Name = i + "-Num Handler"; + bufferQueueGroup.Thread.Start(bufferQueueGroup); + } + } + } + + private void Handle(object o) + { + BufferQueueGroup queueGroup = (BufferQueueGroup)o; + while (true) + { + if (disposable) + { + break; + } + ClientBuffer clientBuffer; + if (queueGroup.bufferAndClient.TryDequeue(out clientBuffer)) + { + this.HandleBuffer(clientBuffer.endPoint, clientBuffer.byteBlock); + } + else + { + queueGroup.isWait = true; + queueGroup.waitHandleBuffer.WaitOne(); + } + } + } + + private void HandleBuffer(EndPoint endPoint, ByteBlock byteBlock) + { + try + { + HandleReceivedData(endPoint, byteBlock); + } + catch (Exception e) + { + Logger.Debug(LogType.Error, this, $"在处理数据时发生错误,信息:{e.Message}"); + } + finally + { + byteBlock.Dispose(); + } + } + + private void IO_Completed(object sender, SocketAsyncEventArgs e) + { + if (e.LastOperation == SocketAsyncOperation.ReceiveFrom) + { + ProcessReceive(e); + } + } + + private void ProcessReceive(SocketAsyncEventArgs e) + { + if (!this.disposable) + { + if (e.SocketError == SocketError.Success) + { + ByteBlock byteBlock = (ByteBlock)e.UserToken; + byteBlock.SetLength(e.BytesTransferred); + + BufferQueueGroup queueGroup = this.bufferQueueGroups[++this.recivedCount % this.bufferQueueGroups.Length]; + + if (this.separateThreadReceive) + { + ClientBuffer clientBuffer = new ClientBuffer(); + clientBuffer.endPoint = e.RemoteEndPoint; + clientBuffer.byteBlock = byteBlock; + queueGroup.bufferAndClient.Enqueue(clientBuffer); + + if (queueGroup.isWait) + { + queueGroup.isWait = false; + queueGroup.waitHandleBuffer.Set(); + } + } + else + { + this.HandleBuffer(e.RemoteEndPoint, byteBlock); + } + + ByteBlock newByteBlock = queueGroup.bytePool.GetByteBlock(this.bufferLength); + e.UserToken = newByteBlock; + e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length); + if (!this.mainSocket.ReceiveFromAsync(this.recviveEventArg)) + { + ProcessReceive(e); + } + } + } + } + + private void ReadIpPort() + { + if (MainSocket == null) + { + this.IP = null; + this.Port = -1; + return; + } + + string ipport; + if (MainSocket.Connected && MainSocket.RemoteEndPoint != null) + { + ipport = MainSocket.RemoteEndPoint.ToString(); + } + else if (MainSocket.IsBound && MainSocket.LocalEndPoint != null) + { + ipport = MainSocket.LocalEndPoint.ToString(); + } + else + { + return; + } + + int r = ipport.LastIndexOf(":"); + this.IP = ipport.Substring(0, r); + this.Port = Convert.ToInt32(ipport.Substring(r + 1, ipport.Length - (r + 1))); + } + } +} \ No newline at end of file